foamDictionary.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2016-2019 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 Application
25  foamDictionary
26 
27 Description
28  Interrogates and manipulates dictionaries.
29 
30 Usage
31  \b foamDictionary [OPTION] dictionary
32 
33  - \par -entry <name>
34  Selects an entry
35 
36  - \par -keywords <name>
37  Prints the keywords (of the selected entry or of the top level if
38  no entry was selected
39 
40  - \par -add <value>
41  Adds the entry (should not exist yet)
42 
43  - \par -set <value>
44  Adds or replaces the entry
45 
46  - \par -merge <value>
47  Merges the entry
48 
49  - \par -dict
50  Set, add or merge entry from a dictionary
51 
52  - \par -remove
53  Remove the selected entry
54 
55  - \par -diff <dictionary>
56  Write differences with respect to the specified dictionary
57  (or sub entry if -entry specified)
58 
59  - \par -expand
60  Read the specified dictionary file, expand the macros etc. and write
61  the resulting dictionary to standard output.
62 
63  - \par -includes
64  List the \c #include and \c #includeIfPresent files to standard output
65 
66  - \par -disableFunctionEntries
67  Do not expand macros or directives (#include etc)
68 
69  Example usage:
70  - Change simulation to run for one timestep only:
71  \verbatim
72  foamDictionary system/controlDict -entry stopAt -set writeNow
73  \endverbatim
74 
75  - Change solver:
76  \verbatim
77  foamDictionary system/fvSolution -entry solvers.p.solver -set PCG
78  \endverbatim
79 
80  - Print bc type:
81  \verbatim
82  foamDictionary 0/U -entry boundaryField.movingWall.type
83  \endverbatim
84 
85  - Change bc parameter:
86  \verbatim
87  foamDictionary 0/U -entry boundaryField.movingWall.value \
88  -set "uniform (2 0 0)"
89  \endverbatim
90 
91  - Change whole bc type:
92  \verbatim
93  foamDictionary 0/U -entry boundaryField.movingWall \
94  -set "{type uniformFixedValue; uniformValue (2 0 0);}"
95  \endverbatim
96 
97  - Write the differences with respect to a template dictionary:
98  \verbatim
99  foamDictionary 0/U -diff $FOAM_ETC/templates/closedVolume/0/U
100  \endverbatim
101 
102  - Write the differences in boundaryField with respect to a
103  template dictionary:
104  \verbatim
105  foamDictionary 0/U -diff $FOAM_ETC/templates/closedVolume/0/U \
106  -entry boundaryField
107  \endverbatim
108 
109  - Change patch type:
110  \verbatim
111  foamDictionary constant/polyMesh/boundary \
112  -entry entry0.fixedWalls.type -set patch
113  \endverbatim
114  This uses special parsing of Lists which stores these in the
115  dictionary with keyword 'entryDDD' where DDD is the position
116  in the dictionary (after ignoring the FoamFile entry).
117 
118 \*---------------------------------------------------------------------------*/
119 
120 #include "argList.H"
121 #include "IOobject.H"
122 #include "Pair.H"
123 #include "IFstream.H"
124 #include "OFstream.H"
125 #include "includeEntry.H"
126 
127 using namespace Foam;
128 
129 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
130 
131 //- Read dictionary from file and return
132 // Sets steam to binary mode if specified in the optional header
133 IOstream::streamFormat readDict(dictionary& dict, const fileName& dictFileName)
134 {
136 
137  IFstream dictFile(dictFileName);
138  if (!dictFile().good())
139  {
141  << "Cannot open file " << dictFileName
142  << exit(FatalError, 1);
143  }
144 
145  // Read the first entry from the dictionary
146  autoPtr<entry> firstEntry(entry::New(dictFile()));
147 
148  // If the first entry is the "FoamFile" header dictionary
149  // read and set the stream format
150  if (firstEntry->isDict() && firstEntry->keyword() == "FoamFile")
151  {
152  dictFormat = IOstream::formatEnum(firstEntry->dict().lookup("format"));
153  dictFile().format(dictFormat);
154  }
155 
156  // Add the first entry to the dictionary
157  dict.add(firstEntry);
158 
159  // Read and add the rest of the dictionary entries
160  // preserving the "FoamFile" header dictionary if present
161  dict.read(dictFile(), true);
162 
163  return dictFormat;
164 }
165 
166 
167 //- Converts old scope syntax to new syntax
168 word scope(const fileName& entryName)
169 {
170  if (entryName.find(':') != string::npos)
171  {
172  wordList entryNames(entryName.components(':'));
173 
174  word entry(entryNames[0]);
175  for (label i = 1; i < entryNames.size(); i++)
176  {
177  entry += word('.') + entryNames[i];
178  }
179  return entry;
180  }
181  else
182  {
183  return entryName;
184  }
185 }
186 
187 
188 //- Extracts dict name and keyword
189 Pair<word> dictAndKeyword(const word& scopedName)
190 {
191  string::size_type i = scopedName.find_last_of(".");
192  if (i != string::npos)
193  {
194  return Pair<word>
195  (
196  scopedName.substr(0, i),
197  scopedName.substr(i+1, string::npos)
198  );
199  }
200  else
201  {
202  return Pair<word>("", scopedName);
203  }
204 }
205 
206 
207 const dictionary& lookupScopedDict
208 (
209  const dictionary& dict,
210  const word& subDictName
211 )
212 {
213  if (subDictName == "")
214  {
215  return dict;
216  }
217  else
218  {
219  const entry* entPtr = dict.lookupScopedEntryPtr
220  (
221  subDictName,
222  false,
223  false
224  );
225  if (!entPtr || !entPtr->isDict())
226  {
228  << "keyword " << subDictName
229  << " is undefined in dictionary "
230  << dict.name() << " or is not a dictionary"
231  << endl
232  << "Valid keywords are " << dict.keys()
233  << exit(FatalIOError);
234  }
235  return entPtr->dict();
236  }
237 }
238 
239 
240 void remove(dictionary& dict, const dictionary& removeDict)
241 {
242  forAllConstIter(dictionary, removeDict, iter)
243  {
244  const entry* entPtr = dict.lookupEntryPtr
245  (
246  iter().keyword(),
247  false,
248  false
249  );
250 
251  if (entPtr)
252  {
253  if (entPtr->isDict())
254  {
255  if (iter().isDict())
256  {
257  remove
258  (
259  const_cast<dictionary&>(entPtr->dict()),
260  iter().dict()
261  );
262 
263  // Check if dictionary is empty
264  if (!entPtr->dict().size())
265  {
266  dict.remove(iter().keyword());
267  }
268  }
269  }
270  else if (!iter().isDict())
271  {
272  if (*entPtr == iter())
273  {
274  dict.remove(iter().keyword());
275  }
276  }
277  }
278  }
279 }
280 
281 
282 int main(int argc, char *argv[])
283 {
284  #include "removeCaseOptions.H"
285 
286  writeInfoHeader = false;
287 
288  argList::addNote("manipulates dictionaries");
289  argList::validArgs.append("dictionary file");
290  argList::addBoolOption("keywords", "list keywords");
291  argList::addOption("entry", "name", "report/select the named entry");
293  (
294  "value",
295  "Print entry value"
296  );
298  (
299  "set",
300  "value",
301  "Set entry value or add new entry"
302  );
304  (
305  "add",
306  "value",
307  "Add a new entry"
308  );
310  (
311  "merge",
312  "value",
313  "Merge entry"
314  );
316  (
317  "dict",
318  "Set, add or merge entry from a dictionary."
319  );
321  (
322  "remove",
323  "Remove the entry."
324  );
326  (
327  "diff",
328  "dict",
329  "Write differences with respect to the specified dictionary"
330  );
332  (
333  "includes",
334  "List the #include/#includeIfPresent files to standard output"
335  );
337  (
338  "expand",
339  "Read the specified dictionary file, expand the macros etc. and write "
340  "the resulting dictionary to standard output"
341  );
343  (
344  "disableFunctionEntries",
345  "Disable expansion of dictionary directives - #include, #codeStream etc"
346  );
347 
348  argList args(argc, argv);
349 
350  const bool listIncludes = args.optionFound("includes");
351 
352  if (listIncludes)
353  {
355  }
356 
357  if (args.optionFound("disableFunctionEntries"))
358  {
360  }
361 
362 
363  const fileName dictFileName(args[1]);
365  IOstream::streamFormat dictFormat = readDict(dict, dictFileName);
366 
367  bool changed = false;
368 
369  if (listIncludes)
370  {
371  return 0;
372  }
373  else if (args.optionFound("expand"))
374  {
376  <<"//\n// " << dictFileName << "\n//\n";
377  dict.write(Info, false);
379 
380  return 0;
381  }
382 
383 
384  // Second dictionary for -diff
385  fileName diffFileName;
386  dictionary diffDict;
387 
388  if (args.optionReadIfPresent("diff", diffFileName))
389  {
390  readDict(diffDict, diffFileName);
391  }
392 
393 
394  word entryName;
395  if (args.optionReadIfPresent("entry", entryName))
396  {
397  word scopedName(scope(entryName));
398 
399  string newValue;
400  if
401  (
402  args.optionReadIfPresent("set", newValue)
403  || args.optionReadIfPresent("add", newValue)
404  || args.optionReadIfPresent("merge", newValue)
405  )
406  {
407  const bool overwrite = args.optionFound("set");
408  const bool merge = args.optionFound("merge");
409 
410  Pair<word> dAk(dictAndKeyword(scopedName));
411  const dictionary& d(lookupScopedDict(dict, dAk.first()));
412 
413  entry* ePtr = nullptr;
414 
415  if (args.optionFound("dict"))
416  {
417  const fileName fromDictFileName(newValue);
418  dictionary fromDict;
419  readDict(fromDict, fromDictFileName);
420 
421  const entry* fePtr
422  (
423  fromDict.lookupScopedEntryPtr
424  (
425  scopedName,
426  false,
427  true // Support wildcards
428  )
429  );
430 
431  if (!fePtr)
432  {
434  << "Cannot find entry " << entryName
435  << " in file " << fromDictFileName
436  << exit(FatalError, 1);
437  }
438 
439  ePtr = fePtr->clone().ptr();
440  }
441  else
442  {
443  IStringStream str(string(dAk.second()) + ' ' + newValue + ';');
444  ePtr = entry::New(str).ptr();
445  }
446 
447  if (overwrite)
448  {
449  const_cast<dictionary&>(d).set(ePtr);
450  }
451  else
452  {
453  const_cast<dictionary&>(d).add(ePtr, merge);
454  }
455  changed = true;
456 
457  // Print the changed entry
458  // const entry* entPtr = dict.lookupScopedEntryPtr
459  // (
460  // scopedName,
461  // false,
462  // true // Support wildcards
463  // );
464  // if (entPtr)
465  // {
466  // Info<< *entPtr;
467  // }
468  }
469  else if (args.optionFound("remove"))
470  {
471  // Extract dictionary name and keyword
472  Pair<word> dAk(dictAndKeyword(scopedName));
473 
474  const dictionary& d(lookupScopedDict(dict, dAk.first()));
475  const_cast<dictionary&>(d).remove(dAk.second());
476  changed = true;
477  }
478  else
479  {
480  // Optionally remove a second dictionary
481  if (args.optionFound("diff"))
482  {
483  Pair<word> dAk(dictAndKeyword(scopedName));
484 
485  const dictionary& d(lookupScopedDict(dict, dAk.first()));
486  const dictionary& d2(lookupScopedDict(diffDict, dAk.first()));
487 
488  const entry* ePtr =
489  d.lookupEntryPtr(dAk.second(), false, true);
490  const entry* e2Ptr =
491  d2.lookupEntryPtr(dAk.second(), false, true);
492 
493  if (ePtr && e2Ptr)
494  {
495  if (*ePtr == *e2Ptr)
496  {
497  const_cast<dictionary&>(d).remove(dAk.second());
498  }
499  else if (ePtr->isDict() && e2Ptr->isDict())
500  {
501  remove
502  (
503  const_cast<dictionary&>(ePtr->dict()),
504  e2Ptr->dict()
505  );
506  }
507  }
508  }
509 
510 
511  const entry* entPtr = dict.lookupScopedEntryPtr
512  (
513  scopedName,
514  false,
515  true // Support wildcards
516  );
517 
518  if (entPtr)
519  {
520  if (args.optionFound("keywords"))
521  {
522  const dictionary& dict = entPtr->dict();
523  forAllConstIter(dictionary, dict, iter)
524  {
525  Info<< iter().keyword() << endl;
526  }
527  }
528  else
529  {
530  if (args.optionFound("value"))
531  {
532  if (entPtr->isStream())
533  {
534  const tokenList& tokens = entPtr->stream();
535  forAll(tokens, i)
536  {
537  Info<< tokens[i];
538  if (i < tokens.size() - 1)
539  {
540  Info<< token::SPACE;
541  }
542  }
543  Info<< endl;
544  }
545  else if (entPtr->isDict())
546  {
547  Info<< entPtr->dict();
548  }
549  }
550  else
551  {
552  Info<< *entPtr;
553  }
554  }
555  }
556  else
557  {
559  << "Cannot find entry " << entryName
560  << exit(FatalIOError, 2);
561  }
562  }
563  }
564  else if (args.optionFound("keywords"))
565  {
566  forAllConstIter(dictionary, dict, iter)
567  {
568  Info<< iter().keyword() << endl;
569  }
570  }
571  else if (args.optionFound("diff"))
572  {
573  remove(dict, diffDict);
574  dict.write(Info, false);
575  }
576  else
577  {
578  dict.write(Info, false);
579  }
580 
581  if (changed)
582  {
583  OFstream os(dictFileName, dictFormat);
585  dict.write(os, false);
587  }
588 
589  return 0;
590 }
591 
592 
593 // ************************************************************************* //
virtual bool isStream() const
Return true if this entry is a stream.
Definition: entry.H:147
void write(Ostream &, const bool subDict=true) const
Write dictionary, normally with sub-dictionary formatting.
Definition: dictionaryIO.C:180
bool read(Istream &)
Read dictionary from Istream.
Definition: dictionaryIO.C:125
virtual autoPtr< entry > clone(const dictionary &parentDict) const =0
Construct on freestore as copy with reference to the.
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
static streamFormat formatEnum(const word &)
Return stream format of given format name.
Definition: IOstream.C:39
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
A class for handling file names.
Definition: fileName.H:79
static Stream & writeBanner(Stream &os, bool noHint=false)
Write the standard OpenFOAM file/dictionary banner.
Definition: IOobjectI.H:45
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:158
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
bool writeInfoHeader
Output to file stream.
Definition: OFstream.H:82
static Stream & writeDivider(Stream &os)
Write the standard file section divider.
Definition: IOobjectI.H:93
static bool New(dictionary &parentDict, Istream &)
Construct from Istream and insert into dictionary.
Definition: entryIO.C:107
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:108
virtual const dictionary & dict() const =0
Return dictionary if this entry is a dictionary.
static SLList< string > validArgs
A list of valid (mandatory) arguments.
Definition: argList.H:153
bool optionReadIfPresent(const word &opt, T &) const
Read a value from the named option if present.
Definition: argListI.H:198
const entry * lookupScopedEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present.
Definition: dictionary.C:594
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:821
wordList components(const char delimiter='/') const
Return path components as wordList.
Definition: fileName.C:302
static int disableFunctionEntries
Definition: entry.H:86
const fileName & name() const
Return the dictionary name.
Definition: dictionary.H:111
A class for handling words, derived from string.
Definition: word.H:59
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:102
static void addOption(const word &opt, const string &param="", const string &usage="")
Add to an option to validOptions with usage information.
Definition: argList.C:127
streamFormat
Enumeration for the format of data in the stream.
Definition: IOstream.H:86
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
virtual bool isDict() const
Return true if this entry is a dictionary.
Definition: entry.H:156
void add(FieldField< Field1, typename typeOfSum< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
Input from file stream.
Definition: IFstream.H:81
List< keyType > keys(bool patterns=false) const
Return the list of available keys or patterns.
Definition: dictionary.C:803
static Stream & writeEndDivider(Stream &os)
Write the standard end file divider.
Definition: IOobjectI.H:103
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:331
Input from memory buffer stream.
Definition: IStringStream.H:49
messageStream Info
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:117
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:158
T * first()
Return the first entry.
Definition: UILList.H:109
static bool log
Report which file is included to stdout.
Definition: includeEntry.H:88
virtual ITstream & stream() const =0
Return token stream if this entry is a primitive entry.
Foam::argList args(argc, argv)
Namespace for OpenFOAM.
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:65
IOerror FatalIOError