Merge branch 'feature-dictionary-scoping-lvalue' into 'develop'

Feature dictionary scoping lvalue

See merge request Development/OpenFOAM-plus!124
This commit is contained in:
Mark Olesen
2017-10-29 15:36:07 +00:00
33 changed files with 2461 additions and 1489 deletions

View File

@ -13,18 +13,19 @@ FoamFile
object testDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#inputMode merge
#includeIfPresent "someUnknownFile"
#includeIfPresent "$FOAM_CASE/someUnknownFile"
#includeIfPresent "$FOAM_CASE/someUnknownFile-$FOAM_CASENAME"
internalField uniform 1;
// use 'protect' to supply defaults
#inputMode protect
internalField uniform 10;
dimensions [ 0 2 -2 0 0 0 0 ];
#inputMode merge
// supply defaults
#default internalField uniform 10;
#default dimensions [ 1 2 -2 0 0 0 0 ];
#overwrite dimensions [ 0 2 -2 0 0 0 0 ];
// #warn dimensions [ 0 2 -2 0 0 0 0 ];
// #error dimensions [ 0 2 -2 0 0 0 0 ];
active
{
@ -86,12 +87,12 @@ boundaryField
#remove inactive
inlet_7 { ${${varType}}} // Test indirection/recursive expansion
#inputMode overwrite
inlet_8 { $active }
#overwrite inlet_8 { type none; }
}
// NB: the inputMode has a global scope
#inputMode merge
#include "testDict2"
foo

View File

@ -17,6 +17,8 @@ FoamFile
// #inputMode overwrite
key1 val1;
val1 val1;
val2 val2;
subdict
{
@ -35,19 +37,75 @@ update
key3 val3;
key2b ${..key2};
key3b $^key1;
key100 100;
key200 200;
key300 300;
key400 400;
}
}
// expands update into top-level
$update
// Can a leading '^' or ':' as anchor for scoping
key3 $^subdict.key1;
_cleanup
{
#remove "/subdict/key300"
"/subdict/key400" 400000;
// Self-destruct not possible
// #remove "/_cleanup"
}
#remove "/_cleanup"
// Can use a leading '^' or ':' as anchor for scoping, but slashes are clearer
key3dot ${^subdict.key1};
key3slash ${/subdict/key1};
key3 ${^update.subdict.key3};
key4 ${:update.subdict...subdict.key1};
// This is currently not working
#remove update.key1
// #remove update
// This will not work, but globs would be interesting:
#remove "/update/subdict/key*"
// This is okay, uses a regexp directly
#remove "val.*"
#remove "/update/subdict/key100"
"/subdict/key2" overridden;
active
{
type turbulentIntensityKineticEnergyInlet;
intensity 0.1;
value 100;
}
// Some more with scoping
"/active/value(pwd)" 200;
"/active/'(pwd|foo)'" 200; // Can use single or double quotes
"/active/intensity" 0.05;
// Auto-vivify intermediate dictionaries
"/active/subdict/type" anotherType;
"/active/subdict/value/type" anotherType;
// This is an error - cannot change type of intermediate dictionaries!
// "active/value/type/of/things" newType;
"/active/subdict/value" change;
"/active/subdict/value" { entry1 value1; entry2 value2; }
// Handle remove as per changeDictionary? TBD
// Removal:
// "~/active/subdict/value"
// "~active"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016-2017 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -33,7 +33,7 @@ Usage
- \par -entry \<name\>
Selects an entry
- \par -keywords \<name\>
- \par -keywords
Prints the keywords (of the selected entry or of the top level if
no entry was selected
@ -50,6 +50,10 @@ Usage
Write differences with respect to the specified dictionary
(or sub entry if -entry specified)
- \par -diffEtc \<dictionary\>
Write differences with respect to the specified dictionary
(or sub entry if -entry specified)
- \par -expand
Read the specified dictionary file, expand the macros etc. and write
the resulting dictionary to standard output.
@ -90,13 +94,13 @@ Usage
- Write the differences with respect to a template dictionary:
\verbatim
foamDictionary 0/U -diff $FOAM_ETC/templates/closedVolume/0/U
foamDictionary 0/U -diffEtc templates/closedVolume/0/U
\endverbatim
- Write the differences in boundaryField with respect to a
template dictionary:
\verbatim
foamDictionary 0/U -diff $FOAM_ETC/templates/closedVolume/0/U \
foamDictionary 0/U -diffEtc templates/closedVolume/0/U \
-entry boundaryField
\endverbatim
@ -115,50 +119,78 @@ Usage
#include "profiling.H"
#include "Time.H"
#include "Fstream.H"
#include "etcFiles.H"
#include "includeEntry.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Converts old scope syntax to new syntax
word scope(const fileName& entryName)
//- Convert older ':' scope syntax to newer '.' scope syntax,
// but leave anything with '/' delimiters untouched
bool upgradeScope(word& entryName)
{
if (entryName.find(':') != string::npos)
if
(
entryName.find('/') == string::npos
&& entryName.find(':') != string::npos
)
{
wordList entryNames(entryName.components(':'));
const wordList names(fileName(entryName).components(':'));
word entry(entryNames[0]);
for (label i = 1; i < entryNames.size(); i++)
entryName.resize(0);
for (const word& name : names)
{
entry += word('.') + entryNames[i];
if (entryName.size()) entryName.append(".");
entryName.append(name);
}
return entry;
}
else
{
return entryName;
return true;
}
// Nothing changed
return false;
}
//- Extracts dict name and keyword
Pair<word> dictAndKeyword(const word& scopedName)
//- Split into dictionary name and the entry name
class dictAndKeyword
{
string::size_type i = scopedName.find_last_of(".");
if (i != string::npos)
word dict_;
word key_;
public:
dictAndKeyword(const word& scopedName)
{
return Pair<word>
(
scopedName.substr(0, i),
scopedName.substr(i+1, string::npos)
);
string::size_type i = scopedName.rfind('/');
if (i == string::npos)
{
i = scopedName.rfind('.');
}
if (i != string::npos)
{
dict_ = scopedName.substr(0, i);
key_ = scopedName.substr(i+1);
}
else
{
key_ = scopedName;
}
}
else
inline const word& dict() const
{
return Pair<word>("", scopedName);
return dict_;
}
}
inline const word& key() const
{
return key_;
}
};
const dictionary& lookupScopedDict
@ -167,71 +199,56 @@ const dictionary& lookupScopedDict
const word& subDictName
)
{
if (subDictName == "")
if (subDictName.empty())
{
return dict;
}
else
const entry* eptr = dict.lookupScopedEntryPtr(subDictName, false, false);
if (!eptr || !eptr->isDict())
{
const entry* entPtr = dict.lookupScopedEntryPtr
(
subDictName,
false,
false
);
if (!entPtr || !entPtr->isDict())
{
FatalIOErrorInFunction(dict)
<< "keyword " << subDictName
<< " is undefined in dictionary "
<< dict.name() << " or is not a dictionary"
<< endl
<< "Valid keywords are " << dict.keys()
<< exit(FatalIOError);
}
return entPtr->dict();
FatalIOErrorInFunction(dict)
<< "keyword " << subDictName
<< " is undefined in dictionary "
<< dict.name() << " or is not a dictionary"
<< endl
<< "Valid keywords are " << dict.keys()
<< exit(FatalIOError);
}
return eptr->dict();
}
void remove(dictionary& dict, const dictionary& removeDict)
void removeDict(dictionary& dict, const dictionary& dictToRemove)
{
forAllConstIter(dictionary, removeDict, iter)
for (const entry& refEntry : dictToRemove)
{
const entry* entPtr = dict.lookupEntryPtr
(
iter().keyword(),
false,
false
);
auto finder = dict.search(refEntry.keyword(), false, false);
if (entPtr)
bool purge = false;
if (finder.isDict())
{
if (entPtr->isDict())
if (refEntry.isDict())
{
if (iter().isDict())
{
remove
(
const_cast<dictionary&>(entPtr->dict()),
iter().dict()
);
removeDict(finder.dict(), refEntry.dict());
// Check if dictionary is empty
if (!entPtr->dict().size())
{
dict.remove(iter().keyword());
}
}
}
else if (!iter().isDict())
{
if (*entPtr == iter())
{
dict.remove(iter().keyword());
}
// Purge if dictionary is empty
purge = finder.dict().empty();
}
}
else if (finder.found() && !refEntry.isDict())
{
// Purge if entries match
purge = (finder.ref() == refEntry);
}
if (purge)
{
dict.remove(refEntry.keyword());
}
}
}
@ -243,7 +260,7 @@ int main(int argc, char *argv[])
argList::noBanner();
argList::noJobInfo();
argList::validArgs.append("dictionary");
argList::addBoolOption("keywords", "list keywords");
argList::addBoolOption("keywords", "List keywords");
argList::addOption("entry", "name", "report/select the named entry");
argList::addBoolOption
(
@ -273,6 +290,12 @@ int main(int argc, char *argv[])
"dict",
"Write differences with respect to the specified dictionary"
);
argList::addOption
(
"diffEtc",
"dict",
"As per -diff, but locate the file as per foamEtcFile"
);
argList::addBoolOption
(
"includes",
@ -303,13 +326,12 @@ int main(int argc, char *argv[])
const bool disableEntries = args.optionFound("disableFunctionEntries");
if (disableEntries)
{
Info<< "Not expanding variables or dictionary directives"
<< endl;
Info<< "Not expanding variables or dictionary directives" << endl;
entry::disableFunctionEntries = true;
}
fileName dictFileName(args[1]);
const fileName dictFileName(args[1]);
autoPtr<IFstream> dictFile(new IFstream(dictFileName));
if (!dictFile().good())
@ -341,28 +363,55 @@ int main(int argc, char *argv[])
}
// Second dictionary for -diff
dictionary diffDict;
fileName diffFileName;
if (args.optionReadIfPresent("diff", diffFileName))
{
autoPtr<IFstream> diffFile(new IFstream(diffFileName));
if (!diffFile().good())
{
FatalErrorInFunction
<< "Cannot open file " << diffFileName
<< exit(FatalError, 1);
}
// Has "diff" or "diffEtc"
bool optDiff = false;
// Read but preserve headers
diffDict.read(diffFile(), true);
// Reference dictionary for -diff / -diffEtc
dictionary diffDict;
{
fileName diffFileName;
if (args.optionReadIfPresent("diff", diffFileName))
{
IFstream diffFile(diffFileName);
if (!diffFile.good())
{
FatalErrorInFunction
<< "Cannot open file " << diffFileName
<< exit(FatalError, 1);
}
// Read but preserve headers
diffDict.read(diffFile, true);
optDiff = true;
}
else if (args.optionReadIfPresent("diffEtc", diffFileName))
{
fileName foundName = findEtcFile(diffFileName);
if (foundName.empty())
{
FatalErrorInFunction
<< "Cannot find etcFile " << diffFileName
<< exit(FatalError, 1);
}
IFstream diffFile(foundName);
if (!diffFile.good())
{
FatalErrorInFunction
<< "Cannot open file " << foundName
<< exit(FatalError, 1);
}
// Read but preserve headers
diffDict.read(diffFile, true);
optDiff = true;
}
}
word entryName;
if (args.optionReadIfPresent("entry", entryName))
word scopedName; // Actually fileName, since it can contain '/' scoping
if (args.optionReadIfPresent("entry", scopedName))
{
word scopedName(scope(entryName));
upgradeScope(scopedName);
string newValue;
if
@ -371,13 +420,17 @@ int main(int argc, char *argv[])
|| args.optionReadIfPresent("add", newValue)
)
{
bool overwrite = args.optionFound("set");
const bool overwrite = args.optionFound("set");
Pair<word> dAk(dictAndKeyword(scopedName));
// Dictionary name and keyword
const dictAndKeyword dAk(scopedName);
IStringStream str(string(dAk.second()) + ' ' + newValue + ';');
// The context for the action
const dictionary& d(lookupScopedDict(dict, dAk.dict()));
// Create a new entry
IStringStream str(string(dAk.key()) + ' ' + newValue + ';');
entry* ePtr(entry::New(str).ptr());
const dictionary& d(lookupScopedDict(dict, dAk.first()));
if (overwrite)
{
@ -390,122 +443,116 @@ int main(int argc, char *argv[])
changed = true;
// Print the changed entry
const entry* entPtr = dict.lookupScopedEntryPtr
const auto finder = dict.csearchScoped
(
scopedName,
false,
true // Support wildcards
true // Support wildcards
);
if (entPtr)
if (finder.found())
{
Info<< *entPtr;
Info<< finder.ref();
}
}
else if (args.optionFound("remove"))
{
// Extract dictionary name and keyword
Pair<word> dAk(dictAndKeyword(scopedName));
// Dictionary name and keyword
const dictAndKeyword dAk(scopedName);
const dictionary& d(lookupScopedDict(dict, dAk.first()));
const_cast<dictionary&>(d).remove(dAk.second());
// The context for the action
const dictionary& d(lookupScopedDict(dict, dAk.dict()));
const_cast<dictionary&>(d).remove(dAk.key());
changed = true;
}
else
{
// Optionally remove a second dictionary
if (args.optionFound("diff"))
if (optDiff)
{
Pair<word> dAk(dictAndKeyword(scopedName));
// Dictionary name and keyword
const dictAndKeyword dAk(scopedName);
const dictionary& d(lookupScopedDict(dict, dAk.first()));
const dictionary& d2(lookupScopedDict(diffDict, dAk.first()));
const dictionary& d1(lookupScopedDict(dict, dAk.dict()));
const dictionary& d2(lookupScopedDict(diffDict, dAk.dict()));
const entry* ePtr =
d.lookupEntryPtr(dAk.second(), false, true);
const entry* e2Ptr =
d2.lookupEntryPtr(dAk.second(), false, true);
const entry* e1Ptr = d1.lookupEntryPtr(dAk.key(), false, true);
const entry* e2Ptr = d2.lookupEntryPtr(dAk.key(), false, true);
if (ePtr && e2Ptr)
if (e1Ptr && e2Ptr)
{
if (*ePtr == *e2Ptr)
if (*e1Ptr == *e2Ptr)
{
const_cast<dictionary&>(d).remove(dAk.second());
const_cast<dictionary&>(d1).remove(dAk.key());
}
else if (ePtr->isDict() && e2Ptr->isDict())
else if (e1Ptr->isDict() && e2Ptr->isDict())
{
remove
removeDict
(
const_cast<dictionary&>(ePtr->dict()),
const_cast<dictionary&>(e1Ptr->dict()),
e2Ptr->dict()
);
}
}
}
const entry* entPtr = dict.lookupScopedEntryPtr
const auto finder = dict.csearchScoped
(
scopedName,
false,
true // Support wildcards
true // Support wildcards
);
if (entPtr)
if (!finder.found())
{
if (args.optionFound("keywords"))
FatalIOErrorInFunction(dictFile())
<< "Cannot find entry " << scopedName
<< exit(FatalIOError, 2);
}
else if (args.optionFound("keywords"))
{
for (const entry& e : finder.dict())
{
const dictionary& dict = entPtr->dict();
forAllConstIter(dictionary, dict, iter)
{
Info<< iter().keyword() << endl;
}
Info<< e.keyword() << endl;
}
else
}
else if (args.optionFound("value"))
{
if (finder.isDict())
{
if (args.optionFound("value"))
Info<< finder.dict();
}
else if (finder.ref().isStream())
{
const tokenList& tokens = finder.ref().stream();
forAll(tokens, i)
{
if (entPtr->isStream())
Info<< tokens[i];
if (i < tokens.size() - 1)
{
const tokenList& tokens = entPtr->stream();
forAll(tokens, i)
{
Info<< tokens[i];
if (i < tokens.size() - 1)
{
Info<< token::SPACE;
}
}
Info<< endl;
}
else if (entPtr->isDict())
{
Info<< entPtr->dict();
Info<< token::SPACE;
}
}
else
{
Info<< *entPtr;
}
Info<< endl;
}
}
else
{
FatalIOErrorInFunction(dictFile)
<< "Cannot find entry " << entryName
<< exit(FatalIOError, 2);
Info<< finder.ref();
}
}
}
else if (args.optionFound("keywords"))
{
forAllConstIter(dictionary, dict, iter)
for (const entry& e : dict)
{
Info<< iter().keyword() << endl;
Info<< e.keyword() << endl;
}
}
else if (args.optionFound("diff"))
else if (optDiff)
{
remove(dict, diffDict);
removeDict(dict, diffDict);
dict.write(Info, false);
}
else

View File

@ -14,8 +14,6 @@ FoamFile
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#inputMode merge;
surfaceConformation
{
pointPairDistanceCoeff 0.1;

View File

@ -203,6 +203,7 @@ $(Pstreams)/PstreamBuffers.C
dictionary = db/dictionary
$(dictionary)/dictionary.C
$(dictionary)/dictionaryIO.C
$(dictionary)/dictionarySearch.C
entry = $(dictionary)/entry
$(entry)/entry.C

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -28,6 +28,12 @@ License
#include "token.H"
#include <cctype>
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
// Truncate error message for readability
static const unsigned errLen = 80;
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
char Foam::ISstream::nextValid()
@ -43,7 +49,7 @@ char Foam::ISstream::nextValid()
// Return if stream is bad - ie, previous get() failed
if (bad() || isspace(c))
{
break;
return 0;
}
// Is this the start of a C/C++ comment?
@ -51,7 +57,7 @@ char Foam::ISstream::nextValid()
{
if (!get(c))
{
// cannot get another character - return this one
// Cannot get another character - return this one
return '/';
}
@ -63,10 +69,10 @@ char Foam::ISstream::nextValid()
}
else if (c == '*')
{
// within a C-style comment
// Within a C-style comment
while (true)
{
// search for end of C-style comment - '*/'
// Search for end of C-style comment - '*/'
if (get(c) && c == '*')
{
if (get(c))
@ -99,7 +105,7 @@ char Foam::ISstream::nextValid()
}
else
{
// a valid character - return it
// A valid character - return it
return c;
}
}
@ -124,14 +130,14 @@ void Foam::ISstream::readWordToken(token& t)
}
else
{
t = wPtr;
t = wPtr; // Token takes ownership
}
}
Foam::Istream& Foam::ISstream::read(token& t)
{
static const int maxLen = 128;
static const unsigned maxLen = 128; // When parsing labels or scalars
static char buf[maxLen];
// Return the put back token if it exists
@ -151,7 +157,7 @@ Foam::Istream& Foam::ISstream::read(token& t)
// Set the line number of this token to the current stream line number
t.lineNumber() = lineNumber();
// return on error
// Return on error
if (!c)
{
t.setBad();
@ -182,7 +188,6 @@ Foam::Istream& Foam::ISstream::read(token& t)
return *this;
}
// String: enclosed by double quotes.
case token::BEGIN_STRING :
{
@ -196,24 +201,24 @@ Foam::Istream& Foam::ISstream::read(token& t)
}
else
{
t = sPtr;
t = sPtr; // Token takes ownership
}
return *this;
}
// Possible verbatim string or dictionary functionEntry
case token::HASH :
{
char nextC;
if (read(nextC).bad())
{
// Return hash as word
// Return lone '#' as word
t = token(word(c));
return *this;
}
else if (nextC == token::BEGIN_BLOCK)
{
// Verbatim string
// Verbatim string: #{ ... #}
string* sPtr = new string;
if (readVerbatim(*sPtr).bad())
@ -223,36 +228,34 @@ Foam::Istream& Foam::ISstream::read(token& t)
}
else
{
t = sPtr;
t = sPtr; // Token takes ownership
t.type() = token::tokenType::VERBATIMSTRING;
}
return *this;
}
else
{
// Word beginning with #
// Word beginning with '#'. Eg, "#include"
putback(nextC);
putback(c);
readWordToken(t);
return *this;
}
return *this;
}
// Dictionary variable (as rvalue)
case '$':
{
// Look ahead
char nextC;
if (read(nextC).bad())
{
// Return $ as word
// Return lone '$' as word
t = token(word(c));
return *this;
}
else if (nextC == token::BEGIN_BLOCK)
{
// Put back so that "${" is included in the variable
putback(nextC);
putback(c);
@ -265,18 +268,20 @@ Foam::Istream& Foam::ISstream::read(token& t)
}
else
{
t = sPtr;
t = sPtr; // Token takes ownership
t.type() = token::tokenType::VARIABLE;
}
return *this;
}
else
{
// Word/variable beginning with '$', but without "{}"
putback(nextC);
putback(c);
readWordToken(t);
return *this;
}
return *this;
}
// Number: integer or floating point
@ -292,7 +297,7 @@ Foam::Istream& Foam::ISstream::read(token& t)
{
bool asLabel = (c != '.');
int nChar = 0;
unsigned nChar = 0;
buf[nChar++] = c;
// get everything that could resemble a number and let
@ -343,43 +348,26 @@ Foam::Istream& Foam::ISstream::read(token& t)
if (nChar == 1 && buf[0] == '-')
{
// a single '-' is punctuation
// A single '-' is punctuation
t = token::punctuationToken(token::SUBTRACT);
}
else
{
if (asLabel)
label labelVal;
scalar scalarVal;
if (asLabel && Foam::read(buf, labelVal))
{
label labelVal = 0;
if (Foam::read(buf, labelVal))
{
t = labelVal;
}
else
{
// Maybe too big? Try as scalar
scalar scalarVal;
if (readScalar(buf, scalarVal))
{
t = scalarVal;
}
else
{
t.setBad();
}
}
t = labelVal;
}
else if (readScalar(buf, scalarVal))
{
// A scalar or too big to fit as a label
t = scalarVal;
}
else
{
scalar scalarVal;
if (readScalar(buf, scalarVal))
{
t = scalarVal;
}
else
{
t.setBad();
}
t.setBad();
}
}
}
@ -409,28 +397,28 @@ Foam::Istream& Foam::ISstream::read(char& c)
Foam::Istream& Foam::ISstream::read(word& str)
{
static const int maxLen = 1024;
static const int errLen = 80; // truncate error message for readability
static const unsigned maxLen = 1024;
static char buf[maxLen];
int nChar = 0;
int listDepth = 0;
unsigned nChar = 0;
unsigned depth = 0; // Track depth of "()" nesting
char c;
while (get(c) && word::valid(c))
{
if (c == token::BEGIN_LIST)
{
listDepth++;
++depth;
}
else if (c == token::END_LIST)
{
if (listDepth)
if (depth)
{
listDepth--;
--depth;
}
else
{
// Had ')' without a previous '(' ... stop
break;
}
}
@ -449,10 +437,13 @@ Foam::Istream& Foam::ISstream::read(word& str)
}
}
// we could probably skip this check
// Terminate string with nul char
buf[nChar] = '\0';
// We could probably skip this check
if (bad())
{
buf[errLen] = buf[nChar] = '\0';
buf[errLen] = '\0';
FatalIOErrorInFunction(*this)
<< "problem while reading word '" << buf << "...' after "
@ -468,9 +459,14 @@ Foam::Istream& Foam::ISstream::read(word& str)
<< "invalid first character found : " << c
<< exit(FatalIOError);
}
else if (depth)
{
IOWarningInFunction(*this)
<< "Missing " << depth << " closing ')' while parsing" << nl << nl
<< buf << nl << endl;
}
// done reading
buf[nChar] = '\0';
// Finalize
str = buf;
putback(c);
@ -480,8 +476,7 @@ Foam::Istream& Foam::ISstream::read(word& str)
Foam::Istream& Foam::ISstream::read(string& str)
{
static const int maxLen = 1024;
static const int errLen = 80; // truncate error message for readability
static const unsigned maxLen = 1024;
static char buf[maxLen];
char c;
@ -505,7 +500,7 @@ Foam::Istream& Foam::ISstream::read(string& str)
return *this;
}
int nChar = 0;
unsigned nChar = 0;
bool escaped = false;
while (get(c))
@ -515,11 +510,11 @@ Foam::Istream& Foam::ISstream::read(string& str)
if (escaped)
{
escaped = false;
nChar--; // overwrite backslash
--nChar; // Overwrite backslash
}
else
{
// done reading
// Done reading
buf[nChar] = '\0';
str = buf;
return *this;
@ -530,7 +525,7 @@ Foam::Istream& Foam::ISstream::read(string& str)
if (escaped)
{
escaped = false;
nChar--; // overwrite backslash
--nChar; // Overwrite backslash
}
else
{
@ -581,12 +576,11 @@ Foam::Istream& Foam::ISstream::read(string& str)
Foam::Istream& Foam::ISstream::readVariable(string& str)
{
static const int maxLen = 1024;
static const int errLen = 80; // truncate error message for readability
static const unsigned maxLen = 1024;
static char buf[maxLen];
int nChar = 0;
int blockCount = 0;
unsigned nChar = 0;
unsigned depth = 0; // Track depth of "{}" nesting
char c;
if (!get(c) || c != '$')
@ -601,8 +595,8 @@ Foam::Istream& Foam::ISstream::readVariable(string& str)
// Read next character to see if '{'
if (get(c) && c == token::BEGIN_BLOCK)
{
// Read, counting brackets
buf[nChar++] = c;
++depth; // Starts with '{'
// Also allow '/' between ${...} blocks for slash-scoping of entries
while
@ -615,6 +609,23 @@ Foam::Istream& Foam::ISstream::readVariable(string& str)
)
)
{
if (c == token::BEGIN_BLOCK)
{
++depth;
}
else if (c == token::END_BLOCK)
{
if (depth)
{
--depth;
}
else
{
// Had '}' without a previous '{' ... stop
break;
}
}
buf[nChar++] = c;
if (nChar == maxLen)
{
@ -627,22 +638,6 @@ Foam::Istream& Foam::ISstream::readVariable(string& str)
return *this;
}
if (c == token::BEGIN_BLOCK)
{
blockCount++;
}
else if (c == token::END_BLOCK)
{
if (blockCount)
{
blockCount--;
}
else
{
break;
}
}
}
}
else
@ -666,10 +661,13 @@ Foam::Istream& Foam::ISstream::readVariable(string& str)
}
}
// Terminate string with nul char
buf[nChar] = '\0';
// we could probably skip this check
if (bad())
{
buf[errLen] = buf[nChar] = '\0';
buf[errLen] = '\0';
FatalIOErrorInFunction(*this)
<< "problem while reading string '" << buf << "...' after "
@ -685,31 +683,29 @@ Foam::Istream& Foam::ISstream::readVariable(string& str)
<< "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)
else if (depth)
{
putback(c);
IOWarningInFunction(*this)
<< "Missing " << depth << " closing '}' while parsing" << nl << nl
<< buf << nl << endl;
}
// Finalize
str = buf;
putback(c);
return *this;
}
Foam::Istream& Foam::ISstream::readVerbatim(string& str)
{
static const int maxLen = 8000;
static const int errLen = 80; // truncate error message for readability
static const unsigned maxLen = 8000;
static char buf[maxLen];
unsigned nChar = 0;
char c;
int nChar = 0;
while (get(c))
{
if (c == token::HASH)
@ -718,6 +714,7 @@ Foam::Istream& Foam::ISstream::readVerbatim(string& str)
get(nextC);
if (nextC == token::END_BLOCK)
{
// The closing "#}" found
buf[nChar] = '\0';
str = buf;
return *this;

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -69,9 +69,12 @@ class ISstream
//- Read a verbatim string (excluding block delimiters).
// The leading "#{" has been removed prior to calling,
// continues until the closing "#}" has been found.
Istream& readVerbatim(string& str);
//- Read a variable name (includes '{')
//- Read a variable name starting with '$'.
// Handles both "$var" and "${var}" forms.
Istream& readVariable(string& str);
//- Disallow default bitwise assignment

View File

@ -102,7 +102,7 @@ Foam::Ostream& Foam::prefixOSstream::write(const char* str)
checkWritePrefix();
OSstream::write(str);
size_t len = strlen(str);
const size_t len = strlen(str);
if (len && str[len-1] == token::NL)
{
printPrefix_ = true;

View File

@ -45,157 +45,6 @@ bool Foam::dictionary::writeOptionalEntries
);
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
namespace Foam
{
// file-scope
//- Walk lists of patterns and regexps for an exact match
// or regular expression match
template<class WcIterator, class ReIterator>
static bool findInPatterns
(
const bool patternMatch,
const word& keyword,
WcIterator& wcIter,
ReIterator& reIter
)
{
while (wcIter.found())
{
if
(
patternMatch
? reIter()->match(keyword)
: wcIter()->keyword() == keyword
)
{
return true;
}
++reIter;
++wcIter;
}
return false;
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
const Foam::entry* Foam::dictionary::lookupScopedSubEntryPtr
(
const word& keyword,
bool recursive,
bool patternMatch
) const
{
string::size_type dotPos = keyword.find('.');
if (dotPos == string::npos)
{
// Non-scoped lookup
return lookupEntryPtr(keyword, recursive, patternMatch);
}
else if (dotPos == 0)
{
// Starting with a '.' -> go up for every further '.' found
++dotPos;
const dictionary* dictPtr = this;
for
(
string::const_iterator it = keyword.begin()+1;
it != keyword.end() && *it == '.';
++dotPos, ++it
)
{
// Go to parent
if (&dictPtr->parent_ != &dictionary::null)
{
dictPtr = &dictPtr->parent_;
}
else
{
FatalIOErrorInFunction
(
*this
) << "No parent of current dictionary when searching for "
<< keyword.substr(1)
<< exit(FatalIOError);
return nullptr;
}
}
return dictPtr->lookupScopedSubEntryPtr
(
keyword.substr(dotPos),
false,
patternMatch
);
}
else
{
// The first word
const entry* entPtr = lookupScopedSubEntryPtr
(
keyword.substr(0, dotPos),
false,
patternMatch
);
if (!entPtr)
{
// Fall back to finding key with '.' so e.g. if keyword is
// a.b.c.d it would try
// a.b, a.b.c, a.b.c.d
while (true)
{
dotPos = keyword.find('.', dotPos+1);
entPtr = lookupEntryPtr
(
keyword.substr(0, dotPos),
false,
patternMatch
);
if (dotPos == string::npos)
{
// Parsed the whole word. Return entry or null.
return entPtr;
}
if (entPtr && entPtr->isDict())
{
return entPtr->dict().lookupScopedSubEntryPtr
(
keyword.substr(dotPos),
false,
patternMatch
);
}
}
}
if (entPtr->isDict())
{
return entPtr->dict().lookupScopedSubEntryPtr
(
keyword.substr(dotPos),
false,
patternMatch
);
}
}
return nullptr;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::dictionary::dictionary()
@ -322,10 +171,8 @@ const Foam::dictionary& Foam::dictionary::topDict() const
{
return p.topDict();
}
else
{
return *this;
}
return *this;
}
@ -335,10 +182,8 @@ Foam::label Foam::dictionary::startLineNumber() const
{
return first()->startLineNumber();
}
else
{
return -1;
}
return -1;
}
@ -348,10 +193,8 @@ Foam::label Foam::dictionary::endLineNumber() const
{
return last()->endLineNumber();
}
else
{
return -1;
}
return -1;
}
@ -395,29 +238,7 @@ bool Foam::dictionary::found
bool patternMatch
) const
{
if (hashedEntries_.found(keyword))
{
return true;
}
if (patternMatch && patterns_.size())
{
pattern_const_iterator wcLink = patterns_.begin();
regexp_const_iterator reLink = regexps_.begin();
// Find in patterns using regular expressions only
if (findInPatterns(patternMatch, keyword, wcLink, reLink))
{
return true;
}
}
if (recursive && &parent_ != &dictionary::null)
{
return parent_.found(keyword, recursive, patternMatch);
}
return false;
return csearch(keyword, recursive, patternMatch).found();
}
@ -428,31 +249,7 @@ const Foam::entry* Foam::dictionary::lookupEntryPtr
bool patternMatch
) const
{
auto iter = hashedEntries_.cfind(keyword);
if (iter.found())
{
return iter();
}
if (patternMatch && patterns_.size())
{
pattern_const_iterator wcLink = patterns_.begin();
regexp_const_iterator reLink = regexps_.begin();
// Find in patterns using regular expressions only
if (findInPatterns(patternMatch, keyword, wcLink, reLink))
{
return wcLink();
}
}
if (recursive && &parent_ != &dictionary::null)
{
return parent_.lookupEntryPtr(keyword, recursive, patternMatch);
}
return nullptr;
return csearch(keyword, recursive, patternMatch).ptr();
}
@ -463,36 +260,7 @@ Foam::entry* Foam::dictionary::lookupEntryPtr
bool patternMatch
)
{
auto iter = hashedEntries_.find(keyword);
if (iter.found())
{
return iter();
}
if (patternMatch && patterns_.size())
{
pattern_iterator wcLink = patterns_.begin();
regexp_iterator reLink = regexps_.begin();
// Find in patterns using regular expressions only
if (findInPatterns(patternMatch, keyword, wcLink, reLink))
{
return wcLink();
}
}
if (recursive && &parent_ != &dictionary::null)
{
return const_cast<dictionary&>(parent_).lookupEntryPtr
(
keyword,
recursive,
patternMatch
);
}
return nullptr;
return search(keyword, recursive, patternMatch).ptr();
}
@ -503,9 +271,9 @@ const Foam::entry& Foam::dictionary::lookupEntry
bool patternMatch
) const
{
const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch);
auto finder = csearch(keyword, recursive, patternMatch);
if (entryPtr == nullptr)
if (!finder.found())
{
FatalIOErrorInFunction
(
@ -515,7 +283,7 @@ const Foam::entry& Foam::dictionary::lookupEntry
<< exit(FatalIOError);
}
return *entryPtr;
return finder.ref();
}
@ -537,29 +305,37 @@ const Foam::entry* Foam::dictionary::lookupScopedEntryPtr
bool patternMatch
) const
{
if ((keyword[0] == ':' || keyword[0] == '^'))
{
// Go up to top level
const dictionary* dictPtr = this;
while (&dictPtr->parent_ != &dictionary::null)
{
dictPtr = &dictPtr->parent_;
}
return csearchScoped(keyword, recursive, patternMatch).ptr();
}
return dictPtr->lookupScopedSubEntryPtr
(
keyword.substr(1),
false,
patternMatch
);
bool Foam::dictionary::substituteKeyword(const word& keyword, bool mergeEntry)
{
if (keyword.size() < 2)
{
return false;
}
return lookupScopedSubEntryPtr
(
keyword,
recursive,
patternMatch
);
// Drop leading '$' to get the var-name, already validated as word.
const word varName(keyword.substr(1), false);
// Lookup the variable name in the given dictionary
const_searcher finder = csearch(varName, true, true);
// If defined insert its entries into this dictionary
if (finder.found())
{
const dictionary& addDict = finder.dict();
forAllConstIters(addDict, iter)
{
add(iter(), mergeEntry);
}
return true;
}
return false;
}
@ -569,16 +345,21 @@ bool Foam::dictionary::substituteScopedKeyword
bool mergeEntry
)
{
// Drop first character of keyword to get the var-name, already validated.
if (keyword.size() < 2)
{
return false;
}
// Drop leading '$' to get the var-name, already validated as word.
const word varName(keyword.substr(1), false);
// Lookup the variable name in the given dictionary
const entry* ePtr = lookupScopedEntryPtr(varName, true, true);
const_searcher finder = csearchScoped(varName, true, true);
// If defined insert its entries into this dictionary
if (ePtr != nullptr)
if (finder.found())
{
const dictionary& addDict = ePtr->dict();
const dictionary& addDict = finder.dict();
forAllConstIter(parent_type, addDict, iter)
{
@ -595,54 +376,30 @@ bool Foam::dictionary::substituteScopedKeyword
bool Foam::dictionary::isDict(const word& keyword) const
{
// Find non-recursive with patterns
const entry* entryPtr = lookupEntryPtr(keyword, false, true);
if (entryPtr)
{
return entryPtr->isDict();
}
else
{
return false;
}
return csearch(keyword, false, true).isDict();
}
const Foam::dictionary* Foam::dictionary::subDictPtr(const word& keyword) const
{
const entry* entryPtr = lookupEntryPtr(keyword, false, true);
if (entryPtr)
{
return &entryPtr->dict();
}
else
{
return nullptr;
}
// Find non-recursive with patterns
return csearch(keyword, false, true).dictPtr();
}
Foam::dictionary* Foam::dictionary::subDictPtr(const word& keyword)
{
entry* entryPtr = lookupEntryPtr(keyword, false, true);
if (entryPtr)
{
return &entryPtr->dict();
}
else
{
return nullptr;
}
// Find non-recursive with patterns
return search(keyword, false, true).dictPtr();
}
const Foam::dictionary& Foam::dictionary::subDict(const word& keyword) const
{
const entry* entryPtr = lookupEntryPtr(keyword, false, true);
// Find non-recursive with patterns
auto finder = csearch(keyword, false, true);
if (entryPtr == nullptr)
if (!finder.found())
{
FatalIOErrorInFunction
(
@ -651,15 +408,17 @@ const Foam::dictionary& Foam::dictionary::subDict(const word& keyword) const
<< name()
<< exit(FatalIOError);
}
return entryPtr->dict();
return finder.dict();
}
Foam::dictionary& Foam::dictionary::subDict(const word& keyword)
{
entry* entryPtr = lookupEntryPtr(keyword, false, true);
// Find non-recursive with patterns
auto finder = search(keyword, false, true);
if (entryPtr == nullptr)
if (!finder.found())
{
FatalIOErrorInFunction
(
@ -668,7 +427,8 @@ Foam::dictionary& Foam::dictionary::subDict(const word& keyword)
<< name()
<< exit(FatalIOError);
}
return entryPtr->dict();
return finder.dict();
}
@ -678,29 +438,35 @@ Foam::dictionary Foam::dictionary::subOrEmptyDict
const bool mustRead
) const
{
const entry* entryPtr = lookupEntryPtr(keyword, false, true);
// Find non-recursive with patterns
auto finder = csearch(keyword, false, true);
if (entryPtr == nullptr)
if (finder.isDict())
{
if (mustRead)
{
FatalIOErrorInFunction
(
*this
) << "keyword " << keyword << " is undefined in dictionary "
<< name()
<< exit(FatalIOError);
return entryPtr->dict();
}
else
{
return dictionary(*this, dictionary(name() + '.' + keyword));
}
// Found and a sub-dictionary
return finder.dict();
}
else
if (mustRead)
{
return entryPtr->dict();
FatalIOErrorInFunction
(
*this
) << "keyword " << keyword
<< " is not a sub-dictionary in dictionary "
<< name()
<< exit(FatalIOError);
}
if (finder.found())
{
IOWarningInFunction((*this))
<< "keyword " << keyword
<< " found but not a sub-dictionary in dictionary "
<< name() << endl;
}
return dictionary(*this, dictionary(name() + '.' + keyword));
}
@ -709,16 +475,23 @@ const Foam::dictionary& Foam::dictionary::optionalSubDict
const word& keyword
) const
{
const entry* entryPtr = lookupEntryPtr(keyword, false, true);
auto finder = csearch(keyword, false, true);
if (entryPtr)
if (finder.isDict())
{
return entryPtr->dict();
// Found and a sub-dictionary
return finder.dict();
}
else
if (finder.found())
{
return *this;
IOWarningInFunction((*this))
<< "keyword " << keyword
<< " found but not a sub-dictionary in dictionary "
<< name() << endl;
}
return *this;
}
@ -726,10 +499,10 @@ Foam::wordList Foam::dictionary::toc() const
{
wordList keys(size());
label nKeys = 0;
forAllConstIter(parent_type, *this, iter)
label n = 0;
forAllConstIters(*this, iter)
{
keys[nKeys++] = iter().keyword();
keys[n++] = iter().keyword();
}
return keys;
@ -746,15 +519,15 @@ Foam::List<Foam::keyType> Foam::dictionary::keys(bool patterns) const
{
List<keyType> keys(size());
label nKeys = 0;
forAllConstIter(parent_type, *this, iter)
label n = 0;
forAllConstIters(*this, iter)
{
if (iter().keyword().isPattern() ? patterns : !patterns)
{
keys[nKeys++] = iter().keyword();
keys[n++] = iter().keyword();
}
}
keys.setSize(nKeys);
keys.setSize(n);
return keys;
}
@ -796,16 +569,15 @@ bool Foam::dictionary::add(entry* entryPtr, bool mergeEntry)
return true;
}
else
{
IOWarningInFunction((*this))
<< "problem replacing entry "<< entryPtr->keyword()
<< " in dictionary " << name() << endl;
parent_type::remove(entryPtr);
delete entryPtr;
return false;
}
IOWarningInFunction((*this))
<< "problem replacing entry "<< entryPtr->keyword()
<< " in dictionary " << name() << endl;
parent_type::remove(entryPtr);
delete entryPtr;
return false;
}
@ -825,16 +597,15 @@ bool Foam::dictionary::add(entry* entryPtr, bool mergeEntry)
return true;
}
else
{
IOWarningInFunction((*this))
<< "attempt to add entry "<< entryPtr->keyword()
<< " which already exists in dictionary " << name()
<< endl;
delete entryPtr;
return false;
}
IOWarningInFunction((*this))
<< "attempt to add entry "<< entryPtr->keyword()
<< " which already exists in dictionary " << name()
<< endl;
delete entryPtr;
return false;
}
@ -844,55 +615,55 @@ void Foam::dictionary::add(const entry& e, bool mergeEntry)
}
void Foam::dictionary::add(const keyType& k, const word& w, bool overwrite)
void Foam::dictionary::add(const keyType& k, const word& v, bool overwrite)
{
add(new primitiveEntry(k, token(w)), overwrite);
add(new primitiveEntry(k, token(v)), overwrite);
}
void Foam::dictionary::add
(
const keyType& k,
const Foam::string& s,
const Foam::string& v,
bool overwrite
)
{
add(new primitiveEntry(k, token(s)), overwrite);
add(new primitiveEntry(k, token(v)), overwrite);
}
void Foam::dictionary::add(const keyType& k, const label l, bool overwrite)
void Foam::dictionary::add(const keyType& k, const label v, bool overwrite)
{
add(new primitiveEntry(k, token(l)), overwrite);
add(new primitiveEntry(k, token(v)), overwrite);
}
void Foam::dictionary::add(const keyType& k, const scalar s, bool overwrite)
void Foam::dictionary::add(const keyType& k, const scalar v, bool overwrite)
{
add(new primitiveEntry(k, token(s)), overwrite);
add(new primitiveEntry(k, token(v)), overwrite);
}
void Foam::dictionary::add
(
const keyType& k,
const dictionary& d,
const dictionary& v,
bool mergeEntry
)
{
add(new dictionaryEntry(k, *this, d), mergeEntry);
add(new dictionaryEntry(k, *this, v), mergeEntry);
}
void Foam::dictionary::set(entry* entryPtr)
{
// Find non-recursive with patterns
entry* existingPtr = lookupEntryPtr(entryPtr->keyword(), false, true);
auto finder = search(entryPtr->keyword(), false, true);
// Clear dictionary so merge acts like overwrite
if (existingPtr && existingPtr->isDict())
if (finder.isDict())
{
existingPtr->dict().clear();
finder.dict().clear();
}
add(entryPtr, true);
}
@ -904,134 +675,14 @@ void Foam::dictionary::set(const entry& e)
}
void Foam::dictionary::set(const keyType& k, const dictionary& d)
void Foam::dictionary::set(const keyType& k, const dictionary& v)
{
set(new dictionaryEntry(k, *this, d));
}
bool Foam::dictionary::remove(const word& keyword)
{
auto iter = hashedEntries_.find(keyword);
if (iter.found())
{
// Delete from patterns
pattern_iterator wcLink = patterns_.begin();
regexp_iterator reLink = regexps_.begin();
// Find in pattern using exact match only
if (findInPatterns(false, keyword, wcLink, reLink))
{
patterns_.remove(wcLink);
regexps_.remove(reLink);
}
parent_type::remove(iter());
delete iter();
hashedEntries_.erase(iter);
return true;
}
else
{
return false;
}
}
bool Foam::dictionary::changeKeyword
(
const keyType& oldKeyword,
const keyType& newKeyword,
bool forceOverwrite
)
{
// No change
if (oldKeyword == newKeyword)
{
return false;
}
// Check that oldKeyword exists and can be changed
auto iter = hashedEntries_.find(oldKeyword);
if (!iter.found())
{
return false;
}
if (iter()->keyword().isPattern())
{
FatalIOErrorInFunction
(
*this
) << "Old keyword "<< oldKeyword
<< " is a pattern."
<< "Pattern replacement not yet implemented."
<< exit(FatalIOError);
}
auto iter2 = hashedEntries_.find(newKeyword);
// newKeyword already exists
if (iter2.found())
{
if (forceOverwrite)
{
if (iter2()->keyword().isPattern())
{
// Delete from patterns
pattern_iterator wcLink = patterns_.begin();
regexp_iterator reLink = regexps_.begin();
// Find in patterns using exact match only
if (findInPatterns(false, iter2()->keyword(), wcLink, reLink))
{
patterns_.remove(wcLink);
regexps_.remove(reLink);
}
}
parent_type::replace(iter2(), iter());
delete iter2();
hashedEntries_.erase(iter2);
}
else
{
IOWarningInFunction
(
*this
) << "cannot rename keyword "<< oldKeyword
<< " to existing keyword " << newKeyword
<< " in dictionary " << name() << endl;
return false;
}
}
// Change name and HashTable, but leave DL-List untouched
iter()->keyword() = newKeyword;
iter()->name() = name() + '.' + newKeyword;
hashedEntries_.erase(oldKeyword);
hashedEntries_.insert(newKeyword, iter());
if (newKeyword.isPattern())
{
patterns_.insert(iter());
regexps_.insert
(
autoPtr<regExp>(new regExp(newKeyword))
);
}
return true;
set(new dictionaryEntry(k, *this, v));
}
bool Foam::dictionary::merge(const dictionary& dict)
{
// Check for assignment to self
if (this == &dict)
{
FatalIOErrorInFunction(*this)
@ -1041,7 +692,7 @@ bool Foam::dictionary::merge(const dictionary& dict)
bool changed = false;
forAllConstIter(parent_type, dict, iter)
forAllConstIters(dict, iter)
{
auto fnd = hashedEntries_.find(iter().keyword());
@ -1112,7 +763,6 @@ Foam::ITstream& Foam::dictionary::operator[](const word& keyword) const
void Foam::dictionary::operator=(const dictionary& rhs)
{
// Check for assignment to self
if (this == &rhs)
{
FatalIOErrorInFunction(*this)
@ -1126,7 +776,7 @@ void Foam::dictionary::operator=(const dictionary& rhs)
// Create clones of the entries in the given dictionary
// resetting the parentDict to this dictionary
forAllConstIter(parent_type, rhs, iter)
forAllConstIters(rhs, iter)
{
add(iter().clone(*this).ptr());
}
@ -1135,15 +785,15 @@ void Foam::dictionary::operator=(const dictionary& rhs)
void Foam::dictionary::operator+=(const dictionary& rhs)
{
// Check for assignment to self
if (this == &rhs)
{
FatalIOErrorInFunction(*this)
<< "attempted addition assignment to self for dictionary " << name()
<< "attempted addition assignment to self for dictionary "
<< name()
<< abort(FatalIOError);
}
forAllConstIter(parent_type, rhs, iter)
forAllConstIters(rhs, iter)
{
add(iter().clone(*this).ptr());
}
@ -1152,15 +802,15 @@ void Foam::dictionary::operator+=(const dictionary& rhs)
void Foam::dictionary::operator|=(const dictionary& rhs)
{
// Check for assignment to self
if (this == &rhs)
{
FatalIOErrorInFunction(*this)
<< "attempted assignment to self for dictionary " << name()
<< "attempted assignment to self for dictionary "
<< name()
<< abort(FatalIOError);
}
forAllConstIter(parent_type, rhs, iter)
forAllConstIters(rhs, iter)
{
if (!found(iter().keyword()))
{
@ -1172,15 +822,15 @@ void Foam::dictionary::operator|=(const dictionary& rhs)
void Foam::dictionary::operator<<=(const dictionary& rhs)
{
// Check for assignment to self
if (this == &rhs)
{
FatalIOErrorInFunction(*this)
<< "attempted assignment to self for dictionary " << name()
<< "attempted assignment to self for dictionary "
<< name()
<< abort(FatalIOError);
}
forAllConstIter(parent_type, rhs, iter)
forAllConstIters(rhs, iter)
{
set(iter().clone(*this).ptr());
}

View File

@ -41,10 +41,13 @@ Description
Note
Within dictionaries, entries can be referenced by using the '$' syntax
familiar from shell programming. A '.' separator is used when referencing
sub-dictionary entries. Leading '.' prefixes can be used to specify
an entry from a parent directory. A leading ':' or '^' prefix specifies
starting from the top-level entry. For example,
familiar from shell programming.
A '.' separator is used when referencing sub-dictionary entries.
Leading '.' prefixes can be used to specify an entry from a parent
dictionary.
An initial '^' anchor (or ':' for backward compatibility) specifies
starting from the top-level entry.
For example,
\verbatim
key1 val1;
@ -70,6 +73,7 @@ Note
SourceFiles
dictionary.C
dictionaryIO.C
dictionarySearch.C
SeeAlso
- Foam::entry
@ -89,6 +93,7 @@ SeeAlso
#include "HashTable.H"
#include "wordList.H"
#include "className.H"
#include <type_traits>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -148,22 +153,20 @@ public:
const word dictName() const
{
const word scopedName = name_.name();
const std::string::size_type i = scopedName.rfind('.');
const auto i = scopedName.rfind('.');
if (i == std::string::npos)
{
return scopedName;
}
else
{
return scopedName.substr(i+1);
}
return scopedName.substr(i+1);
}
};
/*---------------------------------------------------------------------------*\
Class dictionary Declaration
Class dictionary Declaration
\*---------------------------------------------------------------------------*/
class dictionary
@ -171,15 +174,157 @@ class dictionary
public dictionaryName,
public IDLList<entry>
{
public:
// Searching
//- Generic const/non-const dictionary entry %searcher.
// A %searcher provides a uniform means of finding and returning
// an entry pointer as well as the dictionary \a context in which
// the entry was located.
//
// Note that the constructors and set methods are protected such
// that only friends of the class can set things. This safeguards
// against inconsistencies in context/entry.
template<bool Const>
class Searcher
{
public:
friend dictionary;
//- The const/non-const type for the context and sub-dictionaries
typedef typename std::conditional
<Const, const dictionary, dictionary>::type dict_type;
//- The const/non-const type for entries
typedef typename std::conditional
<Const, const entry, entry>::type value_type;
//- A pointer to a const/non-const dictionary
typedef dict_type* dict_pointer;
//- A reference to a const/non-const dictionary
typedef dict_type& dict_reference;
//- A pointer to a const/non-const entry
typedef value_type* pointer;
//- A reference to a const/non-const entry
typedef value_type& reference;
protected:
//- The dictionary context for the entry
dict_pointer dict_;
//- The entry or nullptr
pointer eptr_;
//- Construct null
Searcher()
:
dict_(nullptr),
eptr_(nullptr)
{}
//- Construct for the given dictionary context
Searcher(dict_pointer dict)
:
dict_(dict),
eptr_(nullptr)
{}
//- Assign the entry
void set(pointer eptr)
{
eptr_ = eptr;
}
public:
//- Entry was found.
inline bool found() const
{
return eptr_;
}
//- The containing dictionary context
inline dict_reference context() const
{
return *dict_;
}
//- A pointer to the entry (nullptr if not found)
inline pointer ptr() const
{
return eptr_;
}
//- A reference to the entry (Error if not found)
inline reference ref() const
{
return *eptr_;
}
//- True if found entry is a dictionary.
inline bool isDict() const
{
return eptr_ && eptr_->isDict();
}
//- Pointer to the found entry as a dictionary or nullptr otherwise.
inline dict_pointer dictPtr() const
{
return eptr_ && eptr_->isDict() ? eptr_->dictPtr() : nullptr;
}
//- Reference the found entry as a dictionary.
// (Error if not found, or not a dictionary).
inline dict_reference dict() const
{
return eptr_->dict();
}
//- Permit an explicit cast to the other (const/non-const) searcher
inline explicit operator const Searcher<!Const>&() const
{
return *reinterpret_cast<const Searcher<!Const>*>(this);
}
};
//- Searcher with const access
typedef Searcher<true> const_searcher;
//- Searcher with non-const access
typedef Searcher<false> searcher;
// Friends
//- Declare friendship with the entry class for IO
friend class entry;
//- Declare friendship with the searcher classes
friend const_searcher;
friend searcher;
private:
// Private data
//- Report optional keywords and values if not present in dictionary
// Set/unset via an InfoSwitch
static bool writeOptionalEntries;
//- Parent dictionary
const dictionary& parent_;
//- HashTable of the entries held on the IDLList for quick lookup
//- Quick lookup of the entries held on the IDLList
HashTable<entry*> hashedEntries_;
//- Entries of matching patterns
@ -196,28 +341,49 @@ class dictionary
typedef DLList<entry*>::iterator pattern_iterator;
typedef DLList<entry*>::const_iterator pattern_const_iterator;
typedef DLList<autoPtr<regExp>>::iterator regexp_iterator;
typedef DLList<autoPtr<regExp>>::const_iterator regexp_const_iterator;
// Private Member Functions
//- Find and return an entry data stream pointer if present
// otherwise return nullptr. Allows scoping using '.'
const entry* lookupScopedSubEntryPtr
//- Search using a '.' for scoping.
// A leading dot means to use the parent dictionary.
// An intermediate dot separates a sub-dictionary or sub-entry.
// However, the use of dots is unfortunately ambiguous.
// The value "a.b.c.d" could be a first-level entry, a second-level
// entry (eg, "a" with "b.c.d", "a.b" with "c.d" etc),
// or just about any other combination.
// The heuristic tries sucessively longer top-level entries
// until there is a suitable match.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
const_searcher csearchDotScoped
(
const word& keyword,
bool recursive,
bool patternMatch
) const;
//- Search using a '/' for scoping.
// Semantics as per normal files: an intermediate "." is the current
// dictionary level, an intermediate ".." is the parent dictionary.
// Note that since a slash is not a valid word character, there is no
// ambiguity between separator and content.
// No possibility or need for recursion.
//
// \param patternMatch use regular expressions
const_searcher csearchSlashScoped
(
const word& keyword,
bool patternMatch
) const;
public:
//- Declare friendship with the entry class for IO
friend class entry;
// Declare name of the class and its debug switch
ClassName("dictionary");
@ -234,7 +400,7 @@ public:
explicit dictionary(const fileName& name);
//- Construct given the entry name, parent dictionary and Istream,
// reading entries until lastEntry or EOF
// reading entries until EOF
dictionary
(
const fileName& name,
@ -248,10 +414,10 @@ public:
//- Construct top-level dictionary from Istream,
// reading entries until EOF, optionally keeping the header
dictionary(Istream& is, const bool keepHeader);
dictionary(Istream& is, bool keepHeader);
//- Construct as copy given the parent dictionary
dictionary(const dictionary& parentDict, const dictionary&);
dictionary(const dictionary& parentDict, const dictionary& dict);
//- Construct top-level dictionary as copy
dictionary(const dictionary& dict);
@ -303,284 +469,436 @@ public:
tokenList tokens() const;
// Search and lookup
// Search and lookup
//- Search dictionary for given keyword
// If recursive, search parent dictionaries
// If patternMatch, use regular expressions
bool found
(
const word& keyword,
bool recursive = false,
bool patternMatch = true
) const;
//- Search dictionary for given keyword.
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
bool found
(
const word& keyword,
bool recursive = false,
bool patternMatch = true
) const;
//- Find and return an entry data stream pointer if present
// otherwise return nullptr.
// If recursive, search parent dictionaries.
// If patternMatch, use regular expressions
const entry* lookupEntryPtr
(
const word& keyword,
bool recursive,
bool patternMatch
) const;
//- Find and return an entry pointer if present, or return a nullptr.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
const entry* lookupEntryPtr
(
const word& keyword,
bool recursive,
bool patternMatch
) const;
//- Find and return an entry data stream pointer for manipulation
// if present otherwise return nullptr.
// If recursive, search parent dictionaries.
// If patternMatch, use regular expressions.
entry* lookupEntryPtr
(
const word& keyword,
bool recursive,
bool patternMatch
);
//- Find and return an entry pointer for manipulation if present,
// or return a nullptr.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
entry* lookupEntryPtr
(
const word& keyword,
bool recursive,
bool patternMatch
);
//- Find and return an entry data stream if present otherwise error.
// If recursive, search parent dictionaries.
// If patternMatch, use regular expressions.
const entry& lookupEntry
(
const word& keyword,
bool recursive,
bool patternMatch
) const;
//- Find and return an entry if present otherwise error.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
const entry& lookupEntry
(
const word& keyword,
bool recursive,
bool patternMatch
) const;
//- Find and return an entry data stream
// If recursive, search parent dictionaries.
// If patternMatch, use regular expressions.
ITstream& lookup
(
const word& keyword,
bool recursive = false,
bool patternMatch = true
) const;
//- Find and return an entry data stream.
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
ITstream& lookup
(
const word& keyword,
bool recursive = false,
bool patternMatch = true
) const;
//- Find and return a T,
// if not found throw a fatal error.
// If recursive, search parent dictionaries.
// If patternMatch, use regular expressions.
template<class T>
T lookupType
(
const word&,
bool recursive=false,
bool patternMatch=true
) const;
//- Find and return a T. FatalError if not found.
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
template<class T>
T lookupType
(
const word& keyword,
bool recursive = false,
bool patternMatch = true
) const;
//- Find and return a T, or return the given default value
// If recursive, search parent dictionaries.
// If patternMatch, use regular expressions.
template<class T>
T lookupOrDefault
(
const word& keyword,
const T& deflt,
bool recursive = false,
bool patternMatch = true
) const;
//- Find and return a T, or return the given default value
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
template<class T>
T lookupOrDefault
(
const word& keyword,
const T& deflt,
bool recursive = false,
bool patternMatch = true
) const;
//- Find and return a T, if not found return the given
// default value, and add to dictionary.
// If recursive, search parent dictionaries.
// If patternMatch, use regular expressions.
template<class T>
T lookupOrAddDefault
(
const word& keyword,
const T& deflt,
bool recursive = false,
bool patternMatch = true
);
//- Find and return a T, if not found return the default value
// and add it to dictionary.
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
template<class T>
T lookupOrAddDefault
(
const word& keyword,
const T& deflt,
bool recursive = false,
bool patternMatch = true
);
//- Find an entry if present, and assign to T
// Returns true if the entry was found.
// If recursive, search parent dictionaries.
// If patternMatch, use regular expressions.
template<class T>
bool readIfPresent
(
const word& keyword,
T& val,
bool recursive = false,
bool patternMatch = true
) const;
//- Find an entry if present, and assign to T val.
// Default search: non-recursive with patterns.
//
// \param val the value to read
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
//
// \return true if the entry was found.
template<class T>
bool readIfPresent
(
const word& keyword,
T& val,
bool recursive = false,
bool patternMatch = true
) const;
//- Find and return an entry data stream pointer if present
// otherwise return nullptr. Allows scoping using '.'.
// Special handling for ':' at start of keyword and '..'.
const entry* lookupScopedEntryPtr
(
const word& keyword,
bool recursive,
bool patternMatch
) const;
//- Find and return an entry pointer if present, or return a nullptr.
// Allows scoping using '.'.
// Special handling for an absolute anchor (^) at start of the keyword
// and for '..' to ascend into the parent dictionaries.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
const entry* lookupScopedEntryPtr
(
const word& keyword,
bool recursive,
bool patternMatch
) const;
//- Check if entry is a sub-dictionary
bool isDict(const word& keyword) const;
//- Check if entry exists and is a sub-dictionary.
//
// Search type: non-recursive with patterns.
bool isDict(const word& keyword) const;
//- Find and return a sub-dictionary pointer if present
// otherwise return nullptr.
const dictionary* subDictPtr(const word& keyword) const;
//- Find and return a sub-dictionary pointer if present
// (and a sub-dictionary) otherwise return nullptr.
//
// Search type: non-recursive with patterns.
const dictionary* subDictPtr(const word& keyword) const;
//- Find and return a sub-dictionary pointer if present
// otherwise return nullptr.
dictionary* subDictPtr(const word& keyword);
//- Find and return a sub-dictionary pointer if present
// (and a sub-dictionary) otherwise return nullptr.
//
// Search type: non-recursive with patterns.
dictionary* subDictPtr(const word& keyword);
//- Find and return a sub-dictionary
const dictionary& subDict(const word& keyword) const;
//- Find and return a sub-dictionary.
// Fatal if the entry does not exist or is not a sub-dictionary.
//
// Search type: non-recursive with patterns.
const dictionary& subDict(const word& keyword) const;
//- Find and return a sub-dictionary for manipulation
dictionary& subDict(const word& keyword);
//- Find and return a sub-dictionary for manipulation.
// Fatal if the entry does not exist or is not a sub-dictionary.
//
// Search type: non-recursive with patterns.
dictionary& subDict(const word& keyword);
//- Find and return a sub-dictionary as a copy, or
// return an empty dictionary if the sub-dictionary does not exist
dictionary subOrEmptyDict
(
const word& keyword,
const bool mustRead = false
) const;
//- Find and return a sub-dictionary as a copy, otherwise return
// an empty dictionary.
// Warn if the entry exists but is not a sub-dictionary.
//
// Search type: non-recursive with patterns.
dictionary subOrEmptyDict
(
const word& keyword,
const bool mustRead = false
) const;
//- Find and return a sub-dictionary if found
// otherwise return this dictionary
const dictionary& optionalSubDict(const word&) const;
//- Find and return a sub-dictionary, otherwise return this dictionary.
// Warn if the entry exists but is not a sub-dictionary.
//
// Search type: non-recursive with patterns.
const dictionary& optionalSubDict(const word& keyword) const;
//- Return the table of contents
wordList toc() const;
//- Return the table of contents
wordList toc() const;
//- Return the sorted table of contents
wordList sortedToc() const;
//- Return the sorted table of contents
wordList sortedToc() const;
//- Return table of contents sorted using the specified comparator
template<class Compare>
wordList sortedToc(const Compare& comp) const;
//- Return table of contents sorted using the specified comparator
template<class Compare>
wordList sortedToc(const Compare& comp) const;
//- Return the list of available keys or patterns
List<keyType> keys(bool patterns = false) const;
//- Return the list of available keys or patterns
List<keyType> keys(bool patterns = false) const;
// Editing
// Editing
//- Substitute the given keyword prepended by '$' with the
// corresponding sub-dictionary entries
bool substituteKeyword(const word& keyword, bool mergeEntry=false);
//- Substitute the given keyword (which is prefixed by '$')
// with the corresponding sub-dictionary entries
bool substituteKeyword
(
const word& keyword,
bool mergeEntry = false
);
//- Substitute the given scoped keyword prepended by '$' with the
// corresponding sub-dictionary entries
bool substituteScopedKeyword
(
const word& keyword,
bool mergeEntry=false
);
//- Substitute the given scoped keyword (which is prefixed by '$')
// with the corresponding sub-dictionary entries
bool substituteScopedKeyword
(
const word& keyword,
bool mergeEntry = false
);
//- Add a new entry
// With the merge option, dictionaries are interwoven and
// primitive entries are overwritten
bool add(entry* entryPtr, bool mergeEntry=false);
//- Add a new entry.
// \param mergeEntry dictionaries are interwoven and primitive
// entries are overwritten
bool add(entry* entryPtr, bool mergeEntry=false);
//- Add an entry
// With the merge option, dictionaries are interwoven and
// primitive entries are overwritten
void add(const entry& e, bool mergeEntry=false);
//- Add an entry.
// \param mergeEntry dictionaries are interwoven and primitive
// entries are overwritten
void add(const entry& e, bool mergeEntry=false);
//- Add a word entry
// optionally overwrite an existing entry
void add(const keyType& k, const word& w, bool overwrite=false);
//- Add a word entry.
// \param overwrite force overwrite of an existing entry.
void add(const keyType& k, const word& v, bool overwrite=false);
//- Add a string entry
// optionally overwrite an existing entry
void add(const keyType& k, const string& s, bool overwrite=false);
//- Add a string entry.
// \param overwrite force overwrite of an existing entry.
void add(const keyType& k, const string& v, bool overwrite=false);
//- Add a label entry
// optionally overwrite an existing entry
void add(const keyType&, const label l, bool overwrite=false);
//- Add a label entry.
// \param overwrite force overwrite of an existing entry.
void add(const keyType& k, const label v, bool overwrite=false);
//- Add a scalar entry
// optionally overwrite an existing entry
void add(const keyType&, const scalar s, bool overwrite=false);
//- Add a scalar entry.
// \param overwrite force overwrite of an existing entry.
void add(const keyType& k, const scalar v, bool overwrite=false);
//- Add a dictionary entry
// optionally merge with an existing sub-dictionary
void add
(
const keyType& k,
const dictionary& d,
bool mergeEntry = false
);
//- Add a dictionary entry.
// \param mergeEntry merge into an existing sub-dictionary
void add
(
const keyType& k,
const dictionary& d,
bool mergeEntry = false
);
//- Add a T entry
// optionally overwrite an existing entry
template<class T>
void add(const keyType& k, const T& t, bool overwrite=false);
//- Add a T entry
// \param overwrite force overwrite of existing entry
template<class T>
void add(const keyType& k, const T& v, bool overwrite=false);
//- Assign a new entry, overwrite any existing entry
void set(entry* entryPtr);
//- Assign a new entry, overwriting any existing entry.
void set(entry* entryPtr);
//- Assign a new entry, overwrite any existing entry
void set(const entry& e);
//- Assign a new entry, overwriting any existing entry.
void set(const entry& e);
//- Assign a dictionary entry, overwrite any existing entry
void set(const keyType& k, const dictionary& d);
//- Assign a dictionary entry, overwriting any existing entry.
void set(const keyType& k, const dictionary& v);
//- Assign a T entry, overwrite any existing entry
template<class T>
void set(const keyType& k, const T& t);
//- Assign a T entry, overwriting any existing entry.
template<class T>
void set(const keyType& k, const T& v);
//- Remove an entry specified by keyword
bool remove(const word& Keyword);
//- Remove an entry specified by keyword
bool remove(const word& keyword);
//- Change the keyword for an entry,
// optionally forcing overwrite of an existing entry
bool changeKeyword
(
const keyType& oldKeyword,
const keyType& newKeyword,
bool forceOverwrite=false
);
//- Change the keyword for an entry,
// \param overwrite force overwrite of an existing entry.
bool changeKeyword
(
const keyType& oldKeyword,
const keyType& newKeyword,
bool overwrite=false
);
//- Merge entries from the given dictionary.
// Also merge sub-dictionaries as required.
bool merge(const dictionary& dict);
//- Merge entries from the given dictionary.
// Also merge sub-dictionaries as required.
bool merge(const dictionary& dict);
//- Clear the dictionary
void clear();
//- Clear the dictionary
void clear();
//- Transfer the contents of the argument and annul the argument.
void transfer(dictionary& dict);
//- Transfer the contents of the argument and annul the argument.
void transfer(dictionary& dict);
//- Transfer contents to the Xfer container
Xfer<dictionary> xfer();
//- Transfer contents to the Xfer container
Xfer<dictionary> xfer();
// Read
// Read
//- Read dictionary from Istream
bool read(Istream& is);
//- Read dictionary from Istream
bool read(Istream& is);
//- Read dictionary from Istream, optionally keeping the header
bool read(Istream& is, const bool keepHeader);
//- Read dictionary from Istream, optionally keeping the header
bool read(Istream& is, bool keepHeader);
// Write
// Write
//- Write sub-dictionary with the keyword as its header
void writeEntry(const keyType& keyword, Ostream& os) const;
//- Write sub-dictionary with the keyword as its header
void writeEntry(const keyType& keyword, Ostream& os) const;
//- Write dictionary entries.
// Optionally with extra new line between entries for
// "top-level" dictionaries
void writeEntries(Ostream& os, const bool extraNewLine=false) const;
//- Write dictionary entries.
// \param extraNewLine adds additional newline\n between entries
// for "top-level" dictionaries
void writeEntries(Ostream& os, const bool extraNewLine=false) const;
//- Write dictionary, normally with sub-dictionary formatting
void write(Ostream& os, const bool subDict=true) const;
//- Write dictionary, normally with sub-dictionary formatting
void write(Ostream& os, const bool subDict=true) const;
// Searching
//- Search dictionary for given keyword
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
const_searcher csearch
(
const word& keyword,
bool recursive = false,
bool patternMatch = true
) const;
//- Search dictionary for given keyword
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
const_searcher search
(
const word& keyword,
bool recursive = false,
bool patternMatch = true
) const;
//- Search dictionary for given keyword
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
searcher search
(
const word& keyword,
bool recursive = false,
bool patternMatch = true
);
//- Search using scoping.
// There are two types of scoping available:
// -# dot-scoping, where a '.' is used to delineate the scope
// -# slash-scoping, where a '/' is used to delineate the scope
//
// For dot-scoping, a leading '^' traverses to the top-level
// dictionary, leading dots mean use the parent dictionary and an
// intermediate dot separates a sub-dictionary or sub-entry.
// However, since the use of dots is ambiguous ("a.b.c" could be
// an entry itself or represent a "bc" entry from dictionary "a" etc),
// the heuristic backtracks and attempts successively longer
// top-level entries until a suitable match is found.
//
// For slash-scoping, semantics similar to directory structures are
// used. A leading '/' traverses to the top-level dictionary,
// a single leading or intermediate '.' references the current
// dictionary level. A '..' pair references the parent dictionary.
// Any doubled slashes are silently ignored.
// Since a slash is not a valid keyword character, there is no
// ambiguity between separator and content.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
const_searcher csearchScoped
(
const word& keyword,
bool recursive,
bool patternMatch
) const;
//- Search using dot or slash scoping.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
const_searcher searchScoped
(
const word& keyword,
bool recursive,
bool patternMatch
) const;
//- Search using dot or slash scoping.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
searcher searchScoped
(
const word& keyword,
bool recursive,
bool patternMatch
);
//- Locate a sub-dictionary using slash-scoping
// \return nullptr if the dictionary path does not exist
const dictionary* cfindScopedDictPtr(const fileName& dictPath) const;
//- Locate a sub-dictionary using slash-scoping
// \return nullptr if the dictionary path does not exist
const dictionary* findScopedDictPtr(const fileName& dictPath) const;
//- Locate a sub-dictionary using slash-scoping
// \return nullptr if the dictionary path does not exist
dictionary* findScopedDictPtr(const fileName& dictPath);
//- Locate existing or create sub-dictionary using slash-scoping
// \return nullptr if the dictionary path could not be created
dictionary* makeScopedDictPtr(const fileName& dictPath);
// Member Operators
//- Find and return entry
//- Find and return an entry data stream (identical to #lookup method).
// Default search: non-recursive with patterns.
//
// \param recursive search parent dictionaries
// \param patternMatch use regular expressions
ITstream& operator[](const word& keyword) const;
//- Copy assignment
void operator=(const dictionary& rhs);
//- Include entries from the given dictionary.

View File

@ -55,7 +55,7 @@ Foam::dictionary::dictionary(Istream& is)
}
Foam::dictionary::dictionary(Istream& is, const bool keepHeader)
Foam::dictionary::dictionary(Istream& is, bool keepHeader)
:
dictionaryName(is.name()),
parent_(dictionary::null)
@ -77,8 +77,14 @@ Foam::autoPtr<Foam::dictionary> Foam::dictionary::New(Istream& is)
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
bool Foam::dictionary::read(Istream& is, const bool keepHeader)
bool Foam::dictionary::read(Istream& is, bool keepHeader)
{
// Normally remove FoamFile header when read, but avoid this if it already
// existed prior to the current read.
// We would otherwise lose it with every top-level '#include ...'
keepHeader = keepHeader || hashedEntries_.found("FoamFile");
// Check for empty dictionary
if (is.eof())
{
@ -103,7 +109,6 @@ bool Foam::dictionary::read(Istream& is, const bool keepHeader)
while (!is.eof() && entry::New(*this, is))
{}
// Normally remove the FoamFile header entry if it exists
if (!keepHeader)
{
remove("FoamFile");
@ -128,30 +133,6 @@ bool Foam::dictionary::read(Istream& is)
}
bool Foam::dictionary::substituteKeyword(const word& keyword, bool mergeEntry)
{
const word varName = keyword.substr(1);
// Lookup the variable name in the given dictionary
const entry* ePtr = lookupEntryPtr(varName, true, true);
// If defined insert its entries into this dictionary
if (ePtr != nullptr)
{
const dictionary& addDict = ePtr->dict();
forAllConstIter(parent_type, addDict, iter)
{
add(iter(), mergeEntry);
}
return true;
}
return false;
}
// * * * * * * * * * * * * * * Istream Operator * * * * * * * * * * * * * * //
Foam::Istream& Foam::operator>>(Istream& is, dictionary& dict)

View File

@ -0,0 +1,719 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "dictionary.H"
#include "dictionaryEntry.H"
#include "stringOps.H"
/* * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * * */
namespace Foam
{
// file-scope
//- Walk lists of patterns and regexps for an exact match
// or regular expression match
template<class WcIterator, class ReIterator>
static bool findInPatterns
(
const bool patternMatch,
const word& keyword,
WcIterator& wcIter,
ReIterator& reIter
)
{
while (wcIter.found())
{
if
(
patternMatch
? reIter()->match(keyword)
: wcIter()->keyword() == keyword
)
{
return true;
}
++reIter;
++wcIter;
}
return false;
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::dictionary::const_searcher Foam::dictionary::csearchDotScoped
(
const word& keyword,
bool recursive,
bool patternMatch
) const
{
std::string::size_type scopePos = keyword.find('.');
if (scopePos == string::npos)
{
// Normal, non-scoped search
return csearch(keyword, recursive, patternMatch);
}
if (scopePos == 0)
{
// Starting with a '.' -> go up for every further '.' found
++scopePos;
const dictionary* dictPtr = this;
for
(
string::const_iterator it = keyword.begin()+1;
it != keyword.end() && *it == '.';
++scopePos, ++it
)
{
// Go to parent
if (&dictPtr->parent_ != &dictionary::null)
{
dictPtr = &dictPtr->parent_;
}
else
{
FatalIOErrorInFunction
(
*this
) << "No parent of current dictionary when searching for "
<< keyword.substr(1)
<< exit(FatalIOError);
return nullptr;
}
}
return dictPtr->csearchDotScoped
(
keyword.substr(scopePos),
false,
patternMatch
);
}
// The first word
const_searcher finder = csearchDotScoped
(
keyword.substr(0, scopePos),
false,
patternMatch
);
// Fall back to finding key with '.' so e.g. if keyword is
// a.b.c.d it would try
// a.b, a.b.c, a.b.c.d
if (!finder.found())
{
while (!finder.isDict())
{
scopePos = keyword.find('.', scopePos+1);
// Local entry:
finder = csearch(keyword.substr(0, scopePos), false, patternMatch);
if (scopePos == string::npos)
{
// Parsed the whole word. Return entry or null.
return finder;
}
}
}
if (finder.isDict())
{
return finder.dict().csearchDotScoped
(
keyword.substr(scopePos),
false,
patternMatch
);
}
return finder;
}
Foam::dictionary::const_searcher Foam::dictionary::csearchSlashScoped
(
const word& keyword,
bool patternMatch
) const
{
const dictionary* dictPtr = this;
const auto slash = keyword.find('/');
if (slash == string::npos)
{
// No slashes:
// Can use normal (non-scoped) search at the current dictionary level
return csearch(keyword, false, patternMatch);
}
else if (slash == 0)
{
// (isAbsolute)
// Ascend to top-level
while (&dictPtr->parent_ != &dictionary::null)
{
dictPtr = &dictPtr->parent_;
}
}
// Split on '/'
auto cmpts = stringOps::split<std::string>(keyword, '/');
auto remaining = cmpts.size();
for (const auto& cmpt : cmpts)
{
--remaining; // Decrement now so we can check (remaining == 0)
if (cmpt == ".")
{
// "." - ignore
}
else if (cmpt == "..")
{
// ".." - go to parent
if (&dictPtr->parent_ != &dictionary::null)
{
dictPtr = &dictPtr->parent_;
}
else
{
FatalIOErrorInFunction
(
*dictPtr
) << "No parent of current dictionary when searching for "
<< keyword << " at " << cmpt
<< exit(FatalIOError);
break;
}
}
else
{
// Find entry
const word key = word::validate(cmpt);
auto finder = dictPtr->csearch(key, false, patternMatch);
if (finder.found())
{
if (remaining)
{
// Intermediate must be a dictionary
if (finder.isDict())
{
dictPtr = finder.dictPtr();
}
else
{
return const_searcher(dictPtr);
}
}
else
{
// Last entry - done
return finder;
}
}
else
{
break;
}
}
}
// Failed at this dictionary level
return const_searcher(dictPtr);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::dictionary::const_searcher Foam::dictionary::csearch
(
const word& keyword,
bool recursive,
bool patternMatch
) const
{
const_searcher finder(this);
auto iter = hashedEntries_.cfind(keyword);
if (iter.found())
{
finder.set(iter.object());
return finder;
}
if (patternMatch && patterns_.size())
{
pattern_const_iterator wcLink = patterns_.begin();
regexp_const_iterator reLink = regexps_.begin();
// Find in patterns using regular expressions only
if (findInPatterns(patternMatch, keyword, wcLink, reLink))
{
finder.set(*wcLink);
return finder;
}
}
if (recursive && &parent_ != &dictionary::null)
{
return parent_.csearch
(
keyword,
recursive,
patternMatch
);
}
return finder;
}
Foam::dictionary::const_searcher Foam::dictionary::search
(
const word& keyword,
bool recursive,
bool patternMatch
) const
{
return csearch(keyword, recursive, patternMatch);
}
Foam::dictionary::searcher Foam::dictionary::search
(
const word& keyword,
bool recursive,
bool patternMatch
)
{
const_searcher finder = csearch(keyword, recursive, patternMatch);
return static_cast<const searcher&>(finder);
}
Foam::dictionary::const_searcher Foam::dictionary::csearchScoped
(
const word& keyword,
bool recursive,
bool patternMatch
) const
{
if (keyword.find('/') != string::npos)
{
return csearchSlashScoped(keyword, patternMatch);
}
if (keyword[0] == ':' || keyword[0] == '^')
{
// Ascend to top-level
const dictionary* dictPtr = this;
while (&dictPtr->parent_ != &dictionary::null)
{
dictPtr = &dictPtr->parent_;
}
return dictPtr->csearchDotScoped
(
keyword.substr(1),
false,
patternMatch
);
}
return csearchDotScoped(keyword, recursive, patternMatch);
}
Foam::dictionary::const_searcher Foam::dictionary::searchScoped
(
const word& keyword,
bool recursive,
bool patternMatch
) const
{
return csearchScoped(keyword, recursive, patternMatch);
}
Foam::dictionary::searcher Foam::dictionary::searchScoped
(
const word& keyword,
bool recursive,
bool patternMatch
)
{
const_searcher finder = csearchScoped(keyword, recursive, patternMatch);
return static_cast<const searcher&>(finder);
}
const Foam::dictionary* Foam::dictionary::cfindScopedDictPtr
(
const fileName& dictPath
) const
{
// Or warning
if (dictPath.empty())
{
return nullptr;
}
const dictionary* dictPtr = this;
if (fileName::isAbsolute(dictPath))
{
// Ascend to top-level
while (&dictPtr->parent_ != &dictionary::null)
{
dictPtr = &dictPtr->parent_;
}
}
fileName path = dictPath.clean();
const wordList cmpts = path.components();
for (const word& cmpt : cmpts)
{
if (cmpt == ".")
{
// "." - ignore
}
else if (cmpt == "..")
{
// ".." - go to parent
if (&dictPtr->parent_ != &dictionary::null)
{
dictPtr = &dictPtr->parent_;
}
else
{
FatalIOErrorInFunction
(
*dictPtr
) << "No parent for dictionary while searching "
<< path
<< exit(FatalIOError);
return nullptr;
}
}
else
{
// Non-recursive, no patternMatch
// -> can do direct lookup, without csearch(cmpt, false, false);
auto iter = dictPtr->hashedEntries_.cfind(cmpt);
if (iter.found())
{
const entry *eptr = iter.object();
if (eptr->isDict())
{
dictPtr = eptr->dictPtr();
}
else
{
FatalIOErrorInFunction
(
*dictPtr
) << "Found entry '" << cmpt
<< "' but not a dictionary, while searching scoped"
<< nl
<< " " << path
<< exit(FatalIOError);
return nullptr;
}
}
else
{
return nullptr;
}
}
}
return dictPtr;
}
const Foam::dictionary* Foam::dictionary::findScopedDictPtr
(
const fileName& dictPath
) const
{
return cfindScopedDictPtr(dictPath);
}
Foam::dictionary* Foam::dictionary::findScopedDictPtr
(
const fileName& dictPath
)
{
const dictionary* ptr = cfindScopedDictPtr(dictPath);
return const_cast<dictionary*>(ptr);
}
Foam::dictionary* Foam::dictionary::makeScopedDictPtr(const fileName& dictPath)
{
// Or warning
if (dictPath.empty())
{
return nullptr;
}
dictionary* dictPtr = this;
if (fileName::isAbsolute(dictPath))
{
// Ascend to top-level
while (&dictPtr->parent_ != &dictionary::null)
{
dictPtr = const_cast<dictionary*>(&dictPtr->parent_);
}
}
// Work on a copy, without any assumptions
std::string path = dictPath;
fileName::clean(path);
// Split on '/'
auto cmpts = stringOps::split(path, '/');
for (const auto& cmpt : cmpts)
{
if (cmpt == ".")
{
// "." - ignore
}
else if (cmpt == "..")
{
// ".." - go to parent
if (&dictPtr->parent_ != &dictionary::null)
{
dictPtr = const_cast<dictionary*>(&dictPtr->parent_);
}
else
{
FatalIOErrorInFunction
(
*dictPtr
) << "No parent for dictionary while searching "
<< path
<< exit(FatalIOError);
return nullptr;
}
}
else
{
// Non-recursive, no patternMatch
// -> can do direct lookup, without csearch(cmptName, false, false);
const word cmptName(cmpt.str(), false);
auto iter = dictPtr->hashedEntries_.find(cmptName);
if (iter.found())
{
entry *eptr = iter.object();
if (eptr->isDict())
{
dictPtr = eptr->dictPtr();
}
else
{
FatalIOErrorInFunction
(
*dictPtr
) << "Cannot create sub-dictionary entry '" << cmptName
<< "' - a non-dictionary entry is in the way"
<< nl << "Encountered in scope" << nl
<< " " << path
<< exit(FatalIOError);
return nullptr;
}
}
else
{
dictionaryEntry *eptr =
new dictionaryEntry(cmptName, *dictPtr, dictionary());
// Add *without* merging, since we just checked that the entry
// doesn't exist and to ensure that the pointer remains valid.
if (dictPtr->add(eptr, false)) // NO merge
{
dictPtr = eptr;
}
else
{
return nullptr;
}
}
}
}
return dictPtr;
}
bool Foam::dictionary::remove(const word& keyword)
{
auto iter = hashedEntries_.find(keyword);
if (iter.found())
{
// Delete from patterns
pattern_iterator wcLink = patterns_.begin();
regexp_iterator reLink = regexps_.begin();
// Find in pattern using exact match only
if (findInPatterns(false, keyword, wcLink, reLink))
{
patterns_.remove(wcLink);
regexps_.remove(reLink);
}
parent_type::remove(iter());
delete iter();
hashedEntries_.erase(iter);
return true;
}
else
{
return false;
}
}
bool Foam::dictionary::changeKeyword
(
const keyType& oldKeyword,
const keyType& newKeyword,
bool overwrite
)
{
// No change
if (oldKeyword == newKeyword)
{
return false;
}
// Check that oldKeyword exists and can be changed
auto iter = hashedEntries_.find(oldKeyword);
if (!iter.found())
{
return false;
}
if (iter()->keyword().isPattern())
{
FatalIOErrorInFunction
(
*this
) << "Old keyword "<< oldKeyword
<< " is a pattern."
<< "Pattern replacement not yet implemented."
<< exit(FatalIOError);
}
auto iter2 = hashedEntries_.find(newKeyword);
// newKeyword already exists
if (iter2.found())
{
if (overwrite)
{
if (iter2()->keyword().isPattern())
{
// Delete from patterns
pattern_iterator wcLink = patterns_.begin();
regexp_iterator reLink = regexps_.begin();
// Find in patterns using exact match only
if (findInPatterns(false, iter2()->keyword(), wcLink, reLink))
{
patterns_.remove(wcLink);
regexps_.remove(reLink);
}
}
parent_type::replace(iter2(), iter());
delete iter2();
hashedEntries_.erase(iter2);
}
else
{
IOWarningInFunction
(
*this
) << "cannot rename keyword "<< oldKeyword
<< " to existing keyword " << newKeyword
<< " in dictionary " << name() << endl;
return false;
}
}
// Change name and HashTable, but leave DL-List untouched
iter()->keyword() = newKeyword;
iter()->name() = name() + '.' + newKeyword;
hashedEntries_.erase(oldKeyword);
hashedEntries_.insert(newKeyword, iter());
if (newKeyword.isPattern())
{
patterns_.insert(iter());
regexps_.insert
(
autoPtr<regExp>(new regExp(newKeyword))
);
}
return true;
}
// ************************************************************************* //

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -43,9 +43,9 @@ T Foam::dictionary::lookupType
bool patternMatch
) const
{
const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch);
auto finder = csearch(keyword, recursive, patternMatch);
if (entryPtr == nullptr)
if (!finder.found())
{
FatalIOErrorInFunction
(
@ -55,7 +55,7 @@ T Foam::dictionary::lookupType
<< exit(FatalIOError);
}
return pTraits<T>(entryPtr->stream());
return pTraits<T>(finder.ptr()->stream());
}
@ -68,24 +68,22 @@ T Foam::dictionary::lookupOrDefault
bool patternMatch
) const
{
const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch);
auto finder = csearch(keyword, recursive, patternMatch);
if (entryPtr)
if (finder.found())
{
return pTraits<T>(entryPtr->stream());
return pTraits<T>(finder.ptr()->stream());
}
else
{
if (writeOptionalEntries)
{
IOInfoInFunction(*this)
<< "Optional entry '" << keyword << "' is not present,"
<< " returning the default value '" << deflt << "'"
<< endl;
}
return deflt;
if (writeOptionalEntries)
{
IOInfoInFunction(*this)
<< "Optional entry '" << keyword << "' is not present,"
<< " returning the default value '" << deflt << "'"
<< endl;
}
return deflt;
}
@ -98,25 +96,23 @@ T Foam::dictionary::lookupOrAddDefault
bool patternMatch
)
{
const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch);
auto finder = csearch(keyword, recursive, patternMatch);
if (entryPtr)
if (finder.found())
{
return pTraits<T>(entryPtr->stream());
return pTraits<T>(finder.ptr()->stream());
}
else
{
if (writeOptionalEntries)
{
IOInfoInFunction(*this)
<< "Optional entry '" << keyword << "' is not present,"
<< " adding and returning the default value '" << deflt << "'"
<< endl;
}
add(new primitiveEntry(keyword, deflt));
return deflt;
if (writeOptionalEntries)
{
IOInfoInFunction(*this)
<< "Optional entry '" << keyword << "' is not present,"
<< " adding and returning the default value '" << deflt << "'"
<< endl;
}
add(new primitiveEntry(keyword, deflt));
return deflt;
}
@ -129,39 +125,37 @@ bool Foam::dictionary::readIfPresent
bool patternMatch
) const
{
const entry* entryPtr = lookupEntryPtr(keyword, recursive, patternMatch);
auto finder = csearch(keyword, recursive, patternMatch);
if (entryPtr)
if (finder.found())
{
entryPtr->stream() >> val;
finder.ptr()->stream() >> val;
return true;
}
else
if (writeOptionalEntries)
{
if (writeOptionalEntries)
{
IOInfoInFunction(*this)
<< "Optional entry '" << keyword << "' is not present,"
<< " the default value '" << val << "' will be used."
<< endl;
}
return false;
IOInfoInFunction(*this)
<< "Optional entry '" << keyword << "' is not present,"
<< " the default value '" << val << "' will be used."
<< endl;
}
return false;
}
template<class T>
void Foam::dictionary::add(const keyType& k, const T& t, bool overwrite)
void Foam::dictionary::add(const keyType& k, const T& v, bool overwrite)
{
add(new primitiveEntry(k, t), overwrite);
add(new primitiveEntry(k, v), overwrite);
}
template<class T>
void Foam::dictionary::set(const keyType& k, const T& t)
void Foam::dictionary::set(const keyType& k, const T& v)
{
set(new primitiveEntry(k, t));
set(new primitiveEntry(k, v));
}

View File

@ -62,10 +62,8 @@ bool Foam::entry::getKeyword(keyType& keyword, token& keyToken, Istream& is)
keyword = keyToken.stringToken();
return true;
}
else
{
return false;
}
return false;
}
@ -84,20 +82,17 @@ bool Foam::entry::getKeyword(keyType& keyword, Istream& is)
{
return false;
}
else
{
// Otherwise the token is invalid
cerr<< "--> FOAM Warning :" << nl
<< " From function "
<< FUNCTION_NAME << nl
<< " in file " << __FILE__
<< " at line " << __LINE__ << nl
<< " Reading " << is.name().c_str() << nl
<< " found " << keyToken << nl
<< " expected either " << token::END_BLOCK << " or EOF"
<< std::endl;
return false;
}
// Otherwise the token is invalid
std::cerr
<< "--> FOAM Warning :" << nl
<< " From function " << FUNCTION_NAME << nl
<< " in file " << __FILE__ << " at line " << __LINE__ << nl
<< " Reading " << is.name().c_str() << nl
<< " found " << keyToken << nl
<< " expected either " << token::END_BLOCK << " or EOF"
<< std::endl;
return false;
}
@ -154,22 +149,20 @@ bool Foam::entry::New
false
);
}
else
{
// Otherwise the token is invalid
cerr<< "--> FOAM Warning :" << nl
<< " From function "
<< FUNCTION_NAME << nl
<< " in file " << __FILE__
<< " at line " << __LINE__ << nl
<< " Reading " << is.name().c_str() << nl
<< " found " << keyToken << nl
<< " expected either " << token::END_BLOCK << " or EOF"
<< std::endl;
return false;
}
// Otherwise the token is invalid
std::cerr
<< "--> FOAM Warning :" << nl
<< " From function " << FUNCTION_NAME << nl
<< " in file " << __FILE__ << " at line " << __LINE__ << nl
<< " Reading " << is.name().c_str() << nl
<< " found " << keyToken << nl
<< " expected either " << token::END_BLOCK << " or EOF"
<< std::endl;
return false;
}
else if (keyword[0] == '#')
if (keyword[0] == '#')
{
// Function entry
@ -186,17 +179,11 @@ bool Foam::entry::New
false
);
}
else
{
const word functionName(keyword.substr(1), false);
return functionEntry::execute(functionName, parentDict, is);
}
const word functionName(keyword.substr(1), false);
return functionEntry::execute(functionName, parentDict, is);
}
else if
(
!disableFunctionEntries
&& keyword[0] == '$'
)
else if (!disableFunctionEntries && keyword[0] == '$')
{
// Substitution entry
@ -224,17 +211,12 @@ bool Foam::entry::New
const word varName = keyword.substr(1);
// Lookup the variable name in the given dictionary
const entry* ePtr = parentDict.lookupScopedEntryPtr
(
varName,
true,
true
);
const auto finder = parentDict.csearchScoped(varName, true, true);
if (ePtr)
if (finder.found())
{
// Read as primitiveEntry
const keyType newKeyword(ePtr->stream());
const keyType newKeyword(finder.ptr()->stream());
return parentDict.add
(
@ -242,14 +224,12 @@ bool Foam::entry::New
false
);
}
else
{
FatalIOErrorInFunction(is)
<< "Attempt to use undefined variable " << varName
<< " as keyword"
<< exit(FatalIOError);
return false;
}
FatalIOErrorInFunction(is)
<< "Attempt to use undefined variable " << varName
<< " as keyword"
<< exit(FatalIOError);
return false;
}
else
{
@ -267,7 +247,7 @@ bool Foam::entry::New
}
else
{
// Normal entry
// Normal or scoped entry
token nextToken(is);
is.putBack(nextToken);
@ -281,19 +261,59 @@ bool Foam::entry::New
return false;
}
const bool scoped =
(
!disableFunctionEntries
&& (keyword.find('/') != string::npos)
);
// See (using exact match) if entry already present
auto finder =
(
scoped
? parentDict.searchScoped(keyword, false, false)
: parentDict.search(keyword, false, false)
);
// How to manage duplicate entries
bool mergeEntry = false;
// See (using exact match) if entry already present
entry* existingPtr = parentDict.lookupEntryPtr
(
keyword,
false,
false
);
if (existingPtr)
if (finder.found())
{
// Use keyword from the found entry (ie, eliminate scoping chars)
const keyType key = finder.ref().keyword();
if (mode == inputMode::PROTECT || keyword == "FoamFile")
{
// Read and discard if existing element should be protected,
// or would potentially alter the "FoamFile" header.
// Disable function/variable expansion to avoid side-effects
const int oldFlag = entry::disableFunctionEntries;
entry::disableFunctionEntries = 1;
if (nextToken == token::BEGIN_BLOCK)
{
dictionaryEntry dummy("dummy", finder.context(), is);
}
else
{
primitiveEntry dummy("dummy", finder.context(), is);
}
entry::disableFunctionEntries = oldFlag;
return true;
}
if (mode == inputMode::ERROR)
{
FatalIOErrorInFunction(is)
<< "duplicate entry: " << key
<< exit(FatalIOError);
return false;
}
if (mode == inputMode::MERGE)
{
mergeEntry = true;
@ -301,57 +321,110 @@ bool Foam::entry::New
else if (mode == inputMode::OVERWRITE)
{
// Clear existing dictionary so merge acts like overwrite
if (existingPtr->isDict())
if (finder.isDict())
{
existingPtr->dict().clear();
finder.dict().clear();
}
mergeEntry = true;
}
else if (mode == inputMode::PROTECT)
{
// Read and discard the entry.
// Disable function/variable expansion to avoid side-effects
const int oldFlag = entry::disableFunctionEntries;
entry::disableFunctionEntries = 1;
if (nextToken == token::BEGIN_BLOCK)
// Merge/overwrite data entry
if (nextToken == token::BEGIN_BLOCK)
{
return finder.context().add
(
new dictionaryEntry(key, finder.context(), is),
mergeEntry
);
}
else
{
return finder.context().add
(
new primitiveEntry(key, finder.context(), is),
mergeEntry
);
}
}
else if (scoped)
{
// A slash-scoped entry - did not previously exist
string fullPath(keyword);
fileName::clean(fullPath);
// Get or create the dictionary-path.
// fileName::path == dictionary-path
dictionary* subDictPtr =
parentDict.makeScopedDictPtr
(
fileName::path(fullPath)
);
if (subDictPtr)
{
// fileName::name == keyword-name
string keyName = fileName::name(fullPath);
keyType key;
// Patterns allowed for the final element.
// - use if key name begins with a (single|double) quote
if (keyName.find_first_of("\"'") == 0)
{
dictionaryEntry dummy("dummy", parentDict, is);
// Begins with a quote - treat as pattern
key = keyType(string::validate<keyType>(keyName), true);
}
else
{
primitiveEntry dummy("dummy", parentDict, is);
// Treat as a word
key = word::validate(keyName, false);
}
entry::disableFunctionEntries = oldFlag;
return true;
if (nextToken == token::BEGIN_BLOCK)
{
return subDictPtr->add
(
new dictionaryEntry(key, *subDictPtr, is),
mergeEntry
);
}
else
{
return subDictPtr->add
(
new primitiveEntry(key, *subDictPtr, is),
mergeEntry
);
}
}
else if (mode == inputMode::ERROR)
else
{
FatalIOErrorInFunction(is)
<< "duplicate entry: " << keyword
<< exit(FatalIOError);
// Some error finding/creating intermediate dictionaries
return false;
}
}
if (nextToken == token::BEGIN_BLOCK)
{
return parentDict.add
(
new dictionaryEntry(keyword, parentDict, is),
mergeEntry
);
}
else
{
return parentDict.add
(
new primitiveEntry(keyword, parentDict, is),
mergeEntry
);
// A non-scoped entry - did not previously exist
if (nextToken == token::BEGIN_BLOCK)
{
return parentDict.add
(
new dictionaryEntry(keyword, parentDict, is),
mergeEntry
);
}
else
{
return parentDict.add
(
new primitiveEntry(keyword, parentDict, is),
mergeEntry
);
}
}
}
}

View File

@ -24,11 +24,11 @@ License
\*---------------------------------------------------------------------------*/
#include "includeEntry.H"
#include "IFstream.H"
#include "addToMemberFunctionSelectionTable.H"
#include "stringOps.H"
#include "Time.H"
#include "IFstream.H"
#include "IOstreams.H"
#include "Time.H"
#include "fileOperation.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -62,27 +62,6 @@ namespace functionEntries
// * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
Foam::fileName Foam::functionEntries::includeEntry::resolveFile
(
Istream& is,
const dictionary& dict
)
{
fileName fName(is);
// Substitute dictionary and environment variables.
// Allow empty substitutions.
stringOps::inplaceExpand(fName, dict, true, true);
if (fName.empty() || fName.isAbsolute())
{
return fName;
}
// Relative name
return fileName(is.name()).path()/fName;
}
Foam::fileName Foam::functionEntries::includeEntry::resolveFile
(
const fileName& dir,
@ -91,6 +70,7 @@ Foam::fileName Foam::functionEntries::includeEntry::resolveFile
)
{
fileName fName(f);
// Substitute dictionary and environment variables.
// Allow empty substitutions.
stringOps::inplaceExpand(fName, dict, true, true);
@ -114,7 +94,8 @@ bool Foam::functionEntries::includeEntry::execute
)
{
const fileName rawName(is);
const fileName fName = resolveFile(is.name().path(), rawName, parentDict);
const fileName fName(resolveFile(is.name().path(), rawName, parentDict));
autoPtr<ISstream> ifsPtr(fileHandler().NewIFstream(fName));
ISstream& ifs = ifsPtr();
@ -133,27 +114,22 @@ bool Foam::functionEntries::includeEntry::execute
(
dynamic_cast<const regIOobject&>(top)
);
//Info<< rio.name() << " : adding dependency on included file "
// << fName << endl;
rio.addWatch(fName);
}
parentDict.read(ifs);
return true;
}
else
{
FatalIOErrorInFunction
(
is
) << "Cannot open include file "
<< (ifs.name().size() ? ifs.name() : rawName)
<< " while reading dictionary " << parentDict.name()
<< exit(FatalIOError);
return false;
}
FatalIOErrorInFunction
(
is
) << "Cannot open include file "
<< (ifs.name().size() ? ifs.name() : rawName)
<< " while reading dictionary " << parentDict.name()
<< exit(FatalIOError);
return false;
}
@ -165,7 +141,8 @@ bool Foam::functionEntries::includeEntry::execute
)
{
const fileName rawName(is);
const fileName fName = resolveFile(is.name().path(), rawName, parentDict);
const fileName fName(resolveFile(is.name().path(), rawName, parentDict));
autoPtr<ISstream> ifsPtr(fileHandler().NewIFstream(fName));
ISstream& ifs = ifsPtr();
@ -184,27 +161,23 @@ bool Foam::functionEntries::includeEntry::execute
(
dynamic_cast<const regIOobject&>(top)
);
//Info<< rio.name() << " : adding dependency on included file "
// << fName << endl;
rio.addWatch(fName);
}
entry.read(parentDict, ifs);
return true;
}
else
{
FatalIOErrorInFunction
(
is
) << "Cannot open include file "
<< (ifs.name().size() ? ifs.name() : rawName)
<< " while reading dictionary " << parentDict.name()
<< exit(FatalIOError);
return false;
}
FatalIOErrorInFunction
(
is
) << "Cannot open include file "
<< (ifs.name().size() ? ifs.name() : rawName)
<< " while reading dictionary " << parentDict.name()
<< exit(FatalIOError);
return false;
}
// ************************************************************************* //

View File

@ -68,9 +68,6 @@ protected:
// Protected Member Functions
//- Read the include fileName from Istream, expand and return
static fileName resolveFile(Istream& is, const dictionary& dict);
//- Expand include fileName and return
static fileName resolveFile
(
@ -79,6 +76,7 @@ protected:
const dictionary& dict
);
public:
// Static data members

View File

@ -24,9 +24,10 @@ License
\*---------------------------------------------------------------------------*/
#include "includeEtcEntry.H"
#include "addToMemberFunctionSelectionTable.H"
#include "etcFiles.H"
#include "stringOps.H"
#include "addToMemberFunctionSelectionTable.H"
#include "IFstream.H"
#include "IOstreams.H"
#include "fileOperation.H"
@ -61,7 +62,7 @@ namespace functionEntries
// * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
Foam::fileName Foam::functionEntries::includeEtcEntry::resolveFile
Foam::fileName Foam::functionEntries::includeEtcEntry::resolveEtcFile
(
const fileName& f,
const dictionary& dict
@ -78,7 +79,7 @@ Foam::fileName Foam::functionEntries::includeEtcEntry::resolveFile
return fName;
}
// Search the etc directories for the file
// Search etc directories for the file
return Foam::findEtcFile(fName);
}
@ -92,9 +93,8 @@ bool Foam::functionEntries::includeEtcEntry::execute
)
{
const fileName rawName(is);
const fileName fName(resolveFile(rawName, parentDict));
const fileName fName(resolveEtcFile(rawName, parentDict));
//IFstream ifs(fName);
autoPtr<ISstream> ifsPtr(fileHandler().NewIFstream(fName));
ISstream& ifs = ifsPtr();
@ -107,18 +107,16 @@ bool Foam::functionEntries::includeEtcEntry::execute
parentDict.read(ifs);
return true;
}
else
{
FatalIOErrorInFunction
(
is
) << "Cannot open etc file "
<< (ifs.name().size() ? ifs.name() : rawName)
<< " while reading dictionary " << parentDict.name()
<< exit(FatalIOError);
return false;
}
FatalIOErrorInFunction
(
is
) << "Cannot open etc file "
<< (ifs.name().size() ? ifs.name() : rawName)
<< " while reading dictionary " << parentDict.name()
<< exit(FatalIOError);
return false;
}
@ -130,9 +128,8 @@ bool Foam::functionEntries::includeEtcEntry::execute
)
{
const fileName rawName(is);
const fileName fName(resolveFile(rawName, parentDict));
const fileName fName(resolveEtcFile(rawName, parentDict));
//IFstream ifs(fName);
autoPtr<ISstream> ifsPtr(fileHandler().NewIFstream(fName));
ISstream& ifs = ifsPtr();
@ -145,18 +142,16 @@ bool Foam::functionEntries::includeEtcEntry::execute
entry.read(parentDict, ifs);
return true;
}
else
{
FatalIOErrorInFunction
(
is
) << "Cannot open etc file "
<< (ifs.name().size() ? ifs.name() : rawName)
<< " while reading dictionary " << parentDict.name()
<< exit(FatalIOError);
return false;
}
FatalIOErrorInFunction
(
is
) << "Cannot open etc file "
<< (ifs.name().size() ? ifs.name() : rawName)
<< " while reading dictionary " << parentDict.name()
<< exit(FatalIOError);
return false;
}

View File

@ -79,9 +79,16 @@ class includeEtcEntry
:
public functionEntry
{
//- Expand include fileName and return
static fileName resolveFile(const fileName& f, const dictionary& dict);
protected:
// Protected Member Functions
//- Expand include fileName and search etc directories for the file
static fileName resolveEtcFile
(
const fileName& f,
const dictionary& dict
);
public:

View File

@ -64,7 +64,9 @@ bool Foam::functionEntries::includeIfPresentEntry::execute
Istream& is
)
{
const fileName fName(resolveFile(is, parentDict));
const fileName rawName(is);
const fileName fName(resolveFile(is.name().path(), rawName, parentDict));
autoPtr<ISstream> ifsPtr(fileHandler().NewIFstream(fName));
ISstream& ifs = ifsPtr();
@ -100,7 +102,9 @@ bool Foam::functionEntries::includeIfPresentEntry::execute
Istream& is
)
{
const fileName fName(resolveFile(is, parentDict));
const fileName rawName(is);
const fileName fName(resolveFile(is.name().path(), rawName, parentDict));
autoPtr<ISstream> ifsPtr(fileHandler().NewIFstream(fName));
ISstream& ifs = ifsPtr();

View File

@ -41,6 +41,51 @@ namespace functionEntries
dictionaryIstream,
inputMode
);
addNamedToMemberFunctionSelectionTable
(
functionEntry,
inputModeDefault,
execute,
dictionaryIstream,
default
);
addNamedToMemberFunctionSelectionTable
(
functionEntry,
inputModeMerge,
execute,
dictionaryIstream,
merge
);
addNamedToMemberFunctionSelectionTable
(
functionEntry,
inputModeOverwrite,
execute,
dictionaryIstream,
overwrite
);
addNamedToMemberFunctionSelectionTable
(
functionEntry,
inputModeWarn,
execute,
dictionaryIstream,
warn
);
addNamedToMemberFunctionSelectionTable
(
functionEntry,
inputModeError,
execute,
dictionaryIstream,
error
);
}
}
@ -90,4 +135,54 @@ bool Foam::functionEntries::inputMode::execute
}
bool Foam::functionEntries::inputModeDefault::execute
(
dictionary& parentDict,
Istream& is
)
{
return entry::New(parentDict, is, entry::inputMode::PROTECT);
}
bool Foam::functionEntries::inputModeMerge::execute
(
dictionary& parentDict,
Istream& is
)
{
return entry::New(parentDict, is, entry::inputMode::MERGE);
}
bool Foam::functionEntries::inputModeOverwrite::execute
(
dictionary& parentDict,
Istream& is
)
{
return entry::New(parentDict, is, entry::inputMode::OVERWRITE);
}
bool Foam::functionEntries::inputModeWarn::execute
(
dictionary& parentDict,
Istream& is
)
{
return entry::New(parentDict, is, entry::inputMode::WARN);
}
bool Foam::functionEntries::inputModeError::execute
(
dictionary& parentDict,
Istream& is
)
{
return entry::New(parentDict, is, entry::inputMode::ERROR);
}
// ************************************************************************* //

View File

@ -84,6 +84,86 @@ public:
};
/*---------------------------------------------------------------------------*\
Class inputModeDefault Declaration
\*---------------------------------------------------------------------------*/
//- Temporarily change inputMode to %protect for the following entry
class inputModeDefault
:
public functionEntry
{
public:
//- Execute in a sub-dict context
static bool execute(dictionary& parentDict, Istream& is);
};
/*---------------------------------------------------------------------------*\
Class inputModeMerge Declaration
\*---------------------------------------------------------------------------*/
//- Temporarily change inputMode to %merge for the following entry
class inputModeMerge
:
public functionEntry
{
public:
//- Execute in a sub-dict context
static bool execute(dictionary& parentDict, Istream& is);
};
/*---------------------------------------------------------------------------*\
Class inputModeOverwrite Declaration
\*---------------------------------------------------------------------------*/
//- Temporarily change inputMode to %overwrite for the following entry
class inputModeOverwrite
:
public functionEntry
{
public:
//- Execute in a sub-dict context
static bool execute(dictionary& parentDict, Istream& is);
};
/*---------------------------------------------------------------------------*\
Class inputModeWarn Declaration
\*---------------------------------------------------------------------------*/
//- Temporarily change inputMode to %warn for the following entry
class inputModeWarn
:
public functionEntry
{
public:
//- Execute in a sub-dict context
static bool execute(dictionary& parentDict, Istream& is);
};
/*---------------------------------------------------------------------------*\
Class inputModeError Declaration
\*---------------------------------------------------------------------------*/
//- Temporarily change inputMode to %error for the following entry
class inputModeError
:
public functionEntry
{
public:
//- Execute in a sub-dict context
static bool execute(dictionary& parentDict, Istream& is);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionEntries

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,7 +26,6 @@ License
#include "removeEntry.H"
#include "dictionary.H"
#include "stringListOps.H"
#include "StringStream.H"
#include "addToMemberFunctionSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -55,17 +54,36 @@ bool Foam::functionEntries::removeEntry::execute
Istream& is
)
{
wordList dictKeys = parentDict.toc();
wordReList patterns = readList<wordRe>(is);
const List<keyType> patterns = readList<keyType>(is);
labelList indices = findStrings(patterns, dictKeys);
forAll(indices, indexI)
for (const keyType& key : patterns)
{
parentDict.remove(dictKeys[indices[indexI]]);
if (key.find('/') != string::npos || !key.isPattern())
{
// Remove scoped keyword, or keyword in the local scope
dictionary::searcher finder =
parentDict.searchScoped(key, false, false);
if (finder.found())
{
finder.context().remove(finder.ptr()->keyword());
}
}
else
{
// Remove by pattern
const wordList dictKeys = parentDict.toc();
const labelList indices = findStrings(regExp(key), dictKeys);
for (const auto idx : indices)
{
parentDict.remove(dictKeys[idx]);
}
}
}
return true;
}
// ************************************************************************* //

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,17 +27,22 @@ Class
Description
Remove a dictionary entry.
The \c \#remove directive takes a list or a single wordRe.
The \c \#remove directive takes a list or a single keyType.
For example,
\verbatim
#remove entry0
#remove ( entry1 entry2 entry3 otherEntry )
#remove "entry[1-3]"
#remove ( "entry[1-3]" otherEntry )
#remove ^dict1.subdict2.entry2
#remove "/dict1/subdict2/entry1"
\endverbatim
The removal only occurs in the current context.
Removing sub-entries or parent entries is not supported.
Note
Unless otherwise scoped, the removal occurs in the current context.
To remove from other scopes, a dot-scoped or slash-scoped syntax is
required. The slash-scoped syntax must be quoted to ensure that it
is properly parsed.
SourceFiles
removeEntry.C
@ -57,7 +62,7 @@ namespace functionEntries
{
/*---------------------------------------------------------------------------*\
Class removeEntry Declaration
Class removeEntry Declaration
\*---------------------------------------------------------------------------*/
class removeEntry
@ -66,7 +71,7 @@ class removeEntry
{
public:
//- Remove entries from the current sub-dict context
//- Remove single or multiple entries. Local or scoped entries.
static bool execute(dictionary& parentDict, Istream& is);
};

View File

@ -49,7 +49,7 @@ bool Foam::primitiveEntry::expandVariable
{
// Recursive substitution mode.
// Content between {} is replaced with expansion.
string expanded = varName.substr(1, varName.size()-2);
string expanded(varName.substr(1, varName.size()-2));
// Substitute dictionary and environment variables.
// Do not allow empty substitutions.
@ -57,46 +57,45 @@ bool Foam::primitiveEntry::expandVariable
return expandVariable(expanded, dict);
}
// Lookup variable name in the given dictionary WITHOUT pattern matching.
// Having a pattern match means that in this example:
// {
// internalField XXX;
// boundaryField { ".*" {YYY;} movingWall {value $internalField;}
// }
// The $internalField would be matched by the ".*" !!!
// Recursive, non-patterns
const entry* eptr = dict.lookupScopedEntryPtr(varName, true, false);
if (!eptr)
{
// Not found - revert to environment variable
const string str(getEnv(varName));
if (str.empty())
{
FatalIOErrorInFunction
(
dict
) << "Illegal dictionary entry or environment variable name "
<< varName << endl << "Valid dictionary entries are "
<< dict.toc() << exit(FatalIOError);
return false;
}
append(tokenList(IStringStream('(' + str + ')')()));
}
else if (eptr->isDict())
{
// Found dictionary entry
append(eptr->dict().tokens());
}
else
{
// 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 (ePtr->isDict())
{
append(ePtr->dict().tokens());
}
else
{
append(ePtr->stream());
}
}
else
{
// Not in the dictionary - try an environment variable
const string envStr = getEnv(varName);
if (envStr.empty())
{
FatalIOErrorInFunction
(
dict
) << "Illegal dictionary entry or environment variable name "
<< varName << endl << "Valid dictionary entries are "
<< dict.toc() << exit(FatalIOError);
return false;
}
append(tokenList(IStringStream('(' + envStr + ')')()));
}
// Found primitive entry
append(eptr->stream());
}
return true;

View File

@ -29,11 +29,71 @@ License
#include "etcFiles.H"
#include "StringStream.H"
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Standard handling of "~/", "./" etc.
static void standardExpansions(Foam::string& s)
{
if (s.empty())
{
return;
}
if (s[0] == '.')
{
// Expand a lone '.' and an initial './' into cwd
if (s.size() == 1)
{
s = cwd();
}
else if (s[1] == '/')
{
s.std::string::replace(0, 1, cwd());
}
}
else if (s[0] == '~')
{
// Expand initial ~
// ~/ => home directory
// ~OpenFOAM => site/user OpenFOAM configuration directory
// ~user => home directory for specified user
string user;
fileName file;
const auto slash = s.find('/');
if (slash == std::string::npos)
{
user = s.substr(1);
}
else
{
user = s.substr(1, slash - 1);
file = s.substr(slash + 1);
}
// NB: be a bit lazy and expand ~unknownUser as an
// empty string rather than leaving it untouched.
// otherwise add extra test
if (user == "OpenFOAM")
{
s = findEtcFile(file);
}
else
{
s = home(user)/file;
}
}
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//! \cond fileScope
// 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,
@ -70,6 +130,8 @@ static inline int findParameterAlternative
//! \endcond
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Foam::string Foam::stringOps::expand
(
const string& original,
@ -257,13 +319,14 @@ Foam::string Foam::stringOps::getVariable
{
string value;
const entry* ePtr = dict.lookupScopedEntryPtr
const entry* eptr = dict.lookupScopedEntryPtr
(
name,
true,
false
);
if (ePtr)
if (eptr)
{
OStringStream buf;
// Force floating point numbers to be printed with at least
@ -271,11 +334,8 @@ Foam::string Foam::stringOps::getVariable
buf << fixed;
buf.precision(IOstream::defaultPrecision());
// fail for non-primitiveEntry
dynamicCast<const primitiveEntry>
(
*ePtr
).write(buf, true);
// Fails for non-primitiveEntry
dynamicCast<const primitiveEntry>(*eptr).write(buf, true);
value = buf.str();
}
@ -308,8 +368,11 @@ Foam::string Foam::stringOps::getVariable
}
}
}
}
if (!allowEmpty && value.empty())
if (!allowEmpty && value.empty())
{
if (allowEnvVars)
{
FatalIOErrorInFunction
(
@ -317,15 +380,14 @@ Foam::string Foam::stringOps::getVariable
) << "Cannot find dictionary or environment variable "
<< name << exit(FatalIOError);
}
}
if (!allowEmpty && value.empty())
{
FatalIOErrorInFunction
(
dict
) << "Cannot find dictionary variable "
<< name << exit(FatalIOError);
else
{
FatalIOErrorInFunction
(
dict
) << "Cannot find dictionary variable "
<< name << exit(FatalIOError);
}
}
return value;
@ -360,8 +422,9 @@ Foam::string Foam::stringOps::expand
{
newString.append(string(s[index]));
}
index++;
++index;
}
return newString;
}
@ -390,7 +453,7 @@ Foam::string& Foam::stringOps::inplaceExpand
if (s[begVar+1] == '{')
{
// Recursive variable expansion mode
label stringStart = begVar;
auto stringStart = begVar;
begVar += 2;
string varValue
(
@ -471,53 +534,8 @@ Foam::string& Foam::stringOps::inplaceExpand
}
}
if (!s.empty())
{
if (s[0] == '~')
{
// Expand initial ~
// ~/ => home directory
// ~OpenFOAM => site/user OpenFOAM configuration directory
// ~user => home directory for specified user
string user;
fileName file;
if ((begVar = s.find('/')) != string::npos)
{
user = s.substr(1, begVar - 1);
file = s.substr(begVar + 1);
}
else
{
user = s.substr(1);
}
// NB: be a bit lazy and expand ~unknownUser as an
// empty string rather than leaving it untouched.
// otherwise add extra test
if (user == "OpenFOAM")
{
s = findEtcFile(file);
}
else
{
s = home(user)/file;
}
}
else if (s[0] == '.')
{
// Expand a lone '.' and an initial './' into cwd
if (s.size() == 1)
{
s = cwd();
}
else if (s[1] == '/')
{
s.std::string::replace(0, 1, cwd());
}
}
}
// Standard handling of "~/", "./" etc.
standardExpansions(s);
return s;
}
@ -596,32 +614,33 @@ Foam::string& Foam::stringOps::inplaceExpand
);
// lookup in the dictionary
const entry* ePtr = dict.lookupScopedEntryPtr
// Lookup in the dictionary without wildcards.
// See note in primitiveEntry
const entry* eptr = dict.lookupScopedEntryPtr
(
varName,
true,
false // wildcards disabled. See primitiveEntry
false
);
// if defined - copy its entries
if (ePtr)
if (eptr)
{
OStringStream buf;
// Force floating point numbers to be printed with at least
// some decimal digits.
buf << fixed;
buf.precision(IOstream::defaultPrecision());
if (ePtr->isDict())
if (eptr->isDict())
{
ePtr->dict().write(buf, false);
eptr->dict().write(buf, false);
}
else
{
// fail for other types
// Fail for non-primitiveEntry
dynamicCast<const primitiveEntry>
(
*ePtr
*eptr
).write(buf, true);
}
@ -816,53 +835,8 @@ Foam::string& Foam::stringOps::inplaceExpand
}
}
if (!s.empty())
{
if (s[0] == '~')
{
// Expand initial ~
// ~/ => home directory
// ~OpenFOAM => site/user OpenFOAM configuration directory
// ~user => home directory for specified user
string user;
fileName file;
if ((begVar = s.find('/')) != string::npos)
{
user = s.substr(1, begVar - 1);
file = s.substr(begVar + 1);
}
else
{
user = s.substr(1);
}
// NB: be a bit lazy and expand ~unknownUser as an
// empty string rather than leaving it untouched.
// otherwise add extra test
if (user == "OpenFOAM")
{
s = findEtcFile(file);
}
else
{
s = home(user)/file;
}
}
else if (s[0] == '.')
{
// Expand a lone '.' and an initial './' into cwd
if (s.size() == 1)
{
s = cwd();
}
else if (s[1] == '/')
{
s.std::string::replace(0, 1, cwd());
}
}
}
// Standard handling of "~/", "./" etc.
standardExpansions(s);
return s;
}
@ -886,11 +860,9 @@ bool Foam::stringOps::inplaceReplaceVar(string& s, const word& varName)
{
return false;
}
else
{
s.replace(i, content.size(), string("${" + varName + "}"));
return true;
}
s.replace(i, content.size(), string("${" + varName + "}"));
return true;
}

View File

@ -12,6 +12,4 @@ maxCo 12;
maxDeltaT 1;
#inputMode merge
// ************************************************************************* //

View File

@ -12,6 +12,4 @@ maxCo 2.5;
maxDeltaT 0.3;
#inputMode merge
// ************************************************************************* //

View File

@ -12,6 +12,4 @@ maxCo 8;
maxDeltaT 1;
#inputMode merge
// ************************************************************************* //

View File

@ -12,6 +12,4 @@ maxCo 5;
maxDeltaT 1;
#inputMode merge
// ************************************************************************* //

View File

@ -12,6 +12,4 @@ maxCo 12;
maxDeltaT 1;
#inputMode merge
// ************************************************************************* //

View File

@ -12,6 +12,4 @@ turbulentKE 37;
turbulentOmega 32;
turbulentEpsilon 30;
#inputMode merge
// ************************************************************************* //

View File

@ -10,6 +10,5 @@ flowVelocity (10 0 0);
pressure 0;
turbulentKE 1.5;
turbulentEpsilon 0.88;
#inputMode merge
// ************************************************************************* //

View File

@ -11,6 +11,5 @@ pressure 0;
turbulentKE 0.375;
turbulentOmega 3.6;
turbulentEpsilon 0.12;
#inputMode merge
// ************************************************************************* //