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-2019 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 fileName dictFileName(args[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()
Disable emitting the banner information.
Definition: argList.C:442
Foam::entry
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:67
profiling.H
Foam::entry::New
static bool New(dictionary &parentDict, Istream &is, const inputMode inpMode=inputMode::GLOBAL, const int endChar=0)
Construct from an Istream and insert into the dictionary.
Definition: entryIO.C:104
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::argList::getOrDefault
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:286
Foam::IFstream
Input from file stream, using an ISstream.
Definition: IFstream.H:85
Foam::IOobject::writeBanner
static Ostream & writeBanner(Ostream &os, bool noHint=false)
Write the standard OpenFOAM file/dictionary banner.
Definition: IOobjectWriteHeader.C:45
Foam::IOobject::writeEndDivider
static Ostream & writeEndDivider(Ostream &os)
Write the standard end file divider.
Definition: IOobjectWriteHeader.C:109
Foam::argList::addNote
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:413
Foam::argList::addOptionCompat
static void addOptionCompat(const word &optName, std::pair< const char *, int > compat)
Specify an alias for the option name.
Definition: argList.C:369
Foam::argList
Extract command arguments and options from the supplied argc and argv parameters.
Definition: argList.H:123
Foam::FatalIOError
IOerror FatalIOError
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::Serr
OSstream Serr
An Ostream wrapper for std::cerr.
Foam::argList::readIfPresent
bool readIfPresent(const word &optName, T &val) const
Read a value from the named option if present.
Definition: argListI.H:302
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::argList::addArgument
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:302
Foam::dictionary::keys
List< keyType > keys(bool patterns=false) const
Return the list of available keys or patterns.
Definition: dictionary.C:690
Foam::dictionary::name
const fileName & name() const
The dictionary name.
Definition: dictionary.H:446
Foam::entry::isDict
virtual bool isDict() const
Return true if this entry is a dictionary.
Definition: entry.H:222
Foam::findEtcFile
fileName findEtcFile(const fileName &name, const bool mandatory=false, unsigned short location=0777)
Search for a single FILE within the etc directories.
Definition: etcFiles.C:446
Foam::argList::noJobInfo
static void noJobInfo()
Suppress JobInfo, overriding controlDict setting.
Definition: argList.C:474
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::dictionary::csearchScoped
const_searcher csearchScoped(const word &keyword, enum keyType::option) const
Search using scoping.
Definition: dictionarySearch.C:325
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
argList.H
Foam::functionEntries::includeEntry::log
static bool log
Report to stdout which file is included.
Definition: includeEntry.H:110
Foam::dictionary::Searcher::dict
dict_reference dict() const
Reference the found entry as a dictionary.
Definition: dictionary.H:241
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:121
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:939
Foam::IStringStream
Input from string buffer, using a ISstream.
Definition: StringStream.H:111
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::profiling::disable
static void disable()
Disallow profiling by forcing the InfoSwitch off.
Definition: profiling.C:118
Foam::entry::disableFunctionEntries
static int disableFunctionEntries
Enable or disable use of function entries and variable expansions.
Definition: entry.H:119
Foam::entry::dict
virtual const dictionary & dict() const =0
Return dictionary, if entry is a dictionary.
Foam::dictionary::read
bool read(Istream &is)
Read dictionary from Istream.
Definition: dictionaryIO.C:141
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:87
Foam::UPstream::master
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:439
Foam::OSstream::precision
virtual int precision() const
Get precision of output field.
Definition: OSstream.C:320
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)
Add a bool option to validOptions with usage information.
Definition: argList.C:325
Time.H
Foam::autoPtr
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: HashPtrTable.H:53
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:372
Foam::dictionary::findScoped
const entry * findScoped(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Search for a scoped entry (const access) with the given keyword.
Definition: dictionary.C:394
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Fstream.H
Input/output from file streams.
Foam::IOstream::defaultPrecision
static unsigned int defaultPrecision()
Return the default precision.
Definition: IOstream.H:333
Foam::IOobject::writeDivider
static Ostream & writeDivider(Ostream &os)
Write the standard file section divider.
Definition: IOobjectWriteHeader.C:99
Foam::dictionary::remove
bool remove(const word &keyword)
Remove an entry specified by keyword.
Definition: dictionarySearch.C:582
Foam::dictionary::write
void write(Ostream &os, const bool subDict=true) const
Write dictionary, normally with sub-dictionary formatting.
Definition: dictionaryIO.C:206
Foam::List< word >
Foam::token::SPACE
Space [isspace].
Definition: token.H:118
includeEntry.H
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::keyType::REGEX
Regular expression.
Definition: keyType.H:74
Foam::dictionary::search
const_searcher search(const word &keyword, enum keyType::option=keyType::REGEX) const
Search dictionary for given keyword.
Definition: dictionarySearch.C:303
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:392
Foam::keyType::LITERAL
String literal.
Definition: keyType.H:73
Foam::Sout
OSstream Sout
An Ostream wrapper for std::cout.
Foam::argList::addOption
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Definition: argList.C:336
args
Foam::argList args(argc, argv)
Foam::argList::found
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:157