cfl_token.cpp
Go to the documentation of this file.
1 /** @file cfl_token.cpp @brief Class Token */
2 
3 /* FAU Discrete Event Systems Library (libfaudes)
4 
5 Copyright (C) 2006 Bernd Opitz
6 Exclusive copyright is granted to Klaus Schmidt
7 
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12 
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
21 
22 
23 #include "cfl_token.h"
24 
25 namespace faudes {
26 
27 
28 // Token::Token()
29 Token::Token(void) :
30  mType(None),
31  mStringValue(""),
32  mOptionValue(""),
33  mIntegerValue(0),
34  mFloatValue(0),
35  mPreceedingSpace(false),
36  mPreceedingNewline(false),
37  mAttributeCount(0)
38 {
39 }
40 
41 // copy construct
42 Token::Token(const Token& rToken) :
43  mType(rToken.mType),
44  mStringValue(rToken.mStringValue),
45  mOptionValue(rToken.mOptionValue),
46  mIntegerValue(rToken.mIntegerValue),
47  mFloatValue(rToken.mFloatValue),
48  mPreceedingSpace(rToken.mPreceedingSpace),
49  mPreceedingNewline(rToken.mPreceedingNewline),
50  mAttributes(rToken.mAttributes),
51  mAttributeCount(rToken.mAttributeCount)
52 {
53 }
54 
55 
56 // assignment
57 Token& Token::operator=(const Token& rToken) {
58  mType=rToken.mType;
59  mStringValue=rToken.mStringValue;
60  mOptionValue=rToken.mOptionValue;
62  mFloatValue=rToken.mFloatValue;
65  mAttributes=rToken.mAttributes;
67  return *this;
68 }
69 
70 // destructor
72 }
73 
74 // Token::SetNone()
75 void Token::SetNone(void ) {
76  mType=None;
77  mStringValue="";
78  mOptionValue="";
79  mIntegerValue=0;
80  mFloatValue=0;
81  mAttributes.clear();
83  mPreceedingSpace=false;
84  mPreceedingNewline=false;
85 }
86 
87 // Token::SetString(str)
88 void Token::SetString(const std::string& rName) {
89  SetNone();
90  mType=String;
91  mStringValue=rName;
92 }
93 
94 // Token::SetBegin(str)
95 void Token::SetBegin(const std::string& rName) {
96  SetNone();
97  mType=Begin;
98  mStringValue=rName;
99 }
100 
101 // Token::SetEnd(str)
102 void Token::SetEnd(const std::string& rName) {
103  SetNone();
104  mType=End;
105  mStringValue=rName;
106 }
107 
108 // Token::SetEmpty(str)
109 void Token::SetEmpty(const std::string& rName) {
110  SetNone();
111  mType=End | Begin;
112  mStringValue=rName;
113 }
114 
115 // Token::SetOption(str)
116 void Token::SetOption(const std::string& rName) {
117  SetNone();
118  mType=Option | String;
119  mStringValue="+"+rName+"+";
120  mOptionValue=rName;
121 }
122 
123 // Token::SetInteger(number)
124 void Token::SetInteger(const Int number) {
125  SetNone();
126  mType=Integer | Number;
127  mIntegerValue=number;
128  mFloatValue=number;
129 }
130 
131 // Token::SetInteger16(number)
132 void Token::SetInteger16(const Int number) {
133  SetNone();
135  mIntegerValue=number;
136  mFloatValue=number;
137 }
138 
139 // Token::SetBoolean(number)
140 void Token::SetBoolean(const Int number) {
141  SetNone();
142  mType= Boolean | Integer | Number;
143  mIntegerValue=number;
144  mFloatValue=number;
145 }
146 
147 // Token::SetFloat(number)
148 void Token::SetFloat(const Float number) {
149  SetNone();
150  mType=Number;
151  mIntegerValue=(Int) number;
152  mFloatValue=number;
153 }
154 
155 // Token::SetBinary
156 void Token::SetBinary(const char* data, std::size_t len) {
157  SetNone();
158  mType=Binary | String;
159  mStringValue.assign(data,len);
160 }
161 
162 
163 // Token::ClrEnd()
164 void Token::ClrEnd(void) {
165  mType&= ~End;
166 }
167 
168 
169 // access integer
171  return(mIntegerValue);
172 }
173 
174 
175 // access float
177  return(mFloatValue);
178 }
179 
180 // access string
181 const std::string& Token::StringValue(void) const {
182  if(mType & Option) return(mOptionValue); // compatibility
183  return(mStringValue);
184 }
185 
186 // access option
187 const std::string& Token::OptionValue(void) const {
188  return(mOptionValue);
189 }
190 
191 // access unique type (depreciated!)
193  if(mType & Begin) return Begin;
194  if(mType & End) return End;
195  if(mType & Integer16) return Integer16;
196  if(mType & Boolean) return Boolean;
197  if(mType & Integer) return Integer;
198  if(mType & Number) return Number;
199  if(mType & Option) return Option;
200  if(mType & Binary) return Binary;
201  if(mType & String) return String;
202  return None;
203 }
204 
205 
206 // test type
207 bool Token::IsNone(void) const {
208  return mType == None;
209 }
210 
211 // test type
212 bool Token::IsInteger(void) const {
213  return mType & Integer;
214 }
215 
216 // test type
217 bool Token::IsInteger16(void) const {
218  return mType & Integer16;
219 }
220 
221 // test type
222 bool Token::IsBoolean(void) const {
223  return mType & Boolean;
224 }
225 
226 // test type
227 bool Token::IsFloat(void) const {
228  return mType & Number;
229 }
230 
231 // test type
232 bool Token::IsOption(void) const {
233  return mType & Option;
234 }
235 
236 // test type
237 bool Token::IsString(void) const {
238  return mType & String;
239 }
240 
241 // test type
242 bool Token::IsBinary(void) const {
243  return mType & Binary;
244 }
245 
246 // test type
247 bool Token::IsBegin(void) const {
248  return mType & Begin;
249 }
250 
251 // test type
252 bool Token::IsBegin(const std::string& tag) const {
253  if(! (mType & Begin) ) return false;
254  return mStringValue==tag;
255 }
256 
257 // test type
258 bool Token::IsEnd(void) const {
259  return mType & End;
260 }
261 
262 // test type
263 bool Token::IsEnd(const std::string& tag) const {
264  if(! (mType & End) ) return false;
265  return mStringValue==tag;
266 }
267 
268 // test type
269 bool Token::IsEmpty(void) const {
270  return (mType & Begin) && (mType & End);
271 }
272 
273 // clear attribute
274 void Token::ClrAttribute(const std::string& name) {
275  aiterator ait=mAttributes.find(name);
276  if(ait==mAttributes.end()) return;
277  mAttributes.erase(ait);
278 }
279 
280 // clear all attributes
282  mAttributes.clear();
283  mAttributeCount=0;
284 }
285 
286 
287 // insert attribute for interpretation
288 void Token::InsAttribute(const std::string& name, const std::string& value) {
289  AttributeValue aval;
290  aval.mStringValue=value;
291  aval.mType=None;
292  aval.mSort=mAttributeCount++;
293  mAttributes[name]=aval;
294 }
295 
296 
297 // insert string attribute
298 void Token::InsAttributeString(const std::string& name, const std::string& value) {
299  AttributeValue aval;
300  aval.mStringValue=value;
301  aval.mType=String;
302  aval.mSort=mAttributeCount++;
303  mAttributes[name]=aval;
304 }
305 
306 // insert integer attribute
307 void Token::InsAttributeInteger(const std::string& name, Int value) {
308  AttributeValue aval;
309  aval.mStringValue=ToStringInteger(value);
310  aval.mType=Number | Integer;
311  aval.mSort=mAttributeCount++;
312  mAttributes[name]=aval;
313 }
314 
315 // insert integer attribute
316 void Token::InsAttributeInteger16(const std::string& name, Int value) {
317  AttributeValue aval;
318  aval.mStringValue=ToStringInteger16(value);
319  aval.mType=Number | Integer;
320  aval.mSort=mAttributeCount++;
321  mAttributes[name]=aval;
322 }
323 
324 // insert integer attribute
325 void Token::InsAttributeBoolean(const std::string& name, Int value) {
326  AttributeValue aval;
327  if(value==0) aval.mStringValue="false";
328  else aval.mStringValue="true";
329  aval.mType=Number | Integer;
330  aval.mSort=mAttributeCount++;
331  mAttributes[name]=aval;
332 }
333 
334 // insert float attribute
335 void Token::InsAttributeFloat(const std::string& name, Float value) {
336  AttributeValue aval;
337  aval.mStringValue=ToStringFloat(value);
338  aval.mType=Number;
339  aval.mSort=mAttributeCount++;
340  mAttributes[name]=aval;
341 }
342 
343 // test attribute type
344 bool Token::ExistsAttributeString(const std::string& name) {
345  aiterator ait=mAttributes.find(name);
346  if(ait==mAttributes.end()) return false;
347  InterpretAttribute(ait);
348  if(ait->second.mType & String) return true;
349  return false;
350 }
351 
352 
353 // test attribute type
354 bool Token::ExistsAttributeInteger(const std::string& name) {
355  aiterator ait=mAttributes.find(name);
356  if(ait==mAttributes.end()) return false;
357  InterpretAttribute(ait);
358  if(ait->second.mType & Integer) return true;
359  return false;
360 }
361 
362 
363 // test attribute type
364 bool Token::ExistsAttributeFloat(const std::string& name) {
365  aiterator ait=mAttributes.find(name);
366  if(ait==mAttributes.end()) return false;
367  InterpretAttribute(ait);
368  if(ait->second.mType & Number) return true;
369  return false;
370 }
371 
372 
373 // access attribute value
374 const std::string& Token::AttributeStringValue(const std::string& name) {
375  static const std::string emptystr="";
376  aiterator ait=mAttributes.find(name);
377  if(ait==mAttributes.end()) return emptystr;
378  InterpretAttribute(ait);
379  if(!(ait->second.mType & String)) return emptystr;
380  return ait->second.mStringValue;
381 }
382 
383 
384 // access attribute value
385 Int Token::AttributeIntegerValue(const std::string& name) {
386  aiterator ait=mAttributes.find(name);
387  if(ait==mAttributes.end()) return 0;
388  InterpretAttribute(ait);
389  if(!(ait->second.mType & Integer)) return 0;
390  return ait->second.mIntegerValue;
391 }
392 
393 
394 // access attribute value
395 Float Token::AttributeFloatValue(const std::string& name) {
396  aiterator ait=mAttributes.find(name);
397  if(ait==mAttributes.end()) return 0;
398  InterpretAttribute(ait);
399  if(!(ait->second.mType & Number)) return 0;
400  return ait->second.mFloatValue;
401 }
402 
403 
404 /*
405 pre 2.18 verbatim
406 
407 // WriteVerbatim(pStream)
408 void Token::WriteVerbatim(std::ostream* pStream, const std::string& rString) {
409  // verb marker candidate
410  std::string verb="__VERBATIM__";
411  // adjust marker
412  while(rString.find(verb)!=std::string::npos) {
413  verb = verb+"#";
414  }
415  // do write
416  *pStream << std::endl;
417  *pStream << verb << std::endl;
418  *pStream << rString;
419  *pStream << verb << std::endl;
420 }
421 */
422 
423 // WriteVerbatim(pStream)
424 void Token::WriteVerbatim(std::ostream* pStream, const std::string& rData) {
425  // format (sligtly nonstandard)
426  *pStream << std::endl;
427  *pStream << "<![CDATA[";
428  *pStream << std::endl;
429  // split up cdata sections
430  std::string esc="]]>";
431  std::size_t pos=0;
432  // loop segments
433  while(pos < rData.size()) {
434  std::size_t next= rData.find(esc,pos);
435  if(next==std::string::npos) next=rData.size()+1;
436  // write segment
437  *pStream << rData.substr(pos,next-pos);
438  // write split
439  if(next<=rData.size())
440  *pStream << "]]]]><![CDATA[>";
441  // proceed
442  pos=next+3;
443  }
444  // format
445  *pStream << std::endl;
446  *pStream << "]]>";
447  *pStream << std::endl;
448 }
449 
450 
451 // ReadVerbatim(pStream, char)
452 // (pre 2.18 compatibility only)
453 int Token::ReadVerbatim(std::istream* pStream){
454  FD_DV("Token::ReadVerbatim()");
455  // clear
456  mStringValue = "";
457  std::string verb="";
458  int lc=0;
459  char c;
460  mPreceedingSpace=false;
461  mPreceedingNewline=false;
462  // figure mark
463  while(*pStream) {
464  // check eof
465  if(pStream->eof()) {mType=None; return -1;};
466  // get one character
467  c = pStream->get();
468  // new line, control and space breaks
469  if(c == '\n') { lc++; break; }
470  if(iscntrl(c)) break;
471  if(isblank(c)) break;
472  // others get appended
473  verb.append(1,c);
474  }
475  // test
476  if(verb.size()<2) return -1;
477  if(verb.at(0) !='_') return -1;
478  if(verb.at(1) !='_') return -1;
479  FD_DV("Token::ReadVerbatim(): mark " << verb);
480  // read until mark
481  while(*pStream) {
482  // check eof
483  if (pStream->eof()) {mType=None; return -1;};
484  // get one character
485  c = pStream->get();
486  // count the next lines
487  if(c == '\n') ++lc;
488  // append anything
489  mStringValue.append(1,c);
490  // if c is _ or #, test for end
491  if(c== verb.at(verb.size()-1)) {
492  std::size_t vpos=mStringValue.find(verb);
493  if(vpos!=std::string::npos) {
494  FD_DV("Token::ReadVerbatim(): done with " << mStringValue);
495  mStringValue = mStringValue.substr(0,vpos);
496  return lc;
497  }
498  }
499  }
500  return lc;
501 }
502 
503 // WriteBinary(pStream,data,len)
504  void Token::WriteBinary(std::ostream* pStream, const char* pData, std::size_t len) {
505 
506  // my encoding (hardcoded in read, however)
507  static char Base64EncodingTable[]=
508  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
509 
510  // start
511  *pStream << "=";
512 
513  // loop vars
514  const char* src = pData;
515  std::size_t cnt=len;
516  int step=0;
517  unsigned char c0=0,c1=0,c2=0,c3=0;
518 
519  // encode and output buffer
520  while(cnt>0) {
521  switch(step) {
522  // collect char for 1st byte
523  case 0:
524  c0= ((*src & 0xFC) >> 2);
525  c1= ((*src & 0x03) << 4);
526  c2=0;
527  c3=0;
528  step=1;
529  break;
530  // collect char for 2nd byte
531  case 1:
532  c1|= ((*src & 0xF0) >> 4);
533  c2|= ((*src & 0x0F) << 2);
534  step=2;
535  break;
536  // collect char for 3rd byte, plus output
537  case 2:
538  c2|= ((*src & 0xC0) >> 6);
539  c3|= (*src & 0x3F);
540  *pStream << Base64EncodingTable[c0] << Base64EncodingTable[c1] <<
541  Base64EncodingTable[c2] << Base64EncodingTable[c3];
542  step=0;
543  break;
544  default: break;
545  }
546  cnt--;
547  src++;
548  }
549  // flush left overs, incl padding
550  switch(step) {
551  case 0:
552  *pStream << "= ";
553  break;
554  case 1:
555  *pStream << Base64EncodingTable[c0] << Base64EncodingTable[c1] << "=== ";
556  break;
557  case 2:
558  *pStream << Base64EncodingTable[c0] << Base64EncodingTable[c1] <<
559  Base64EncodingTable[c2] << "== ";
560  break;
561  }
562 }
563 
564 // WriteBinary(pStream)
565 void Token::WriteBinary(std::ostream* pStream) const {
566  if(mType!=Binary) return;
567  WriteBinary(pStream,mStringValue.data(),mStringValue.size());
568 }
569 
570 
571 // ReadBinary ... to mStringValue
572 int Token::ReadBinary(std::istream* pStream) {
573 
574  // line count
575  int lc;
576 
577  // swallow leading '='
578  char c1=pStream->get();
579  if(c1!='=') return -1;
580 
581  // read as string, excl. marks '='
582  lc=ReadString(pStream,'=');
583 
584  // swallow one trailing '='
585  c1=pStream->get();
586  if(c1!='=') return -1;
587 
588  // take any extra trailing padding =
589  while(!pStream->eof()) {
590  if(pStream->peek()!='=') break;
591  pStream->get();
592  mStringValue.append("=");
593  }
594 
595  // loop vars
596  std::string::iterator src=mStringValue.begin();
597  std::string::iterator dst=mStringValue.begin();
598  std::size_t cnt=0;
599  int c=0, d0=0, d1=0, d2=0;
600  unsigned char cs[4];
601  unsigned int step=0;
602 
603  // loop
604  while(true) {
605 
606  // get data
607  while(true) {
608  // sense eof
609  if(src==mStringValue.end()) { c = -1; break; }
610  // get char
611  c=*(src++);
612  // decode
613  if(c>='A' && c <='Z') { c-='A'; break; }
614  if(c>='a' && c <='z') { c-='a'; c+= ('Z'-'A')+1; break; }
615  if(c>='0' && c <='9') { c-='0'; c+= 2*('Z'-'A')+2; break; }
616  if(c=='+') {c= 62; break; }
617  if(c=='/') {c= 63; break; }
618  if(c=='=') {c= 0xFF; break; };
619  }
620  // pass on eof
621  if(c== -1) break;
622  // record and continue
623  cs[step++] = c;
624  if(step<=3) continue;
625  step=0;
626  // sort bits
627  d0= ((cs[0] << 2) & 0xFC) | ((cs[1] >> 4) & 0x03);
628  d1= ((cs[1] << 4) & 0xF0) | ((cs[2] >> 2) & 0x0F);
629  d2= ((cs[2] << 6) & 0xC0) | (cs[3] & 0x3F);
630  // record result
631  if(cs[0]!= 0xFF && cs[1]!=0xFF) {*(dst++)=d0; cnt++;}
632  if(cs[1]!= 0xFF && cs[2]!=0xFF) {*(dst++)=d1; cnt++;}
633  if(cs[2]!= 0xFF && cs[3]!=0xFF) {*(dst++)=d2; cnt++;}
634  // sense end
635  if(cs[3]==0xFF) break;
636  }
637 
638  // set data length (sets the length incl termination char??)
639  mStringValue.resize(cnt);
640 
641  // return padding error or line count
642  return step==0 ? lc : -1;
643 }
644 
645 
646 
647 // ReadSpace(pStream)
648 int Token::ReadSpace(std::istream* pStream){
649  char c = '\0';
650  int lc = 0;
651  FD_DV("Token::ReadSpace()");
652  // check the whole pStream
653  while(*pStream) {
654  while(*pStream) {
655  // check eof
656  if (pStream->eof()) return lc;
657  // look one character ahead
658  c = pStream->peek();
659  // count the next lines
660  if(c == '\n') {
661  ++lc;
662  mPreceedingSpace=true;
663  mPreceedingNewline=true;
664  pStream->get();
665  continue;
666  }
667  // swallow controls
668  if(iscntrl(c)) {
669  mPreceedingSpace=true;
670  pStream->get();
671  continue;
672  }
673  // swallow space
674  if(isspace(c)) {
675  mPreceedingSpace=true;
676  pStream->get();
677  continue;
678  }
679  // break
680  break;
681  }
682  // if the next charakter starts a faudes comment
683  if(c != '%') break;
684  while (*pStream) {
685  // check eof
686  if (pStream->eof()) {return(lc);};
687  // get the next character
688  c = pStream->get();
689  mPreceedingSpace=true;
690  mPreceedingNewline=true;
691  // count the next lines
692  if (c == '\n') ++lc;
693  // terminate with the next new line character
694  if (c == '\n') break;
695  if (c == '\r') break;
696  }
697  }
698  // termination if the next character is neither a space, a control, or a '%'.
699  FD_DV("Token::ReadSpace(): lc " << lc);
700  return lc;
701 }
702 
703 // InterpretAttribute(aval)
705  if(ait->second.mType != None) return;
707  ait->second.mStringValue, ait->second.mType,
708  ait->second.mIntegerValue, ait->second.mFloatValue);
709  ait->second.mType |= String;
710 }
711 
712 // InterpretNumber(string)
715 }
716 
717 // InterpretNumber(string, ...)
718 bool Token::InterpretNumber(const std::string& numstr, int& type, Int& ival, Float& fval) {
719  char c, vc;
720  Float fv=0;
721  Int iv=0;
722  int comma = -1;
723  bool minus = false;
724  int base=10;
725  bool ok=false;
726  int cnt=0;
727  type &= ~(Integer | Integer16 | Number);
728  // test for special cases
729  if(numstr=="inf" || numstr=="+inf") {
730  ival = std::numeric_limits<Int>::max();
731  fval = ival;
732  type|= (Integer | Number );
733  return true;
734  }
735  // test for special casess
736  if(numstr=="-inf") {
737  ival=std::numeric_limits<Int>::min()+1;
738  fval=ival;
739  type|= (Integer | Number);
740  return true;
741  }
742  // test for special cases
743  if(numstr=="true" || numstr=="True") {
744  ival = 1;
745  fval = ival;
746  type|= (Integer | Boolean);
747  return true;
748  }
749  // test for special cases
750  if(numstr=="false" || numstr=="False") {
751  ival = 0;
752  fval = ival;
753  type|= (Integer | Boolean);
754  return true;
755  }
756  // iterate over string
757  std::string::const_iterator cit=numstr.begin();
758  for(;cit!=numstr.end(); cit++) {
759  // check next charakter
760  c = *cit;
761  cnt++;
762  // change base on x
763  if(c=='x' && iv==0 && cnt==2 && comma<0 && !minus)
764  {base = 16; continue;}
765  // change sign on -
766  if(c=='-' && cnt==1)
767  {minus = true; continue;}
768  // record comma
769  if(c=='.' && comma<0 && base==10)
770  {comma = 0; continue;}
771  // break if it is not a digit
772  if(!isdigit(c) && base==10) break;
773  if(!isxdigit(c) && base==16) break;
774  // compute the value of c
775  vc=0;
776  if(c>='0' && c<= '9') vc = c-'0';
777  else if(c>='a' && c<= 'f') vc = c-'a' + 10;
778  else if(c>='A' && c<= 'F') vc = c-'A' + 10;
779  // compute the corresponding number
780  iv = base * iv + vc;
781  fv = base * fv + vc;
782  if(comma>=0) comma++;
783  ok = true;
784  }
785  // detect error
786  if(cit!=numstr.end()) ok=false;
787  // fix sign
788  if(minus) {
789  iv=-iv;
790  fv=-fv;
791  }
792  // fix decimal point
793  for(;comma>0;comma--) {
794  iv/=base;
795  fv/=base;
796  }
797  // assign the numeric value and type in Token
798  if(ok) {
799  ival = iv;
800  fval = fv;
801  type |= Number;
802  if(comma<=0 && !minus) type |= Integer;
803  if(comma<=0 && !minus && base==16) type |= Integer16;
804  }
805  return ok;
806 }
807 
808 // Write(pStream)
809 void Token::Write(std::ostream* pStream) const {
810  FD_DV("Token::Write: mType=" << (int) mType
811  << "\" mStringValue=\"" << mStringValue
812  << "\" mIntegerValue=" <<mIntegerValue
813  << "\" mFloatValue=" <<mFloatValue <<"\n");
814  // preceeding space and newline
815  if(mPreceedingSpace) *pStream << " ";
816  if(mPreceedingNewline) *pStream << std::endl;
817  // numerics first
818  if(mType & Integer16) {
820  } else if(mType & Integer) {
822  } else if(mType & Number) {
823  *pStream << ExpandString(ToStringFloat(mFloatValue), FD_NAMELEN) << " ";
824  }
825  // mark up: begin
826  else if(mType & Begin) {
827  *pStream << '<' << mStringValue;
828  std::map<int,caiterator> sortnames;
829  for(caiterator ait=mAttributes.begin(); ait!=mAttributes.end(); ait++)
830  sortnames[ait->second.mSort]=ait;
831  std::map<int,caiterator>::iterator sit;
832  for(sit=sortnames.begin(); sit!=sortnames.end(); sit++) {
833  caiterator ait=sit->second;
834  *pStream << " ";
835  WriteEscapedString(pStream,ait->first);
836  *pStream << "=\"";
837  WriteEscapedString(pStream,ait->second.mStringValue);
838  *pStream << "\"";
839  }
840  if(mType & End) *pStream << "/";
841  *pStream << ">";
842  }
843  // mark up:end
844  else if(mType & End) {
845  *pStream << "</" << mStringValue << ">";
846  }
847  // cdata markup
848  else if(mType & Cdata) {
849  WriteVerbatim(pStream,mStringValue);
850  }
851  // string
852  else if(mType & Option) {
853  WriteString(pStream,""); // '+' is incl. mStringValue
854  } else if(mType & Binary) {
855  WriteBinary(pStream);
856  } else if(mType & String) {
857  // figure delimiter
858  bool quote=false;
859  if(mStringValue.size()==0) quote=true;
860  if(mStringValue.size()>0)
861  if(!isalpha(mStringValue[0])) quote=true;
862  static const std::string white=" \n\r\t\f";
863  if(mStringValue.find_first_of(white)!=std::string::npos)
864  quote=true;
865  if(quote)
866  WriteString(pStream,"\"");
867  else
868  WriteString(pStream,"");
869  }
870  // error (should we have an exception here?)
871  else { /* assert(0) */ };
872 }
873 
874 // WriteEscapedString(pStream)
875 int Token::WriteEscapedString(std::ostream* pStream, const std::string& outstr) {
876  // assemble escape character string
877  std::string escstr="<>&\"";
878  // no escape characters
879  if(outstr.find_first_of(escstr)==std::string::npos) {
880  *pStream << outstr;
881  return outstr.size();
882  }
883  // do escape substitution
884  int cc=0;
885  std::string::const_iterator cit=outstr.begin();
886  for(;cit!=outstr.end(); cit++) {
887  if(*cit=='<')
888  { *pStream << "&lt;"; cc+=4; continue;}
889  if(*cit=='>')
890  { *pStream << "&gt;"; cc+=4; continue;}
891  if(*cit=='&')
892  { *pStream << "&amp;"; cc+=5; continue;}
893  if(*cit=='"')
894  { *pStream << "&quot;"; cc+=6; continue;}
895  *pStream << *cit; cc++;
896  }
897  return cc;
898 }
899 
900 // WriteString(pStream, delim)
901 void Token::WriteString(std::ostream* pStream, const std::string& delim) const {
902  int cc=0;
903  *pStream << delim;
904  cc+=delim.size();
905  cc+=WriteEscapedString(pStream,mStringValue);
906  *pStream << delim << " ";
907  cc+=delim.size()+1;
908  while(cc< FD_NAMELEN) {
909  *pStream << " "; cc++;
910  }
911 }
912 
913 // ReadString(pStream, char)
914 int Token::ReadString(std::istream* pStream, char stop) {
915  int ll= ReadEscapedString(pStream,stop,mStringValue);
916  if(ll<0) mType=None;
917  return ll;
918 }
919 
920 
921 // ReadEscapedString(pStream, rString, char)
922 int Token::ReadEscapedString(std::istream* pStream, char stop, std::string& rString) {
923  int lc=0;
924  char c;
925  std::string entref="";
926  bool ctrlblank = false;
927  rString = "";
928  // check the whole pStream
929  while (*pStream) {
930  // check eof
931  if(pStream->eof()) return -1;
932  // test one character
933  c = pStream->peek();
934  // break on mark up
935  if(c == '<') break;
936  if(c == '>') break;
937  // break on stop
938  if(c == stop) break;
939  if(isblank(c) && stop==' ') break;
940  if(iscntrl(c) && stop==' ') break;
941  // get one character
942  c = pStream->get();
943  // count the next lines
944  if(c=='\n') ++lc;
945  // replace sequence of control characters by one blanc
946  if(iscntrl(c) && ctrlblank) continue;
947  ctrlblank=false;
948  if(iscntrl(c)) { c=' '; ctrlblank=true;}
949  // if in escape mode ...
950  if(entref.size()!=0) {
951  //record reference
952  entref.append(1,c);
953  // error: reference must not contain a white space
954  if(c == ' ') return -1;
955  // decode reference
956  if(c == ';') {
957  if(entref=="&amp;") rString.append(1,'&');
958  else if(entref=="&quot;") rString.append(1,'"');
959  else if(entref=="&apos;") rString.append(1,'\'');
960  else if(entref=="&lt;") rString.append(1,'<');
961  else if(entref=="&gt;") rString.append(1,'>');
962  // plain copy unknown
963  else rString.append(entref);
964  entref="";
965  }
966  continue;
967  }
968  // ... sense escape
969  if(c == '&') entref.append(1,c);
970  // ... add character
971  if(c != '&') rString.append(1,c);
972  continue;
973  }
974  // space seperated string must be nontrivial
975  if(stop==' ' && rString.size()==0) return -1;
976  // ok
977  return lc;
978 }
979 
980 
981 // ReadCharacterDate(pStream, rString)
982 int Token::ReadCharacterData(std::istream* pStream, std::string& rString) {
983  int lc=0;
984  char c;
985  std::string entref="";
986  rString = "";
987  // check the whole pStream
988  while (*pStream) {
989  // break on eof
990  if(pStream->eof()) break;
991  // check other errors
992  if(!pStream->good()) return -1;
993  // test one character
994  c = pStream->peek();
995  // break on mark up
996  if(c == '<') break;
997  // again: test state
998  if(pStream->eof()) break;
999  if(!pStream->good()) return -1;
1000  // get one character
1001  c = pStream->get();
1002  // count the next lines
1003  if(c=='\n') ++lc;
1004  // ... add character
1005  rString.append(1,c);
1006  }
1007  return lc;
1008 }
1009 
1010 
1011 // ReadAttributes(pStream)
1012 // (and swallow all space after the last attribute)
1013 int Token::ReadAttributes(std::istream* pStream) {
1014  int lc=0;
1015  char c=0;
1016  FD_DV("Token::ReadAttributes()");
1017  // scan until excl. '>'
1018  while (*pStream) {
1019  // skip space
1020  while (*pStream) {
1021  if(pStream->eof()) return -1;
1022  c = pStream->peek();
1023  if(!(isblank(c) || iscntrl(c))) break;
1024  pStream->get();
1025  if(c=='\n') ++lc;
1026  }
1027  // get attrname
1028  std::string aname;
1029  while (*pStream) {
1030  if(pStream->eof()) return -1;
1031  c = pStream->peek();
1032  if(isblank(c) || iscntrl(c)) break;
1033  if(c=='=') break;
1034  if(c=='>') break;
1035  if(c=='/') break;
1036  pStream->get();
1037  aname.append(1,c);
1038  }
1039  FD_DV("Token::ReadAttributes(): aname " << aname);
1040  // no name so we're done
1041  if(aname.size()==0) {
1042  return lc;
1043  }
1044  // skip space
1045  while(*pStream) {
1046  if(pStream->eof()) return -1;
1047  c = pStream->peek();
1048  if(!(isblank(c) || iscntrl(c))) break;
1049  pStream->get();
1050  if(c=='\n') ++lc;
1051  }
1052  // insist in eq
1053  if(c!='=') return -1;
1054  pStream->get();
1055  // skip space
1056  while (*pStream) {
1057  if(pStream->eof()) return -1;
1058  c = pStream->peek();
1059  if(!(isblank(c) || iscntrl(c))) break;
1060  pStream->get();
1061  if(c=='\n') ++lc;
1062  }
1063  // strict version, value by '"'
1064  if(c == '"') {
1065  pStream->get();
1066  int ll=ReadString(pStream,'"');
1067  if(ll<0) return -1;
1068  pStream->get();
1069  lc+=ll;
1070  }
1071  // relaxed version, value by "space"
1072  else {
1073  int ll=ReadString(pStream,' ');
1074  if(ll<0) return -1;
1075  lc+=ll;
1076  }
1077  std::string aval=mStringValue;
1078  FD_DV("Token::ReadAttributes(): aval " << aval);
1079  // record attribute
1080  InsAttribute(aname,aval);
1081  }
1082  // done
1083  return lc;
1084 }
1085 
1086 // ReadMarkup(pStream)
1087 // (leading "<" has allready been read)
1088 int Token::ReadMarkup(std::istream* pStream) {
1089  int lc=0;
1090  int ll;
1091  char c=0;
1092  mStringValue = "";
1093  mType=None;
1094  // figure indicator character
1095  char p1=0;
1096  char p2=0;
1097  if(pStream->eof()) return -1;
1098  c = pStream->peek();
1099  if(!(isalpha(c) || c=='_' || c==':')) {
1100  p1 = pStream->get();
1101  if(pStream->eof()) return -1;
1102  p2 = pStream->peek();
1103  }
1104  FD_DV("Token::ReadMarkup: " << c << "-" << p1 << "-" << p2);
1105  // its a begin tag ...
1106  if(p1==0) {
1107  FD_DV("Token::ReadMarkup: sensed XML tag");
1108  // ... get the name
1109  std::string name;
1110  while (*pStream) {
1111  if(pStream->eof()) return -1;
1112  c = pStream->peek();
1113  if(c == '>') break;
1114  if(c == '/') break;
1115  if(isblank(c) || iscntrl(c)) break;
1116  pStream->get();
1117  name.append(1,c);
1118  }
1119  if(name.size()==0) return -1;
1120  mType = Begin;
1121  ll=ReadAttributes(pStream);
1122  if(ll<0) return -1;
1123  if(pStream->eof()) return -1;
1124  c = pStream->peek();
1125  if(c=='/') mType |= End;
1126  lc+=ll;
1127  mStringValue=name;
1128  FD_DV("Token::ReadMarkup: sensed XML tag, type " << mType << " name " << mStringValue);
1129  }
1130  // its an end tag: get the name
1131  if(p1=='/') {
1132  std::string name;
1133  while(*pStream) {
1134  if(pStream->eof()) return -1;
1135  c = pStream->peek();
1136  if(c == '>') break;
1137  if(c == '/') break;
1138  if(isblank(c) || iscntrl(c)) break;
1139  pStream->get();
1140  name.append(1,c);
1141  }
1142  if(name.size()==0) return -1;
1143  if(c!='>') return -1;
1144  mType = End;
1145  mStringValue=name;
1146  }
1147  // its an xml comment
1148  if(p1=='!' && p2=='-') {
1149  FD_DV("Token::ReadMarkup: sensed XML comment <" << p1 << p2);
1150  c=pStream->get();
1151  if(pStream->eof()) return -1;
1152  c=pStream->get();
1153  if(c!='-') return -1;
1154  char c2=0;
1155  char c3=0;
1156  while (*pStream) {
1157  c3=c2; c2=c;
1158  if(pStream->eof()) return -1;
1159  c = pStream->peek();
1160  if(c3== '-' && c2=='-' && c == '>') break;
1161  pStream->get();
1162  if(c=='\n') ++lc;
1163  }
1164  FD_DV("Token::ReadMarkup: sensed XML comment end " << c3 << c2 << c);
1165  }
1166  // its an xml doctypedec (which we cannot handle properly)
1167  if(p1=='!' && (p2=='D' || p2=='d')) {
1168  FD_DV("Token::ReadMarkup doc.type.dec. not implemented (!)");
1169  c=pStream->get();
1170  while(*pStream) {
1171  if(pStream->eof()) return -1;
1172  c = pStream->peek();
1173  if(c == '>') break;
1174  pStream->get();
1175  if(c=='\n') ++lc;
1176  }
1177  }
1178  // its an xml cdata (interpret as string)
1179  if(p1=='!' && p2=='[' ) {
1180  FD_DV("Token::ReadMarkup: sense CDATA?");
1181  // sense "<![CDATA["
1182  c=pStream->get();
1183  if(pStream->eof()) return -1;
1184  if(pStream->get()!='C') return -1;
1185  if(pStream->eof()) return -1;
1186  if(pStream->get()!='D') return -1;
1187  if(pStream->eof()) return -1;
1188  if(pStream->get()!='A') return -1;
1189  if(pStream->eof()) return -1;
1190  if(pStream->get()!='T') return -1;
1191  if(pStream->eof()) return -1;
1192  if(pStream->get()!='A') return -1;
1193  if(pStream->eof()) return -1;
1194  if(pStream->get()!='[') return -1;
1195  // read until "]]>"
1196  FD_DV("Token::ReadMarkup: sense CDATA!");
1197  char c2=0;
1198  char c3=0;
1199  while(*pStream) {
1200  c3=c2; c2=c;
1201  if(pStream->eof()) return -1;
1202  c = pStream->peek();
1203  if(c3== ']' && c2==']' && c == '>') break;
1204  if(pStream->eof()) return -1;
1205  pStream->get();
1206  if(c=='\n') ++lc;
1207  mStringValue.append(1,c);
1208  }
1209  FD_DV("Token::ReadMarkup: sense CDATA:" << mStringValue);
1210  // drop "]]"
1211  if(mStringValue.size()>=2)
1212  mStringValue.erase(mStringValue.size()-2);
1213  // drop leading endl
1214  if(mStringValue.size()>=2)
1215  if(mStringValue.at(0)=='\r')
1216  if(mStringValue.at(1)=='\n')
1217  mStringValue=mStringValue.substr(2);
1218  if(mStringValue.size()>=1)
1219  if(mStringValue.at(0)=='\n')
1220  mStringValue=mStringValue.substr(1);
1221  // drop tailing endl
1222  if(mStringValue.size()>=1)
1223  if(mStringValue.at(mStringValue.size()-1)=='\n')
1224  mStringValue=mStringValue.substr(0,mStringValue.size()-1);
1225  if(mStringValue.size()>=1)
1226  if(mStringValue.at(mStringValue.size()-1)=='\r')
1227  mStringValue=mStringValue.substr(0,mStringValue.size()-1);
1228  mType |= String;
1229  mType |= Cdata;
1230  FD_DV("Token::ReadMarkup: sense CDATA:" << mStringValue);
1231  }
1232  // its an xml proc.intstruction (which we ignore)
1233  if(p1=='?') {
1234  if(pStream->eof()) return -1;
1235  c = pStream->get();
1236  char c2=0;
1237  while (*pStream) {
1238  c2=c;
1239  if(pStream->eof()) return -1;
1240  c = pStream->peek();
1241  if(c2=='?' && c == '>') break;
1242  pStream->get();
1243  if(c=='\n') ++lc;
1244  }
1245  }
1246  // error
1247  if(pStream->eof()) return -1;
1248  c = pStream->peek();
1249  if(c!='>') {
1250  FD_DV("Token::ReadMarkup: mismatch (?) " << mStringValue);
1251  while (*pStream) {
1252  if(pStream->eof()) return -1;
1253  c = pStream->peek();
1254  if(c == '>') break;
1255  if(c=='\n') ++lc;
1256  pStream->get();
1257  }
1258  }
1259  // done
1260  pStream->get();
1261  FD_DV("Token::ReadMarkup: return type " << mType << " string " << mStringValue << " lc" << lc);
1262  return lc;
1263 }
1264 
1265 // Read(pStream)
1266 int Token::Read(std::istream* pStream){
1267  char c1;
1268  int lc = 0;
1269  int ll;
1270  // the token is initialized with the type "None"
1271  SetNone();
1272  // check eof
1273  if(pStream->eof()) return(lc);
1274  // read all spaces in the pStream
1275  lc += ReadSpace(pStream);
1276  // check eof
1277  if(pStream->eof()) return(lc);
1278  // get the first useful character
1279  c1=pStream->peek();
1280  // token is a quoted string if it starts with '"'
1281  if(c1 == '"') {
1282  pStream->get();
1283  // read the string until '"'
1284  ll=ReadString(pStream,'"');
1285  if(ll>=0) {
1286  lc+=ll;
1287  pStream->get();
1288  mType |= String;
1289  }
1290  }
1291  // token is a quoted string if it starts with '''
1292  else if(c1 == '\'') {
1293  pStream->get();
1294  // read the string until '''
1295  ll=ReadString(pStream,'\'');
1296  if(ll>=0) {
1297  lc+=ll;
1298  pStream->get();
1299  mType |= String;
1300  }
1301  }
1302  // token is an option string if it starts with '+'
1303  else if(c1 == '+') {
1304  pStream->get();
1305  // read the string until '+'
1306  ll=ReadString(pStream,'+');
1308  mStringValue="+" + mOptionValue + "+";
1309  if(ll>=0) {
1310  lc+=ll;
1311  pStream->get();
1312  mType |= (Option | String);
1313  }
1314  }
1315  // token is a binary string if it starts with '='
1316  else if(c1 == '=') {
1317  // read the string until '=', incl padding
1318  ll=ReadBinary(pStream);
1319  if(ll>=0) lc+=ll;
1320  if(ll>=0) mType |= (Binary | String);
1321  }
1322  // token is a verbatim string if it starts with '_'
1323  else if(c1 == '_') {
1324  // read the string until the corresponding end marker (2.18 compatibility)
1325  ll=ReadVerbatim(pStream);
1326  if(ll>=0) lc+=ll;
1327  if(ll>=0) mType = String;
1328  }
1329  // token is markup if it starts with <
1330  else if(c1 == '<') {
1331  pStream->get();
1332  // check eof
1333  if(pStream->eof()) return(lc);
1334  // read and interpret
1335  ll=ReadMarkup(pStream);
1336  if(ll>=0) lc+=ll;
1337  // if this is not a faudes token, get the next
1338  if(mType==None && ll>=0) {
1339  ll=Read(pStream);
1340  if(ll>=0) lc+=ll;
1341  else mType=None;
1342  }
1343  // error
1344  if(ll<0) return -1;
1345  }
1346  // token is a space seperated string, perhaps a number
1347  else {
1348  if(ReadString(pStream,' ')>=0) {
1349  // pStream->get(); 20101218: dont get the seperator, could be "<" of starting markup
1350  mType |= String;
1351  InterpretNumber();
1352  }
1353  }
1354  // report result
1355  FD_DV("Token::Read: " << Str());
1356  return(lc);
1357 }
1358 
1359 
1360 // Str()
1361 std::string Token::Str(void) const {
1362  std::stringstream ostr;
1363  ostr << "Token( Type=";
1364  if(IsNone()) { ostr << "None)"; return ostr.str();}
1365  if(IsInteger()) ostr << "Integer";
1366  if(IsInteger16()) ostr << "Integer16";
1367  if(IsBoolean()) ostr << "Boolean";
1368  if(IsFloat()) ostr << "Float";
1369  if(IsString()) ostr << "String";
1370  if(IsBegin()) ostr << "Begin";
1371  if(IsEnd()) ostr << "End";
1372  ostr << " Value=\"";
1373  if(IsFloat()) ostr << FloatValue();
1374  else if(IsBegin() || IsEnd()) ostr << StringValue();
1375  else if(IsString()) ostr << StringValue();
1376  ostr << "\"";
1377  caiterator ait;
1378  for(ait=mAttributes.begin(); ait!=mAttributes.end(); ait++)
1379  ostr << " attr[" << ait->first << "=\"" << ait->second.mStringValue << "\"]";
1380  ostr << " spacing=" << mPreceedingSpace << "/"<< mPreceedingNewline;
1381  ostr << ")";
1382  return ostr.str();
1383 }
1384 
1385 
1386 
1387 } // namespace faudes

libFAUDES 2.24g --- 2014.09.15 --- c++ api documentaion by doxygen