Merge branch 'master' of ssh://git.code.sf.net/p/foam-extend/foam-extend-3.2
[foam-extend-3.2.git] / src / foam / db / IOstreams / Sstreams / ISstream.C
blob46b8bfec3bd3c7e001dce5934d679d80504c5904
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     | Version:     3.2
5     \\  /    A nd           | Web:         http://www.foam-extend.org
6      \\/     M anipulation  | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9     This file is part of foam-extend.
11     foam-extend is free software: you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by the
13     Free Software Foundation, either version 3 of the License, or (at your
14     option) any later version.
16     foam-extend is distributed in the hope that it will be useful, but
17     WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19     General Public License for more details.
21     You should have received a copy of the GNU General Public License
22     along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "ISstream.H"
27 #include "int.H"
28 #include "token.H"
29 #include <cctype>
32 // * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
34 char Foam::ISstream::nextValid()
36     char c = 0;
38     while (true)
39     {
40         // Get next non-whitespace character
41         while (get(c) && isspace(c))
42         {}
44         // Return if stream is bad
45         if (bad() || isspace(c))
46         {
47             return 0;
48         }
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             }
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                     }
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     }
102 Foam::Istream& Foam::ISstream::read(token& t)
104     static char numberBuffer[100];
106     // Return the put back token if it exists
107     if (Istream::getBack(t))
108     {
109         return *this;
110     }
112     // Assume that the streams supplied are in working order.
113     // Lines are counted by '\n'
115     // Get next 'valid character': i.e. proceed through any white space
116     // and/or comments until a semantically valid character is hit upon.
118     char c = nextValid();
120     // Set the line number of this token to the current stream line number
121     t.lineNumber() = lineNumber();
123     // return on error
124     if (!c)
125     {
126         t.setBad();
127         return *this;
128     }
130     // Analyse input starting with this character.
131     switch (c)
132     {
133         // First check for punctuation characters.
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         {
150             t = token::punctuationToken(c);
151             return *this;
152         }
154         // Strings: enclosed by double quotes.
155         case token::BEGIN_STRING :
156         {
157             putback(c);
158             string* sPtr = new string;
160             if (!read(*sPtr).bad())
161             {
162                 t = sPtr;
163             }
164             else
165             {
166                 delete sPtr;
167                 t.setBad();
168             }
169             return *this;
170         }
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;
180             if (c == '.')
181             {
182                 isScalar = true;
183             }
185             int i=0;
186             numberBuffer[i++] = c;
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;
203                 if (!isdigit(c))
204                 {
205                     isScalar = true;
206                 }
207             }
208             numberBuffer[i] = '\0';
210             setState(is_.rdstate());
212             if (!is_.bad())
213             {
214                 is_.putback(c);
216                 if (i == 1 && numberBuffer[0] == '-')
217                 {
218                     t = token::punctuationToken(token::SUBTRACT);
219                 }
220                 else if (isScalar)
221                 {
222                     t = scalar(atof(numberBuffer));
223                 }
224                 else
225                 {
226                     long lt = atol(numberBuffer);
227                     t = label(lt);
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             }
243             return *this;
244         }
246         // Should be a word (which can be a single character)
247         default:
248         {
249             putback(c);
250             word* wPtr = new word;
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     }
275 Foam::Istream& Foam::ISstream::read(char& c)
277     c = nextValid();
278     return *this;
282 Foam::Istream& Foam::ISstream::read(word& str)
284     static const int maxLen = 1024;
285     static const int errLen = 80; // truncate error message for readability
286     static char buf[maxLen];
288     register int i = 0;
289     register int bc = 0;
290     char c;
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';
306             FatalIOErrorIn("ISstream::read(word&)", *this)
307                 << "problem while reading word '" << buf << "'\n"
308                 << exit(FatalIOError);
310             return *this;
311         }
313         if (i >= maxLen)
314         {
315             buf[maxLen-1] = '\0';
316             buf[errLen] = '\0';
318             FatalIOErrorIn("ISstream::read(word&)", *this)
319                 << "word '" << buf << "' ...\n"
320                 << "    is too long (max. " << maxLen << " characters)"
321                 << exit(FatalIOError);
323             return *this;
324         }
326         if (c == token::BEGIN_LIST)
327         {
328             bc++;
329         }
330         else if (c == token::END_LIST)
331         {
332             bc--;
334             if (bc == -1)
335             {
336                 break;
337             }
338         }
340         buf[i++] = c;
341     }
343     if (i == 0)
344     {
345         FatalIOErrorIn("ISstream::read(word&)", *this)
346             << "invalid first character found : " << c
347             << exit(FatalIOError);
348     }
350     buf[i] = '\0';        // Terminator
351     str = buf;
352     putback(c);
354     return *this;
358 Foam::Istream& Foam::ISstream::read(string& str)
360     static const int maxLen = 1024;
361     static const int errLen = 80; // truncate error message for readability
362     static char buf[maxLen];
364     char c;
366     if (!get(c))
367     {
368         buf[0] = '\0';
370         FatalIOErrorIn("ISstream::read(string&)", *this)
371             << "cannot read start of string"
372             << exit(FatalIOError);
374         return *this;
375     }
377     char endTok = token::END_STRING;
379     // Note, we could also handle single-quoted strings here (if desired)
380     if (c != token::BEGIN_STRING)
381     {
382         buf[0] = '\0';
384         FatalIOErrorIn("ISstream::read(string&)", *this)
385             << "Incorrect start of string character"
386             << exit(FatalIOError);
388         return *this;
389     }
391     register int i = 0;
392     bool escaped = false;
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';
423                 FatalIOErrorIn("ISstream::read(string&)", *this)
424                     << "found '\\n' while reading string \""
425                     << buf << "...\""
426                     << exit(FatalIOError);
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         }
440         buf[i] = c;
441         if (i++ == maxLen)
442         {
443             buf[maxLen-1] = '\0';
444             buf[errLen] = '\0';
446             FatalIOErrorIn("ISstream::read(string&)", *this)
447                 << "string \"" << buf << "...\"\n"
448                 << "    is too long (max. " << maxLen << " characters)"
449                 << exit(FatalIOError);
451             return *this;
452         }
453     }
456     // don't worry about a dangling backslash if string terminated prematurely
457     buf[i] = '\0';
458     buf[errLen] = '\0';
460     FatalIOErrorIn("ISstream::read(string&)", *this)
461         << "problem while reading string \"" << buf << "...\""
462         << exit(FatalIOError);
464     return *this;
468 Foam::Istream& Foam::ISstream::read(label& val)
470     is_ >> val;
471     setState(is_.rdstate());
472     return *this;
476 Foam::Istream& Foam::ISstream::read(floatScalar& val)
478     is_ >> val;
479     setState(is_.rdstate());
480     return *this;
484 Foam::Istream& Foam::ISstream::read(doubleScalar& val)
486     is_ >> val;
487     setState(is_.rdstate());
488     return *this;
492 Foam::Istream& Foam::ISstream::read(longDoubleScalar& val)
494     is_ >> val;
495     setState(is_.rdstate());
496     return *this;
500 // read binary block
501 Foam::Istream& Foam::ISstream::read(char* buf, std::streamsize count)
503     if (format() != BINARY)
504     {
505         FatalIOErrorIn("ISstream::read(char*, std::streamsize)", *this)
506             << "stream format not binary"
507             << exit(FatalIOError);
508     }
510     readBegin("binaryBlock");
511     is_.read(buf, count);
512     readEnd("binaryBlock");
514     setState(is_.rdstate());
516     return *this;
520 Foam::Istream& Foam::ISstream::rewind()
522     stream().rdbuf()->pubseekpos(0);
524     return *this;
528 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
531 std::ios_base::fmtflags Foam::ISstream::flags() const
533     return is_.flags();
537 std::ios_base::fmtflags Foam::ISstream::flags(const ios_base::fmtflags f)
539     return is_.flags(f);
543 // ************************************************************************* //