foamDictionary.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2016-2017 OpenFOAM Foundation
9  Copyright (C) 2017-2021 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 Application
28  foamDictionary
29 
30 Description
31  Interrogate and manipulate dictionaries.
32 
33 Usage
34  \b foamDictionary [OPTION] dictionary
35 
36  - \par -entry <name>
37  Selects an entry
38 
39  - \par -keywords
40  Prints the keywords (of the selected entry or of the top level if
41  no entry was selected
42 
43  - \par -add <value>
44  Adds the entry (should not exist yet)
45 
46  - \par -set <value>
47  Adds or replaces the entry
48 
49  - \par -remove
50  Remove the selected entry
51 
52  - \par -diff <dictionary>
53  Write differences with respect to the specified dictionary
54  (or sub entry if -entry specified)
55 
56  - \par -diff-etc <dictionary>
57  Write differences with respect to the specified dictionary
58  (or sub entry if -entry specified)
59 
60  - \par -expand
61  Read the specified dictionary file, expand the macros etc. and write
62  the resulting dictionary to standard output.
63 
64  - \par -includes
65  List the \c \#include and \c \#sinclude files to standard output
66 
67  - \par -disableFunctionEntries
68  Do not expand macros or directives (\#include etc)
69 
70  - \par -precision int
71  Set default write precision for IOstreams
72 
73  Example usage:
74  - Change simulation to run for one timestep only:
75  \verbatim
76  foamDictionary system/controlDict -entry stopAt -set writeNow
77  \endverbatim
78 
79  - Change solver:
80  \verbatim
81  foamDictionary system/fvSolution -entry solvers.p.solver -set PCG
82  \endverbatim
83 
84  - Print bc type:
85  \verbatim
86  foamDictionary 0/U -entry boundaryField.movingWall.type
87  \endverbatim
88 
89  - Change bc parameter:
90  \verbatim
91  foamDictionary 0/U -entry boundaryField.movingWall.value \
92  -set "uniform (2 0 0)"
93  \endverbatim
94 
95  - Change whole bc type:
96  \verbatim
97  foamDictionary 0/U -entry boundaryField.movingWall \
98  -set "{type uniformFixedValue; uniformValue (2 0 0);}"
99  \endverbatim
100 
101  - Write the differences with respect to a template dictionary:
102  \verbatim
103  foamDictionary 0/U -diff-etc templates/closedVolume/0/U
104  \endverbatim
105 
106  - Write the differences in boundaryField with respect to a
107  template dictionary:
108  \verbatim
109  foamDictionary 0/U -diff-etc templates/closedVolume/0/U \
110  -entry boundaryField
111  \endverbatim
112 
113  - Change patch type:
114  \verbatim
115  foamDictionary constant/polyMesh/boundary \
116  -entry entry0.fixedWalls.type -set patch
117  \endverbatim
118  This uses special parsing of Lists which stores these in the
119  dictionary with keyword 'entryDDD' where DDD is the position
120  in the dictionary (after ignoring the FoamFile entry).
121 
122  Notes:
123  - the use of '.' as the scoping symbol might conflict with
124  e.g. file extensions ('.' is not really considered
125  to be a valid word character). Instead use the '/' as a scoping
126  character e.g.
127  foamDictionary system/snappyHexMeshDict \
128  -entry /geometry/motorBike.obj -remove
129 
130 \*---------------------------------------------------------------------------*/
131 
132 #include "argList.H"
133 #include "profiling.H"
134 #include "Time.H"
135 #include "Fstream.H"
136 #include "etcFiles.H"
137 #include "includeEntry.H"
138 
139 using namespace Foam;
140 
141 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
142 
143 //- Convert older ':' scope syntax to newer '.' scope syntax,
144 // but leave anything with '/' delimiters untouched
145 bool upgradeScope(word& entryName)
146 {
147  if
148  (
149  entryName.find('/') == string::npos
150  && entryName.find(':') != string::npos
151  )
152  {
153  const wordList names(fileName(entryName).components(':'));
154 
155  entryName.resize(0);
156 
157  for (const word& name : names)
158  {
159  if (entryName.size()) entryName.append(".");
160 
161  entryName.append(name);
162  }
163 
164  return true;
165  }
166 
167  // Nothing changed
168  return false;
169 }
170 
171 
172 //- Split into dictionary name and the entry name
173 class dictAndKeyword
174 {
175  word dict_;
176  word key_;
177 
178 public:
179 
180  dictAndKeyword(const word& scopedName)
181  {
182  auto i = scopedName.rfind('/');
183  if (i == string::npos)
184  {
185  i = scopedName.rfind('.');
186  }
187 
188  if (i != string::npos)
189  {
190  dict_ = scopedName.substr(0, i);
191  key_ = scopedName.substr(i+1);
192  }
193  else
194  {
195  key_ = scopedName;
196  }
197  }
198 
199  inline const word& dict() const
200  {
201  return dict_;
202  }
203 
204  inline const word& key() const
205  {
206  return key_;
207  }
208 };
209 
210 
211 const dictionary& lookupScopedDict
212 (
213  const dictionary& dict,
214  const word& subDictName
215 )
216 {
217  if (subDictName.empty())
218  {
219  return dict;
220  }
221 
222  const entry* eptr = dict.findScoped(subDictName, keyType::LITERAL);
223 
224  if (!eptr || !eptr->isDict())
225  {
227  << "'" << subDictName << "' not found in dictionary "
228  << dict.name() << " or is not a dictionary" << nl
229  << "Known entries are " << dict.keys()
230  << exit(FatalIOError);
231  }
232 
233  return eptr->dict();
234 }
235 
236 
237 void removeDict(dictionary& dict, const dictionary& dictToRemove)
238 {
239  for (const entry& refEntry : dictToRemove)
240  {
241  auto finder = dict.search(refEntry.keyword(), keyType::LITERAL);
242 
243  bool purge = false;
244 
245  if (finder.isDict())
246  {
247  if (refEntry.isDict())
248  {
249  removeDict(finder.dict(), refEntry.dict());
250 
251  // Purge if dictionary is empty
252  purge = finder.dict().empty();
253  }
254  }
255  else if (finder.found() && !refEntry.isDict())
256  {
257  // Purge if entries match
258  purge = (finder.ref() == refEntry);
259  }
260 
261  if (purge)
262  {
263  dict.remove(refEntry.keyword());
264  }
265  }
266 }
267 
268 
269 int main(int argc, char *argv[])
270 {
272  (
273  "Interrogate and manipulate dictionaries"
274  );
275 
278  argList::addArgument("dict", "The dictionary file to process");
279  argList::addBoolOption("keywords", "List keywords");
280  argList::addOption("entry", "name", "Report/select the named entry");
282  (
283  "value",
284  "Print entry value"
285  );
287  (
288  "set",
289  "value",
290  "Set entry value or add new entry"
291  );
293  (
294  "add",
295  "value",
296  "Add a new entry"
297  );
299  (
300  "remove",
301  "Remove the entry"
302  );
304  (
305  "diff",
306  "dict",
307  "Write differences with respect to the specified dictionary"
308  );
310  (
311  "diff-etc",
312  "dict",
313  "As per -diff, but locate the file as per foamEtcFile"
314  );
315  argList::addOptionCompat("diff-etc", {"diffEtc", 1712});
317  (
318  "precision",
319  "int",
320  "Set default write precision for IOstreams"
321  );
322 
324  (
325  "includes",
326  "List the #include/#sinclude files to standard output"
327  );
329  (
330  "expand",
331  "Read the specified dictionary file, expand the macros etc. and write "
332  "the resulting dictionary to standard output"
333  );
335  (
336  "disableFunctionEntries",
337  "Disable expansion of dictionary directives - #include, #codeStream etc"
338  );
339  profiling::disable(); // Disable profiling (and its output)
340 
341  argList args(argc, argv);
342 
343  const bool listIncludes = args.found("includes");
344 
345  if (listIncludes)
346  {
348  }
349 
350  const bool disableEntries = args.found("disableFunctionEntries");
351  if (disableEntries)
352  {
353  // Report on stderr (once) to avoid polluting the output
354  if (Pstream::master())
355  {
356  Serr<< "Not expanding variables or dictionary directives" << endl;
357  }
359  }
360 
361  // Set the default output precision
362  {
363  const unsigned prec = args.getOrDefault<unsigned>("precision", 0u);
364  if (prec)
365  {
366  // if (Pstream::master())
367  // {
368  // Serr<< "Output write precision set to " << prec << endl;
369  // }
370 
372  Sout.precision(prec);
373  }
374  }
375 
376  const auto dictFileName = args.get<fileName>(1);
377 
378  autoPtr<IFstream> dictFile(new IFstream(dictFileName));
379  if (!dictFile().good())
380  {
382  << "Cannot open file " << dictFileName
383  << exit(FatalError, 1);
384  }
385 
386 
387  bool changed = false;
388 
389  // Read but preserve headers
390  dictionary dict(dictFile(), true);
391 
392  if (listIncludes)
393  {
394  return 0;
395  }
396  else if (args.found("expand"))
397  {
399  <<"//\n// " << dictFileName << "\n//\n";
400  dict.write(Info, false);
402 
403  return 0;
404  }
405 
406 
407  // Has "diff" or "diff-etc"
408  bool optDiff = false;
409 
410  // Reference dictionary for -diff / -diff-etc
411  dictionary diffDict;
412  {
413  fileName diffFileName;
414  if (args.readIfPresent("diff", diffFileName))
415  {
416  IFstream diffFile(diffFileName);
417  if (!diffFile.good())
418  {
420  << "Cannot open file " << diffFileName
421  << exit(FatalError, 1);
422  }
423 
424  // Read but preserve headers
425  diffDict.read(diffFile, true);
426  optDiff = true;
427  }
428  else if (args.readIfPresent("diff-etc", diffFileName))
429  {
430  fileName foundName = findEtcFile(diffFileName);
431  if (foundName.empty())
432  {
434  << "Cannot find etcFile " << diffFileName
435  << exit(FatalError, 1);
436  }
437 
438  IFstream diffFile(foundName);
439  if (!diffFile.good())
440  {
442  << "Cannot open file " << foundName
443  << exit(FatalError, 1);
444  }
445 
446  // Read but preserve headers
447  diffDict.read(diffFile, true);
448  optDiff = true;
449  }
450  }
451 
452  word scopedName; // Actually fileName, since it can contain '/' scoping
453  if (args.readIfPresent("entry", scopedName))
454  {
455  upgradeScope(scopedName);
456 
457  string newValue;
458  if
459  (
460  args.readIfPresent("set", newValue)
461  || args.readIfPresent("add", newValue)
462  )
463  {
464  const bool overwrite = args.found("set");
465 
466  // Dictionary name and keyword
467  const dictAndKeyword dAk(scopedName);
468 
469  // The context for the action
470  const dictionary& d(lookupScopedDict(dict, dAk.dict()));
471 
472  // Create a new entry
473  IStringStream str(string(dAk.key()) + ' ' + newValue + ';');
474  entry* ePtr(entry::New(str).ptr());
475 
476  if (overwrite)
477  {
478  const_cast<dictionary&>(d).set(ePtr);
479  }
480  else
481  {
482  const_cast<dictionary&>(d).add(ePtr, false);
483  }
484  changed = true;
485 
486  // Print the changed entry
487  const auto finder = dict.csearchScoped(scopedName, keyType::REGEX);
488 
489  if (finder.found())
490  {
491  Info<< finder.ref();
492  }
493  }
494  else if (args.found("remove"))
495  {
496  // Dictionary name and keyword
497  const dictAndKeyword dAk(scopedName);
498 
499  // The context for the action
500  const dictionary& d(lookupScopedDict(dict, dAk.dict()));
501 
502  const_cast<dictionary&>(d).remove(dAk.key());
503  changed = true;
504  }
505  else
506  {
507  // Optionally remove a second dictionary
508  if (optDiff)
509  {
510  // Dictionary name and keyword
511  const dictAndKeyword dAk(scopedName);
512 
513  const dictionary& d1(lookupScopedDict(dict, dAk.dict()));
514  const dictionary& d2(lookupScopedDict(diffDict, dAk.dict()));
515 
516  const entry* e1Ptr = d1.findEntry(dAk.key(), keyType::REGEX);
517  const entry* e2Ptr = d2.findEntry(dAk.key(), keyType::REGEX);
518 
519  if (e1Ptr && e2Ptr)
520  {
521  if (*e1Ptr == *e2Ptr)
522  {
523  const_cast<dictionary&>(d1).remove(dAk.key());
524  }
525  else if (e1Ptr->isDict() && e2Ptr->isDict())
526  {
527  removeDict
528  (
529  const_cast<dictionary&>(e1Ptr->dict()),
530  e2Ptr->dict()
531  );
532  }
533  }
534  }
535 
536  const auto finder = dict.csearchScoped(scopedName, keyType::REGEX);
537 
538  if (!finder.found())
539  {
540  FatalIOErrorInFunction(dictFile())
541  << "Cannot find entry " << scopedName
542  << exit(FatalIOError, 2);
543  }
544  else if (args.found("keywords"))
545  {
546  for (const entry& e : finder.dict())
547  {
548  Info<< e.keyword() << endl;
549  }
550  }
551  else if (args.found("value"))
552  {
553  if (finder.isDict())
554  {
555  Info<< finder.dict();
556  }
557  else if (finder.ref().isStream())
558  {
559  const tokenList& tokens = finder.ref().stream();
560  forAll(tokens, i)
561  {
562  Info<< tokens[i];
563  if (i < tokens.size() - 1)
564  {
565  Info<< token::SPACE;
566  }
567  }
568  Info<< endl;
569  }
570  }
571  else
572  {
573  Info<< finder.ref();
574  }
575  }
576  }
577  else if (args.found("keywords"))
578  {
579  for (const entry& e : dict)
580  {
581  Info<< e.keyword() << endl;
582  }
583  }
584  else if (optDiff)
585  {
586  removeDict(dict, diffDict);
587  dict.write(Info, false);
588  }
589  else
590  {
591  dict.write(Info, false);
592  }
593 
594  if (changed)
595  {
596  dictFile.clear();
597  OFstream os(dictFileName);
600  dict.write(os, false);
602  }
603 
604  return 0;
605 }
606 
607 
608 // ************************************************************************* //
Foam::argList::noBanner
static void noBanner()
Definition: argList.C:434
Foam::entry
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:63
profiling.H
Foam::entry::New
static bool New(dictionary &parentDict, Istream &is, const inputMode inpMode=inputMode::GLOBAL, const int endChar=0)
Definition: entryIO.C:98
Foam::BitOps::set
void set(List< bool > &bools, const labelRange &range)
Definition: BitOps.C:30
Foam::dictionary::name
const fileName & name() const noexcept
Definition: dictionaryI.H:41
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:63
Foam::fileName
A class for handling file names.
Definition: fileName.H:71
Foam::argList::getOrDefault
T getOrDefault(const word &optName, const T &deflt) const
Definition: argListI.H:300
Foam::IFstream
Input from file stream, using an ISstream.
Definition: IFstream.H:49
Foam::IOobject::writeEndDivider
static Ostream & writeEndDivider(Ostream &os)
Definition: IOobjectWriteHeader.C:135
Foam::entry::isDict
virtual bool isDict() const noexcept
Definition: entry.H:229
Foam::glTF::key
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
Foam::argList::addNote
static void addNote(const string &note)
Definition: argList.C:405
Foam::UPstream::master
static bool master(const label communicator=worldComm)
Definition: UPstream.H:453
Foam::argList::addOptionCompat
static void addOptionCompat(const word &optName, std::pair< const char *, int > compat)
Definition: argList.C:361
Foam::argList
Extract command arguments and options from the supplied argc and argv parameters.
Definition: argList.H:119
Foam::FatalIOError
IOerror FatalIOError
Foam::endl
Ostream & endl(Ostream &os)
Definition: Ostream.H:381
Foam::Serr
OSstream Serr
Foam::argList::get
T get(const label index) const
Definition: argListI.H:271
Foam::IOobject::writeBanner
static Ostream & writeBanner(Ostream &os, const bool noSyntaxHint=false)
Definition: IOobjectWriteHeader.C:69
Foam::argList::readIfPresent
bool readIfPresent(const word &optName, T &val) const
Definition: argListI.H:316
forAll
#define forAll(list, i)
Definition: stdFoam.H:349
Foam::argList::addArgument
static void addArgument(const string &argName, const string &usage="")
Definition: argList.C:294
Foam::dictionary::keys
List< keyType > keys(bool patterns=false) const
Definition: dictionary.C:615
Foam::findEtcFile
fileName findEtcFile(const fileName &name, const bool mandatory=false, unsigned short location=0777)
Definition: etcFiles.C:439
Foam::argList::noJobInfo
static void noJobInfo()
Definition: argList.C:486
Foam::Info
messageStream Info
Foam::dictionary::csearchScoped
const_searcher csearchScoped(const word &keyword, enum keyType::option) const
Definition: dictionarySearch.C:318
argList.H
Foam::functionEntries::includeEntry::log
static bool log
Definition: includeEntry.H:106
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:119
Foam::add
void add(FieldField< Field1, typename typeOfSum< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
Definition: FieldFieldFunctions.C:932
os
OBJstream os(runTime.globalPath()/outputName)
Foam::IStringStream
Definition: StringStream.H:108
Foam
Definition: atmBoundaryLayer.C:26
Foam::profiling::disable
static void disable()
Definition: profiling.C:110
Foam::entry::disableFunctionEntries
static int disableFunctionEntries
Definition: entry.H:123
Foam::entry::dict
virtual const dictionary & dict() const =0
Foam::dictionary::read
bool read(Istream &is)
Definition: dictionaryIO.C:134
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:49
Foam::OSstream::precision
virtual int precision() const
Definition: OSstream.C:319
etcFiles.H
Functions to search 'etc' directories for configuration files etc.
Foam::argList::addBoolOption
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Definition: argList.C:317
Foam::IOstream::defaultPrecision
static unsigned int defaultPrecision() noexcept
Definition: IOstream.H:338
Time.H
Foam::autoPtr
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: HashPtrTable.H:49
FatalErrorInFunction
#define FatalErrorInFunction
Definition: error.H:465
Foam::dictionary::findScoped
const entry * findScoped(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryI.H:110
Foam::nl
constexpr char nl
Definition: Ostream.H:424
Fstream.H
Foam::IOobject::writeDivider
static Ostream & writeDivider(Ostream &os)
Definition: IOobjectWriteHeader.C:125
Foam::dictionary::remove
bool remove(const word &keyword)
Definition: dictionarySearch.C:575
Foam::dictionary::write
void write(Ostream &os, const bool subDict=true) const
Definition: dictionaryIO.C:199
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:58
Foam::token::SPACE
@ SPACE
Space [isspace].
Definition: token.H:121
includeEntry.H
Foam::constant::electromagnetic::e
const dimensionedScalar e
Definition: createFields.H:11
Foam::keyType::REGEX
@ REGEX
Regular expression.
Definition: keyType.H:80
Foam::dictionary::search
const_searcher search(const word &keyword, enum keyType::option=keyType::REGEX) const
Definition: dictionarySearch.C:296
Foam::name
word name(const expressions::valueTypeCode typeCode)
Definition: exprTraits.C:52
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Definition: error.H:494
Foam::keyType::LITERAL
@ LITERAL
String literal.
Definition: keyType.H:79
Foam::Sout
OSstream Sout
Foam::argList::addOption
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Definition: argList.C:328
args
Foam::argList args(argc, argv)
Foam::PtrListOps::names
List< word > names(const UPtrList< T > &list, const UnaryMatchPredicate &matcher)
Foam::argList::found
bool found(const word &optName) const
Definition: argListI.H:171