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-2018 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 -remove
47  Remove the selected entry
48 
49  - \par -diff <dictionary>
50  Write differences with respect to the specified dictionary
51  (or sub entry if -entry specified)
52 
53  - \par -expand
54  Read the specified dictionary file, expand the macros etc. and write
55  the resulting dictionary to standard output.
56 
57  - \par -includes
58  List the \c #include and \c #includeIfPresent files to standard output
59 
60  - \par -disableFunctionEntries
61  Do not expand macros or directives (#include etc)
62 
63  Example usage:
64  - Change simulation to run for one timestep only:
65  \verbatim
66  foamDictionary system/controlDict -entry stopAt -set writeNow
67  \endverbatim
68 
69  - Change solver:
70  \verbatim
71  foamDictionary system/fvSolution -entry solvers.p.solver -set PCG
72  \endverbatim
73 
74  - Print bc type:
75  \verbatim
76  foamDictionary 0/U -entry boundaryField.movingWall.type
77  \endverbatim
78 
79  - Change bc parameter:
80  \verbatim
81  foamDictionary 0/U -entry boundaryField.movingWall.value \
82  -set "uniform (2 0 0)"
83  \endverbatim
84 
85  - Change whole bc type:
86  \verbatim
87  foamDictionary 0/U -entry boundaryField.movingWall \
88  -set "{type uniformFixedValue; uniformValue (2 0 0);}"
89  \endverbatim
90 
91  - Write the differences with respect to a template dictionary:
92  \verbatim
93  foamDictionary 0/U -diff $FOAM_ETC/templates/closedVolume/0/U
94  \endverbatim
95 
96  - Write the differences in boundaryField with respect to a
97  template dictionary:
98  \verbatim
99  foamDictionary 0/U -diff $FOAM_ETC/templates/closedVolume/0/U \
100  -entry boundaryField
101  \endverbatim
102 
103  - Change patch type:
104  \verbatim
105  foamDictionary constant/polyMesh/boundary \
106  -entry entry0.fixedWalls.type -set patch
107  \endverbatim
108  This uses special parsing of Lists which stores these in the
109  dictionary with keyword 'entryDDD' where DDD is the position
110  in the dictionary (after ignoring the FoamFile entry).
111 
112 \*---------------------------------------------------------------------------*/
113 
114 #include "argList.H"
115 #include "Time.H"
116 #include "IFstream.H"
117 #include "OFstream.H"
118 #include "includeEntry.H"
119 
120 using namespace Foam;
121 
122 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
123 
124 //- Converts old scope syntax to new syntax
125 word scope(const fileName& entryName)
126 {
127  if (entryName.find(':') != string::npos)
128  {
129  wordList entryNames(entryName.components(':'));
130 
131  word entry(entryNames[0]);
132  for (label i = 1; i < entryNames.size(); i++)
133  {
134  entry += word('.') + entryNames[i];
135  }
136  return entry;
137  }
138  else
139  {
140  return entryName;
141  }
142 }
143 
144 
145 //- Extracts dict name and keyword
146 Pair<word> dictAndKeyword(const word& scopedName)
147 {
148  string::size_type i = scopedName.find_last_of(".");
149  if (i != string::npos)
150  {
151  return Pair<word>
152  (
153  scopedName.substr(0, i),
154  scopedName.substr(i+1, string::npos)
155  );
156  }
157  else
158  {
159  return Pair<word>("", scopedName);
160  }
161 }
162 
163 
164 const dictionary& lookupScopedDict
165 (
166  const dictionary& dict,
167  const word& subDictName
168 )
169 {
170  if (subDictName == "")
171  {
172  return dict;
173  }
174  else
175  {
176  const entry* entPtr = dict.lookupScopedEntryPtr
177  (
178  subDictName,
179  false,
180  false
181  );
182  if (!entPtr || !entPtr->isDict())
183  {
185  << "keyword " << subDictName
186  << " is undefined in dictionary "
187  << dict.name() << " or is not a dictionary"
188  << endl
189  << "Valid keywords are " << dict.keys()
190  << exit(FatalIOError);
191  }
192  return entPtr->dict();
193  }
194 }
195 
196 
197 void remove(dictionary& dict, const dictionary& removeDict)
198 {
199  forAllConstIter(dictionary, removeDict, iter)
200  {
201  const entry* entPtr = dict.lookupEntryPtr
202  (
203  iter().keyword(),
204  false,
205  false
206  );
207 
208  if (entPtr)
209  {
210  if (entPtr->isDict())
211  {
212  if (iter().isDict())
213  {
214  remove
215  (
216  const_cast<dictionary&>(entPtr->dict()),
217  iter().dict()
218  );
219 
220  // Check if dictionary is empty
221  if (!entPtr->dict().size())
222  {
223  dict.remove(iter().keyword());
224  }
225  }
226  }
227  else if (!iter().isDict())
228  {
229  if (*entPtr == iter())
230  {
231  dict.remove(iter().keyword());
232  }
233  }
234  }
235  }
236 }
237 
238 
239 int main(int argc, char *argv[])
240 {
241  #include "removeCaseOptions.H"
242 
243  writeInfoHeader = false;
244 
245  argList::addNote("manipulates dictionaries");
246  argList::validArgs.append("dictionary file");
247  argList::addBoolOption("keywords", "list keywords");
248  argList::addOption("entry", "name", "report/select the named entry");
250  (
251  "value",
252  "Print entry value"
253  );
255  (
256  "set",
257  "value",
258  "Set entry value or add new entry"
259  );
261  (
262  "add",
263  "value",
264  "Add a new entry"
265  );
267  (
268  "remove",
269  "Remove the entry."
270  );
272  (
273  "diff",
274  "dict",
275  "Write differences with respect to the specified dictionary"
276  );
278  (
279  "includes",
280  "List the #include/#includeIfPresent files to standard output"
281  );
283  (
284  "expand",
285  "Read the specified dictionary file, expand the macros etc. and write "
286  "the resulting dictionary to standard output"
287  );
289  (
290  "disableFunctionEntries",
291  "Disable expansion of dictionary directives - #include, #codeStream etc"
292  );
293 
294  argList args(argc, argv);
295 
296  const bool listIncludes = args.optionFound("includes");
297 
298  if (listIncludes)
299  {
301  }
302 
303  if (args.optionFound("disableFunctionEntries"))
304  {
306  }
307 
308 
309  fileName dictFileName(args[1]);
310 
311  autoPtr<IFstream> dictFile(new IFstream(dictFileName));
312  if (!dictFile().good())
313  {
315  << "Cannot open file " << dictFileName
316  << exit(FatalError, 1);
317  }
318 
319 
320  bool changed = false;
321 
322  // Read but preserve headers
324  dict.read(dictFile(), true);
325 
326  if (listIncludes)
327  {
328  return 0;
329  }
330  else if (args.optionFound("expand"))
331  {
333  <<"//\n// " << dictFileName << "\n//\n";
334  dict.write(Info, false);
336 
337  return 0;
338  }
339 
340 
341  // Second dictionary for -diff
342  dictionary diffDict;
343  fileName diffFileName;
344  if (args.optionReadIfPresent("diff", diffFileName))
345  {
346  autoPtr<IFstream> diffFile(new IFstream(diffFileName));
347  if (!diffFile().good())
348  {
350  << "Cannot open file " << diffFileName
351  << exit(FatalError, 1);
352  }
353 
354  // Read but preserve headers
355  diffDict.read(diffFile(), true);
356  }
357 
358 
359  word entryName;
360  if (args.optionReadIfPresent("entry", entryName))
361  {
362  word scopedName(scope(entryName));
363 
364  string newValue;
365  if
366  (
367  args.optionReadIfPresent("set", newValue)
368  || args.optionReadIfPresent("add", newValue)
369  )
370  {
371  const bool overwrite = args.optionFound("set");
372 
373  Pair<word> dAk(dictAndKeyword(scopedName));
374 
375  IStringStream str(string(dAk.second()) + ' ' + newValue + ';');
376  entry* ePtr(entry::New(str).ptr());
377  const dictionary& d(lookupScopedDict(dict, dAk.first()));
378 
379  if (overwrite)
380  {
381  const_cast<dictionary&>(d).set(ePtr);
382  }
383  else
384  {
385  const_cast<dictionary&>(d).add(ePtr, false);
386  }
387  changed = true;
388 
389  // Print the changed entry
390  // const entry* entPtr = dict.lookupScopedEntryPtr
391  // (
392  // scopedName,
393  // false,
394  // true // Support wildcards
395  // );
396  // if (entPtr)
397  // {
398  // Info<< *entPtr;
399  // }
400  }
401  else if (args.optionFound("remove"))
402  {
403  // Extract dictionary name and keyword
404  Pair<word> dAk(dictAndKeyword(scopedName));
405 
406  const dictionary& d(lookupScopedDict(dict, dAk.first()));
407  const_cast<dictionary&>(d).remove(dAk.second());
408  changed = true;
409  }
410  else
411  {
412  // Optionally remove a second dictionary
413  if (args.optionFound("diff"))
414  {
415  Pair<word> dAk(dictAndKeyword(scopedName));
416 
417  const dictionary& d(lookupScopedDict(dict, dAk.first()));
418  const dictionary& d2(lookupScopedDict(diffDict, dAk.first()));
419 
420  const entry* ePtr =
421  d.lookupEntryPtr(dAk.second(), false, true);
422  const entry* e2Ptr =
423  d2.lookupEntryPtr(dAk.second(), false, true);
424 
425  if (ePtr && e2Ptr)
426  {
427  if (*ePtr == *e2Ptr)
428  {
429  const_cast<dictionary&>(d).remove(dAk.second());
430  }
431  else if (ePtr->isDict() && e2Ptr->isDict())
432  {
433  remove
434  (
435  const_cast<dictionary&>(ePtr->dict()),
436  e2Ptr->dict()
437  );
438  }
439  }
440  }
441 
442 
443  const entry* entPtr = dict.lookupScopedEntryPtr
444  (
445  scopedName,
446  false,
447  true // Support wildcards
448  );
449 
450  if (entPtr)
451  {
452  if (args.optionFound("keywords"))
453  {
454  const dictionary& dict = entPtr->dict();
455  forAllConstIter(dictionary, dict, iter)
456  {
457  Info<< iter().keyword() << endl;
458  }
459  }
460  else
461  {
462  if (args.optionFound("value"))
463  {
464  if (entPtr->isStream())
465  {
466  const tokenList& tokens = entPtr->stream();
467  forAll(tokens, i)
468  {
469  Info<< tokens[i];
470  if (i < tokens.size() - 1)
471  {
472  Info<< token::SPACE;
473  }
474  }
475  Info<< endl;
476  }
477  else if (entPtr->isDict())
478  {
479  Info<< entPtr->dict();
480  }
481  }
482  else
483  {
484  Info<< *entPtr;
485  }
486  }
487  }
488  else
489  {
490  FatalIOErrorInFunction(dictFile)
491  << "Cannot find entry " << entryName
492  << exit(FatalIOError, 2);
493  }
494  }
495  }
496  else if (args.optionFound("keywords"))
497  {
498  forAllConstIter(dictionary, dict, iter)
499  {
500  Info<< iter().keyword() << endl;
501  }
502  }
503  else if (args.optionFound("diff"))
504  {
505  remove(dict, diffDict);
506  dict.write(Info, false);
507  }
508  else
509  {
510  dict.write(Info, false);
511  }
512 
513  if (changed)
514  {
515  dictFile.clear();
516  OFstream os(dictFileName);
518  dict.write(os, false);
520  }
521 
522  return 0;
523 }
524 
525 
526 // ************************************************************************* //
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:172
bool read(Istream &)
Read dictionary from Istream.
Definition: dictionaryIO.C:125
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
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:69
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:137
#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:587
wordList components(const char delimiter='/') const
Return path components as wordList.
Definition: fileName.C:298
static int disableFunctionEntries
Definition: entry.H:86
const fileName & name() const
Return the dictionary name.
Definition: dictionary.H:103
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:120
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:796
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:110
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:151
T * first()
Return the first entry.
Definition: UILList.H:106
static bool log
Report which file is included to stdout.
Definition: includeEntry.H:94
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