Loading...
Searching...
No Matches
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-2024 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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
35bool 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
99bool Foam::primitiveEntry::expandFunction
100(
101 const word& functionName,
102 const dictionary& dict,
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 {
140 {
141 if (depth >= 0 && depth < 61)
142 {
143 balanced &= ~(1u << depth); // clear bit
144 }
145 ++depth;
146 }
147 break;
148
150 {
151 if (depth >= 0 && depth < 61)
152 {
153 balanced |= (1u << depth); // set bit
154 }
155 ++depth;
156 }
157 break;
159 case token::END_LIST:
160 {
161 --depth;
162 if (depth < 0)
163 {
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 ITstream::add_tokens(std::move(tok)); // Add at tokenIndex
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
208 }
209
210 if (depth)
211 {
212 reportReadWarning(is, "Imbalanced brackets");
213 }
214
216 return tok.good();
217}
218
219
220void Foam::primitiveEntry::readEntry(const dictionary& dict, Istream& is)
221{
222 const label keywordLineNumber = is.lineNumber();
223
224 if (ITstream::empty())
225 {
227 }
229
230 if (read(dict, is)) // Read with 'lazy' appending
231 {
232 ITstream::resize(tokenIndex()); // Truncate to number tokens read
234 }
235 else
236 {
237 std::ostringstream os;
238 os << "ill defined primitiveEntry starting at keyword '"
239 << keyword() << '\''
240 << " on line " << keywordLineNumber
241 << " and ending at line " << is.lineNumber();
242
244 (
245 is,
246 os.str()
247 );
248 }
249}
250
251
252// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
253
255(
256 const keyType& key,
257 const dictionary& dict,
258 Istream& is
259)
260:
261 entry(key),
262 ITstream
263 (
264 static_cast<IOstreamOption>(is),
265 fileName::concat(is.name(), key, '/')
266 )
267{
268 readEntry(dict, is);
269}
270
271
275{}
276
277
278// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
279
280void Foam::primitiveEntry::write(Ostream& os, const bool contentsOnly) const
281{
282 if (!contentsOnly)
283 {
284 os.writeKeyword(keyword());
285 }
286
287 // Like FlatOutput::OutputAdaptor write()
288 // with open/close = '\0', separator = token::SPACE
289
290 bool started = false; // Separate from previous token?
291 for (const token& tok : *this)
292 {
293 if (started)
294 {
295 os << token::SPACE;
296 }
297 else
298 {
299 started = true;
300 }
301
302 // Output token with direct handling in Ostream(s),
303 // or use normal '<<' output operator
304 if (!os.write(tok))
305 {
306 os << tok;
307 }
308 }
309
310 if (!contentsOnly)
311 {
312 os.endEntry();
313 }
314}
315
316
317void Foam::primitiveEntry::write(Ostream& os) const
318{
319 this->write(os, false);
320}
321
322
323// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
324
325template<>
326Foam::Ostream& Foam::operator<<
327(
328 Ostream& os,
329 const InfoProxy<primitiveEntry>& iproxy
330)
331{
332 const auto& e = *iproxy;
333
334 e.print(os);
335
336 const label nPrintTokens = Foam::min(label(10), label(e.size()));
337
338 os << " primitiveEntry '" << e.keyword() << "' comprises ";
339
340 for (label i = 0; i < nPrintTokens; ++i)
341 {
342 os << nl << " " << e[i].info();
343 }
344
345 if (10 < e.size())
346 {
347 os << " ...";
348 }
349
350 os << endl;
351
352 return os;
353}
354
355
356// ************************************************************************* //
A simple container for options an IOstream can normally have.
label lineNumber() const noexcept
Const access to the current stream line number.
Definition IOstream.H:409
bool fatalCheck(const char *operation) const
Check IOstream status for given operation.
Definition IOstream.C:51
bool bad() const noexcept
True if stream is corrupted.
Definition IOstream.H:305
void add_tokens(const token &tok)
Copy append a token at the current tokenIndex, incrementing the index.
Definition ITstream.C:709
void seek(label pos) noexcept
Move tokenIndex to the specified position and adjust the stream status (open/good/eof ....
Definition ITstream.C:353
ITstream(const ITstream &is)
Copy construct.
Definition ITstream.C:148
A helper class for outputting values to Ostream.
Definition InfoProxy.H:49
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition Istream.H:60
virtual Istream & read(token &)=0
Return next token from stream.
void resize(const label len)
static const List< token > & null() noexcept
Definition List.H:138
virtual Ostream & write(const char c) override
Write character.
Definition OBJstream.C:69
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition Ostream.H:59
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
entry(const keyType &keyword)
Construct from keyword.
Definition entry.C:62
const keyType & keyword() const noexcept
Return keyword.
Definition entry.H:231
static void reportReadWarning(const IOstream &, const std::string &)
Report a read warning (on std::cerr).
Definition entry.C:41
static int disableFunctionEntries
Enable or disable use of function entries and variable expansions.
Definition entry.H:139
A class for handling file names.
Definition fileName.H:75
static bool execute(const dictionary &parentDict, primitiveEntry &thisEntry, Istream &is)
Execute in a primitiveEntry context, extracts token or line.
Definition evalEntry.C:243
static bool execute(const word &functionName, dictionary &parentDict, Istream &is)
Execute the functionEntry in a sub-dict context.
A class for handling keywords in dictionaries.
Definition keyType.H:69
primitiveEntry(const keyType &key)
Construct from keyword and no tokens.
virtual const fileName & name() const
Return the token stream name.
virtual void write(Ostream &os) const
Write.
virtual bool read(const dictionary &dict, Istream &is)
Read tokens from the given stream.
virtual const dictionary & dict() const
This entry is not a dictionary, calling this function generates a FatalError.
A token holds an item read from Istream.
Definition token.H:70
bool isPunctuation() const noexcept
Token is PUNCTUATION.
Definition tokenI.H:650
@ BEGIN_BLOCK
Begin block [isseparator].
Definition token.H:178
@ END_BLOCK
End block [isseparator].
Definition token.H:179
@ END_STATEMENT
End entry [isseparator].
Definition token.H:173
@ NULL_TOKEN
Nul character.
Definition token.H:141
@ BEGIN_LIST
Begin list [isseparator].
Definition token.H:174
@ END_LIST
End list [isseparator].
Definition token.H:175
@ SPACE
Space [isspace].
Definition token.H:144
punctuationToken pToken() const
Return punctuation character.
Definition tokenI.H:676
bool good() const noexcept
True if token is not UNDEFINED or ERROR.
Definition tokenI.H:584
A class for handling words, derived from Foam::string.
Definition word.H:66
#define SafeFatalIOErrorInFunction(ios, msg)
Report an error message using Foam::FatalIOError.
Definition error.H:662
OBJstream os(runTime.globalPath()/outputName)
#define FUNCTION_NAME
constexpr auto key(const Type &t) noexcept
Helper function to return the enum value.
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition int32.H:127
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
runTime write()
dictionary dict
volScalarField & e