diff --git a/applications/test/dictionary/testDict b/applications/test/dictionary/testDict index af6c565f6f..9aee1a35bf 100644 --- a/applications/test/dictionary/testDict +++ b/applications/test/dictionary/testDict @@ -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 } } diff --git a/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C b/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C index 04ed33f224..a3161386e6 100644 --- a/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C +++ b/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C @@ -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 -#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; diff --git a/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.H b/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.H index 9e1bb29610..3f6ebb42cd 100644 --- a/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.H +++ b/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.H @@ -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&); diff --git a/src/OpenFOAM/db/dictionary/entry/entryIO.C b/src/OpenFOAM/db/dictionary/entry/entryIO.C index dd16f4e6ed..c958b8f949 100644 --- a/src/OpenFOAM/db/dictionary/entry/entryIO.C +++ b/src/OpenFOAM/db/dictionary/entry/entryIO.C @@ -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; } diff --git a/src/OpenFOAM/db/dictionary/functionEntries/includeEntry/includeEntry.C b/src/OpenFOAM/db/dictionary/functionEntries/includeEntry/includeEntry.C index ee191e4eeb..bf57b9e3c8 100644 --- a/src/OpenFOAM/db/dictionary/functionEntries/includeEntry/includeEntry.C +++ b/src/OpenFOAM/db/dictionary/functionEntries/includeEntry/includeEntry.C @@ -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()) diff --git a/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntry.C b/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntry.C index 1349e66ebf..0566b8f350 100644 --- a/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntry.C +++ b/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntry.C @@ -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& 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; } diff --git a/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntry.H b/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntry.H index 06f680acaf..aa2c2ed36a 100644 --- a/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntry.H +++ b/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntry.H @@ -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 diff --git a/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntryIO.C b/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntryIO.C index 763981488c..d5626972cc 100644 --- a/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntryIO.C +++ b/src/OpenFOAM/db/dictionary/primitiveEntry/primitiveEntryIO.C @@ -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;