FreeFOAM The Cross-Platform CFD Toolkit
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) 1991-2010 OpenCFD Ltd.
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 <OpenFOAM/int.H>
28 #include <OpenFOAM/token.H>
29 #include <cctype>
30 
31 
32 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
33 
34 char Foam::ISstream::nextValid()
35 {
36  char c = 0;
37 
38  while (true)
39  {
40  // Get next non-whitespace character
41  while (get(c) && isspace(c))
42  {}
43 
44  // Return if stream is bad
45  if (bad() || isspace(c))
46  {
47  return 0;
48  }
49 
50  // Is this the start of a C/C++ comment?
51  if (c == '/')
52  {
53  // If cannot get another character, return this one
54  if (!get(c))
55  {
56  return '/';
57  }
58 
59  if (c == '/')
60  {
61  // This is the start of a C++ style one-line comment
62  while (get(c) && c != '\n')
63  {}
64  }
65  else if (c == '*')
66  {
67  // This is the start of a C style comment
68  while (true)
69  {
70  if (get(c) && c == '*')
71  {
72  if (get(c) && c == '/')
73  {
74  break;
75  }
76  else
77  {
78  putback(c);
79  }
80  }
81 
82  if (!good())
83  {
84  return 0;
85  }
86  }
87  }
88  else // A lone '/' so return it.
89  {
90  putback(c);
91  return '/';
92  }
93  }
94  else // c is a valid character so return it
95  {
96  return c;
97  }
98  }
99 }
100 
101 
103 {
104  static char numberBuffer[100];
105 
106  // Return the put back token if it exists
107  if (Istream::getBack(t))
108  {
109  return *this;
110  }
111 
112  // Assume that the streams supplied are in working order.
113  // Lines are counted by '\n'
114 
115  // Get next 'valid character': i.e. proceed through any white space
116  // and/or comments until a semantically valid character is hit upon.
117 
118  char c = nextValid();
119 
120  // Set the line number of this token to the current stream line number
121  t.lineNumber() = lineNumber();
122 
123  // return on error
124  if (!c)
125  {
126  t.setBad();
127  return *this;
128  }
129 
130  // Analyse input starting with this character.
131  switch (c)
132  {
133  // First check for punctuation characters.
134 
135  case token::END_STATEMENT :
136  case token::BEGIN_LIST :
137  case token::END_LIST :
138  case token::BEGIN_SQR :
139  case token::END_SQR :
140  case token::BEGIN_BLOCK :
141  case token::END_BLOCK :
142  case token::COLON :
143  case token::COMMA :
144  case token::ASSIGN :
145  case token::ADD :
146  // case token::SUBTRACT : // Handled later as the posible start of a number
147  case token::MULTIPLY :
148  case token::DIVIDE :
149  {
151  return *this;
152  }
153 
154  // Strings: enclosed by double quotes.
155  case token::BEGIN_STRING :
156  {
157  putback(c);
158  string* sPtr = new string;
159 
160  if (!read(*sPtr).bad())
161  {
162  t = sPtr;
163  }
164  else
165  {
166  delete sPtr;
167  t.setBad();
168  }
169  return *this;
170  }
171 
172  // Numbers: do not distinguish at this point between Types.
173  case '-' :
174  case '.' :
175  case '0' : case '1' : case '2' : case '3' : case '4' :
176  case '5' : case '6' : case '7' : case '8' : case '9' :
177  {
178  bool isScalar = false;
179 
180  if (c == '.')
181  {
182  isScalar = true;
183  }
184 
185  int i=0;
186  numberBuffer[i++] = c;
187 
188  while
189  (
190  is_.get(c)
191  && (
192  isdigit(c)
193  || c == '.'
194  || c == 'e'
195  || c == 'E'
196  || c == '+'
197  || c == '-'
198  )
199  )
200  {
201  numberBuffer[i++] = c;
202 
203  if (!isdigit(c))
204  {
205  isScalar = true;
206  }
207  }
208  numberBuffer[i] = '\0';
209 
210  setState(is_.rdstate());
211 
212  if (!is_.bad())
213  {
214  is_.putback(c);
215 
216  if (i == 1 && numberBuffer[0] == '-')
217  {
219  }
220  else if (isScalar)
221  {
222  t = scalar(atof(numberBuffer));
223  }
224  else
225  {
226  long lt = atol(numberBuffer);
227  t = label(lt);
228 
229  // If the integer is too large to be represented as a label
230  // return it as a scalar
231  if (t.labelToken() != lt)
232  {
233  isScalar = true;
234  t = scalar(atof(numberBuffer));
235  }
236  }
237  }
238  else
239  {
240  t.setBad();
241  }
242 
243  return *this;
244  }
245 
246  // Should be a word (which can be a single character)
247  default:
248  {
249  putback(c);
250  word* wPtr = new word;
251 
252  if (!read(*wPtr).bad())
253  {
254  if (token::compound::isCompound(*wPtr))
255  {
256  t = token::compound::New(*wPtr, *this).ptr();
257  delete wPtr;
258  }
259  else
260  {
261  t = wPtr;
262  }
263  }
264  else
265  {
266  delete wPtr;
267  t.setBad();
268  }
269  return *this;
270  }
271  }
272 }
273 
274 
276 {
277  c = nextValid();
278  return *this;
279 }
280 
281 
283 {
284  static const int maxLen = 1024;
285  static const int errLen = 80; // truncate error message for readability
286  static char buf[maxLen];
287 
288  register int i = 0;
289  register int bc = 0;
290  char c;
291 
292  while (get(c) && word::valid(c))
293  {
294  if (fail())
295  {
296  if (i < maxLen-1)
297  {
298  buf[i] = '\0';
299  }
300  else
301  {
302  buf[maxLen-1] = '\0';
303  }
304  buf[errLen] = '\0';
305 
306  FatalIOErrorIn("ISstream::read(word&)", *this)
307  << "problem while reading word '" << buf << "'\n"
308  << exit(FatalIOError);
309 
310  return *this;
311  }
312 
313  if (i >= maxLen)
314  {
315  buf[maxLen-1] = '\0';
316  buf[errLen] = '\0';
317 
318  FatalIOErrorIn("ISstream::read(word&)", *this)
319  << "word '" << buf << "' ...\n"
320  << " is too long (max. " << maxLen << " characters)"
321  << exit(FatalIOError);
322 
323  return *this;
324  }
325 
326  if (c == token::BEGIN_LIST)
327  {
328  bc++;
329  }
330  else if (c == token::END_LIST)
331  {
332  bc--;
333 
334  if (bc == -1)
335  {
336  break;
337  }
338  }
339 
340  buf[i++] = c;
341  }
342 
343  if (i == 0)
344  {
345  FatalIOErrorIn("ISstream::read(word&)", *this)
346  << "invalid first character found : " << c
347  << exit(FatalIOError);
348  }
349 
350  buf[i] = '\0'; // Terminator
351  str = buf;
352  putback(c);
353 
354  return *this;
355 }
356 
357 
359 {
360  static const int maxLen = 1024;
361  static const int errLen = 80; // truncate error message for readability
362  static char buf[maxLen];
363 
364  char c;
365 
366  if (!get(c))
367  {
368  buf[0] = '\0';
369 
370  FatalIOErrorIn("ISstream::read(string&)", *this)
371  << "cannot read start of string"
372  << exit(FatalIOError);
373 
374  return *this;
375  }
376 
377  char endTok = token::END_STRING;
378 
379  // Note, we could also handle single-quoted strings here (if desired)
380  if (c != token::BEGIN_STRING)
381  {
382  buf[0] = '\0';
383 
384  FatalIOErrorIn("ISstream::read(string&)", *this)
385  << "Incorrect start of string character"
386  << exit(FatalIOError);
387 
388  return *this;
389  }
390 
391  register int i = 0;
392  bool escaped = false;
393 
394  while (get(c))
395  {
396  if (c == endTok)
397  {
398  if (escaped)
399  {
400  escaped = false;
401  i--; // overwrite backslash
402  }
403  else
404  {
405  // done reading string
406  buf[i] = '\0';
407  str = buf;
408  return *this;
409  }
410  }
411  else if (c == token::NL)
412  {
413  if (escaped)
414  {
415  escaped = false;
416  i--; // overwrite backslash
417  }
418  else
419  {
420  buf[i] = '\0';
421  buf[errLen] = '\0';
422 
423  FatalIOErrorIn("ISstream::read(string&)", *this)
424  << "found '\\n' while reading string \""
425  << buf << "...\""
426  << exit(FatalIOError);
427 
428  return *this;
429  }
430  }
431  else if (c == '\\')
432  {
433  escaped = !escaped; // toggle state (retains backslashes)
434  }
435  else
436  {
437  escaped = false;
438  }
439 
440  buf[i] = c;
441  if (i++ == maxLen)
442  {
443  buf[maxLen-1] = '\0';
444  buf[errLen] = '\0';
445 
446  FatalIOErrorIn("ISstream::read(string&)", *this)
447  << "string \"" << buf << "...\"\n"
448  << " is too long (max. " << maxLen << " characters)"
449  << exit(FatalIOError);
450 
451  return *this;
452  }
453  }
454 
455 
456  // don't worry about a dangling backslash if string terminated prematurely
457  buf[i] = '\0';
458  buf[errLen] = '\0';
459 
460  FatalIOErrorIn("ISstream::read(string&)", *this)
461  << "problem while reading string \"" << buf << "...\""
462  << exit(FatalIOError);
463 
464  return *this;
465 }
466 
467 
469 {
470  is_ >> val;
471  setState(is_.rdstate());
472  return *this;
473 }
474 
475 
477 {
478  is_ >> val;
479  setState(is_.rdstate());
480  return *this;
481 }
482 
483 
485 {
486  is_ >> val;
487  setState(is_.rdstate());
488  return *this;
489 }
490 
491 
492 // read binary block
493 Foam::Istream& Foam::ISstream::read(char* buf, std::streamsize count)
494 {
495  if (format() != BINARY)
496  {
497  FatalIOErrorIn("ISstream::read(char*, std::streamsize)", *this)
498  << "stream format not binary"
499  << exit(FatalIOError);
500  }
501 
502  readBegin("binaryBlock");
503  is_.read(buf, count);
504  readEnd("binaryBlock");
505 
506  setState(is_.rdstate());
507 
508  return *this;
509 }
510 
511 
513 {
514  stream().rdbuf()->pubseekpos(0);
515 
516  return *this;
517 }
518 
519 
520 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
521 
522 
523 std::ios_base::fmtflags Foam::ISstream::flags() const
524 {
525  return is_.flags();
526 }
527 
528 
529 std::ios_base::fmtflags Foam::ISstream::flags(const ios_base::fmtflags f)
530 {
531  return is_.flags(f);
532 }
533 
534 
535 // ************************ vim: set sw=4 sts=4 et: ************************ //