primitiveEntry.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-2016 OpenFOAM Foundation
9  Copyright (C) 2017-2023 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 "dictionary.H"
31 #include "OSspecific.H"
32 #include "stringOps.H"
33 
34 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
35 
36 // Find the type/position of the ":-" or ":+" alternative values
37 // Returns 0, '-', '+' corresponding to not-found or ':-' or ':+'
38 static inline char findParameterAlternative
39 (
40  const std::string& s,
42  std::string::size_type endPos = std::string::npos
43 )
44 {
45  while (pos != std::string::npos)
46  {
47  pos = s.find(':', pos);
48  if (pos != std::string::npos)
49  {
50  if (pos < endPos)
51  {
52  // in-range: check for '+' or '-' following the ':'
53  const char altType = s[pos+1];
54  if (altType == '+' || altType == '-')
55  {
56  return altType;
57  }
58 
59  ++pos; // unknown/unsupported - continue at next position
60  }
61  else
62  {
63  // out-of-range: abort
64  pos = std::string::npos;
65  }
66  }
67  }
68 
69  return 0;
70 }
71 
72 
73 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
74 
75 bool Foam::primitiveEntry::expandVariable
76 (
77  const string& varName,
78  const dictionary& dict
79 )
80 {
81  char altType = 0; // Type ('-' or '+') for ":-" or ":+" alternatives
82  word expanded;
83  string altValue;
84 
85  // Any ${{ expr }} entries have been trapped and processed elsewhere
86 
87  if (varName[0] == token::BEGIN_BLOCK && varName.size() > 1)
88  {
89  // Replace content between {} with string expansion and
90  // handle ${parameter:-word} or ${parameter:+word}
91 
92  // Copy into a word without stripping
93  expanded.assign(varName, 1, varName.size()-2);
94 
95  // Substitute dictionary and environment variables.
96  // - Allow environment.
97  // - No empty substitutions.
98  // - No sub-dictionary lookups
99 
100  stringOps::inplaceExpand(expanded, dict, true, false, false);
101 
102  // Position of ":-" or ":+" alternative values
103  std::string::size_type altPos = 0;
104 
105  // Check for parameter:-word or parameter:+word
106  altType = findParameterAlternative(expanded, altPos);
107 
108  if (altType)
109  {
110  altValue = expanded.substr(altPos + 2);
111  expanded.erase(altPos);
112  }
113 
114  // Catch really bad expansions and let them die soon after.
115  // Eg, ${:-other} should not be allowed.
116  if (expanded.empty())
117  {
118  altType = 0;
119  altValue.clear();
120  }
121 
122  // Fallthrough for further processing
123  }
124 
125 
126  // Lookup variable name in the given dictionary WITHOUT pattern matching.
127  // Having a pattern match means that in this example:
128  // {
129  // internalField XXX;
130  // boundaryField { ".*" {YYY;} movingWall {value $internalField;}
131  // }
132  // The $internalField would be matched by the ".*" !!!
133 
134  // Recursive, non-patterns
135 
136  const word& lookupName = (expanded.empty() ? varName : expanded);
137 
138  const entry* eptr =
140 
141  if (!eptr)
142  {
143  // Not found - revert to environment variable
144  // and parse into a series of tokens.
145 
146  // We wish to fail if the environment variable returns
147  // an empty string and there is no alternative given.
148  //
149  // Always allow empty strings as alternative parameters,
150  // since the user provided them for a reason.
151 
152  string str(Foam::getEnv(lookupName));
153 
154  if (str.empty() ? (altType == '-') : (altType == '+'))
155  {
156  // Not found or empty: use ":-" alternative value
157  // Found and not empty: use ":+" alternative value
158  str = std::move(altValue);
159  }
160  else if (str.empty())
161  {
163  << "Illegal dictionary entry or environment variable name "
164  << lookupName << nl
165  << "Known dictionary entries: " << dict.toc() << nl
166  << exit(FatalIOError);
167 
168  return false;
169  }
170 
171  // Parse string into a series of tokens
172 
173  tokenList toks(ITstream::parse(str)); // ASCII
174 
175  ITstream::add_tokens(std::move(toks)); // Add at tokenIndex
176  }
177  else if (eptr->isDict())
178  {
179  // Found dictionary entry
180 
181  tokenList toks(eptr->dict().tokens());
182 
183  if (toks.empty() ? (altType == '-') : (altType == '+'))
184  {
185  // Not found or empty: use ":-" alternative value
186  // Found and not empty: use ":+" alternative value
187 
188  toks = ITstream::parse(altValue); // ASCII
189  }
190 
191  ITstream::add_tokens(std::move(toks)); // Add at tokenIndex
192  }
193  else
194  {
195  // Found primitive entry - copy tokens
196 
197  if (eptr->stream().empty() ? (altType == '-') : (altType == '+'))
198  {
199  // Not found or empty: use ":-" alternative value
200  // Found and not empty: use ":+" alternative value
201 
202  tokenList toks(ITstream::parse(altValue)); // ASCII
203 
204  ITstream::add_tokens(std::move(toks)); // Add at tokenIndex
205  }
206  else
207  {
208  ITstream::add_tokens(eptr->stream()); // Add at tokenIndex
209  }
210  }
212  return true;
213 }
214 
215 
216 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
217 
219 :
220  entry(key),
221  ITstream(Foam::zero{}, key)
222 {}
223 
224 
226 :
227  entry(key),
228  ITstream(key, tokenList(Foam::one{}, tok))
229 {}
230 
231 
232 Foam::primitiveEntry::primitiveEntry(const keyType& key, token&& tok)
233 :
234  entry(key),
235  ITstream(key, tokenList(Foam::one{}, std::move(tok)))
236 {}
237 
238 
240 (
241  const keyType& key,
242  const UList<token>& tokens
243 )
244 :
245  entry(key),
246  ITstream(key, tokens)
247 {}
248 
249 
251 (
252  const keyType& key,
253  List<token>&& tokens
254 )
255 :
256  entry(key),
257  ITstream(key, std::move(tokens))
258 {}
259 
260 
262 (
263  const keyType& key,
264  const ITstream& is
265 )
266 :
267  entry(key),
268  ITstream(is)
269 {
271 }
272 
273 
274 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
275 
277 {
278  ITstream& is = const_cast<primitiveEntry&>(*this);
279  is.rewind();
280  return is;
281 }
282 
283 
285 {
287  << "Attempt to return primitive entry " << info()
288  << " as a sub-dictionary"
289  << abort(FatalError);
290 
291  return dictionary::null;
292 }
293 
294 
296 {
298  << "Attempt to return primitive entry " << info()
299  << " as a sub-dictionary"
300  << abort(FatalError);
301 
302  return const_cast<dictionary&>(dictionary::null);
303 }
304 
305 
306 // ************************************************************************* //
void add_tokens(const token &tok)
Copy append a token at the current tokenIndex, incrementing the index.
Definition: ITstream.C:735
Begin block [isseparator].
Definition: token.H:165
A class for handling keywords in dictionaries.
Definition: keyType.H:66
entry(const keyType &keyword)
Construct from keyword.
Definition: entry.C:62
dictionary dict
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
static char findParameterAlternative(const std::string &s, std::string::size_type &pos, std::string::size_type endPos=std::string::npos)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
A token holds an item read from Istream.
Definition: token.H:65
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: POSIX.C:339
List< token > tokenList
List of token, used for dictionary primitive entry (for example)
Definition: tokenList.H:32
wordList toc() const
Return the table of contents.
Definition: dictionary.C:587
const entry * findScoped(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Search for a scoped entry (const access) with the given keyword.
Definition: dictionaryI.H:114
static tokenList parse(const UList< char > &input, IOstreamOption streamOpt=IOstreamOption())
Create token list by parsing the input character sequence until no good tokens remain.
Definition: ITstream.C:88
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read...
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
dimensionedScalar pos(const dimensionedScalar &ds)
static const dictionary null
An empty dictionary, which is also the parent for all dictionaries.
Definition: dictionary.H:474
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:68
errorManip< error > abort(error &err)
Definition: errorManip.H:139
virtual ITstream & stream() const
Return token stream for this primitive entry.
void inplaceExpand(std::string &s, const HashTable< string > &mapping, const char sigil='$')
Inplace expand occurrences of variables according to the mapping. Does not use environment values...
Definition: stringOps.C:718
virtual const fileName & name() const override
The name of the input token stream.
Definition: ITstream.H:276
virtual const dictionary & dict() const
This entry is not a dictionary, calling this function generates a FatalError.
static fileName concat(const std::string &s1, const std::string &s2, const char delim='/')
Join two strings with a path separator (&#39;/&#39; by default).
Definition: fileName.C:211
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:627
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition: zero.H:57
primitiveEntry(const keyType &key)
Construct from keyword and no tokens.
virtual void rewind() override
Rewind the stream so that it may be read again. Same as seek(0)
Definition: ITstream.C:729
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
An input stream of tokens.
Definition: ITstream.H:52
Namespace for OpenFOAM.
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:63
A class representing the concept of 1 (one) that can be used to avoid manipulating objects known to b...
Definition: one.H:56
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...