diff --git a/applications/test/dictionary/testSubkeyword b/applications/test/dictionary/testSubkeyword index f8ee148501..3465f0623e 100644 --- a/applications/test/dictionary/testSubkeyword +++ b/applications/test/dictionary/testSubkeyword @@ -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" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/db/dictionary/entry/entryIO.C b/src/OpenFOAM/db/dictionary/entry/entryIO.C index f6879570d2..3e549c9faf 100644 --- a/src/OpenFOAM/db/dictionary/entry/entryIO.C +++ b/src/OpenFOAM/db/dictionary/entry/entryIO.C @@ -262,7 +262,7 @@ bool Foam::entry::New } else { - // Normal entry + // Normal or scoped entry token nextToken(is); is.putBack(nextToken); @@ -279,11 +279,25 @@ bool Foam::entry::New // How to manage duplicate entries bool mergeEntry = false; + const bool scoped = + ( + !disableFunctionEntries + && (keyword.find('/') != string::npos) + ); + // See (using exact match) if entry already present - auto finder = parentDict.search(keyword, false, false); + auto finder = + ( + scoped + ? parentDict.searchScoped(keyword, false, false) + : parentDict.search(keyword, false, false) + ); if (finder.found()) { + // Use keyword from the found entry (ie, eliminate scoping chars) + const keyType key = finder.ref().keyword(); + if (mode == inputMode::MERGE) { mergeEntry = true; @@ -306,11 +320,11 @@ bool Foam::entry::New if (nextToken == token::BEGIN_BLOCK) { - dictionaryEntry dummy("dummy", parentDict, is); + dictionaryEntry dummy("dummy", finder.context(), is); } else { - primitiveEntry dummy("dummy", parentDict, is); + primitiveEntry dummy("dummy", finder.context(), is); } entry::disableFunctionEntries = oldFlag; @@ -319,29 +333,109 @@ bool Foam::entry::New else if (mode == inputMode::ERROR) { FatalIOErrorInFunction(is) - << "duplicate entry: " << keyword + << "duplicate entry: " << key << exit(FatalIOError); return false; } + + // 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 + ); + } } - - - if (nextToken == token::BEGIN_BLOCK) + else if (scoped) { - return parentDict.add - ( - new dictionaryEntry(keyword, parentDict, is), - mergeEntry - ); + // 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) + { + // Begins with a quote - treat as pattern + key = keyType(string::validate(keyName), true); + } + else + { + // Treat as a word + key = word::validate(keyName, false); + } + + 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 + { + // Some error finding/creating intermediate dictionaries + return false; + } } 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 + ); + } } } } diff --git a/src/OpenFOAM/db/dictionary/functionEntries/removeEntry/removeEntry.C b/src/OpenFOAM/db/dictionary/functionEntries/removeEntry/removeEntry.C index a0c413edd8..ebe2baf216 100644 --- a/src/OpenFOAM/db/dictionary/functionEntries/removeEntry/removeEntry.C +++ b/src/OpenFOAM/db/dictionary/functionEntries/removeEntry/removeEntry.C @@ -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(is); + const List patterns = readList(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; } + // ************************************************************************* // diff --git a/src/OpenFOAM/db/dictionary/functionEntries/removeEntry/removeEntry.H b/src/OpenFOAM/db/dictionary/functionEntries/removeEntry/removeEntry.H index 5e8fbdd836..6cdb5441a5 100644 --- a/src/OpenFOAM/db/dictionary/functionEntries/removeEntry/removeEntry.H +++ b/src/OpenFOAM/db/dictionary/functionEntries/removeEntry/removeEntry.H @@ -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); };