primitiveEntryIO.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 | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2015 OpenFOAM Foundation
9  Copyright (C) 2017-2021 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "primitiveEntry.H"
30 #include "functionEntry.H"
31 #include "evalEntry.H"
32 
33 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
34 
35 bool Foam::primitiveEntry::acceptToken
36 (
37  const token& tok,
38  const dictionary& dict,
39  Istream& is
40 )
41 {
42  bool accept = tok.good();
43 
44  if (tok.isDirective())
45  {
46  // Directive (wordToken) begins with '#'. Eg, "#include"
47  // Remove leading '#' sigil before dispatching
48 
49  const word& key = tok.wordToken();
50 
51  // Min-size is 2: sigil '#' with any content
52  accept =
53  (
54  (disableFunctionEntries || key.size() < 2)
55  || !expandFunction(key.substr(1), dict, is)
56  );
57  }
58  else if (tok.isExpression())
59  {
60  // Expression (stringToken): ${{ expr }}
61  // Surrounding delimiters are stripped as required in evalEntry
62 
63  const string& key = tok.stringToken();
64 
65  // Min-size is 6: decorators '${{}}' with any content
66  accept =
67  (
68  (disableFunctionEntries || key.size() < 6)
70  (
71  dict,
72  *this,
73  key,
74  1, // Field width is 1
75  is // For error messages
76  )
77  );
78  }
79  else if (tok.isVariable())
80  {
81  // Variable (stringToken): starts with '$'
82  // Eg, "$varName" or "${varName}"
83  // Remove leading '$' sigil before dispatching
84 
85  const string& key = tok.stringToken();
86 
87  // Min-size is 2: sigil '$' with any content
88  accept =
89  (
90  (disableFunctionEntries || key.size() < 2)
91  || !expandVariable(key.substr(1), dict)
92  );
93  }
94 
95  return accept;
96 }
97 
98 
99 bool Foam::primitiveEntry::expandFunction
100 (
101  const word& functionName,
102  const dictionary& dict,
103  Istream& is
104 )
105 {
106  return functionEntry::execute(functionName, dict, *this, is);
107 }
108 
109 
111 {
113 
114  // Track balanced bracket/brace pairs, with max stack depth of 60.
115  // Use a bitmask to track the opening char: 0 = '()', 1 = '{}'
116  //
117  // Notes
118  // - the bitmask is set *before* increasing the depth since the left
119  // shift implicitly carries a 1-offset with it.
120  // Eg, (1u << 0) already corresponds to depth=1 (the first bit)
121  //
122  // - similarly, the bitmask is tested *after* decreasing depth
123 
124  uint64_t balanced = 0u;
125  int depth = 0;
126  token tok;
127 
128  while
129  (
130  !is.read(tok).bad() && tok.good()
131  && !(tok == token::END_STATEMENT && depth == 0)
132  )
133  {
134  if (tok.isPunctuation())
135  {
136  const char c = tok.pToken();
137  switch (c)
138  {
139  case token::BEGIN_LIST:
140  {
141  if (depth >= 0 && depth < 61)
142  {
143  balanced &= ~(1u << depth); // clear bit
144  }
145  ++depth;
146  }
147  break;
148 
149  case token::BEGIN_BLOCK:
150  {
151  if (depth >= 0 && depth < 61)
152  {
153  balanced |= (1u << depth); // set bit
154  }
155  ++depth;
156  }
157  break;
158 
159  case token::END_LIST:
160  {
161  --depth;
162  if (depth < 0)
163  {
164  reportReadWarning
165  (
166  is,
167  "Too many closing ')' ... was a ';' forgotten?"
168  );
169  }
170  else if (depth < 61 && ((balanced >> depth) & 1u))
171  {
172  // Bit was set, but expected it to be unset.
173  reportReadWarning(is, "Imbalanced '{' with ')'");
174  }
175  }
176  break;
177 
178  case token::END_BLOCK:
179  {
180  --depth;
181  if (depth < 0)
182  {
183  reportReadWarning
184  (
185  is,
186  "Too many closing '}' ... was a ';' forgotten?"
187  );
188  }
189  else if (depth < 61 && !((balanced >> depth) & 1u))
190  {
191  // Bit was unset, but expected it to be set.
192  reportReadWarning(is, "Imbalanced '(' with '}'");
193  }
194  }
195  break;
196  }
197  }
198 
199  if (acceptToken(tok, dict, is))
200  {
201  newElmt(tokenIndex()++) = std::move(tok);
202  }
203 
204  // With/without move: clear any old content and force to have a
205  // known good token so that we can rely on it for the return value.
206 
207  tok = token::punctuationToken::NULL_TOKEN;
208  }
209 
210  if (depth)
211  {
212  reportReadWarning(is, "Imbalanced brackets");
213  }
214 
216  return tok.good();
217 }
218 
219 
220 void Foam::primitiveEntry::readEntry(const dictionary& dict, Istream& is)
221 {
222  const label keywordLineNumber = is.lineNumber();
223  tokenIndex() = 0;
224 
225  if (read(dict, is))
226  {
227  setSize(tokenIndex());
228  tokenIndex() = 0;
229  }
230  else
231  {
232  std::ostringstream os;
233  os << "ill defined primitiveEntry starting at keyword '"
234  << keyword() << '\''
235  << " on line " << keywordLineNumber
236  << " and ending at line " << is.lineNumber();
237 
239  (
240  is,
241  os.str()
242  );
243  }
244 }
245 
246 
247 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
248 
250 (
251  const keyType& key,
252  const dictionary& dict,
253  Istream& is
254 )
255 :
256  entry(key),
257  ITstream
258  (
259  is.name() + '.' + key,
260  tokenList(10),
261  static_cast<IOstreamOption>(is)
262  )
263 {
264  readEntry(dict, is);
265 }
266 
267 
269 :
270  primitiveEntry(key, dictionary::null, is)
271 {}
272 
273 
274 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
275 
276 void Foam::primitiveEntry::write(Ostream& os, const bool contentsOnly) const
277 {
278  if (!contentsOnly)
279  {
280  os.writeKeyword(keyword());
281  }
282 
283  bool addSpace = false; // Separate from previous token with a space
284  for (const token& tok : *this)
285  {
286  if (addSpace) os << token::SPACE;
287  addSpace = true;
288 
289  // Output token with direct handling in Ostream(s),
290  // or use normal '<<' output operator
291  if (!os.write(tok))
292  {
293  os << tok;
294  }
295  }
296 
297  if (!contentsOnly)
298  {
300  }
301 }
302 
303 
305 {
306  this->write(os, false);
307 }
308 
309 
310 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
311 
312 template<>
313 Foam::Ostream& Foam::operator<<
314 (
315  Ostream& os,
316  const InfoProxy<primitiveEntry>& ip
317 )
318 {
319  const primitiveEntry& e = ip.t_;
320 
321  e.print(os);
322 
323  const label nPrintTokens = 10;
324 
325  os << " primitiveEntry '" << e.keyword() << "' comprises ";
326 
327  for (label i=0; i<min(e.size(), nPrintTokens); ++i)
328  {
329  os << nl << " " << e[i].info();
330  }
331 
332  if (e.size() > nPrintTokens)
333  {
334  os << " ...";
335  }
336 
337  os << endl;
338 
339  return os;
340 }
341 
342 
343 // ************************************************************************* //
Foam::entry
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:67
setSize
points setSize(newPointi)
Foam::primitiveEntry
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read,...
Definition: primitiveEntry.H:63
primitiveEntry.H
Foam::InfoProxy
A helper class for outputting values to Ostream.
Definition: InfoProxy.H:47
Foam::read
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:108
evalEntry.H
Foam::primitiveEntry::primitiveEntry
primitiveEntry(const keyType &key)
Construct from keyword and no tokens.
Definition: primitiveEntry.C:218
Foam::glTF::key
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:108
Foam::IOstream::fatalCheck
bool fatalCheck(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:64
Foam::IOstream::lineNumber
label lineNumber() const noexcept
Const access to the current stream line number.
Definition: IOstream.H:318
Foam::primitiveEntry::read
virtual bool read(const dictionary &dict, Istream &is)
Read tokens from the given stream.
Definition: primitiveEntryIO.C:110
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::token
A token holds an item read from Istream.
Definition: token.H:68
Foam::primitiveEntry::write
virtual void write(Ostream &os) const
Write.
Definition: primitiveEntryIO.C:304
functionEntry.H
Foam::OBJstream::write
virtual Ostream & write(const char c)
Write character.
Definition: OBJstream.C:78
Foam::primitiveEntry::dict
virtual const dictionary & dict() const
This entry is not a dictionary,.
Definition: primitiveEntry.C:299
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Foam::token::pToken
punctuationToken pToken() const
Return punctuation character.
Definition: tokenI.H:485
Foam::keyType
A class for handling keywords in dictionaries.
Definition: keyType.H:68
Foam::ITstream
An input stream of tokens.
Definition: ITstream.H:52
Foam::Istream
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:61
Foam::IOstreamOption
The IOstreamOption is a simple container for options an IOstream can normally have.
Definition: IOstreamOption.H:63
Foam::token::isPunctuation
bool isPunctuation() const noexcept
Token is PUNCTUATION.
Definition: tokenI.H:459
Foam::IOstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: IOstream.C:40
Foam::token::END_STATEMENT
End entry [isseparator].
Definition: token.H:154
Foam::token::END_BLOCK
End block [isseparator].
Definition: token.H:160
dict
dictionary dict
Definition: searchingEngine.H:14
SafeFatalIOErrorInFunction
#define SafeFatalIOErrorInFunction(ios, msg)
Report an error message using Foam::FatalIOError.
Definition: error.H:497
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
os
OBJstream os(runTime.globalPath()/outputName)
Foam::IOstream::bad
bool bad() const noexcept
True if stream is corrupted.
Definition: IOstream.H:251
Foam::Ostream::writeKeyword
virtual Ostream & writeKeyword(const keyType &kw)
Write the keyword followed by an appropriate indentation.
Definition: Ostream.C:57
Foam::entry::disableFunctionEntries
static int disableFunctionEntries
Enable or disable use of function entries and variable expansions.
Definition: entry.H:127
Foam::token::BEGIN_BLOCK
Begin block [isseparator].
Definition: token.H:159
Foam::tokenList
List< token > tokenList
List of tokens, used for a IOdictionary entry.
Definition: tokenList.H:44
Foam::token::good
bool good() const noexcept
True if token is not UNDEFINED or ERROR.
Definition: tokenI.H:405
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::token::SPACE
Space [isspace].
Definition: token.H:125
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
FUNCTION_NAME
#define FUNCTION_NAME
Definition: messageStream.H:295
Foam::vtk::write
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
Definition: foamVtkOutputTemplates.C:36
Foam::token::END_LIST
End list [isseparator].
Definition: token.H:156
Foam::functionEntries::evalEntry::execute
static bool execute(const dictionary &parentDict, primitiveEntry &thisEntry, Istream &is)
Execute in a primitiveEntry context, extracts token or line.
Definition: evalEntry.C:250
Foam::constant::universal::c
const dimensionedScalar c
Speed of light in a vacuum.
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
Foam::token::BEGIN_LIST
Begin list [isseparator].
Definition: token.H:155
Foam::functionEntry::execute
static bool execute(const word &functionName, dictionary &parentDict, Istream &is)
Execute the functionEntry in a sub-dict context.
Definition: functionEntry.C:98
Foam::Istream::read
virtual Istream & read(token &)=0
Return next token from stream.