ENH: handle entry alternatives outside of string expansion

- string expansions have supported "${var:-default}" syntax for
  several versions, but this did not apply plain dictionary expansions.

  Eg, the following did not parse

     massFlow  ${entry1:-100};

ENH: remove content and length restriction on '${..}' quoted variables

- allows this type of content:

     velocity2  ${velocity1:- ( 0 -100 10) };

- accept empty parameter strings for entries. This allows the
  following expansion to work as expected:

      hex (n1 n2..)  ${inletBlock:-} (10 10 10) simpleGrading (1 1 1)

  ie, optionally define the cellZone name for a given block

ENH: add single parameter dictionary writeEntry method.

- the dictionary knows its own name (dictName), which can be used
  when writing content
This commit is contained in:
Mark Olesen
2020-02-21 14:37:11 +01:00
parent 3c9c39e92a
commit 083181cac4
5 changed files with 218 additions and 42 deletions

View File

@ -436,7 +436,7 @@ Foam::Istream& Foam::ISstream::read(word& str)
{ {
if (!depth) if (!depth)
{ {
break; // Closed ')' without a '(' ? ... stop break; // Closed ')' without an opening '(' ? ... stop
} }
--depth; --depth;
} }
@ -627,43 +627,55 @@ Foam::Istream& Foam::ISstream::readVariable(std::string& str)
} }
buf[nChar++] = c; buf[nChar++] = c;
char endChar = token::END_LIST; str.clear();
if (c == token::BEGIN_BLOCK) if (c == token::BEGIN_BLOCK)
{ {
// Processing ${...} style // Processing ${...} style.
endChar = token::END_BLOCK;
++depth; ++depth;
// Could check that the next char is good and not one of '{}' // Could check that the next char is good and not one of '{}'
// since this would indicate "${}", "${{..." or truncated "${" // since this would indicate "${}", "${{..." or truncated "${"
while while (get(c))
(
(nChar < maxLen) && get(c)
&&
(
validVariableChar(c)
|| (c == token::BEGIN_BLOCK || c == token::END_BLOCK)
)
)
{ {
buf[nChar++] = c;
if (nChar == maxLen)
{
str.append(buf, nChar);
nChar = 0;
}
if (c == token::BEGIN_BLOCK) if (c == token::BEGIN_BLOCK)
{ {
++depth; ++depth;
} }
else if (c == token::END_BLOCK) else if (c == token::END_BLOCK)
{ {
--depth;
if (!depth) if (!depth)
{ {
break; // Closed '}' without a '{' ? ... stop // Found closing '}' character
str.append(buf, nChar);
return *this;
} }
--depth;
} }
buf[nChar++] = c;
} }
// 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);
}
FatalIOErrorInFunction(*this)
<< "stream terminated while reading variable '"
<< str.c_str() << "...' [" << nChar << "]\n"
<< exit(FatalIOError);
return *this;
} }
else if (validVariableChar(c)) else if (validVariableChar(c))
{ {
@ -683,7 +695,7 @@ Foam::Istream& Foam::ISstream::readVariable(std::string& str)
{ {
if (!depth) if (!depth)
{ {
break; // Closed ')' without a '(' ? ... stop break; // Closed ')' without an opening '(' ? ... stop
} }
--depth; --depth;
} }
@ -733,7 +745,7 @@ Foam::Istream& Foam::ISstream::readVariable(std::string& str)
{ {
IOWarningInFunction(*this) IOWarningInFunction(*this)
<< "Missing " << depth << "Missing " << depth
<< " closing '" << endChar << "' while parsing" << nl << nl << " closing ')' while parsing" << nl << nl
<< buf << nl << endl; << buf << nl << endl;
} }
@ -762,7 +774,7 @@ Foam::Istream& Foam::ISstream::readVerbatim(std::string& str)
get(nextC); get(nextC);
if (nextC == token::END_BLOCK) if (nextC == token::END_BLOCK)
{ {
// The closing "#}" found // Found closing "#}" sequence
str.append(buf, nChar); str.append(buf, nChar);
return *this; return *this;
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-2019 OpenCFD Ltd. Copyright (C) 2016-2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -937,6 +937,9 @@ public:
// Write // Write
//- Write sub-dictionary with its dictName as its header
void writeEntry(Ostream& os) const;
//- Write sub-dictionary with the keyword as its header //- Write sub-dictionary with the keyword as its header
void writeEntry(const keyType& keyword, Ostream& os) const; void writeEntry(const keyType& keyword, Ostream& os) const;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-2019 OpenCFD Ltd. Copyright (C) 2016-2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -161,6 +161,14 @@ Foam::Istream& Foam::operator>>(Istream& is, dictionary& dict)
// * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * * //
void Foam::dictionary::writeEntry(Ostream& os) const
{
os.beginBlock(dictName());
writeEntries(os);
os.endBlock();
}
void Foam::dictionary::writeEntry(const keyType& kw, Ostream& os) const void Foam::dictionary::writeEntry(const keyType& kw, Ostream& os) const
{ {
os.beginBlock(kw); os.beginBlock(kw);

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2019 OpenCFD Ltd. Copyright (C) 2017-2020 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -31,6 +31,45 @@ License
#include "OSspecific.H" #include "OSspecific.H"
#include "stringOps.H" #include "stringOps.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
// Find the type/position of the ":-" or ":+" alternative values
// Returns 0, '-', '+' corresponding to not-found or ':-' or ':+'
static inline int findParameterAlternative
(
const std::string& s,
std::string::size_type& pos,
std::string::size_type endPos = std::string::npos
)
{
while (pos != std::string::npos)
{
pos = s.find(':', pos);
if (pos != std::string::npos)
{
if (pos < endPos)
{
// in-range: check for '+' or '-' following the ':'
const int altType = s[pos+1];
if (altType == '+' || altType == '-')
{
return altType;
}
++pos; // unknown/unsupported - continue at next position
}
else
{
// out-of-range: abort
pos = std::string::npos;
}
}
}
return 0;
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
bool Foam::primitiveEntry::expandVariable bool Foam::primitiveEntry::expandVariable
@ -39,19 +78,49 @@ bool Foam::primitiveEntry::expandVariable
const dictionary& dict const dictionary& dict
) )
{ {
int altType = 0; // Type ('-' or '+') for ":-" or ":+" alternatives
word expanded;
string altValue;
if (varName.size() > 1 && varName[0] == token::BEGIN_BLOCK) if (varName.size() > 1 && varName[0] == token::BEGIN_BLOCK)
{ {
// Recursive substitution mode. // Replace content between {} with string expansion and
// Content between {} is replaced with expansion. // handle ${parameter:-word} or ${parameter:+word}
string expanded(varName.substr(1, varName.size()-2));
// Copy into a word without stripping
expanded.assign(varName, 1, varName.size()-2);
// Substitute dictionary and environment variables. // Substitute dictionary and environment variables.
// Do not allow empty substitutions. // - Allow environment.
stringOps::inplaceExpand(expanded, dict, true, false); // - No empty substitutions.
// - No sub-dictionary lookups
return expandVariable(expanded, dict); stringOps::inplaceExpand(expanded, dict, true, false, false);
// Position of ":-" or ":+" alternative values
std::string::size_type altPos = 0;
// Check for parameter:-word or parameter:+word
altType = findParameterAlternative(expanded, altPos);
if (altType)
{
altValue = expanded.substr(altPos + 2);
expanded.erase(altPos);
}
// Catch really bad expansions and let them die soon after.
// Eg, ${:-other} should not be allowed.
if (expanded.empty())
{
altType = 0;
altValue.clear();
}
// Fallthrough for further processing
} }
// Lookup variable name in the given dictionary WITHOUT pattern matching. // Lookup variable name in the given dictionary WITHOUT pattern matching.
// Having a pattern match means that in this example: // Having a pattern match means that in this example:
// { // {
@ -61,18 +130,36 @@ bool Foam::primitiveEntry::expandVariable
// The $internalField would be matched by the ".*" !!! // The $internalField would be matched by the ".*" !!!
// Recursive, non-patterns // Recursive, non-patterns
const entry* eptr = dict.findScoped(varName, keyType::LITERAL_RECURSIVE);
const word& lookupName = (expanded.empty() ? varName : expanded);
const entry* eptr =
dict.findScoped(lookupName, keyType::LITERAL_RECURSIVE);
if (!eptr) if (!eptr)
{ {
// Not found - revert to environment variable // Not found - revert to environment variable
const string str(Foam::getEnv(varName)); // and parse into a series of tokens.
if (str.empty()) // We wish to fail if the environment variable returns
// an empty string and there is no alternative given.
//
// Always allow empty strings as alternative parameters,
// since the user provided them for a reason.
string str(Foam::getEnv(lookupName));
if (str.empty() ? (altType == '-') : (altType == '+'))
{
// Not found or empty: use ":-" alternative value
// Found and not empty: use ":+" alternative value
str = std::move(altValue);
}
else if (str.empty())
{ {
FatalIOErrorInFunction(dict) FatalIOErrorInFunction(dict)
<< "Illegal dictionary entry or environment variable name " << "Illegal dictionary entry or environment variable name "
<< varName << nl << lookupName << nl
<< "Known dictionary entries: " << dict.toc() << nl << "Known dictionary entries: " << dict.toc() << nl
<< exit(FatalIOError); << exit(FatalIOError);
@ -91,12 +178,33 @@ bool Foam::primitiveEntry::expandVariable
tokenList toks(eptr->dict().tokens()); tokenList toks(eptr->dict().tokens());
if (toks.empty() ? (altType == '-') : (altType == '+'))
{
// Not found or empty: use ":-" alternative value
// Found and not empty: use ":+" alternative value
toks = ITstream::parse(altValue, IOstream::ASCII);
}
ITstream::append(std::move(toks), true); // Lazy resizing ITstream::append(std::move(toks), true); // Lazy resizing
} }
else else
{ {
// Found primitive entry - copy tokens // Found primitive entry - copy tokens
ITstream::append(eptr->stream(), true); // Lazy resizing
if (eptr->stream().empty() ? (altType == '-') : (altType == '+'))
{
// Not found or empty: use ":-" alternative value
// Found and not empty: use ":+" alternative value
tokenList toks(ITstream::parse(altValue, IOstream::ASCII));
ITstream::append(std::move(toks), true); // Lazy resizing
}
else
{
ITstream::append(eptr->stream(), true); // Lazy resizing
}
} }
return true; return true;

View File

@ -1,7 +1,7 @@
/*--------------------------------*- C++ -*----------------------------------*\ /*--------------------------------*- C++ -*----------------------------------*\
| ========= | | | ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1912 | | \\ / O peration | Version: v2006 |
| \\ / A nd | Website: www.openfoam.com | | \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | | | \\/ M anipulation | |
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -14,21 +14,48 @@ FoamFile
} }
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Do comparison // Do comparison. Handles the first token after then '#if', which should
// correspond to a logical (true/false, ...) and integer (0,1, ...)
// but also a floating-point value with 0-1 range.
#if #eval "${FOAM_API:-0}" #if ${FOAM_API:-false}
foamApi nonZero; foamApi nonZero is ${FOAM_API:-0};
#else #else
foamApi zeroValue; foamApi zeroValue;
#endif #endif
#if #eval "${XX_XXX_FOAM_API:-1000}" #if ${XX_XXX_FOAM_API:-1000}
other "some entry"; other "some entry" ${XX_XXX_FOAM_API:-(0 1 0)};
#else #else
other "unexpected"; other "unexpected";
#endif #endif
#if 0.1
roundToZero failed;
#else
roundToZero good with ${__expand_or_ignore_:-};
#endif
#if 0.99
roundToOne good;
#else
roundToOne failed;
#endif
#if -0.1
roundNegZero failed;
#else
roundNegZero good;
#endif
#if -0.99
roundToNegOne good;
#else
roundToNegOne failed;
#endif
#if #eval "${FOAM_API:-0} >= 1910" #if #eval "${FOAM_API:-0} >= 1910"
evalType hasEvalWithConditionals; evalType hasEvalWithConditionals;
#else #else
@ -44,5 +71,23 @@ FoamFile
condition false; condition false;
#endif #endif
// Some other conditionals
condition1 true;
condition2 false;
#if ${unknown:-${condition2:-${condition1}}}
multiExpansion1 failed;
#else
multiExpansion1 good;
#endif
#if ${unknown:-${unknown:-${condition2:+true}}}
multiExpansion2 good = ${unkn:-${unkn:-${condition2:+on}}};
#else
multiExpansion2 failed;
#endif
// ************************************************************************* // // ************************************************************************* //