Files
openfoam/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C
Mark Olesen 2792624996 Expose STL std streams in a consistent manner for serial streams.
Previously Fstreams had stdStream() as a public member and the other
streams had stream() as a protected member.

All serial streams now have public method stdStream() and the stream()
method has been eliminated. This is not only more consistent, but also
avoids confusion (for the programmer, not the compiler) with the
ITstream::stream() method.
2009-12-21 10:24:35 +01:00

576 lines
14 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\*---------------------------------------------------------------------------*/
#include "ISstream.H"
#include "int.H"
#include "token.H"
#include <cctype>
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
char Foam::ISstream::nextValid()
{
char c = 0;
while (true)
{
// Get next non-whitespace character
while (get(c) && isspace(c))
{}
// Return if stream is bad - ie, previous get() failed
if (bad() || isspace(c))
{
break;
}
// Is this the start of a C/C++ comment?
if (c == '/')
{
if (!get(c))
{
// cannot get another character - return this one
return '/';
}
if (c == '/')
{
// C++ style single-line comment - skip through past end-of-line
while (get(c) && c != '\n')
{}
}
else if (c == '*')
{
// within a C-style comment
while (true)
{
// search for end of C-style comment - '*/'
if (get(c) && c == '*')
{
if (get(c))
{
if (c == '/')
{
// matched '*/'
break;
}
else if (c == '*')
{
// check again
putback(c);
}
}
}
if (!good())
{
return 0;
}
}
}
else
{
// The '/' did not start a C/C++ comment - return it
putback(c);
return '/';
}
}
else
{
// a valid character - return it
return c;
}
}
return 0;
}
Foam::Istream& Foam::ISstream::read(token& t)
{
static const int maxLen = 128;
static char buf[maxLen];
// Return the put back token if it exists
if (Istream::getBack(t))
{
return *this;
}
// Assume that the streams supplied are in working order.
// Lines are counted by '\n'
// Get next 'valid character': i.e. proceed through any whitespace
// and/or comments until a semantically valid character is found
char c = nextValid();
// Set the line number of this token to the current stream line number
t.lineNumber() = lineNumber();
// return on error
if (!c)
{
t.setBad();
return *this;
}
// Analyse input starting with this character.
switch (c)
{
// Check for punctuation first
case token::END_STATEMENT :
case token::BEGIN_LIST :
case token::END_LIST :
case token::BEGIN_SQR :
case token::END_SQR :
case token::BEGIN_BLOCK :
case token::END_BLOCK :
case token::COLON :
case token::COMMA :
case token::ASSIGN :
case token::ADD :
// NB: token::SUBTRACT handled later as the possible start of a Number
case token::MULTIPLY :
case token::DIVIDE :
{
t = token::punctuationToken(c);
return *this;
}
// String: enclosed by double quotes.
case token::BEGIN_STRING :
{
putback(c);
string* sPtr = new string;
if (read(*sPtr).bad())
{
delete sPtr;
t.setBad();
}
else
{
t = sPtr;
}
return *this;
}
// Number: integer or floating point
//
// ideally match the equivalent of this regular expression
//
// /[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)([Ee][-+]?[0-9]+)?/
//
case '-' :
case '.' :
case '0' : case '1' : case '2' : case '3' : case '4' :
case '5' : case '6' : case '7' : case '8' : case '9' :
{
bool asLabel = (c != '.');
int nChar = 0;
buf[nChar++] = c;
// get everything that could resemble a number and let
// strtod() determine the validity
while
(
is_.get(c)
&& (
isdigit(c)
|| c == '+'
|| c == '-'
|| c == '.'
|| c == 'E'
|| c == 'e'
)
)
{
if (asLabel)
{
asLabel = isdigit(c);
}
buf[nChar++] = c;
if (nChar == maxLen)
{
// runaway argument - avoid buffer overflow
buf[maxLen-1] = '\0';
FatalIOErrorIn("ISstream::read(token&)", *this)
<< "number '" << buf << "...'\n"
<< " is too long (max. " << maxLen << " characters)"
<< exit(FatalIOError);
t.setBad();
return *this;
}
}
buf[nChar] = '\0';
setState(is_.rdstate());
if (is_.bad())
{
t.setBad();
}
else
{
is_.putback(c);
if (nChar == 1 && buf[0] == '-')
{
// a single '-' is punctuation
t = token::punctuationToken(token::SUBTRACT);
}
else
{
char *endptr;
if (asLabel)
{
long longVal(strtol(buf, &endptr, 10));
t = label(longVal);
// return as a scalar if doesn't fit in a label
if (t.labelToken() != longVal)
{
t = scalar(strtod(buf, &endptr));
}
}
else
{
scalar scalarVal(strtod(buf, &endptr));
t = scalarVal;
// ---------------------------------------
// this would also be possible if desired:
// ---------------------------------------
// // return as a label when possible
// // eg, 1E6 -> 1000000
// if (scalarVal <= labelMax && scalarVal >= labelMin)
// {
// label labelVal(scalarVal);
//
// if (labelVal == scalarVal)
// {
// t = labelVal;
// }
// }
}
// not everything converted: bad format or trailing junk
if (*endptr)
{
t.setBad();
}
}
}
return *this;
}
// Should be a word (which can also be a single character)
default:
{
putback(c);
word* wPtr = new word;
if (read(*wPtr).bad())
{
delete wPtr;
t.setBad();
}
else if (token::compound::isCompound(*wPtr))
{
t = token::compound::New(*wPtr, *this).ptr();
delete wPtr;
}
else
{
t = wPtr;
}
return *this;
}
}
}
Foam::Istream& Foam::ISstream::read(char& c)
{
c = nextValid();
return *this;
}
Foam::Istream& Foam::ISstream::read(word& str)
{
static const int maxLen = 1024;
static const int errLen = 80; // truncate error message for readability
static char buf[maxLen];
register int nChar = 0;
register int listDepth = 0;
char c;
while (get(c) && word::valid(c))
{
if (c == token::BEGIN_LIST)
{
listDepth++;
}
else if (c == token::END_LIST)
{
if (listDepth)
{
listDepth--;
}
else
{
break;
}
}
buf[nChar++] = c;
if (nChar == maxLen)
{
buf[errLen] = '\0';
FatalIOErrorIn("ISstream::read(word&)", *this)
<< "word '" << buf << "...'\n"
<< " is too long (max. " << maxLen << " characters)"
<< exit(FatalIOError);
return *this;
}
}
// we could probably skip this check
if (bad())
{
buf[errLen] = buf[nChar] = '\0';
FatalIOErrorIn("ISstream::read(word&)", *this)
<< "problem while reading word '" << buf << "...' after "
<< nChar << " characters\n"
<< exit(FatalIOError);
return *this;
}
if (nChar == 0)
{
FatalIOErrorIn("ISstream::read(word&)", *this)
<< "invalid first character found : " << c
<< exit(FatalIOError);
}
// done reading
buf[nChar] = '\0';
str = buf;
putback(c);
return *this;
}
Foam::Istream& Foam::ISstream::read(string& str)
{
static const int maxLen = 1024;
static const int errLen = 80; // truncate error message for readability
static char buf[maxLen];
char c;
if (!get(c))
{
FatalIOErrorIn("ISstream::read(string&)", *this)
<< "cannot read start of string"
<< exit(FatalIOError);
return *this;
}
// Note, we could also handle single-quoted strings here (if desired)
if (c != token::BEGIN_STRING)
{
FatalIOErrorIn("ISstream::read(string&)", *this)
<< "Incorrect start of string character found : " << c
<< exit(FatalIOError);
return *this;
}
register int nChar = 0;
bool escaped = false;
while (get(c))
{
if (c == token::END_STRING)
{
if (escaped)
{
escaped = false;
nChar--; // overwrite backslash
}
else
{
// done reading
buf[nChar] = '\0';
str = buf;
return *this;
}
}
else if (c == token::NL)
{
if (escaped)
{
escaped = false;
nChar--; // overwrite backslash
}
else
{
buf[errLen] = buf[nChar] = '\0';
FatalIOErrorIn("ISstream::read(string&)", *this)
<< "found '\\n' while reading string \""
<< buf << "...\""
<< exit(FatalIOError);
return *this;
}
}
else if (c == '\\')
{
escaped = !escaped; // toggle state (retains backslashes)
}
else
{
escaped = false;
}
buf[nChar++] = c;
if (nChar == maxLen)
{
buf[errLen] = '\0';
FatalIOErrorIn("ISstream::read(string&)", *this)
<< "string \"" << buf << "...\"\n"
<< " is too long (max. " << maxLen << " characters)"
<< exit(FatalIOError);
return *this;
}
}
// don't worry about a dangling backslash if string terminated prematurely
buf[errLen] = buf[nChar] = '\0';
FatalIOErrorIn("ISstream::read(string&)", *this)
<< "problem while reading string \"" << buf << "...\""
<< exit(FatalIOError);
return *this;
}
Foam::Istream& Foam::ISstream::read(label& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
Foam::Istream& Foam::ISstream::read(floatScalar& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
Foam::Istream& Foam::ISstream::read(doubleScalar& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
// read binary block
Foam::Istream& Foam::ISstream::read(char* buf, std::streamsize count)
{
if (format() != BINARY)
{
FatalIOErrorIn("ISstream::read(char*, std::streamsize)", *this)
<< "stream format not binary"
<< exit(FatalIOError);
}
readBegin("binaryBlock");
is_.read(buf, count);
readEnd("binaryBlock");
setState(is_.rdstate());
return *this;
}
Foam::Istream& Foam::ISstream::rewind()
{
stdStream().rdbuf()->pubseekpos(0);
return *this;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
std::ios_base::fmtflags Foam::ISstream::flags() const
{
return is_.flags();
}
std::ios_base::fmtflags Foam::ISstream::flags(const ios_base::fmtflags f)
{
return is_.flags(f);
}
// ************************************************************************* //