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 bool Foam::entry::New(dictionary& parentDict, Istream& is)
104 {
105  is.fatalCheck("entry::New(const dictionary& parentDict, Istream&)");
106 
107  keyType keyword;
108  label keywordLineNo = -1;
109  token keyToken;
110 
111  // Get the next keyword and if valid return true
112  bool valid = getKeyword(keyword, keyToken, keywordLineNo, is);
113 
114  if (!valid)
115  {
116  // Do some more checking
117  if (keyToken == token::END_BLOCK || is.eof())
118  {
119  return false;
120  }
121  else if
122  (
123  keyToken.isLabel()
124  || (keyToken.isPunctuation() && keyToken.pToken() == token::BEGIN_LIST)
125  )
126  {
127  is.putBack(keyToken);
128  return parentDict.add
129  (
130  new dictionaryListEntry(parentDict, is),
131  false
132  );
133  }
134  else
135  {
136  // Otherwise the token is invalid
137  cerr<< "--> FOAM Warning : " << std::endl
138  << " From function "
139  << "entry::New(dictionary&, Istream&)" << std::endl
140  << " in file " << __FILE__
141  << " at line " << __LINE__ << std::endl
142  << " Reading " << is.name().c_str() << std::endl
143  << " found " << keyToken << std::endl
144  << " expected either " << token::END_BLOCK << " or EOF"
145  << std::endl;
146  return false;
147  }
148  }
149  else // Keyword starts entry ...
150  {
151  if (keyword.isFunctionName()) // ... Function entry
152  {
153  const word functionName = keyword(1, keyword.size() - 1);
154 
155  if (disableFunctionEntries)
156  {
157  bool success = parentDict.add
158  (
159  new functionEntry
160  (
161  keyword,
162  parentDict,
163  is
164  ),
165  false
166  );
167 
168  return success;
169  }
170  else
171  {
172  return functionEntry::execute(functionName, parentDict, is);
173  }
174  }
175  else if
176  (
177  !disableFunctionEntries
178  && keyword.isVariable()
179  ) // ... Substitution entry
180  {
181  token nextToken(is);
182  is.putBack(nextToken);
183 
184  if (keyword.size() > 2 && keyword[1] == token::BEGIN_BLOCK)
185  {
186  // Recursive substitution mode. Replace between {} with
187  // expansion and then let standard variable expansion deal
188  // with rest.
189  string s(keyword(2, keyword.size() - 3));
190 
191  // Substitute dictionary and environment variables. Do not allow
192  // empty substitutions.
193  stringOps::inplaceExpandEntry(s, parentDict, true, false);
194  keyword.std::string::replace(1, keyword.size() - 1, s);
195  }
196 
197  if (nextToken == token::BEGIN_BLOCK)
198  {
199  const word varName = keyword(1, keyword.size() - 1);
200 
201  // Lookup the variable name in the given dictionary
202  const entry* ePtr = parentDict.lookupScopedEntryPtr
203  (
204  varName,
205  true,
206  true
207  );
208 
209  if (ePtr == nullptr)
210  {
212  << "Attempt to use undefined variable " << varName
213  << " as keyword"
214  << exit(FatalIOError);
215  return false;
216  }
217  else if (ePtr->isStream())
218  {
219  // Read as primitiveEntry
220  const keyType newKeyword(ePtr->stream());
221 
222  return parentDict.add
223  (
224  new dictionaryEntry(newKeyword, parentDict, is),
225  false
226  );
227  }
228  else if (ePtr->isDict())
229  {
231  << "Attempt to substitute sub-dictionary"
232  << nl << *ePtr
233  << "for keyword " << varName
234  << exit(FatalIOError);
235  return false;
236  }
237  }
238  else
239  {
240  const word varName = keyword(1, keyword.size() - 1);
241 
242  // Lookup the variable name in the given dictionary
243  const entry* ePtr = parentDict.lookupScopedEntryPtr
244  (
245  varName,
246  true,
247  true
248  );
249 
250  if (ePtr == nullptr)
251  {
253  << "Attempt to use undefined variable " << keyword
254  << " as a keyword"
255  << exit(FatalIOError);
256  return false;
257  }
258  else if (ePtr->isDict())
259  {
260  // Insert the sub-dict entries into this dictionary
261  const dictionary& addDict = ePtr->dict();
262 
263  forAllConstIter(IDLList<entry>, addDict, iter)
264  {
265  parentDict.add(iter());
266  }
267  return true;
268  }
269  else
270  {
272  << "Attempt to substitute primitive entry "
273  << *ePtr << "as a sub-dictionary"
274  << exit(FatalIOError);
275  return false;
276  }
277  }
278 
279  return true;
280  }
281  else // ... Data entries
282  {
283  token nextToken(is);
284  is.putBack(nextToken);
285 
286  // Deal with duplicate entries
287  bool mergeEntry = false;
288 
289  // If function entries are disabled allow duplicate entries
290  if (disableFunctionEntries)
291  {
292  mergeEntry = false;
293  }
294  else
295  {
296  // See (using exact match) if entry already present
297  entry* existingPtr = parentDict.lookupEntryPtr
298  (
299  keyword,
300  false,
301  false
302  );
303 
304  if (existingPtr)
305  {
307  {
308  mergeEntry = true;
309  }
311  {
312  // Clear dictionary so merge acts like overwrite
313  if (existingPtr->isDict())
314  {
315  existingPtr->dict().clear();
316  }
317  mergeEntry = true;
318  }
320  {
321  // Read and discard the entry
322  if (nextToken == token::BEGIN_BLOCK)
323  {
324  dictionaryEntry dummy
325  (
326  keyword,
327  keywordLineNo,
328  parentDict,
329  is
330  );
331  }
332  else
333  {
334  primitiveEntry dummy(keyword, parentDict, is);
335  }
336  return true;
337  }
339  {
341  << "ERROR! duplicate entry: " << keyword
342  << exit(FatalIOError);
343  return false;
344  }
345  }
346  }
347 
348  if (nextToken == token::BEGIN_BLOCK)
349  {
350  return parentDict.add
351  (
352  new dictionaryEntry(keyword, keywordLineNo, parentDict, is),
353  mergeEntry
354  );
355  }
356  else
357  {
358  return parentDict.add
359  (
360  new primitiveEntry(keyword, parentDict, is),
361  mergeEntry
362  );
363  }
364  }
365  }
366 }
367 
368 
370 {
371  is.fatalCheck("entry::New(Istream&)");
372 
373  keyType keyword;
374  label keywordLineNo = -1;
375 
376  // Get the next keyword and if invalid return false
377  if (!getKeyword(keyword, keywordLineNo, is))
378  {
379  return autoPtr<entry>(nullptr);
380  }
381  else // Keyword starts entry ...
382  {
383  token nextToken(is);
384  is.putBack(nextToken);
385 
386  if (nextToken == token::BEGIN_BLOCK)
387  {
388  return autoPtr<entry>
389  (
390  new dictionaryEntry
391  (
392  keyword,
393  keywordLineNo,
395  is
396  )
397  );
398  }
399  else
400  {
401  return autoPtr<entry>
402  (
403  new primitiveEntry(keyword, is)
404  );
405  }
406  }
407 }
408 
409 
410 // * * * * * * * * * * * * * Ostream operator * * * * * * * * * * * * * * * //
411 
413 {
414  e.write(os);
415  return os;
416 }
417 
418 
419 // ************************************************************************* //
bool success
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:476
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:105
bool eof() const
Return true if end of input seen.
Definition: IOstream.H:339
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
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
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:578
const entry * lookupScopedEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present,.
Definition: dictionary.C:767
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:1020
void clear()
Clear the dictionary.
Definition: dictionary.C:1359
static const dictionary null
Null dictionary.
Definition: dictionary.H:273
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:103
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.
A functionEntry causes entries to be added/manipulated on the specified dictionary given an input str...
Definition: functionEntry.H:66
static bool execute(const word &functionName, dictionary &parentDict, Istream &)
Execute the functionEntry in a sub-dict context.
A functionName is a word starting with '#'.
Definition: functionName.H:60
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:73
bool isLabel() const
Definition: tokenI.H:571
bool isPunctuation() const
Definition: tokenI.H:280
@ BEGIN_BLOCK
Definition: token.H:113
@ END_BLOCK
Definition: token.H:114
@ END_STATEMENT
Definition: token.H:108
@ BEGIN_LIST
Definition: token.H:109
punctuationToken pToken() const
Definition: tokenI.H:285
A class for handling words, derived from string.
Definition: word.H:62
#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:258
IOerror FatalIOError
Ostream & operator<<(Ostream &os, const fvConstraints &constraints)
static const char nl
Definition: Ostream.H:267