ENH: dictionary: recursive variable expansion

This commit is contained in:
mattijs
2012-10-15 16:00:03 +01:00
parent 78a7cdf7f3
commit 6dc4de7d3f
8 changed files with 246 additions and 29 deletions

View File

@ -38,6 +38,15 @@ inactive
type zeroGradient;
}
// Indirection
varType active;
// Indirection of values
x 5;
varName x;
boundaryField
{
Default_Boundary_Region
@ -52,7 +61,7 @@ boundaryField
inlet_5 "a primitiveEntry is squashed by a directory entry";
inlet_5 { $inactive }
inlet_6 { $.inactive } // Test scoping
inlet_7 { $inactive }
inlet_7 { ${inactive}} // Test variable expansion
inlet_8 { $inactive }
#include "testDictInc"
@ -63,14 +72,14 @@ boundaryField
inletValue $internalField;
value #include "value";
// error #remove self;
x 5;
x ${${varName}}; // Test indirection/recursive expansion
y 6;
}
// this should have no effect
#remove inactive
inlet_7 { $active }
inlet_7 { ${${varType}}} // Test indirection/recursive expansion
#inputMode overwrite
inlet_8 { $active }
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -27,8 +27,6 @@ License
#include "int.H"
#include "token.H"
#include <cctype>
#include "IOstreams.H"
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
@ -243,6 +241,44 @@ Foam::Istream& Foam::ISstream::read(token& t)
}
}
case '$':
{
// Look ahead
char nextC;
if (read(nextC).bad())
{
// Return $ as word
t = token(word(c));
return *this;
}
else if (nextC == token::BEGIN_BLOCK)
{
putback(nextC);
putback(c);
string* sPtr = new string;
if (readVariable(*sPtr).bad())
{
delete sPtr;
t.setBad();
}
else
{
t = sPtr;
t.type() = token::STRING;
}
return *this;
}
else
{
putback(nextC);
putback(c);
readWordToken(t);
return *this;
}
}
// Number: integer or floating point
//
// ideally match the equivalent of this regular expression
@ -549,6 +585,127 @@ Foam::Istream& Foam::ISstream::read(string& str)
}
// Special handling of '{' in variables
Foam::Istream& Foam::ISstream::readVariable(string& 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 blockCount = 0;
char c;
if (!get(c) || c != '$')
{
FatalIOErrorIn("ISstream::readVariable(string&)", *this)
<< "invalid first character found : " << c
<< exit(FatalIOError);
}
buf[nChar++] = c;
// Read next character to see if '{'
if (get(c) && c == token::BEGIN_BLOCK)
{
// Read, counting brackets
buf[nChar++] = c;
while
(
get(c)
&& (
c == token::BEGIN_BLOCK
|| c == token::END_BLOCK
|| word::valid(c)
)
)
{
buf[nChar++] = c;
if (nChar == maxLen)
{
buf[errLen] = '\0';
FatalIOErrorIn("ISstream::readVariable(string&)", *this)
<< "word '" << buf << "...'\n"
<< " is too long (max. " << maxLen << " characters)"
<< exit(FatalIOError);
return *this;
}
if (c == token::BEGIN_BLOCK)
{
blockCount++;
}
else if (c == token::END_BLOCK)
{
if (blockCount)
{
blockCount--;
}
else
{
break;
}
}
}
}
else
{
buf[nChar++] = c;
while (get(c) && word::valid(c))
{
buf[nChar++] = c;
if (nChar == maxLen)
{
buf[errLen] = '\0';
FatalIOErrorIn("ISstream::readVariable(string&)", *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::readVariable(string&)", *this)
<< "problem while reading string '" << buf << "...' after "
<< nChar << " characters\n"
<< exit(FatalIOError);
return *this;
}
if (nChar == 0)
{
FatalIOErrorIn("ISstream::readVariable(string&)", *this)
<< "invalid first character found : " << c
<< exit(FatalIOError);
}
// done reading
buf[nChar] = '\0';
str = buf;
// Note: check if we exited due to '}' or just !word::valid.
if (c != token::END_BLOCK)
{
putback(c);
}
return *this;
}
Foam::Istream& Foam::ISstream::readVerbatim(string& str)
{
static const int maxLen = 8000;

View File

@ -71,6 +71,8 @@ class ISstream
//- Read a verbatim string (excluding block delimiters).
Istream& readVerbatim(string&);
//- Read a variable name (includes '{')
Istream& readVariable(string&);
//- Disallow default bitwise assignment
void operator=(const ISstream&);

View File

@ -28,6 +28,7 @@ License
#include "functionEntry.H"
#include "includeEntry.H"
#include "inputModeEntry.H"
#include "stringOps.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -110,8 +111,19 @@ bool Foam::entry::New(dictionary& parentDict, Istream& is)
else if
(
!disableFunctionEntries
&& keyword[0] == '$') // ... Substitution entry
&& keyword[0] == '$'
) // ... Substitution entry
{
if (keyword.size() > 2 && keyword[1] == token::BEGIN_BLOCK)
{
// Recursive substitution mode. Replace between {} with
// expansion.
string s(keyword(2, keyword.size()-3));
// Substitute dictionary and environment variables. Allow
// empty substitutions.
stringOps::inplaceExpand(s, parentDict, true, true);
keyword.std::string::replace(1, keyword.size()-1, s);
}
parentDict.substituteScopedKeyword(keyword);
return true;
}

View File

@ -74,7 +74,8 @@ Foam::fileName Foam::functionEntries::includeEntry::includeFileName
)
{
fileName fName(is);
// Substitute dictionary and environment variables
// Substitute dictionary and environment variables. Allow empty
// substitutions.
stringOps::inplaceExpand(fName, dict, true, true);
if (fName.empty() || fName.isAbsolute())

View File

@ -26,6 +26,7 @@ License
#include "primitiveEntry.H"
#include "dictionary.H"
#include "OSspecific.H"
#include "stringOps.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -40,35 +41,52 @@ void Foam::primitiveEntry::append(const UList<token>& varTokens)
bool Foam::primitiveEntry::expandVariable
(
const word& w,
const string& w,
const dictionary& dict
)
{
word varName = w(1, w.size()-1);
// lookup the variable name in the given dictionary....
// Note: allow wildcards to match? For now disabled since following
// would expand internalField to wildcard match and not expected
// internalField:
// internalField XXX;
// boundaryField { ".*" {YYY;} movingWall {value $internalField;}
const entry* ePtr = dict.lookupScopedEntryPtr(varName, true, false);
// ...if defined append its tokens into this
if (ePtr)
if (w.size() > 2 && w[0] == '$' && w[1] == token::BEGIN_BLOCK)
{
append(ePtr->stream());
// Recursive substitution mode. Replace between {} with
// expansion.
string s(w(2, w.size()-3));
// Substitute dictionary and environment variables. Allow
// empty substitutions.
stringOps::inplaceExpand(s, dict, true, true);
string newW(w);
newW.std::string::replace(1, newW.size()-1, s);
return expandVariable(newW, dict);
}
else
{
// not in the dictionary - try an environment variable
string envStr = getEnv(varName);
string varName = w(1, w.size()-1);
if (envStr.empty())
// lookup the variable name in the given dictionary....
// Note: allow wildcards to match? For now disabled since following
// would expand internalField to wildcard match and not expected
// internalField:
// internalField XXX;
// boundaryField { ".*" {YYY;} movingWall {value $internalField;}
const entry* ePtr = dict.lookupScopedEntryPtr(varName, true, false);
// ...if defined append its tokens into this
if (ePtr)
{
return false;
append(ePtr->stream());
}
else
{
// not in the dictionary - try an environment variable
string envStr = getEnv(varName);
if (envStr.empty())
{
return false;
}
append(tokenList(IStringStream('(' + envStr + ')')()));
}
append(tokenList(IStringStream('(' + envStr + ')')()));
}
return true;
}

View File

@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@ -79,7 +79,7 @@ class primitiveEntry
);
//- Expand the given variable (keyword starts with $)
bool expandVariable(const word&, const dictionary&);
bool expandVariable(const string&, const dictionary&);
//- Expand the given function (keyword starts with #)
bool expandFunction

View File

@ -55,6 +55,24 @@ void Foam::primitiveEntry::append
newElmt(tokenIndex()++) = currToken;
}
}
else if (currToken.isString())
{
const string& w = currToken.stringToken();
if
(
disableFunctionEntries
|| w.size() <= 3
|| !(
w[0] == '$'
&& w[1] == token::BEGIN_BLOCK
&& expandVariable(w, dict)
)
)
{
newElmt(tokenIndex()++) = currToken;
}
}
else
{
newElmt(tokenIndex()++) = currToken;