mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
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.
576 lines
14 KiB
C
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);
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|