Commit 083181ca authored by Mark Olesen's avatar Mark Olesen
Browse files

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
parent 3c9c39e9
......@@ -436,7 +436,7 @@ Foam::Istream& Foam::ISstream::read(word& str)
{
if (!depth)
{
break; // Closed ')' without a '(' ? ... stop
break; // Closed ')' without an opening '(' ? ... stop
}
--depth;
}
......@@ -627,43 +627,55 @@ Foam::Istream& Foam::ISstream::readVariable(std::string& str)
}
buf[nChar++] = c;
char endChar = token::END_LIST;
str.clear();
if (c == token::BEGIN_BLOCK)
{
// Processing ${...} style
endChar = token::END_BLOCK;
// Processing ${...} style.
++depth;
// Could check that the next char is good and not one of '{}'
// since this would indicate "${}", "${{..." or truncated "${"
while
(
(nChar < maxLen) && get(c)
&&
(
validVariableChar(c)
|| (c == token::BEGIN_BLOCK || c == token::END_BLOCK)
)
)
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)
{
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))
{
......@@ -683,7 +695,7 @@ Foam::Istream& Foam::ISstream::readVariable(std::string& str)
{
if (!depth)
{
break; // Closed ')' without a '(' ? ... stop
break; // Closed ')' without an opening '(' ? ... stop
}
--depth;
}
......@@ -733,7 +745,7 @@ Foam::Istream& Foam::ISstream::readVariable(std::string& str)
{
IOWarningInFunction(*this)
<< "Missing " << depth
<< " closing '" << endChar << "' while parsing" << nl << nl
<< " closing ')' while parsing" << nl << nl
<< buf << nl << endl;
}
......@@ -762,7 +774,7 @@ Foam::Istream& Foam::ISstream::readVerbatim(std::string& str)
get(nextC);
if (nextC == token::END_BLOCK)
{
// The closing "#}" found
// Found closing "#}" sequence
str.append(buf, nChar);
return *this;
}
......
......@@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-2019 OpenCFD Ltd.
Copyright (C) 2016-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -937,6 +937,9 @@ public:
// Write
//- Write sub-dictionary with its dictName as its header
void writeEntry(Ostream& os) const;
//- Write sub-dictionary with the keyword as its header
void writeEntry(const keyType& keyword, Ostream& os) const;
......
......@@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-2019 OpenCFD Ltd.
Copyright (C) 2016-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -161,6 +161,14 @@ Foam::Istream& Foam::operator>>(Istream& is, dictionary& dict)
// * * * * * * * * * * * * * * 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
{
os.beginBlock(kw);
......
......@@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2019 OpenCFD Ltd.
Copyright (C) 2017-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -31,6 +31,45 @@ License
#include "OSspecific.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 * * * * * * * * * * * //
bool Foam::primitiveEntry::expandVariable
......@@ -39,19 +78,49 @@ bool Foam::primitiveEntry::expandVariable
const dictionary& dict
)
{
int altType = 0; // Type ('-' or '+') for ":-" or ":+" alternatives
word expanded;
string altValue;
if (varName.size() > 1 && varName[0] == token::BEGIN_BLOCK)
{
// Recursive substitution mode.
// Content between {} is replaced with expansion.
string expanded(varName.substr(1, varName.size()-2));
// Replace content between {} with string expansion and
// handle ${parameter:-word} or ${parameter:+word}
// Copy into a word without stripping
expanded.assign(varName, 1, varName.size()-2);
// Substitute dictionary and environment variables.
// Do not allow empty substitutions.
stringOps::inplaceExpand(expanded, dict, true, false);
// - Allow environment.
// - No empty substitutions.
// - No sub-dictionary lookups
stringOps::inplaceExpand(expanded, dict, true, false, false);
// Position of ":-" or ":+" alternative values
std::string::size_type altPos = 0;
return expandVariable(expanded, dict);
// 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.
// Having a pattern match means that in this example:
// {
......@@ -61,18 +130,36 @@ bool Foam::primitiveEntry::expandVariable
// The $internalField would be matched by the ".*" !!!
// 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)
{
// 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)
<< "Illegal dictionary entry or environment variable name "
<< varName << nl
<< lookupName << nl
<< "Known dictionary entries: " << dict.toc() << nl
<< exit(FatalIOError);
......@@ -91,12 +178,33 @@ bool Foam::primitiveEntry::expandVariable
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
}
else
{
// 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;
......
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v1912 |
| \\ / O peration | Version: v2006 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ 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}"
foamApi nonZero;
#if ${FOAM_API:-false}
foamApi nonZero is ${FOAM_API:-0};
#else
foamApi zeroValue;
#endif
#if #eval "${XX_XXX_FOAM_API:-1000}"
other "some entry";
#if ${XX_XXX_FOAM_API:-1000}
other "some entry" ${XX_XXX_FOAM_API:-(0 1 0)};
#else
other "unexpected";
#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"
evalType hasEvalWithConditionals;
#else
......@@ -44,5 +71,23 @@ FoamFile
condition false;
#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
// ************************************************************************* //
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment