# PhasicFlow: src/phasicFlow/streams/Stream/Istream.cpp Source File

Istream.cpp
Go to the documentation of this file.
/*------------------------------- phasicFlow ---------------------------------
O C enter of
O O E ngineering and
O O M ultiscale modeling of
OOOOOOO F luid flow
------------------------------------------------------------------------------
Copyright (C): www.cemf.ir
email: hamid.r.norouzi AT gmail.com
------------------------------------------------------------------------------
Licence:
This file is part of phasicFlow code. It is a free software for simulating
granular and multiphase flows. You can redistribute it and/or modify it under
the terms of GNU General Public License v3 or any other later versions.
phasicFlow is distributed to help others in their research in the field of
granular and multiphase flows, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-----------------------------------------------------------------------------*/
// based on OpenFOAM stream, with some modifications/simplifications
// to be tailored to our needs
#include "Istream.hpp"
#include "token.hpp"
#include "error.hpp"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
// Truncate error message for readability
static constexpr const unsigned errLen = 80;
namespace
{
// Convert a single character to a word with length 1
inline static pFlow::word charToWord(char c)
{
return pFlow::word(std::string(1, c), false);
}
// Permit slash-scoping of entries
static inline bool validVariableChar(char c)
{
return (pFlow::validWord(c) || c == '/');
}
} // End anonymous namespace
char pFlow::Istream::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))
{
return 0;
}
// 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;
}
void pFlow::Istream::readWordToken(token& t)
{
word val;
if (read(val).bad())
{
t.setBad();
}
else
{
t = std::move(val); // Move contents to token
}
}
pFlow::Istream& pFlow::Istream::readVariable(word& str)
{
constexpr const unsigned maxLen = 1024;
static char buf[maxLen];
unsigned nChar = 0;
unsigned depth = 0; // Track depth of (..) or {..} nesting
char c;
// First character must be '$'
if (!get(c) || c != token::DOLLAR)
{
ioErrorInFile( name(), lineNumber())
<< "Invalid first character found : " << c << nl;
fatalExit;
}
buf[nChar++] = c;
// Next character should also exist.
// This should never fail, since it was checked before calling.
if (!get(c))
{
str.assign(buf, nChar);
warningInFunction
<< "Truncated variable name : " << str << nl;
return *this;
}
buf[nChar++] = c;
str.clear();
if (c == token::BEGIN_BLOCK)
{
// Processing ${...} style.
++depth;
// Could check that the next char is good and not one of '{}'
// since this would indicate "${}", "${{..." or truncated "${"
while (get(c))
{
buf[nChar++] = c;
if (nChar == maxLen)
{
str.append(buf, nChar);
nChar = 0;
}
if (c == token::BEGIN_BLOCK)
{
++depth;
}
else if (c == token::END_BLOCK)
{
--depth;
if (!depth)
{
// Found closing '}' character
str.append(buf, nChar);
return *this;
}
}
}
// Should never reach here on normal input
str.append(buf, nChar); // Finalize pending buffer input
nChar = str.length();
if (str.length() > errLen)
{
str.erase(errLen);
}
ioErrorInFile(name(), lineNumber())
<< "stream terminated while reading variable '"
<< str.c_str() << "...' [" << static_cast< int32 >(nChar) << "]\n";
fatalExit;
return *this;
}
else if (validVariableChar(c))
{
// Processing $var style
while
(
(nChar < maxLen) && get(c)
&& (validVariableChar(c))
)
{
if (c == token::BEGIN_LIST)
{
++depth;
}
else if (c == token::END_LIST)
{
if (!depth)
{
break; // Closed ')' without an opening '(' ? ... stop
}
--depth;
}
buf[nChar++] = c;
}
}
else
{
// Invalid character. Terminate string (for message) without
// including the invalid character in the count.
buf[nChar--] = '\0';
warningInFunction
<< "Bad variable name: " << buf << nl << endl;
}
if (nChar >= maxLen)
{
buf[errLen] = '\0';
ioErrorInFile(name(), lineNumber())
<< "variable '" << buf << "...'\n"
<< " is too long (max. " << static_cast< int32 >(maxLen) << " characters)";
fatalExit;
return *this;
}
buf[nChar] = '\0'; // Terminate string
if (bad())
{
// Could probably skip this check
buf[errLen] = '\0';
ioErrorInFile(name(), lineNumber())
<< "Problem while reading variable '" << buf << "...' after "
<< static_cast< int32 >(nChar) << " characters\n";
fatalExit;
ioErrorInFile(name(), lineNumber());
return *this;
}
if (depth)
{
warningInFunction
<< "Missing " << static_cast< int32 >(depth)
<< " closing ')' while parsing" << nl << nl
<< buf << nl << endl;
}
// Finalize
str.assign(buf, nChar);
putback(c);
return *this;
}
pFlow::Istream::Istream
(
std::istream& is,
const word& streamName
)
:
iIstream(),
name_(streamName),
is_(is)
{
if (is_.good())
{
setOpened();
setGood();
}
else
{
setState(is_.rdstate());
}
}
pFlow::Istream& pFlow::Istream::get(char& c)
{
is_.get(c);
setState(is_.rdstate());
if (good() && c == '\n')
{
++lineNumber_;
}
return *this;
}
int pFlow::Istream::peek()
{
return is_.peek();
}
pFlow::Istream& pFlow::Istream::getLine(std::string& str, char delim)
{
std::getline(is_, str, delim);
setState(is_.rdstate());
if (delim == '\n')
{
++lineNumber_;
}
return *this;
}
std::streamsize pFlow::Istream::getLine(std::nullptr_t, char delim)
{
is_.ignore(std::numeric_limits<std::streamsize>::max(), delim);
setState(is_.rdstate());
std::streamsize count = is_.gcount();
if (count && delim == '\n')
{
++lineNumber_;
}
return count;
}
pFlow::Istream& pFlow::Istream::putback(const char c)
{
if (c == '\n')
{
--lineNumber_;
}
if (!is_.putback(c))
{
setBad();
}
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(token& t)
{
constexpr const unsigned maxLen = 128; // Max length for units/scalars
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 - same as token::isseparator()
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::DIVIDE :
{
t = token::punctuationToken(c);
return *this;
}
// String: enclosed by double quotes.
case token::BEGIN_STRING :
{
putback(c);
word val;
if (readString(val).bad())
{
t.setBad();
}
else
{
t = std::move(val); // Move contents to token
}
return *this;
}
// Dictionary variable (as rvalue)
case token::DOLLAR :
{
char nextC;
if (read(nextC).bad())
{
// Return lone '$' as word
t = charToWord(c);
}
else
{
// Put back both so that '$...' is included in the variable
putback(nextC);
putback(c);
word val;
if (readVariable(val).bad())
{
t.setBad();
}
else
{
t = std::move(val); // Move contents to token
t.setType(token::tokenType::VARIABLE);
}
}
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' :
{
int64 int64Val = (c != '.'); // used as bool here
unsigned nChar = 0;
buf[nChar++] = c;
// get everything that could resemble a number and let
// readScalar determine the validity
while
(
is_.get(c)
&& (
isdigit(c)
|| c == '+'
|| c == '-'
|| c == '.'
|| c == 'E'
|| c == 'e'
)
)
{
if (int64Val)
{
int64Val = isdigit(c);
}
buf[nChar++] = c;
if (nChar == maxLen)
{
// Runaway argument - avoid buffer overflow
buf[maxLen-1] = '\0';
ioErrorInFile( name(), lineNumber())
<< "number '" << buf << "...'\n"
<< " is too long (max. " <<
static_cast< int32 >(maxLen) << " characters)";
fatalExit;
t.setBad();
return *this;
}
}
buf[nChar] = '\0'; // Terminate string
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 if (int64Val && readInt64(buf, int64Val))
{
t = int64Val;
}
else
{
real realVal;
if (readReal(buf, realVal))
{
// A scalar or too big to fit as a unit
t = realVal;
}
else
{
t.setBad();
}
}
}
return *this;
}
// Should be a word (which can also be a single character)
default:
{
putback(c);
readWordToken(t);
return *this;
}
}
}
pFlow::iIstream& pFlow::Istream::read(char& c)
{
c = nextValid();
return *this;
}
pFlow::iIstream& pFlow::Istream::read(word& str)
{
constexpr const unsigned maxLen = 1024;
static char buf[maxLen];
unsigned nChar = 0;
unsigned depth = 0; // Track depth of (..) nesting
char c;
while
(
(nChar < maxLen)
&& get(c)
&& validWord(c)
)
{
if (c == token::BEGIN_LIST)
{
++depth;
}
else if (c == token::END_LIST)
{
if (!depth)
{
break; // Closed ')' without an opening '(' ? ... stop
}
--depth;
}
buf[nChar++] = c;
}
if (nChar >= maxLen)
{
buf[errLen] = '\0';
ioErrorInFile(name(), lineNumber())
<< "word '" << buf << "...'\n"
<< " is too long (max. " <<
static_cast< int32 >(maxLen) << " characters)";
fatalExit;
return *this;
}
buf[nChar] = '\0'; // Terminate string
if (bad())
{
// Could probably skip this check
buf[errLen] = '\0';
ioErrorInFile(name(), lineNumber())
<< "Problem while reading word '" << buf << "...' after "
<< static_cast< int32 >(nChar) << " characters\n";
fatalExit;
return *this;
}
if (nChar == 0)
{
ioErrorInFile(name(), lineNumber())
<< "Invalid first character found : " << c;
fatalExit;
}
else if (depth)
{
warningInFunction
<< "Missing " << static_cast< int32 >(depth)
<< " closing ')' while parsing" << nl << nl
<< buf << nl << endl;
}
// Finalize: content already validated, assign without additional checks.
str.assign(buf, nChar);
putback(c);
return *this;
}
pFlow::iIstream& pFlow::Istream::readString(word& str)
{
constexpr const unsigned maxLen = 1024;
static char buf[maxLen];
char c;
if (!get(c))
{
ioErrorInFile(name(), lineNumber())
<< "cannot read start of string";
fatalExit;
return *this;
}
// Note, we could also handle single-quoted strings here (if desired)
if (c != token::BEGIN_STRING)
{
ioErrorInFile(name(), lineNumber())
<< "Incorrect start of string character found : " << c;
fatalExit;
return *this;
}
unsigned nChar = 0;
bool escaped = false;
while
(
(nChar < maxLen)
&& get(c)
)
{
if (c == token::END_STRING)
{
if (escaped)
{
escaped = false;
--nChar; // Overwrite backslash
}
else
{
// Done reading
str.assign(buf, nChar);
return *this;
}
}
else if (c == token::NL)
{
if (escaped)
{
escaped = false;
--nChar; // Overwrite backslash
}
else
{
buf[errLen] = buf[nChar] = '\0';
ioErrorInFile(name(), lineNumber())
<< "found '\\n' while reading string \""
<< buf << "...\"";
fatalExit;
return *this;
}
}
else if (c == '\\')
{
escaped = !escaped; // toggle state (retains backslashes)
}
else
{
escaped = false;
}
buf[nChar++] = c;
}
if (nChar >= maxLen)
{
buf[errLen] = '\0';
ioErrorInFile(name(), lineNumber())
<< "string \"" << buf << "...\"\n"
<< " is too long (max. " << static_cast< int32 >(maxLen) << " characters)";
fatalExit;
return *this;
}
// Don't worry about a dangling backslash if string terminated prematurely
buf[errLen] = buf[nChar] = '\0';
ioErrorInFile(name(), lineNumber())
<< "Problem while reading string \"" << buf << "...\"";
fatalExit;
return *this;
}
pFlow::iIstream& pFlow::Istream::read(int64& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(int32& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(int16& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(int8& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(label& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(uint32& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(uint16& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(float& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
pFlow::iIstream& pFlow::Istream::read(double& val)
{
is_ >> val;
setState(is_.rdstate());
return *this;
}
void pFlow::Istream::rewind()
{
lineNumber_ = 1; // Reset line number
stdStream().clear(); // Clear the iostate error state flags
setGood(); // Sync local copy of iostate
// pubseekpos() rather than seekg() so that it works with gzstream
stdStream().rdbuf()->pubseekpos(0, std::ios_base::in);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
std::ios_base::fmtflags pFlow::Istream::flags() const
{
return is_.flags();
}
std::ios_base::fmtflags pFlow::Istream::flags(const ios_base::fmtflags f)
{
return is_.flags(f);
}
// ************************************************************************* //
pFlow::token::setType
bool setType(const tokenType tokType)
Definition: tokenI.hpp:290
pFlow::real
float real
Definition: builtinTypes.hpp:46
fatalExit
#define fatalExit
Definition: error.hpp:57
pFlow::token
Definition: token.hpp:42
pFlow::Istream::nextValid
char nextValid()
Definition: Istream.cpp:53
pFlow::Istream::readWordToken
void readWordToken(token &t)
Definition: Istream.cpp:131
errLen
static constexpr const unsigned errLen
Definition: Istream.cpp:32
warningInFunction
#define warningInFunction
Definition: error.hpp:55
pFlow::token::punctuationToken
punctuationToken
Definition: token.hpp:81
pFlow::token::END_BLOCK
@ END_BLOCK
End block [isseparator].
Definition: token.hpp:94
pFlow::uint32
unsigned int uint32
Definition: builtinTypes.hpp:59
pFlow::readReal
bool readReal(const word &w, real &val)
Definition: bTypesFunctions.cpp:335
token.hpp
pFlow::word
std::string word
Definition: builtinTypes.hpp:63
pFlow::token::NL
@ NL
Newline [isspace].
Definition: token.hpp:86
pFlow::int64
long long int int64
Definition: builtinTypes.hpp:55
pFlow::validWord
bool validWord(char c)
Definition: bTypesFunctions.cpp:180
Istream.hpp
pFlow::endl
iOstream & endl(iOstream &os)
Definition: iOstream.hpp:312
pFlow::token::BEGIN_BLOCK
@ BEGIN_BLOCK
Begin block [isseparator].
Definition: token.hpp:93
pFlow::readInt64
bool readInt64(const word &w, int64 &val)
Definition: bTypesFunctions.cpp:262
pFlow::Istream::rewind
virtual void rewind()
Definition: Istream.cpp:850
pFlow::Istream::readString
virtual iIstream & readString(word &str) override
Definition: Istream.cpp:683
pFlow::Istream
Definition: Istream.hpp:38
pFlow::int16
short int int16
Definition: builtinTypes.hpp:51
pFlow::uint16
unsigned short int uint16
Definition: builtinTypes.hpp:57
pFlow::iIstream
Definition: iIstream.hpp:33
pFlow::IOstream::bad
bool bad() const
Definition: IOstream.hpp:168
pFlow::iIstream::getBack
bool getBack(token &tok)
Definition: iIstream.cpp:27
pFlow::Istream::readVariable
Istream & readVariable(word &str)
Definition: Istream.cpp:145
pFlow::int32
int int32
Definition: builtinTypes.hpp:53
pFlow::algorithms::KOKKOS::max
INLINE_FUNCTION_H Type max(const Type *first, int32 numElems)
Definition: kokkosAlgorithms.hpp:104
pFlow::Istream::read
virtual iIstream & read(token &t) override
Definition: Istream.cpp:395
pFlow::token::BEGIN_STRING
@ BEGIN_STRING
Begin string with double quote.
Definition: token.hpp:104
pFlow::token::END_LIST
@ END_LIST
End list [isseparator].
Definition: token.hpp:90
pFlow::token::DOLLAR
@ DOLLAR
Dollar - start variable.
Definition: token.hpp:97
pFlow::count
auto count(const Vector< T, Allocator > &vec, const T &val)
Definition: VectorAlgorithm.hpp:26
pFlow::Istream::get
Istream & get(char &c)
Definition: Istream.cpp:328
pFlow::token::COLON
@ COLON
Colon [isseparator].
Definition: token.hpp:95
pFlow::token::END_STATEMENT
@ END_STATEMENT
End entry [isseparator].
Definition: token.hpp:88
pFlow::IOstream::good
bool good() const
Definition: IOstream.hpp:150
pFlow::token::SUBTRACT
@ SUBTRACT
Subtract or start of negative number.
Definition: token.hpp:101
pFlow::token::BEGIN_LIST
@ BEGIN_LIST
Begin list [isseparator].
Definition: token.hpp:89
pFlow::Istream::Istream
Istream(std::istream &is, const word &streamName)
Definition: Istream.cpp:308
pFlow::token::BEGIN_SQR
@ BEGIN_SQR
Begin dimensions [isseparator].
Definition: token.hpp:91
pFlow::token::DIVIDE
@ DIVIDE
Divide [isseparator].
Definition: token.hpp:102
ioErrorInFile
#define ioErrorInFile(fileName, lineNumber)
Definition: error.hpp:49
pFlow::label
std::size_t label
Definition: builtinTypes.hpp:61
pFlow::token::COMMA
@ COMMA
Comma [isseparator].
Definition: token.hpp:96
pFlow::int8
signed char int8
Definition: builtinTypes.hpp:49
pFlow::Istream::peek
int peek()
Definition: Istream.cpp:342
pFlow::Istream::flags
virtual ios_base::fmtflags flags() const
Definition: Istream.cpp:864
pFlow::token::END_STRING
@ END_STRING
End string with double quote.
Definition: token.hpp:105
pFlow::Istream::putback
Istream & putback(const char c)
Definition: Istream.cpp:378
pFlow::Istream::getLine
Istream & getLine(word &str, char delim='\n')
Definition: Istream.cpp:348
pFlow::nl
constexpr char nl
Definition: iOstream.hpp:409
pFlow::token::END_SQR
@ END_SQR
End dimensions [isseparator].
Definition: token.hpp:92
pFlow::token::setBad
void setBad()
Definition: tokenI.hpp:658
pFlow::token::lineNumber
int32 lineNumber() const
Definition: tokenI.hpp:360
error.hpp