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 | Copyright (C) 2016-2017 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  argList::addNote("manipulates dictionaries");
242 
244  argList::validArgs.append("dictionary file");
245  argList::addBoolOption("keywords", "list keywords");
246  argList::addOption("entry", "name", "report/select the named entry");
248  (
249  "value",
250  "Print entry value"
251  );
253  (
254  "set",
255  "value",
256  "Set entry value or add new entry"
257  );
259  (
260  "add",
261  "value",
262  "Add a new entry"
263  );
265  (
266  "remove",
267  "Remove the entry."
268  );
270  (
271  "diff",
272  "dict",
273  "Write differences with respect to the specified dictionary"
274  );
276  (
277  "includes",
278  "List the #include/#includeIfPresent files to standard output"
279  );
281  (
282  "expand",
283  "Read the specified dictionary file, expand the macros etc. and write "
284  "the resulting dictionary to standard output"
285  );
287  (
288  "disableFunctionEntries",
289  "Disable expansion of dictionary directives - #include, #codeStream etc"
290  );
291 
292  argList args(argc, argv);
293 
294  const bool listIncludes = args.optionFound("includes");
295 
296  if (listIncludes)
297  {
299  }
300 
301  const bool disableEntries = args.optionFound("disableFunctionEntries");
302  if (disableEntries)
303  {
304  Info<< "Not expanding variables or dictionary directives"
305  << endl;
307  }
308 
309 
310  fileName dictFileName(args[1]);
311 
312  autoPtr<IFstream> dictFile(new IFstream(dictFileName));
313  if (!dictFile().good())
314  {
316  << "Cannot open file " << dictFileName
317  << exit(FatalError, 1);
318  }
319 
320 
321  bool changed = false;
322 
323  // Read but preserve headers
325  dict.read(dictFile(), true);
326 
327  if (listIncludes)
328  {
329  return 0;
330  }
331  else if (args.optionFound("expand"))
332  {
334  <<"//\n// " << dictFileName << "\n//\n";
335  dict.write(Info, false);
337 
338  return 0;
339  }
340 
341 
342  // Second dictionary for -diff
343  dictionary diffDict;
344  fileName diffFileName;
345  if (args.optionReadIfPresent("diff", diffFileName))
346  {
347  autoPtr<IFstream> diffFile(new IFstream(diffFileName));
348  if (!diffFile().good())
349  {
351  << "Cannot open file " << diffFileName
352  << exit(FatalError, 1);
353  }
354 
355  // Read but preserve headers
356  diffDict.read(diffFile(), true);
357  }
358 
359 
360  word entryName;
361  if (args.optionReadIfPresent("entry", entryName))
362  {
363  word scopedName(scope(entryName));
364 
365  string newValue;
366  if
367  (
368  args.optionReadIfPresent("set", newValue)
369  || args.optionReadIfPresent("add", newValue)
370  )
371  {
372  bool overwrite = args.optionFound("set");
373 
374  Pair<word> dAk(dictAndKeyword(scopedName));
375 
376  IStringStream str(string(dAk.second()) + ' ' + newValue + ';');
377  entry* ePtr(entry::New(str).ptr());
378  const dictionary& d(lookupScopedDict(dict, dAk.first()));
379 
380  if (overwrite)
381  {
382  const_cast<dictionary&>(d).set(ePtr);
383  }
384  else
385  {
386  const_cast<dictionary&>(d).add(ePtr, false);
387  }
388  changed = true;
389 
390  // Print the changed entry
391  const entry* entPtr = dict.lookupScopedEntryPtr
392  (
393  scopedName,
394  false,
395  true // Support wildcards
396  );
397  if (entPtr)
398  {
399  Info<< *entPtr;
400  }
401  }
402  else if (args.optionFound("remove"))
403  {
404  // Extract dictionary name and keyword
405  Pair<word> dAk(dictAndKeyword(scopedName));
406 
407  const dictionary& d(lookupScopedDict(dict, dAk.first()));
408  const_cast<dictionary&>(d).remove(dAk.second());
409  changed = true;
410  }
411  else
412  {
413  // Optionally remove a second dictionary
414  if (args.optionFound("diff"))
415  {
416  Pair<word> dAk(dictAndKeyword(scopedName));
417 
418  const dictionary& d(lookupScopedDict(dict, dAk.first()));
419  const dictionary& d2(lookupScopedDict(diffDict, dAk.first()));
420 
421  const entry* ePtr =
422  d.lookupEntryPtr(dAk.second(), false, true);
423  const entry* e2Ptr =
424  d2.lookupEntryPtr(dAk.second(), false, true);
425 
426  if (ePtr && e2Ptr)
427  {
428  if (*ePtr == *e2Ptr)
429  {
430  const_cast<dictionary&>(d).remove(dAk.second());
431  }
432  else if (ePtr->isDict() && e2Ptr->isDict())
433  {
434  remove
435  (
436  const_cast<dictionary&>(ePtr->dict()),
437  e2Ptr->dict()
438  );
439  }
440  }
441  }
442 
443 
444  const entry* entPtr = dict.lookupScopedEntryPtr
445  (
446  scopedName,
447  false,
448  true // Support wildcards
449  );
450 
451  if (entPtr)
452  {
453  if (args.optionFound("keywords"))
454  {
455  const dictionary& dict = entPtr->dict();
456  forAllConstIter(dictionary, dict, iter)
457  {
458  Info<< iter().keyword() << endl;
459  }
460  }
461  else
462  {
463  if (args.optionFound("value"))
464  {
465  if (entPtr->isStream())
466  {
467  const tokenList& tokens = entPtr->stream();
468  forAll(tokens, i)
469  {
470  Info<< tokens[i];
471  if (i < tokens.size() - 1)
472  {
473  Info<< token::SPACE;
474  }
475  }
476  Info<< endl;
477  }
478  else if (entPtr->isDict())
479  {
480  Info<< entPtr->dict();
481  }
482  }
483  else
484  {
485  Info<< *entPtr;
486  }
487  }
488  }
489  else
490  {
491  FatalIOErrorInFunction(dictFile)
492  << "Cannot find entry " << entryName
493  << exit(FatalIOError, 2);
494  }
495  }
496  }
497  else if (args.optionFound("keywords"))
498  {
499  forAllConstIter(dictionary, dict, iter)
500  {
501  Info<< iter().keyword() << endl;
502  }
503  }
504  else if (args.optionFound("diff"))
505  {
506  remove(dict, diffDict);
507  dict.write(Info, false);
508  }
509  else
510  {
511  dict.write(Info, false);
512  }
513 
514  if (changed)
515  {
516  dictFile.clear();
517  OFstream os(dictFileName);
519  dict.write(os, false);
521  }
522 
523  return 0;
524 }
525 
526 
527 // ************************************************************************* //
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
Output to file stream.
Definition: OFstream.H:82
static Stream & writeDivider(Stream &os)
Write the standard file section divider.
Definition: IOobjectI.H:98
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:253
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:154
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:299
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:95
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:108
#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
static void noBanner()
Disable emitting the banner information.
Definition: argList.C:142
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:85
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:126
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