entryIO.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) 2011-2025 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 \*---------------------------------------------------------------------------*/
25 
26 #include "entry.H"
27 #include "dictionaryListEntry.H"
28 #include "includeEntry.H"
29 #include "inputModeEntry.H"
30 #include "stringOps.H"
31 
32 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
33 
34 bool Foam::entry::getKeyword
35 (
36  keyType& keyword,
37  token& keywordToken,
38  label& keywordLineNo,
39  Istream& is
40 )
41 {
42  // Read the next valid token discarding spurious ';'s
43  do
44  {
45  if
46  (
47  is.read(keywordToken).bad()
48  || is.eof()
49  || !keywordToken.good()
50  )
51  {
52  return false;
53  }
54  }
55  while (keywordToken == token::END_STATEMENT);
56 
57  keyword = keywordToken;
58  keywordLineNo = is.lineNumber();
59 
60  return !keyword.isUndefined();
61 }
62 
63 
64 bool Foam::entry::getKeyword
65 (
66  keyType& keyword,
67  label& keywordLineNo,
68  Istream& is
69 )
70 {
71  token keywordToken;
72  bool ok = getKeyword(keyword, keywordToken, keywordLineNo, is);
73 
74  if (ok)
75  {
76  return true;
77  }
78  else
79  {
80  // Do some more checking
81  if (keywordToken == token::END_BLOCK || is.eof())
82  {
83  return false;
84  }
85  else
86  {
87  // Otherwise the token is invalid
88  cerr<< "--> FOAM Warning : " << std::endl
89  << " From function "
90  << "entry::getKeyword(keyType&, Istream&)" << std::endl
91  << " in file " << __FILE__
92  << " at line " << __LINE__ << std::endl
93  << " Reading " << is.name().c_str() << std::endl
94  << " found " << keywordToken << std::endl
95  << " expected either " << token::END_BLOCK << " or EOF"
96  << std::endl;
97  return false;
98  }
99  }
100 }
101 
102 
103 // * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
104 
105 bool Foam::entry::New(dictionary& parentDict, Istream& is)
106 {
107  is.fatalCheck("entry::New(const dictionary& parentDict, Istream&)");
108 
109  keyType keyword;
110  label keywordLineNo = -1;
111  token keyToken;
112 
113  // Get the next keyword and if valid return true
114  bool valid = getKeyword(keyword, keyToken, keywordLineNo, is);
115 
116  if (!valid)
117  {
118  // Do some more checking
119  if (keyToken == token::END_BLOCK || is.eof())
120  {
121  return false;
122  }
123  else if
124  (
125  keyToken.isLabel()
126  || (keyToken.isPunctuation() && keyToken.pToken() == token::BEGIN_LIST)
127  )
128  {
129  is.putBack(keyToken);
130  return parentDict.add
131  (
132  new dictionaryListEntry(parentDict, is),
133  false
134  );
135  }
136  else
137  {
138  // Otherwise the token is invalid
139  cerr<< "--> FOAM Warning : " << std::endl
140  << " From function "
141  << "entry::New(dictionary&, Istream&)" << std::endl
142  << " in file " << __FILE__
143  << " at line " << __LINE__ << std::endl
144  << " Reading " << is.name().c_str() << std::endl
145  << " found " << keyToken << std::endl
146  << " expected either " << token::END_BLOCK << " or EOF"
147  << std::endl;
148  return false;
149  }
150  }
151  else // Keyword starts entry ...
152  {
153  if (keyword.isFunctionName()) // ... Function entry
154  {
156  (
157  functionEntry::New(keyword, parentDict, is)
158  );
159 
160  if (disableFunctionEntries)
161  {
162  // Add the unexpanded functionEntry to the dictionary
163  // for future processing
164  return parentDict.add(fe.ptr(), false);
165  }
166  else
167  {
168  // Expand the functionEntry
169  return fe->execute(parentDict, is);
170  }
171  }
172  else if
173  (
174  !disableFunctionEntries
175  && keyword.isVariable()
176  ) // ... Substitution entry
177  {
178  token nextToken(is);
179  is.putBack(nextToken);
180 
181  if (keyword.size() > 2 && keyword[1] == token::BEGIN_BLOCK)
182  {
183  // Recursive substitution mode. Replace between {} with
184  // expansion and then let standard variable expansion deal
185  // with rest.
186  string s(keyword(2, keyword.size() - 3));
187 
188  // Substitute dictionary and environment variables. Do not allow
189  // empty substitutions.
190  stringOps::inplaceExpandEntry(s, parentDict, true, false);
191  keyword.std::string::replace(1, keyword.size() - 1, s);
192  }
193 
194  if (nextToken == token::BEGIN_BLOCK)
195  {
196  const word varName = keyword(1, keyword.size() - 1);
197 
198  // Lookup the variable name in the given dictionary
199  const entry* ePtr = parentDict.lookupScopedEntryPtr
200  (
201  varName,
202  true,
203  true
204  );
205 
206  if (ePtr == nullptr)
207  {
209  << "Attempt to use undefined variable " << varName
210  << " as keyword"
211  << exit(FatalIOError);
212  return false;
213  }
214  else if (ePtr->isStream())
215  {
216  // Read as primitiveEntry
217  const keyType newKeyword(ePtr->stream());
218 
219  return parentDict.add
220  (
221  new dictionaryEntry(newKeyword, parentDict, is),
222  false
223  );
224  }
225  else if (ePtr->isDict())
226  {
228  << "Attempt to substitute sub-dictionary"
229  << nl << *ePtr
230  << "for keyword " << varName
231  << exit(FatalIOError);
232  return false;
233  }
234  }
235  else
236  {
237  const word varName = keyword(1, keyword.size() - 1);
238 
239  // Lookup the variable name in the given dictionary
240  const entry* ePtr = parentDict.lookupScopedEntryPtr
241  (
242  varName,
243  true,
244  true
245  );
246 
247  if (ePtr == nullptr)
248  {
250  << "Attempt to use undefined variable " << keyword
251  << " as a keyword"
252  << exit(FatalIOError);
253  return false;
254  }
255  else if (ePtr->isDict())
256  {
257  // Insert the sub-dict entries into this dictionary
258  const dictionary& addDict = ePtr->dict();
259 
260  forAllConstIter(IDLList<entry>, addDict, iter)
261  {
262  parentDict.add(iter());
263  }
264  return true;
265  }
266  else
267  {
269  << "Attempt to substitute primitive entry "
270  << *ePtr << "as a sub-dictionary"
271  << exit(FatalIOError);
272  return false;
273  }
274  }
275 
276  return true;
277  }
278  else // ... Data entries
279  {
280  token nextToken(is);
281  is.putBack(nextToken);
282 
283  // Deal with duplicate entries
284  bool mergeEntry = false;
285 
286  // If function entries are disabled allow duplicate entries
287  if (disableFunctionEntries)
288  {
289  mergeEntry = false;
290  }
291  else
292  {
293  // See (using exact match) if entry already present
294  entry* existingPtr = parentDict.lookupEntryPtr
295  (
296  keyword,
297  false,
298  false
299  );
300 
301  if (existingPtr)
302  {
304  {
305  mergeEntry = true;
306  }
308  {
309  // Clear dictionary so merge acts like overwrite
310  if (existingPtr->isDict())
311  {
312  existingPtr->dict().clear();
313  }
314  mergeEntry = true;
315  }
317  {
318  // Read and discard the entry
319  if (nextToken == token::BEGIN_BLOCK)
320  {
321  dictionaryEntry dummy
322  (
323  keyword,
324  keywordLineNo,
325  parentDict,
326  is
327  );
328  }
329  else
330  {
331  primitiveEntry dummy(keyword, parentDict, is);
332  }
333  return true;
334  }
336  {
338  << "ERROR! duplicate entry: " << keyword
339  << exit(FatalIOError);
340  return false;
341  }
342  }
343  }
344 
345  if (nextToken == token::BEGIN_BLOCK)
346  {
347  return parentDict.add
348  (
349  new dictionaryEntry(keyword, keywordLineNo, parentDict, is),
350  mergeEntry
351  );
352  }
353  else
354  {
355  return parentDict.add
356  (
357  new primitiveEntry(keyword, parentDict, is),
358  mergeEntry
359  );
360  }
361  }
362  }
363 }
364 
365 
367 {
368  is.fatalCheck("entry::New(Istream&)");
369 
370  keyType keyword;
371  label keywordLineNo = -1;
372 
373  // Get the next keyword and if invalid return false
374  if (!getKeyword(keyword, keywordLineNo, is))
375  {
376  return autoPtr<entry>(nullptr);
377  }
378  else // Keyword starts entry ...
379  {
380  token nextToken(is);
381  is.putBack(nextToken);
382 
383  if (nextToken == token::BEGIN_BLOCK)
384  {
385  return autoPtr<entry>
386  (
387  new dictionaryEntry
388  (
389  keyword,
390  keywordLineNo,
392  is
393  )
394  );
395  }
396  else
397  {
398  return autoPtr<entry>
399  (
400  new primitiveEntry(keyword, is)
401  );
402  }
403  }
404 }
405 
406 
407 // * * * * * * * * * * * * * Ostream operator * * * * * * * * * * * * * * * //
408 
410 {
411  e.write(os);
412  return os;
413 }
414 
415 
416 // ************************************************************************* //
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:492
Template class for intrusive linked lists.
Definition: ILList.H:67
virtual const fileName & name() const
Return the name of the stream.
Definition: IOstream.H:297
void fatalCheck(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:121
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:60
void putBack(const token &)
Put back token.
Definition: Istream.C:30
bool eof() const
Return true if end of input seen.
Definition: Istream.H:107
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
T * ptr()
Return object pointer for reuse.
Definition: autoPtrI.H:90
A keyword and a list of tokens is a 'dictionaryEntry'.
Read/write List of dictionaries.
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
const entry * lookupEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present.
Definition: dictionary.C:507
const entry * lookupScopedEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present,.
Definition: dictionary.C:696
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:1019
void clear()
Clear the dictionary.
Definition: dictionary.C:1358
static const dictionary null
Null dictionary.
Definition: dictionary.H:261
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:68
virtual bool isDict() const
Return true if this entry is a dictionary.
Definition: entry.H:178
virtual ITstream & stream() const =0
Return token stream if this entry is a primitive entry.
const keyType & keyword() const
Return keyword.
Definition: entry.H:136
static bool New(dictionary &parentDict, Istream &)
Construct from Istream and insert into dictionary.
Definition: entryIO.C:105
virtual const dictionary & dict() const =0
Return dictionary if this entry is a dictionary.
virtual bool isStream() const
Return true if this entry is a stream.
Definition: entry.H:169
static bool overwrite()
Return true if the inputMode is overwrite.
static bool protect()
Return true if the inputMode is protect.
static bool merge()
Return true if the inputMode is merge.
static bool error()
Return true if the inputMode is error.
static autoPtr< functionEntry > New(const keyType &functionName, const dictionary &parentDict, Istream &is)
Construct from Istream and insert into dictionary.
A class for handling keywords in dictionaries.
Definition: keyType.H:69
bool isVariable() const
Return true if the keyword is a variable.
Definition: keyTypeI.H:91
bool isFunctionName() const
Return true if the keyword is a functionName.
Definition: keyTypeI.H:85
bool isUndefined() const
Return true if the type has not been defined.
Definition: keyTypeI.H:79
A keyword and a list of tokens is a 'primitiveEntry'. An primitiveEntry can be read,...
A token holds items read from Istream.
Definition: token.H:74
bool isLabel() const
Definition: tokenI.H:615
bool isPunctuation() const
Definition: tokenI.H:324
@ BEGIN_BLOCK
Definition: token.H:114
@ END_BLOCK
Definition: token.H:115
@ END_STATEMENT
Definition: token.H:109
@ BEGIN_LIST
Definition: token.H:110
punctuationToken pToken() const
Definition: tokenI.H:329
A class for handling words, derived from string.
Definition: word.H:63
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
bool valid(const PtrList< ModelType > &l)
string & inplaceExpandEntry(string &s, const dictionary &dict, const bool allowEnvVars, const bool allowEmpty, const char sigil='$')
Inplace expand occurrences of variables according to the dictionary.
Definition: stringOps.C:760
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const doubleScalar e
Definition: doubleScalar.H:106
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
IOerror FatalIOError
Ostream & operator<<(Ostream &os, const fvConstraints &constraints)
static const char nl
Definition: Ostream.H:297