ISstream.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "ISstream.H"
27 #include "int.H"
28 #include "token.H"
29 #include <cctype>
30 
31 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
32 
34 {
35  char c = 0;
36 
37  while (true)
38  {
39  // Get next non-whitespace character
40  while (get(c) && isspace(c))
41  {}
42 
43  // Return if stream is bad - ie, previous get() failed
44  if (bad() || isspace(c))
45  {
46  break;
47  }
48 
49  // Is this the start of a C/C++ comment?
50  if (c == '/')
51  {
52  if (!get(c))
53  {
54  // cannot get another character - return this one
55  return '/';
56  }
57 
58  if (c == '/')
59  {
60  // C++ style single-line comment - skip through past end-of-line
61  while (get(c) && c != '\n')
62  {}
63  }
64  else if (c == '*')
65  {
66  // within a C-style comment
67  while (true)
68  {
69  // search for end of C-style comment - '*/'
70  if (get(c) && c == '*')
71  {
72  if (get(c))
73  {
74  if (c == '/')
75  {
76  // matched '*/'
77  break;
78  }
79  else if (c == '*')
80  {
81  // check again
82  putback(c);
83  }
84  }
85  }
86 
87  if (!good())
88  {
89  return 0;
90  }
91  }
92  }
93  else
94  {
95  // The '/' did not start a C/C++ comment - return it
96  putback(c);
97  return '/';
98  }
99  }
100  else
101  {
102  // a valid character - return it
103  return c;
104  }
105  }
106 
107  return 0;
108 }
109 
110 
112 {
113  word* wPtr = new word;
114 
115  if (read(*wPtr).bad())
116  {
117  delete wPtr;
118  t.setBad();
119  }
120  else if (token::compound::isCompound(*wPtr))
121  {
122  t = token::compound::New(*wPtr, *this).ptr();
123  delete wPtr;
124  }
125  else
126  {
127  t = wPtr;
128  }
129 }
130 
131 
133 {
134  static const int maxLen = 128;
135  static char buf[maxLen];
136 
137  // Return the put back token if it exists
138  if (Istream::getBack(t))
139  {
140  return *this;
141  }
142 
143  // Assume that the streams supplied are in working order.
144  // Lines are counted by '\n'
145 
146  // Get next 'valid character': i.e. proceed through any whitespace
147  // and/or comments until a semantically valid character is found
148 
149  char c = nextValid();
150 
151  // Set the line number of this token to the current stream line number
152  t.lineNumber() = lineNumber();
153 
154  // return on error
155  if (!c)
156  {
157  t.setBad();
158  return *this;
159  }
160 
161  // Analyse input starting with this character.
162  switch (c)
163  {
164  // Check for punctuation first
165 
166  case token::END_STATEMENT :
167  case token::BEGIN_LIST :
168  case token::END_LIST :
169  case token::BEGIN_SQR :
170  case token::END_SQR :
171  case token::BEGIN_BLOCK :
172  case token::END_BLOCK :
173  case token::COLON :
174  case token::COMMA :
175  case token::ASSIGN :
176  case token::ADD :
177  // NB: token::SUBTRACT handled later as the possible start of a Number
178  case token::MULTIPLY :
179  case token::DIVIDE :
180  {
182  return *this;
183  }
184 
185 
186  // String: enclosed by double quotes.
187  case token::BEGIN_STRING :
188  {
189  putback(c);
190  string* sPtr = new string;
191 
192  if (read(*sPtr).bad())
193  {
194  delete sPtr;
195  t.setBad();
196  }
197  else
198  {
199  t = sPtr;
200  }
201 
202  return *this;
203  }
204  // Possible verbatim string or dictionary functionEntry
205  case token::HASH :
206  {
207  char nextC;
208  if (read(nextC).bad())
209  {
210  // Return hash as word
211  t = token(word(c));
212  return *this;
213  }
214  else if (nextC == token::BEGIN_BLOCK)
215  {
216  // Verbatim string
217  string* sPtr = new string;
218 
219  if (readVerbatim(*sPtr).bad())
220  {
221  delete sPtr;
222  t.setBad();
223  }
224  else
225  {
226  t = sPtr;
228  }
229 
230  return *this;
231  }
232  else
233  {
234  // Word beginning with #
235  putback(nextC);
236  putback(c);
237 
238  readWordToken(t);
239 
240  return *this;
241  }
242  }
243 
244  case '$':
245  {
246  // Look ahead
247  char nextC;
248  if (read(nextC).bad())
249  {
250  // Return $ as word
251  t = token(word(c));
252  return *this;
253  }
254  else if (nextC == token::BEGIN_BLOCK)
255  {
256  putback(nextC);
257  putback(c);
258 
259  string* sPtr = new string;
260 
261  if (readVariable(*sPtr).bad())
262  {
263  delete sPtr;
264  t.setBad();
265  }
266  else
267  {
268  t = sPtr;
269  t.type() = token::VARIABLE;
270  }
271  return *this;
272  }
273  else
274  {
275  putback(nextC);
276  putback(c);
277  readWordToken(t);
278  return *this;
279  }
280  }
281 
282  // Number: integer or floating point
283  //
284  // ideally match the equivalent of this regular expression
285  //
286  // /[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)([Ee][-+]?[0-9]+)?/
287  //
288  case '-' :
289  case '.' :
290  case '0' : case '1' : case '2' : case '3' : case '4' :
291  case '5' : case '6' : case '7' : case '8' : case '9' :
292  {
293  bool asLabel = (c != '.');
294 
295  int nChar = 0;
296  buf[nChar++] = c;
297 
298  // get everything that could resemble a number and let
299  // readScalar determine the validity
300  while
301  (
302  is_.get(c)
303  && (
304  isdigit(c)
305  || c == '+'
306  || c == '-'
307  || c == '.'
308  || c == 'E'
309  || c == 'e'
310  )
311  )
312  {
313  if (asLabel)
314  {
315  asLabel = isdigit(c);
316  }
317 
318  buf[nChar++] = c;
319  if (nChar == maxLen)
320  {
321  // runaway argument - avoid buffer overflow
322  buf[maxLen-1] = '\0';
323 
325  << "number '" << buf << "...'\n"
326  << " is too long (max. " << maxLen << " characters)"
327  << exit(FatalIOError);
328 
329  t.setBad();
330  return *this;
331  }
332  }
333  buf[nChar] = '\0';
334 
335  setState(is_.rdstate());
336  if (is_.bad())
337  {
338  t.setBad();
339  }
340  else
341  {
342  is_.putback(c);
343 
344  if (nChar == 1 && buf[0] == '-')
345  {
346  // a single '-' is punctuation
348  }
349  else
350  {
351  if (asLabel)
352  {
353  label labelVal = 0;
354  if (Foam::read(buf, labelVal))
355  {
356  t = labelVal;
357  }
358  else
359  {
360  // Maybe too big? Try as scalar
361  scalar scalarVal;
362  if (readScalar(buf, scalarVal))
363  {
364  t = scalarVal;
365  }
366  else
367  {
368  t.setBad();
369  }
370  }
371  }
372  else
373  {
374  scalar scalarVal;
375  if (readScalar(buf, scalarVal))
376  {
377  t = scalarVal;
378  }
379  else
380  {
381  t.setBad();
382  }
383  }
384  }
385  }
386 
387  return *this;
388  }
389 
390 
391  // Should be a word (which can also be a single character)
392  default:
393  {
394  putback(c);
395  readWordToken(t);
396 
397  return *this;
398  }
399  }
400 }
401 
402 
404 {
405  c = nextValid();
406  return *this;
407 }
408 
409 
411 {
412  static const int maxLen = 1024;
413  static const int errLen = 80; // truncate error message for readability
414  static char buf[maxLen];
415 
416  int nChar = 0;
417  int listDepth = 0;
418  char c;
419 
420  while (get(c) && word::valid(c))
421  {
422  if (c == token::BEGIN_LIST)
423  {
424  listDepth++;
425  }
426  else if (c == token::END_LIST)
427  {
428  if (listDepth)
429  {
430  listDepth--;
431  }
432  else
433  {
434  break;
435  }
436  }
437 
438  buf[nChar++] = c;
439  if (nChar == maxLen)
440  {
441  buf[errLen] = '\0';
442 
444  << "word '" << buf << "...'\n"
445  << " is too long (max. " << maxLen << " characters)"
446  << exit(FatalIOError);
447 
448  return *this;
449  }
450  }
451 
452  // we could probably skip this check
453  if (bad())
454  {
455  buf[errLen] = buf[nChar] = '\0';
456 
458  << "problem while reading word '" << buf << "...' after "
459  << nChar << " characters\n"
460  << exit(FatalIOError);
461 
462  return *this;
463  }
464 
465  if (nChar == 0)
466  {
468  << "invalid first character found : " << c
469  << exit(FatalIOError);
470  }
471 
472  // done reading
473  buf[nChar] = '\0';
474  str = buf;
475  putback(c);
476 
477  return *this;
478 }
479 
480 
482 {
483  static const int maxLen = 1024;
484  static const int errLen = 80; // truncate error message for readability
485  static char buf[maxLen];
486 
487  char c;
488 
489  if (!get(c))
490  {
492  << "cannot read start of string"
493  << exit(FatalIOError);
494 
495  return *this;
496  }
497 
498  // Note, we could also handle single-quoted strings here (if desired)
499  if (c != token::BEGIN_STRING)
500  {
502  << "Incorrect start of string character found : " << c
503  << exit(FatalIOError);
504 
505  return *this;
506  }
507 
508  int nChar = 0;
509  bool escaped = false;
510 
511  while (get(c))
512  {
513  if (c == token::END_STRING)
514  {
515  if (escaped)
516  {
517  escaped = false;
518  nChar--; // overwrite backslash
519  }
520  else
521  {
522  // done reading
523  buf[nChar] = '\0';
524  str = buf;
525  return *this;
526  }
527  }
528  else if (c == token::NL)
529  {
530  if (escaped)
531  {
532  escaped = false;
533  nChar--; // overwrite backslash
534  }
535  else
536  {
537  buf[errLen] = buf[nChar] = '\0';
538 
540  << "found '\\n' while reading string \""
541  << buf << "...\""
542  << exit(FatalIOError);
543 
544  return *this;
545  }
546  }
547  else if (c == '\\')
548  {
549  escaped = !escaped; // toggle state (retains backslashes)
550  }
551  else
552  {
553  escaped = false;
554  }
555 
556  buf[nChar++] = c;
557  if (nChar == maxLen)
558  {
559  buf[errLen] = '\0';
560 
562  << "string \"" << buf << "...\"\n"
563  << " is too long (max. " << maxLen << " characters)"
564  << exit(FatalIOError);
565 
566  return *this;
567  }
568  }
569 
570 
571  // don't worry about a dangling backslash if string terminated prematurely
572  buf[errLen] = buf[nChar] = '\0';
573 
575  << "problem while reading string \"" << buf << "...\""
576  << exit(FatalIOError);
577 
578  return *this;
579 }
580 
581 
582 // Special handling of '{' in variables
584 {
585  static const int maxLen = 1024;
586  static const int errLen = 80; // truncate error message for readability
587  static char buf[maxLen];
588 
589  int nChar = 0;
590  int blockCount = 0;
591  char c;
592 
593  if (!get(c) || c != '$')
594  {
596  << "invalid first character found : " << c
597  << exit(FatalIOError);
598  }
599 
600  buf[nChar++] = c;
601 
602  // Read next character to see if '{'
603  if (get(c) && c == token::BEGIN_BLOCK)
604  {
605  // Read, counting brackets
606  buf[nChar++] = c;
607 
608  while
609  (
610  get(c)
611  && (
613  || c == token::END_BLOCK
614  || word::valid(c)
615  )
616  )
617  {
618  buf[nChar++] = c;
619  if (nChar == maxLen)
620  {
621  buf[errLen] = '\0';
622 
624  << "word '" << buf << "...'\n"
625  << " is too long (max. " << maxLen << " characters)"
626  << exit(FatalIOError);
627 
628  return *this;
629  }
630 
631  if (c == token::BEGIN_BLOCK)
632  {
633  blockCount++;
634  }
635  else if (c == token::END_BLOCK)
636  {
637  if (blockCount)
638  {
639  blockCount--;
640  }
641  else
642  {
643  break;
644  }
645  }
646  }
647  }
648  else
649  {
650  buf[nChar++] = c;
651 
652  while (get(c) && word::valid(c))
653  {
654  buf[nChar++] = c;
655  if (nChar == maxLen)
656  {
657  buf[errLen] = '\0';
658 
660  << "word '" << buf << "...'\n"
661  << " is too long (max. " << maxLen << " characters)"
662  << exit(FatalIOError);
663 
664  return *this;
665  }
666  }
667  }
668 
669  // we could probably skip this check
670  if (bad())
671  {
672  buf[errLen] = buf[nChar] = '\0';
673 
675  << "problem while reading string '" << buf << "...' after "
676  << nChar << " characters\n"
677  << exit(FatalIOError);
678 
679  return *this;
680  }
681 
682  if (nChar == 0)
683  {
685  << "invalid first character found : " << c
686  << exit(FatalIOError);
687  }
688 
689  // done reading
690  buf[nChar] = '\0';
691  str = buf;
692 
693  // Note: check if we exited due to '}' or just !word::valid.
694  if (c != token::END_BLOCK)
695  {
696  putback(c);
697  }
698 
699  return *this;
700 }
701 
702 
704 {
705  static const int maxLen = 8000;
706  static const int errLen = 80; // truncate error message for readability
707  static char buf[maxLen];
708 
709  char c;
710 
711  int nChar = 0;
712 
713  while (get(c))
714  {
715  if (c == token::HASH)
716  {
717  char nextC;
718  get(nextC);
719  if (nextC == token::END_BLOCK)
720  {
721  buf[nChar] = '\0';
722  str = buf;
723  return *this;
724  }
725  else
726  {
727  putback(nextC);
728  }
729  }
730 
731  buf[nChar++] = c;
732  if (nChar == maxLen)
733  {
734  buf[errLen] = '\0';
735 
737  << "string \"" << buf << "...\"\n"
738  << " is too long (max. " << maxLen << " characters)"
739  << exit(FatalIOError);
740 
741  return *this;
742  }
743  }
744 
745 
746  // don't worry about a dangling backslash if string terminated prematurely
747  buf[errLen] = buf[nChar] = '\0';
748 
750  << "problem while reading string \"" << buf << "...\""
751  << exit(FatalIOError);
752 
753  return *this;
754 }
755 
756 
758 {
759  is_ >> val;
760  setState(is_.rdstate());
761  return *this;
762 }
763 
764 
766 {
767  is_ >> val;
768  setState(is_.rdstate());
769  return *this;
770 }
771 
772 
774 {
775  is_ >> val;
776  setState(is_.rdstate());
777  return *this;
778 }
779 
780 
781 // read binary block
782 Foam::Istream& Foam::ISstream::read(char* buf, std::streamsize count)
783 {
784  if (format() != BINARY)
785  {
787  << "stream format not binary"
788  << exit(FatalIOError);
789  }
790 
791  readBegin("binaryBlock");
792  is_.read(buf, count);
793  readEnd("binaryBlock");
794 
795  setState(is_.rdstate());
796 
797  return *this;
798 }
799 
800 
802 {
803  stdStream().rdbuf()->pubseekpos(0);
804 
805  return *this;
806 }
807 
808 
809 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
810 
811 
812 std::ios_base::fmtflags Foam::ISstream::flags() const
813 {
814  return is_.flags();
815 }
816 
817 
818 std::ios_base::fmtflags Foam::ISstream::flags(const ios_base::fmtflags f)
819 {
820  return is_.flags(f);
821 }
822 
823 
824 // ************************************************************************* //
token.H
Foam::token::compound::New
static autoPtr< compound > New(const word &type, Istream &)
Select null constructed.
Definition: token.C:60
Foam::word::valid
static bool valid(char)
Is this character valid for a word.
Definition: wordI.H:117
Foam::token::END_STATEMENT
@ END_STATEMENT
Definition: token.H:99
format
word format(conversionProperties.lookup("format"))
Foam::doubleScalar
double doubleScalar
Double precision floating point scalar type.
Definition: doubleScalar.H:49
int.H
System integer.
Foam::token::ADD
@ ADD
Definition: token.H:114
Foam::word
A class for handling words, derived from string.
Definition: word.H:59
Foam::ISstream::get
ISstream & get(char &)
Raw, low-level get character function.
Definition: ISstreamI.H:57
Foam::ISstream::readWordToken
void readWordToken(token &)
Definition: ISstream.C:111
Foam::token::COMMA
@ COMMA
Definition: token.H:107
Foam::read
bool read(const char *, int32_t &)
Definition: int32IO.C:87
Foam::floatScalar
float floatScalar
Float precision floating point scalar type.
Definition: floatScalar.H:49
Foam::ISstream::putback
ISstream & putback(const char &)
Raw, low-level putback character function.
Definition: ISstreamI.H:87
ISstream.H
Foam::token::punctuationToken
punctuationToken
Standard punctuation tokens.
Definition: token.H:92
Foam::token::SUBTRACT
@ SUBTRACT
Definition: token.H:115
Foam::FatalIOError
IOerror FatalIOError
Foam::token
A token holds items read from Istream.
Definition: token.H:67
Foam::token::lineNumber
label lineNumber() const
Definition: tokenI.H:381
Foam::string
A class for handling character strings derived from std::string.
Definition: string.H:74
Foam::token::NL
@ NL
Definition: token.H:97
Foam::token::COLON
@ COLON
Definition: token.H:106
Foam::token::type
tokenType type() const
Definition: tokenI.H:178
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::Istream
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:57
Foam::token::MULTIPLY
@ MULTIPLY
Definition: token.H:116
Foam::token::VARIABLE
@ VARIABLE
Definition: token.H:79
Foam::token::compound::isCompound
static bool isCompound(const word &name)
Return true if name is a compound type.
Definition: token.C:83
Foam::ISstream::nextValid
char nextValid()
Definition: ISstream.C:33
Foam::token::BEGIN_STRING
@ BEGIN_STRING
Definition: token.H:110
Foam::IOstream::bad
bool bad() const
Return true if stream is corrupted.
Definition: IOstream.H:351
Foam::ISstream::readVerbatim
Istream & readVerbatim(string &)
Read a verbatim string (excluding block delimiters).
Definition: ISstream.C:703
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Foam::ISstream::readVariable
Istream & readVariable(string &)
Read a variable name (includes '{')
Definition: ISstream.C:583
Foam::token::BEGIN_LIST
@ BEGIN_LIST
Definition: token.H:100
Foam::readScalar
bool readScalar(const char *buf, doubleScalar &s)
Read whole of buf as a scalar. Return true if succesful.
Definition: doubleScalar.H:63
f
labelList f(nPoints)
Foam::token::END_BLOCK
@ END_BLOCK
Definition: token.H:105
Foam::ISstream::read
virtual Istream & read(token &)
Return next token from stream.
Definition: ISstream.C:132
Foam::ISstream::flags
virtual ios_base::fmtflags flags() const
Return flags of output stream.
Definition: ISstream.C:812
Foam::token::DIVIDE
@ DIVIDE
Definition: token.H:117
Foam::token::END_SQR
@ END_SQR
Definition: token.H:103
Foam::token::HASH
@ HASH
Definition: token.H:108
Foam::constant::universal::c
const dimensionedScalar c
Speed of light in a vacuum.
Foam::token::BEGIN_BLOCK
@ BEGIN_BLOCK
Definition: token.H:104
Foam::token::BEGIN_SQR
@ BEGIN_SQR
Definition: token.H:102
Foam::ISstream::rewind
virtual Istream & rewind()
Rewind and return the stream so that it may be read again.
Definition: ISstream.C:801
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:330
Foam::token::ASSIGN
@ ASSIGN
Definition: token.H:113
Foam::IOstream::good
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
Foam::Istream::getBack
bool getBack(token &)
Get the put back token if there is one and return true.
Definition: Istream.C:52
Foam::isspace
bool isspace(char c)
Definition: char.H:53
Foam::token::VERBATIMSTRING
@ VERBATIMSTRING
Definition: token.H:81
Foam::token::END_LIST
@ END_LIST
Definition: token.H:101
Foam::token::setBad
void setBad()
Set bad.
Definition: tokenI.H:392
Foam::token::END_STRING
@ END_STRING
Definition: token.H:111