diff --git a/etc/codeTemplates/dynamicCode/codeStreamTemplate.C b/etc/codeTemplates/dynamicCode/codeStreamTemplate.C index f90b42dd1e..4d7582bb02 100644 --- a/etc/codeTemplates/dynamicCode/codeStreamTemplate.C +++ b/etc/codeTemplates/dynamicCode/codeStreamTemplate.C @@ -27,8 +27,10 @@ Description \*---------------------------------------------------------------------------*/ #include "dictionary.H" +#include "fieldTypes.H" #include "Ostream.H" #include "Pstream.H" +#include "read.H" #include "unitConversion.H" //{{{ begin codeInclude diff --git a/src/OpenFOAM/db/dictionary/dictionary.H b/src/OpenFOAM/db/dictionary/dictionary.H index da905ba2df..4174ff7d2b 100644 --- a/src/OpenFOAM/db/dictionary/dictionary.H +++ b/src/OpenFOAM/db/dictionary/dictionary.H @@ -513,9 +513,11 @@ public: bool patternMatch=true ) const; - //- Find and return an entry data stream pointer if present - // otherwise return nullptr. Allows scoping using '/' with - // special handling for '!' and '..'. + //- Find and return an entry data stream pointer if present, + // otherwise return nullptr. + // If recursive, search parent dictionaries. + // If patternMatch, use regular expressions. + // Allows scoping using '/' with special handling for '!' and '..'. const entry* lookupScopedEntryPtr ( const word&, @@ -523,6 +525,19 @@ public: bool patternMatch ) const; + //- Find and return a T, + // if not found throw a fatal error. + // If recursive, search parent dictionaries. + // If patternMatch, use regular expressions. + // Allows scoping using '/' with special handling for '!' and '..'. + template + T lookupScoped + ( + const word&, + bool recursive=false, + bool patternMatch=true + ) const; + //- Check if entry is a sub-dictionary bool isDict(const word&) const; diff --git a/src/OpenFOAM/db/dictionary/dictionaryTemplates.C b/src/OpenFOAM/db/dictionary/dictionaryTemplates.C index 8cb82d2408..ead0342f04 100644 --- a/src/OpenFOAM/db/dictionary/dictionaryTemplates.C +++ b/src/OpenFOAM/db/dictionary/dictionaryTemplates.C @@ -223,6 +223,31 @@ bool Foam::dictionary::readIfPresent } +template +T Foam::dictionary::lookupScoped +( + const word& keyword, + bool recursive, + bool patternMatch +) const +{ + const entry* entryPtr = + lookupScopedEntryPtr(keyword, recursive, patternMatch); + + if (entryPtr == nullptr) + { + FatalIOErrorInFunction + ( + *this + ) << "keyword " << keyword << " is undefined in dictionary " + << name() + << exit(FatalIOError); + } + + return pTraits(entryPtr->stream()); +} + + template void Foam::dictionary::add(const keyType& k, const T& t, bool overwrite) { diff --git a/src/OpenFOAM/primitives/strings/string/string.C b/src/OpenFOAM/primitives/strings/string/string.C index b2f338c83c..a092aaa402 100644 --- a/src/OpenFOAM/primitives/strings/string/string.C +++ b/src/OpenFOAM/primitives/strings/string/string.C @@ -295,4 +295,26 @@ void Foam::string::strip(const string& str) } +Foam::string::size_type Foam::string::findClosing +( + const char c, + string::size_type i0 = 0 +) const +{ + size_t level = 1; + + string::size_type i = i0 + 1; + + while (level > 0 && i < size()) + { + if (operator[](i) == operator[](i0)) ++level; + if (operator[](i) == c) --level; + + ++i; + } + + return level == 0 ? i - 1 : string::npos; +} + + // ************************************************************************* // diff --git a/src/OpenFOAM/primitives/strings/string/string.H b/src/OpenFOAM/primitives/strings/string/string.H index b8c299ad06..6ea0485d9d 100644 --- a/src/OpenFOAM/primitives/strings/string/string.H +++ b/src/OpenFOAM/primitives/strings/string/string.H @@ -244,6 +244,24 @@ public: //- Strip characters from the start and end of the string void strip(const string&); + //- Find the closing character. Brackets counting algorithm. The + // opening bracket character is taken to be the one at the starting + // position. The closing character is provided by argument. + // + // Examples: + // + // [char #1] [char #15] + // | | + // V V + // string("0(2(4,6)8,a(c)e)g").findClosing(')',1) == 15 + // + // [char #3] [char #7] + // | | + // V V + // string("0(2(4,6)8,a(c)e)g").findClosing(')',3) == 7 + // + size_type findClosing(const char, const size_type) const; + // Member Operators diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOps.C b/src/OpenFOAM/primitives/strings/stringOps/stringOps.C index e2e9b0aebc..ff57c15eea 100644 --- a/src/OpenFOAM/primitives/strings/stringOps/stringOps.C +++ b/src/OpenFOAM/primitives/strings/stringOps/stringOps.C @@ -410,6 +410,7 @@ Foam::string& Foam::stringOps::inplaceExpandCodeString ( string& s, const dictionary& dict, + const word& dictVar, const char sigil ) { @@ -427,16 +428,28 @@ Foam::string& Foam::stringOps::inplaceExpandCodeString { // Find end of first occurrence string::size_type endVar = begVar; - string::size_type delim = 0; + string::size_type begDelim = 0, endDelim = 0; - if (s[begVar+1] == '{') + // Get the type, if any + word varType; + if (s[begVar+1] == '<') { - endVar = s.find('}', begVar); - delim = 1; + begDelim += s.findClosing('>', begVar+1) - begVar; + varType = s.substr(begVar+2, begDelim-2); + } + + // Parse any braces and find the end of the variable + if (s[begVar+begDelim+1] == '{') + { + endVar = s.find('}', begVar+begDelim); + begDelim += 1; + endDelim += 1; } else { - string::iterator iter = s.begin() + begVar + 1; + endVar = begVar + begDelim; + + string::iterator iter = s.begin() + begVar + begDelim + 1; // Accept all dictionary and environment variable characters while @@ -474,8 +487,8 @@ Foam::string& Foam::stringOps::inplaceExpandCodeString ( s.substr ( - begVar + 1 + delim, - endVar - begVar - 2*delim + begVar + begDelim + 1, + (endVar - endDelim) - (begVar + begDelim) ), false ); @@ -491,25 +504,54 @@ Foam::string& Foam::stringOps::inplaceExpandCodeString // Substitute if found if (ePtr) { - // Write to string buffer. Force floating point numbers to - // be printed with at least some decimal digits. OStringStream buf; - buf << scientific; - buf.precision(IOstream::defaultPrecision()); - if (ePtr->isDict()) + if (!dictVar.empty() && !varType.empty()) { - ePtr->dict().write(buf, false); + // If the dictionary is accessible and the type is + // known, then lookup the variable in the code, rather + // than substituting its value. That way we don't need + // to recompile this string if the value changes. + buf << dictVar + << ".lookupScoped<" << varType << ">" + << "(\"" << varName << "\", true, false)"; } - else if (isA(*ePtr)) + + if (dictVar.empty() && !varType.empty()) { - dynamicCast(*ePtr) - .write(buf, true); + // If the dictionary is not accessible but the type is + // known, then read the substituted value from a string + buf << "read<" << varType << ">(\""; } - else + + if (dictVar.empty() || varType.empty()) { - // Can't do any other types. Fail. - dynamicCast(*ePtr); + // If the dictionary is not accessible and/or the type + // is not known, then we need to substitute the + // variable's value + + // Make sure floating point values print with at least + // some decimal points + buf << scientific; + buf.precision(IOstream::defaultPrecision()); + + // Write the dictionary or primitive entry. Fail if + // anything else. + if (ePtr->isDict()) + { + ePtr->dict().write(buf, false); + } + else + { + dynamicCast(*ePtr) + .write(buf, true); + } + } + + if (dictVar.empty() && !varType.empty()) + { + // Close the string and read function as necessary + buf << "\")"; } s.std::string::replace diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H index f6ab369fe1..23167fcc2a 100644 --- a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H +++ b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H @@ -110,6 +110,7 @@ namespace stringOps ( string&, const dictionary& dict, + const word& dictVar = "dict", const char sigil = '$' );