mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: change internal dictionary separator to '/' (#1073)
- simplifies internal handling (like a fileName) and allows the dictionary name to be used with unambiguous addressing. The previous dot (.) separator is ambiguous (ie, as dictionary separator or as part of a keyword). ENH: foamDictionary report -add/-set to stderr
This commit is contained in:
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016-2017 OpenFOAM Foundation
|
||||
Copyright (C) 2017-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2017-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -78,23 +78,23 @@ Usage
|
||||
|
||||
- Change solver:
|
||||
\verbatim
|
||||
foamDictionary system/fvSolution -entry solvers.p.solver -set PCG
|
||||
foamDictionary system/fvSolution -entry solvers/p/solver -set PCG
|
||||
\endverbatim
|
||||
|
||||
- Print bc type:
|
||||
\verbatim
|
||||
foamDictionary 0/U -entry boundaryField.movingWall.type
|
||||
foamDictionary 0/U -entry boundaryField/movingWall/type
|
||||
\endverbatim
|
||||
|
||||
- Change bc parameter:
|
||||
\verbatim
|
||||
foamDictionary 0/U -entry boundaryField.movingWall.value \
|
||||
foamDictionary 0/U -entry boundaryField/movingWall/value \
|
||||
-set "uniform (2 0 0)"
|
||||
\endverbatim
|
||||
|
||||
- Change whole bc type:
|
||||
\verbatim
|
||||
foamDictionary 0/U -entry boundaryField.movingWall \
|
||||
foamDictionary 0/U -entry boundaryField/movingWall \
|
||||
-set "{type uniformFixedValue; uniformValue (2 0 0);}"
|
||||
\endverbatim
|
||||
|
||||
@ -113,7 +113,7 @@ Usage
|
||||
- Change patch type:
|
||||
\verbatim
|
||||
foamDictionary constant/polyMesh/boundary \
|
||||
-entry entry0.fixedWalls.type -set patch
|
||||
-entry entry0/fixedWalls/type -set patch
|
||||
\endverbatim
|
||||
This uses special parsing of Lists which stores these in the
|
||||
dictionary with keyword 'entryDDD' where DDD is the position
|
||||
@ -140,21 +140,31 @@ using namespace Foam;
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
//- Convert older ':' scope syntax to newer '.' scope syntax,
|
||||
//- Convert very old ':' scope syntax to less old '.' scope syntax,
|
||||
// but leave anything with '/' delimiters untouched
|
||||
bool upgradeScope(word& entryName)
|
||||
{
|
||||
if (!entryName.contains('/') && entryName.contains(':'))
|
||||
if (entryName.contains(':') && !entryName.contains('/'))
|
||||
{
|
||||
const wordList names(fileName(entryName).components(':'));
|
||||
InfoErr
|
||||
<< "Warning: upgrading very old ':' scope syntax: \""
|
||||
<< entryName << '"' << endl;
|
||||
|
||||
entryName.resize(0);
|
||||
// Make copy - cannot use stringOps::split
|
||||
const wordList cmpts(fileName(entryName).components(':'));
|
||||
|
||||
for (const word& name : names)
|
||||
entryName.clear();
|
||||
|
||||
bool addSep = false;
|
||||
|
||||
for (const word& cmpt : cmpts)
|
||||
{
|
||||
if (entryName.size()) entryName.append(".");
|
||||
|
||||
entryName.append(name);
|
||||
if (addSep) entryName += '.';
|
||||
if (!cmpt.empty())
|
||||
{
|
||||
addSep = true;
|
||||
entryName += cmpt;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -176,12 +186,12 @@ public:
|
||||
dictAndKeyword(const word& scopedName)
|
||||
{
|
||||
auto i = scopedName.rfind('/');
|
||||
if (i == string::npos)
|
||||
if (i == std::string::npos)
|
||||
{
|
||||
i = scopedName.rfind('.');
|
||||
}
|
||||
|
||||
if (i != string::npos)
|
||||
if (i != std::string::npos)
|
||||
{
|
||||
dict_ = scopedName.substr(0, i);
|
||||
key_ = scopedName.substr(i+1);
|
||||
@ -192,15 +202,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
inline const word& dict() const
|
||||
{
|
||||
return dict_;
|
||||
}
|
||||
const word& dict() const noexcept { return dict_; }
|
||||
|
||||
inline const word& key() const
|
||||
{
|
||||
return key_;
|
||||
}
|
||||
const word& key() const noexcept { return key_; }
|
||||
};
|
||||
|
||||
|
||||
@ -347,10 +351,7 @@ int main(int argc, char *argv[])
|
||||
if (disableEntries)
|
||||
{
|
||||
// Report on stderr (once) to avoid polluting the output
|
||||
if (Pstream::master())
|
||||
{
|
||||
Serr<< "Not expanding variables or dictionary directives" << endl;
|
||||
}
|
||||
InfoErr<< "Not expanding variables or dictionary directives" << endl;
|
||||
entry::disableFunctionEntries = true;
|
||||
}
|
||||
|
||||
@ -359,11 +360,7 @@ int main(int argc, char *argv[])
|
||||
const unsigned prec = args.getOrDefault<unsigned>("precision", 0u);
|
||||
if (prec)
|
||||
{
|
||||
// if (Pstream::master())
|
||||
// {
|
||||
// Serr<< "Output write precision set to " << prec << endl;
|
||||
// }
|
||||
|
||||
// InfoErr<< "Output write precision set to " << prec << endl;
|
||||
IOstream::defaultPrecision(prec);
|
||||
Sout.precision(prec);
|
||||
}
|
||||
@ -479,12 +476,12 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
changed = true;
|
||||
|
||||
// Print the changed entry
|
||||
const auto finder = dict.csearchScoped(scopedName, keyType::REGEX);
|
||||
|
||||
// Print the changed entry to stderr
|
||||
if (finder.good())
|
||||
{
|
||||
Info<< finder.ref();
|
||||
InfoErr<< finder.ref();
|
||||
}
|
||||
}
|
||||
else if (args.found("remove"))
|
||||
@ -539,6 +536,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else if (args.found("keywords"))
|
||||
{
|
||||
// Report keywords to stdout
|
||||
for (const entry& e : finder.dict())
|
||||
{
|
||||
Info<< e.keyword() << endl;
|
||||
@ -546,32 +544,36 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else if (args.found("value"))
|
||||
{
|
||||
// Report value to stdout
|
||||
if (finder.isDict())
|
||||
{
|
||||
Info<< finder.dict();
|
||||
}
|
||||
else if (finder.ref().isStream())
|
||||
{
|
||||
bool addSep = false;
|
||||
|
||||
const tokenList& tokens = finder.ref().stream();
|
||||
forAll(tokens, i)
|
||||
|
||||
for (const token& tok : tokens)
|
||||
{
|
||||
Info<< tokens[i];
|
||||
if (i < tokens.size() - 1)
|
||||
{
|
||||
Info<< token::SPACE;
|
||||
}
|
||||
if (addSep) Info<< token::SPACE;
|
||||
addSep = true;
|
||||
Info<< tok;
|
||||
}
|
||||
Info<< endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Report entry to stdout
|
||||
Info<< finder.ref();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (args.found("keywords"))
|
||||
{
|
||||
// Report keywords to stdout
|
||||
for (const entry& e : dict)
|
||||
{
|
||||
Info<< e.keyword() << endl;
|
||||
@ -579,11 +581,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else if (optDiff)
|
||||
{
|
||||
// Report difference to stdout
|
||||
removeDict(dict, diffDict);
|
||||
dict.write(Info, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Report dictionary to stdout
|
||||
dict.write(Info, false);
|
||||
}
|
||||
|
||||
|
||||
@ -153,7 +153,7 @@ Foam::dictionary::dictionary
|
||||
parent_(parentDict)
|
||||
{
|
||||
transfer(dict);
|
||||
name() = fileName::concat(parentDict.name(), name(), '.');
|
||||
name() = fileName::concat(parentDict.name(), name(), '/');
|
||||
}
|
||||
|
||||
|
||||
@ -658,7 +658,7 @@ Foam::entry* Foam::dictionary::add(entry* entryPtr, bool mergeEntry)
|
||||
if (hashedEntries_.insert(entryPtr->keyword(), entryPtr))
|
||||
{
|
||||
entryPtr->name() =
|
||||
fileName::concat(name(), entryPtr->keyword(), '.');
|
||||
fileName::concat(name(), entryPtr->keyword(), '/');
|
||||
|
||||
if (entryPtr->keyword().isPattern())
|
||||
{
|
||||
@ -684,7 +684,7 @@ Foam::entry* Foam::dictionary::add(entry* entryPtr, bool mergeEntry)
|
||||
if (hashedEntries_.insert(entryPtr->keyword(), entryPtr))
|
||||
{
|
||||
entryPtr->name() =
|
||||
fileName::concat(name(), entryPtr->keyword(), '.');
|
||||
fileName::concat(name(), entryPtr->keyword(), '/');
|
||||
|
||||
parent_type::push_back(entryPtr);
|
||||
|
||||
|
||||
@ -43,35 +43,44 @@ Description
|
||||
as a bootstrap dictionary for the objectRegistry data dictionaries.
|
||||
|
||||
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
|
||||
dictionary.
|
||||
An initial '^' anchor (or ':' for backward compatibility) specifies
|
||||
starting from the top-level entry.
|
||||
For example,
|
||||
Within dictionaries, entries can be referenced by using the
|
||||
\c '$' syntax familiar from shell programming.
|
||||
Similarly, the \c '/' separator is used when referencing
|
||||
sub-dictionary entries:
|
||||
- <b> "./" </b> : the current dictionary
|
||||
- <b> "../" </b> : the parent dictionary
|
||||
- <b> "../../" </b> : the grandparent dictionary
|
||||
.
|
||||
|
||||
An initial \c '/' anchor specifies that the path starts from the
|
||||
top-level entry. It is also possible to use the '${}' syntax for clarity.
|
||||
|
||||
For example,
|
||||
\verbatim
|
||||
key1 val1;
|
||||
key2 $key1; // use key1 value from current scope
|
||||
key3 $.key1; // use key1 value from current scope
|
||||
key2 $key1; // Use key1 value from current scope
|
||||
key3 $./key1; // Use key1 value from current scope
|
||||
|
||||
subdict1
|
||||
{
|
||||
key1 val1b;
|
||||
key2 $..key1; // use key1 value from parent
|
||||
key2 $../key1; // Use key1 value from parent
|
||||
subdict2
|
||||
{
|
||||
key2 val2;
|
||||
key3 $...key1; // use key1 value from grandparent
|
||||
key3 $../../key1; // Use key1 value from grandparent
|
||||
}
|
||||
}
|
||||
|
||||
key4 $^subdict1.subdict2.key3; // lookup with absolute scoping
|
||||
key4 $/subdict1/subdict2/key3; // Lookup with absolute scoping
|
||||
\endverbatim
|
||||
|
||||
It is also possible to use the '${}' syntax for clarity.
|
||||
Prior to OpenFOAM-v1712, a dot-scoping (.) syntax was used, which is
|
||||
still supported (AUG-2023) but deprecated in favour of the
|
||||
less ambiguous slash-scoping (/) syntax.
|
||||
With dot-scoping, an initial \c '^' anchor, or an initial (:), was used
|
||||
to specify that the path starts from the top-level entry.
|
||||
|
||||
|
||||
SourceFiles
|
||||
dictionary.C
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2021 OpenCFD Ltd.
|
||||
Copyright (C) 2021-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -59,15 +59,19 @@ inline Foam::fileName& Foam::dictionary::name() noexcept
|
||||
|
||||
inline Foam::word Foam::dictionary::dictName() const
|
||||
{
|
||||
word scopedName(name_.name());
|
||||
// With other (non-slash) separator. Eg, with '.'
|
||||
// word scopedName(name_.name());
|
||||
//
|
||||
// const auto i = scopedName.rfind('.');
|
||||
// if (i == std::string::npos)
|
||||
// {
|
||||
// return scopedName;
|
||||
// }
|
||||
//
|
||||
// return scopedName.substr(i+1);
|
||||
|
||||
const auto i = scopedName.rfind('.');
|
||||
if (i == std::string::npos)
|
||||
{
|
||||
return scopedName;
|
||||
}
|
||||
|
||||
return scopedName.substr(i+1);
|
||||
// With '/' separator, this is just fileName::name()
|
||||
return name_.name();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ Foam::dictionary::dictionary
|
||||
bool keepHeader
|
||||
)
|
||||
:
|
||||
name_(fileName::concat(parentDict.name(), name, '.')),
|
||||
name_(fileName::concat(parentDict.name(), name, '/')),
|
||||
parent_(parentDict)
|
||||
{
|
||||
read(is, keepHeader);
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2017-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2017-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -38,7 +38,7 @@ namespace
|
||||
template<class WcIterator, class ReIterator>
|
||||
bool findInPatterns
|
||||
(
|
||||
const bool patternMatch,
|
||||
const bool literal,
|
||||
const Foam::word& keyword,
|
||||
WcIterator& wcIter,
|
||||
ReIterator& reIter
|
||||
@ -48,9 +48,9 @@ namespace
|
||||
{
|
||||
if
|
||||
(
|
||||
patternMatch
|
||||
? reIter()->match(keyword)
|
||||
: wcIter()->keyword() == keyword
|
||||
literal
|
||||
? wcIter()->keyword() == keyword
|
||||
: reIter()->match(keyword)
|
||||
)
|
||||
{
|
||||
return true;
|
||||
@ -76,7 +76,7 @@ Foam::dictionary::const_searcher Foam::dictionary::csearchDotScoped
|
||||
{
|
||||
auto scopePos = keyword.find('.');
|
||||
|
||||
if (scopePos == string::npos)
|
||||
if (scopePos == std::string::npos)
|
||||
{
|
||||
// Normal, non-scoped search
|
||||
return csearch(keyword, matchOpt);
|
||||
@ -141,7 +141,7 @@ Foam::dictionary::const_searcher Foam::dictionary::csearchDotScoped
|
||||
// Local entry:
|
||||
finder = csearch(keyword.substr(0, scopePos), matchOpt);
|
||||
|
||||
if (scopePos == string::npos)
|
||||
if (scopePos == std::string::npos)
|
||||
{
|
||||
// Parsed the whole word. Return entry or null.
|
||||
return finder;
|
||||
@ -176,7 +176,7 @@ Foam::dictionary::const_searcher Foam::dictionary::csearchSlashScoped
|
||||
|
||||
const auto slash = keyword.find('/');
|
||||
|
||||
if (slash == string::npos)
|
||||
if (slash == std::string::npos)
|
||||
{
|
||||
// No slashes:
|
||||
// Can use normal (non-scoped) search at the current dictionary level
|
||||
@ -282,8 +282,8 @@ Foam::dictionary::const_searcher Foam::dictionary::csearch
|
||||
auto wcLink = patterns_.cbegin();
|
||||
auto reLink = regexps_.cbegin();
|
||||
|
||||
// Find in patterns using regular expressions only
|
||||
if (findInPatterns(true, keyword, wcLink, reLink))
|
||||
// Find in patterns : non-literal matching
|
||||
if (findInPatterns(false, keyword, wcLink, reLink))
|
||||
{
|
||||
finder.set(*wcLink);
|
||||
return finder;
|
||||
@ -334,7 +334,7 @@ Foam::dictionary::const_searcher Foam::dictionary::csearchScoped
|
||||
|
||||
if (keyword[0] == ':' || keyword[0] == '^')
|
||||
{
|
||||
// It is ':' scoped - force non-recusive searching
|
||||
// It is ':' scoped - force non-recursive searching
|
||||
matchOpt = keyType::option(matchOpt & ~(keyType::RECURSIVE));
|
||||
|
||||
// Ascend to top-level
|
||||
@ -397,9 +397,9 @@ const Foam::dictionary* Foam::dictionary::cfindScopedDict
|
||||
|
||||
fileName path(dictPath); // Work on copy
|
||||
path.clean(); // Remove unneeded ".."
|
||||
const wordList dictCmpts(path.components()); // Split on '/'
|
||||
auto dictCmpts = stringOps::split(path, '/'); // Split on '/'
|
||||
|
||||
for (const word& cmpt : dictCmpts)
|
||||
for (const auto& cmpt : dictCmpts)
|
||||
{
|
||||
if (cmpt == ".")
|
||||
{
|
||||
@ -424,10 +424,12 @@ const Foam::dictionary* Foam::dictionary::cfindScopedDict
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-recursive, no patternMatch
|
||||
// -> can do direct lookup, without csearch(cmpt, false, false);
|
||||
// Non-recursive, no patternMatch:
|
||||
// do direct lookup, without csearch(cmpt, keyType::LITERAL)
|
||||
|
||||
auto iter = dictPtr->hashedEntries_.cfind(cmpt);
|
||||
const word cmptName(cmpt.str(), false);
|
||||
|
||||
auto iter = dictPtr->hashedEntries_.cfind(cmptName);
|
||||
|
||||
if (iter.good())
|
||||
{
|
||||
@ -440,7 +442,7 @@ const Foam::dictionary* Foam::dictionary::cfindScopedDict
|
||||
else
|
||||
{
|
||||
FatalIOErrorInFunction(*dictPtr)
|
||||
<< "Found entry '" << cmpt
|
||||
<< "Found entry '" << cmptName
|
||||
<< "' but not a dictionary, while searching scoped"
|
||||
<< nl
|
||||
<< " " << path
|
||||
@ -527,9 +529,9 @@ Foam::dictionary* Foam::dictionary::makeScopedDict(const fileName& dictPath)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Non-recursive, no patternMatch
|
||||
// -> can do direct lookup,
|
||||
// without csearch(cmptName, keyType::LITERAL);
|
||||
// Non-recursive, no patternMatch:
|
||||
// do direct lookup, without csearch(cmptName, keyType::LITERAL)
|
||||
|
||||
const word cmptName(cmpt.str(), false);
|
||||
|
||||
auto iter = dictPtr->hashedEntries_.find(cmptName);
|
||||
@ -589,8 +591,8 @@ bool Foam::dictionary::remove(const word& keyword)
|
||||
auto wcLink = patterns_.begin();
|
||||
auto reLink = regexps_.begin();
|
||||
|
||||
// Find in pattern using exact match only
|
||||
if (findInPatterns(false, keyword, wcLink, reLink))
|
||||
// Find in patterns : literal matching
|
||||
if (findInPatterns(true, keyword, wcLink, reLink))
|
||||
{
|
||||
patterns_.remove(wcLink);
|
||||
regexps_.remove(reLink);
|
||||
@ -650,8 +652,8 @@ bool Foam::dictionary::changeKeyword
|
||||
auto wcLink = patterns_.begin();
|
||||
auto reLink = regexps_.begin();
|
||||
|
||||
// Find in patterns using exact match only
|
||||
if (findInPatterns(false, iter2()->keyword(), wcLink, reLink))
|
||||
// Find in patterns : literal matching
|
||||
if (findInPatterns(true, iter2()->keyword(), wcLink, reLink))
|
||||
{
|
||||
patterns_.remove(wcLink);
|
||||
regexps_.remove(reLink);
|
||||
@ -674,7 +676,7 @@ bool Foam::dictionary::changeKeyword
|
||||
|
||||
// Change name and HashTable, but leave DL-List untouched
|
||||
iter()->keyword() = newKeyword;
|
||||
iter()->name() = name() + '.' + newKeyword;
|
||||
iter()->name() = fileName::concat(name(), newKeyword, '/');
|
||||
hashedEntries_.erase(oldKeyword);
|
||||
hashedEntries_.insert(newKeyword, iter());
|
||||
|
||||
|
||||
@ -267,7 +267,7 @@ Foam::primitiveEntry::primitiveEntry
|
||||
entry(key),
|
||||
ITstream(is)
|
||||
{
|
||||
ITstream::name() += '.' + key;
|
||||
ITstream::name() = fileName::concat(ITstream::name(), key, '/');
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -262,7 +262,7 @@ Foam::primitiveEntry::primitiveEntry
|
||||
ITstream
|
||||
(
|
||||
static_cast<IOstreamOption>(is),
|
||||
is.name() + '.' + key
|
||||
fileName::concat(is.name(), key, '/')
|
||||
)
|
||||
{
|
||||
readEntry(dict, is);
|
||||
|
||||
Reference in New Issue
Block a user