diff --git a/applications/test/dictionary/testDict b/applications/test/dictionary/testDict
index 5b27ede5d7..19020de7ed 100644
--- a/applications/test/dictionary/testDict
+++ b/applications/test/dictionary/testDict
@@ -10,7 +10,7 @@ FoamFile
version 2.0;
format ascii;
class dictionary;
- object testDict;
+ object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/test/dictionary/testDict2 b/applications/test/dictionary/testDict2
index 9d481de49a..52967f024d 100644
--- a/applications/test/dictionary/testDict2
+++ b/applications/test/dictionary/testDict2
@@ -10,7 +10,7 @@ FoamFile
version 2.0;
format ascii;
class dictionary;
- object testDict;
+ object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/test/dictionary/testDictAPI b/applications/test/dictionary/testDictAPI
index d0ae9a9a8c..4c4d56743c 100644
--- a/applications/test/dictionary/testDictAPI
+++ b/applications/test/dictionary/testDictAPI
@@ -10,7 +10,7 @@ FoamFile
version 2.0;
format ascii;
class dictionary;
- object testDict;
+ object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/test/dictionary/testDictCalc1 b/applications/test/dictionary/testDictCalc1
index 85dac5911e..5396d387c2 100644
--- a/applications/test/dictionary/testDictCalc1
+++ b/applications/test/dictionary/testDictCalc1
@@ -10,7 +10,7 @@ FoamFile
version 2.0;
format ascii;
class dictionary;
- object testDictCalc1;
+ object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/test/dictionary/testDictEval1 b/applications/test/dictionary/testDictEval1
index bd94dcab6b..13491110df 100644
--- a/applications/test/dictionary/testDictEval1
+++ b/applications/test/dictionary/testDictEval1
@@ -10,7 +10,7 @@ FoamFile
version 2.0;
format ascii;
class dictionary;
- object testDictEval1;
+ object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/test/dictionary/testDictEval2 b/applications/test/dictionary/testDictEval2
index d154bf7700..77cefec4c1 100644
--- a/applications/test/dictionary/testDictEval2
+++ b/applications/test/dictionary/testDictEval2
@@ -10,7 +10,7 @@ FoamFile
version 2.0;
format ascii;
class dictionary;
- object testDictEval1;
+ object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/test/dictionary/testDictEval3 b/applications/test/dictionary/testDictEval3
index 79bebc9c20..6c6ffe9b61 100644
--- a/applications/test/dictionary/testDictEval3
+++ b/applications/test/dictionary/testDictEval3
@@ -10,7 +10,7 @@ FoamFile
version 2.0;
format ascii;
class dictionary;
- object testDictEval1;
+ object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/test/dictionary/testDictEval4 b/applications/test/dictionary/testDictEval4
new file mode 100644
index 0000000000..81a4563ebc
--- /dev/null
+++ b/applications/test/dictionary/testDictEval4
@@ -0,0 +1,121 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| ========= | |
+| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
+| \\ / O peration | Version: v2012 |
+| \\ / A nd | Website: www.openfoam.com |
+| \\/ M anipulation | |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+ version 2.0;
+ format ascii;
+ class dictionary;
+ object dictionary;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Test expansion with negative signs
+
+value 0.5;
+
+radius 3;
+
+negValue -$value;
+
+select1 10;
+
+sqrt05 #eval{ sqrt(0.5) };
+
+vector ( -10 ${{-$sqrt05}} $value );
+
+corner ( ${{ -$radius*sqrt(0.5) }} 1 0 );
+
+corner2 ${{
+ vector(-${radius}*sqrt(0.5), ${radius}*sqrt(0.5), 2)
+}};
+
+
+// Just a future idea (2021-05-14) - does not yet work!
+#if 0
+corner3 #eval #{
+ variables ( "outer = $radius*sqrt(0.5)" );
+ vector(-outer, outer, 2)
+#};
+#endif
+
+
+// The brace-bracket #eval with multi-lines failed for v2012 and earlier
+
+corner2b #eval
+{
+ vector(-${radius}*sqrt(0.5), $radius*sqrt(0.5), 2)
+};
+
+corner2c #eval
+${{
+ vector(-${radius}*sqrt(0.5), $radius*sqrt(0.5), 2)
+}};
+
+
+longSlurp #eval
+{
+ // This is actually a very simple expression
+ 1 + 2
+// With a long comment that is stripped out
+// during reading anyhow.
+};
+
+
+longVariable
+${{
+ // This is actually a very simple expression in variable syntax
+ 1 + 2
+/*
+// With a long comment that is stripped out
+// during reading anyhow.
+*/
+}};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Geometric parameters
+rxo 2;
+ryo 3;
+rzo 4;
+
+// Geometric parameters
+outerRadius 1;
+innerRatio 0.75;
+
+geometry
+{
+ sphere
+ {
+ type sphere;
+ origin (0 0 0);
+ radius ($rxo $ryo $rzo);
+ }
+
+ innerSphere
+ {
+ $sphere
+
+ // Different solutions to the same problem
+ radius_v1
+ (
+ ${{ $innerRatio*$rxo }}
+ ${{ $innerRatio*$ryo }}
+ ${{ $innerRatio*$rzo }}
+ );
+
+ radius_v2 #eval{ $innerRatio*vector($rxo, $ryo, $rzo) };
+ radius_v3 ${{ $innerRatio*$[(vector) ../sphere/radius] }};
+
+ // Inplace overwrite the same value
+ radius ${{ $innerRatio*$[(vector) radius] }};
+ }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/dictionary/testDictList b/applications/test/dictionary/testDictList
index a8c7197356..08cafe93c0 100644
--- a/applications/test/dictionary/testDictList
+++ b/applications/test/dictionary/testDictList
@@ -10,7 +10,7 @@ FoamFile
version 2.0;
format ascii;
class dictionary;
- object testDict;
+ object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Test some parsing
diff --git a/applications/test/dictionary/testDictRegex b/applications/test/dictionary/testDictRegex
index 15aae07200..3970712478 100644
--- a/applications/test/dictionary/testDictRegex
+++ b/applications/test/dictionary/testDictRegex
@@ -10,7 +10,7 @@ FoamFile
version 2.0;
format ascii;
class dictionary;
- object testDictRegex;
+ object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#inputMode merge
diff --git a/applications/test/dictionary/testPrimitiveEntry b/applications/test/dictionary/testPrimitiveEntry
index f4bffb9cf8..2596012243 100644
--- a/applications/test/dictionary/testPrimitiveEntry
+++ b/applications/test/dictionary/testPrimitiveEntry
@@ -10,7 +10,7 @@ FoamFile
version 2.0;
format ascii;
class dictionary;
- object testDict;
+ object dictionary;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/test/dictionary/testSubkeyword b/applications/test/dictionary/testSubkeyword
index 21f3579f69..c995e0040f 100644
--- a/applications/test/dictionary/testSubkeyword
+++ b/applications/test/dictionary/testSubkeyword
@@ -10,7 +10,7 @@ FoamFile
version 2.0;
format ascii;
class dictionary;
- object testDict;
+ object dictionary;
note "test with foamDictionary -expand";
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/test/dictionary3/Make/files b/applications/test/dictionary3/Make/files
new file mode 100644
index 0000000000..bdcfe73b04
--- /dev/null
+++ b/applications/test/dictionary3/Make/files
@@ -0,0 +1,3 @@
+Test-dictionary3.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-dictionary3
diff --git a/applications/test/dictionary3/Make/options b/applications/test/dictionary3/Make/options
new file mode 100644
index 0000000000..18e6fe47af
--- /dev/null
+++ b/applications/test/dictionary3/Make/options
@@ -0,0 +1,2 @@
+/* EXE_INC = */
+/* EXE_LIBS = */
diff --git a/applications/test/dictionary3/Test-dictionary3.C b/applications/test/dictionary3/Test-dictionary3.C
new file mode 100644
index 0000000000..11c1835b28
--- /dev/null
+++ b/applications/test/dictionary3/Test-dictionary3.C
@@ -0,0 +1,78 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2021 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+Application
+ Test-dictionary3
+
+Description
+ Test expressions and re-expansions
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "IOstreams.H"
+#include "dictionary.H"
+#include "vector.H"
+#include "StringStream.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main(int argc, char *argv[])
+{
+ argList::noParallel();
+
+ {
+ IStringStream is
+ (
+ "value 10;"
+ "scalar1 $value;"
+ "scalar2 -$value;"
+
+ // Use #eval expansion entirely
+ "vector1 ${{vector($value, -$value, $value)}};"
+ "vector2 ($value -$value $value);"
+ );
+
+ dictionary dict(is);
+
+ Info<< "input dictionary:" << dict << nl;
+
+ Info<< "value: " << dict.get("value") << nl;
+
+ Info<< "scalar1: " << dict.get("scalar1") << nl;
+ Info<< "scalar2: " << dict.get("scalar2") << nl;
+
+ Info<< "vector1: " << dict.get("vector1") << nl;
+ Info<< "vector2: " << dict.get("vector2") << nl;
+ }
+
+ return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/namedDictionary/Make/files b/applications/test/namedDictionary/Make/files
new file mode 100644
index 0000000000..7877feb85b
--- /dev/null
+++ b/applications/test/namedDictionary/Make/files
@@ -0,0 +1,3 @@
+Test-namedDictionary.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-namedDictionary
diff --git a/applications/test/namedDictionary/Make/options b/applications/test/namedDictionary/Make/options
new file mode 100644
index 0000000000..18e6fe47af
--- /dev/null
+++ b/applications/test/namedDictionary/Make/options
@@ -0,0 +1,2 @@
+/* EXE_INC = */
+/* EXE_LIBS = */
diff --git a/applications/test/namedDictionary/Test-namedDictionary.C b/applications/test/namedDictionary/Test-namedDictionary.C
new file mode 100644
index 0000000000..fc7e418547
--- /dev/null
+++ b/applications/test/namedDictionary/Test-namedDictionary.C
@@ -0,0 +1,84 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2021 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+Application
+ Test-namedDictionary
+
+Description
+ Test handling of keyType/dictionary
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "IOstreams.H"
+#include "IOobject.H"
+#include "IFstream.H"
+#include "namedDictionary.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main(int argc, char *argv[])
+{
+ argList::noBanner();
+ argList::noParallel();
+ argList::addArgument("file1 .. fileN");
+ argList args(argc, argv, false, true);
+
+ if (args.size() <= 1)
+ {
+ InfoErr<< "Provide a file or files to test" << nl;
+ }
+ else
+ {
+ for (label argi=1; argi < args.size(); ++argi)
+ {
+ const auto dictFile = args.get(argi);
+ IFstream ifs(dictFile);
+
+ dictionary dict(ifs);
+
+ IOobject::writeDivider(Info) << nl;
+
+ for (const entry& dEntry : dict)
+ {
+ if (!dEntry.isStream())
+ {
+ continue;
+ }
+ Info<< "input: " << dEntry << nl;
+ List list(dEntry.stream());
+ Info<< "list: " << list << nl;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/namedDictionary/testDict1 b/applications/test/namedDictionary/testDict1
new file mode 100644
index 0000000000..99c1960109
--- /dev/null
+++ b/applications/test/namedDictionary/testDict1
@@ -0,0 +1,83 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| ========= | |
+| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
+| \\ / O peration | Version: v2012 |
+| \\ / A nd | Website: www.openfoam.com |
+| \\/ M anipulation | |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+ version 2.0;
+ format ascii;
+ class dictionary;
+ object dictionary;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+entry1
+(
+ value1
+ value2 ; // spurious trailing ';' is removed
+ this { correct true; }
+
+ { } // Empty everything == ignore
+
+ { anonymous true; }
+);
+
+
+actions1
+(
+ starting
+ {
+ name self;
+ type faceSet;
+ action new;
+ source something;
+ }
+
+ {
+ name self;
+ type faceSet;
+ action subset;
+ source something;
+ }
+);
+
+
+actions2
+(
+ {
+ name self;
+ type faceSet;
+ action new;
+ source something;
+ }
+
+ {
+ name self;
+ type faceSet;
+ action subset;
+ source something;
+ }
+);
+
+actions3
+(
+ {
+ name self;
+ type faceSet;
+ action new;
+ source something;
+ }
+
+ subset
+ {
+ name self;
+ type faceSet;
+ action subset;
+ source something;
+ }
+);
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/test/splitFunctionArgs/Make/files b/applications/test/splitFunctionArgs/Make/files
new file mode 100644
index 0000000000..5bb22f6261
--- /dev/null
+++ b/applications/test/splitFunctionArgs/Make/files
@@ -0,0 +1,3 @@
+Test-splitFunctionArgs.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-splitFunctionArgs
diff --git a/applications/test/splitFunctionArgs/Make/options b/applications/test/splitFunctionArgs/Make/options
new file mode 100644
index 0000000000..18e6fe47af
--- /dev/null
+++ b/applications/test/splitFunctionArgs/Make/options
@@ -0,0 +1,2 @@
+/* EXE_INC = */
+/* EXE_LIBS = */
diff --git a/applications/test/splitFunctionArgs/Test-splitFunctionArgs.C b/applications/test/splitFunctionArgs/Test-splitFunctionArgs.C
new file mode 100644
index 0000000000..8deaf6b5d0
--- /dev/null
+++ b/applications/test/splitFunctionArgs/Test-splitFunctionArgs.C
@@ -0,0 +1,155 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2021 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+Application
+ Test-splitFunctionArgs
+
+Description
+ Test splitting of function name args
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "IOstreams.H"
+#include "IOobject.H"
+#include "IFstream.H"
+#include "dictionary.H"
+#include "stringOps.H"
+#include "Tuple2.H"
+
+using namespace Foam;
+
+// Split out function name and any arguments
+// - use as per functionObjectList
+void testFunctionNameAndArgsSplit(const std::string& line)
+{
+ word funcName;
+ wordRes args;
+ List> namedArgs;
+
+ const auto lbracket = line.find('(');
+ if (lbracket == std::string::npos)
+ {
+ funcName = word::validate(line);
+ // No args
+ }
+ else
+ {
+ funcName = word::validate(line.substr(0, lbracket));
+ std::string params;
+
+ const auto rbracket = line.rfind(')');
+ if (rbracket != std::string::npos && lbracket < rbracket)
+ {
+ params = line.substr(lbracket+1, (rbracket - lbracket - 1));
+ }
+ else
+ {
+ params = line.substr(lbracket+1);
+ }
+
+ Info<<"parsing: " << params << nl;
+
+ stringOps::splitFunctionArgs(params, args, namedArgs);
+ }
+
+ Info<< nl
+ << line << nl
+ << "function: <" << funcName << '>' << nl
+ << " args: " << args << nl
+ << " named: " << namedArgs << nl;
+}
+
+
+// Split out any arguments
+void testArgsSplit(const std::string& line)
+{
+ wordRes args;
+ List> namedArgs;
+ stringOps::splitFunctionArgs(line, args, namedArgs);
+
+ Info<< nl
+ << line << nl
+ << " args: " << args << nl
+ << " named: " << namedArgs << nl;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main(int argc, char *argv[])
+{
+ argList::noBanner();
+ argList::noParallel();
+ argList::addArgument("file1 .. fileN");
+ argList args(argc, argv, false, true);
+
+ if (args.size() <= 1)
+ {
+ InfoErr<< "Provide a file or files to test" << nl;
+ }
+ else
+ {
+ for (label argi=1; argi < args.size(); ++argi)
+ {
+ IOobject::writeDivider(Info);
+
+ const auto inputFile = args.get(argi);
+ IFstream is(inputFile);
+
+ string line;
+ while (is.getLine(line))
+ {
+ if (line.empty() || line[0] == '#')
+ {
+ continue;
+ }
+
+ if (line.starts_with("function:"))
+ {
+ auto trim = line.find(':');
+ ++trim;
+ while (isspace(line[trim]))
+ {
+ ++trim;
+ }
+
+ line.erase(0, trim);
+ testFunctionNameAndArgsSplit(line);
+ }
+ else
+ {
+ testArgsSplit(line);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/splitFunctionArgs/testNames1 b/applications/test/splitFunctionArgs/testNames1
new file mode 100644
index 0000000000..8d771f5e5d
--- /dev/null
+++ b/applications/test/splitFunctionArgs/testNames1
@@ -0,0 +1,47 @@
+# -----------------------------------------------------------------------------
+# Test names for splitting. Comment character as per -*- sh -*- mode
+#
+# Prefix with "function: " to test with function name splitting
+
+function: basic
+
+function: func1( a , b );
+
+function: func2(a, value=10);
+
+# discard or flag bad/missing parameters?
+function: func3(a , , , value=10);
+
+function: func4();
+
+function: func5( abc );
+
+start=1, end=2
+
+start=1, end=2,
+
+start=100, end= 200, abc
+
+value=100
+
+start=1, end=2
+
+origin=(0 0 0), scale=2, normal=(0 0 1)
+
+
+# Canonical with named args
+function: patchAverage(patch=inlet, p)
+
+# Canonical with unnamed and named args
+function: patchAverage(other, patch=inlet, pval)
+
+
+function: patchAverage(patch=(inlet|outlet), p)
+
+# General
+(a, b)
+
+allow=(inlet|outlet), deny=false, regular(value)
+
+
+# -----------------------------------------------------------------------------
diff --git a/applications/utilities/mesh/manipulation/topoSet/topoSet.C b/applications/utilities/mesh/manipulation/topoSet/topoSet.C
index 162fd3fd10..6e590a82bb 100644
--- a/applications/utilities/mesh/manipulation/topoSet/topoSet.C
+++ b/applications/utilities/mesh/manipulation/topoSet/topoSet.C
@@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
- Copyright (C) 2018-2020 OpenCFD Ltd.
+ Copyright (C) 2018-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@@ -47,6 +47,7 @@ Description
#include "faceZoneSet.H"
#include "pointZoneSet.H"
#include "IOdictionary.H"
+#include "namedDictionary.H"
using namespace Foam;
@@ -237,7 +238,7 @@ int main(int argc, char *argv[])
IOdictionary topoSetDict(dictIO);
// Read set construct info from dictionary
- PtrList actions(topoSetDict.lookup("actions"));
+ List actionEntries(topoSetDict.lookup("actions"));
forAll(timeDirs, timeI)
{
@@ -248,8 +249,13 @@ int main(int argc, char *argv[])
meshReadUpdate(mesh);
// Execute all actions
- for (const dictionary& dict : actions)
+ for (const namedDictionary& actionEntry : actionEntries)
{
+ const dictionary& dict = actionEntry.dict();
+ if (dict.empty())
+ {
+ continue;
+ }
const word setName(dict.get("name"));
const word setType(dict.get("type"));
diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files
index 2bfb23509a..cd25b075df 100644
--- a/src/OpenFOAM/Make/files
+++ b/src/OpenFOAM/Make/files
@@ -145,6 +145,7 @@ $(strings)/parsing/genericRagelLemonDriver.C
$(strings)/stringOps/stringOps.C
$(strings)/stringOps/stringOpsEvaluate.C
$(strings)/stringOps/stringOpsSort.C
+$(strings)/stringOps/stringOpsSplit.C
expr = expressions
$(expr)/exprEntry/expressionEntry.C
@@ -275,7 +276,9 @@ $(dictionary)/dictionaryIO.C
$(dictionary)/dictionarySearch.C
$(dictionary)/dictionaryCompat.C
+/* Additional helpers */
$(dictionary)/dictionaryContent/dictionaryContent.C
+$(dictionary)/namedDictionary/namedDictionary.C
entry = $(dictionary)/entry
$(entry)/entry.C
diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.C b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.C
index eed1e261cb..f999a3f093 100644
--- a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.C
+++ b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.C
@@ -218,8 +218,8 @@ Foam::Istream& Foam::UIPstream::read(token& t)
case token::COLON :
case token::COMMA :
case token::ASSIGN :
- case token::ADD :
- case token::SUBTRACT :
+ case token::PLUS :
+ case token::MINUS :
case token::MULTIPLY :
case token::DIVIDE :
{
@@ -227,12 +227,12 @@ Foam::Istream& Foam::UIPstream::read(token& t)
return *this;
}
- // Word/directive
+ // The word-variants
case token::tokenType::WORD :
case token::tokenType::DIRECTIVE :
{
word val;
- if (read(val))
+ if (readStringFromBuffer(val))
{
if (token::compound::isCompound(val))
{
@@ -251,13 +251,14 @@ Foam::Istream& Foam::UIPstream::read(token& t)
return *this;
}
- // String types
+ // The string-variants
case token::tokenType::STRING :
+ case token::tokenType::EXPRESSION :
case token::tokenType::VARIABLE :
case token::tokenType::VERBATIM :
{
string val;
- if (read(val))
+ if (readStringFromBuffer(val))
{
t = std::move(val);
t.setType(token::tokenType(c));
diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.C b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.C
index f550056ca0..5480f63a73 100644
--- a/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.C
+++ b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.C
@@ -202,14 +202,19 @@ bool Foam::UOPstream::write(const token& tok)
return true;
}
+ // The word-variants
+ case token::tokenType::WORD :
case token::tokenType::DIRECTIVE :
{
- writeToBuffer(char(token::tokenType::DIRECTIVE));
+ writeToBuffer(char(tok.type()));
writeStringToBuffer(tok.wordToken());
return true;
}
+ // The string-variants
+ case token::tokenType::STRING :
+ case token::tokenType::EXPRESSION :
case token::tokenType::VARIABLE :
case token::tokenType::VERBATIM :
{
diff --git a/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C b/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C
index d1c4adc93d..bdb22307ae 100644
--- a/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C
+++ b/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.C
@@ -30,6 +30,7 @@ License
#include "int.H"
#include "token.H"
#include
+#include
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -42,14 +43,14 @@ namespace
{
// Convert a single character to a word with length 1
-inline static Foam::word charToWord(char c)
+inline Foam::word charToWord(char c)
{
return Foam::word(std::string(1, c), false);
}
// Permit slash-scoping of entries
-static inline bool validVariableChar(char c)
+inline bool validVariableChar(char c)
{
return (Foam::word::valid(c) || c == '/');
}
@@ -59,23 +60,51 @@ static inline bool validVariableChar(char c)
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
+bool Foam::ISstream::seekCommentEnd_Cstyle()
+{
+ // Search for end of C-style comment - "*/"
+
+ // Can use getLine(nullptr, '*') in the logic,
+ // but written out looks less obscure
+
+ char c = 0;
+ bool star = false;
+
+ while (get(c))
+ {
+ if (c == '*')
+ {
+ star = true;
+ }
+ else if (star)
+ {
+ star = false;
+ if (c == '/')
+ {
+ // Matched "*/"
+ return true;
+ }
+ }
+ }
+
+ // Exhausted stream without finding "*/" sequence
+ return false;
+}
+
+
char Foam::ISstream::nextValid()
{
char c = 0;
- while (true)
+ // Get next non-whitespace character
+ while (get(c))
{
- // Get next non-whitespace character
- while (get(c) && isspace(c))
- {}
-
- // Return if stream is bad - ie, previous get() failed
- if (bad() || isspace(c))
+ if (isspace(c))
{
- return 0;
+ continue;
}
- // Is this the start of a C/C++ comment?
+ // Check if this starts a C/C++ comment
if (c == '/')
{
if (!get(c))
@@ -86,37 +115,15 @@ char Foam::ISstream::nextValid()
if (c == '/')
{
- // C++ style single-line comment - skip through past end-of-line
- while (get(c) && c != '\n')
- {}
+ // C++ comment: discard through newline
+ (void) getLine(nullptr, '\n');
}
else if (c == '*')
{
- // Within a C-style comment
- while (true)
+ // C-style comment: discard through to "*/" ending
+ if (!seekCommentEnd_Cstyle())
{
- // Search for end of C-style comment - '*/'
- if (get(c) && c == '*')
- {
- if (get(c))
- {
- if (c == '/')
- {
- // matched '*/'
- break;
- }
- else if (c == '*')
- {
- // check again
- putback(c);
- }
- }
- }
-
- if (!good())
- {
- return 0;
- }
+ return 0;
}
}
else
@@ -137,28 +144,261 @@ char Foam::ISstream::nextValid()
}
-void Foam::ISstream::readWordToken(token& t)
+// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
+
+namespace Foam
{
- word val;
- if (read(val).bad())
+
+// Read a verbatim string (excluding block delimiters),
+// continuing until a closing "#}" has been found.
+//
+// The leading "#{" removed from stream prior to calling.
+static ISstream& readVerbatim
+(
+ ISstream& is,
+ std::string& str
+)
+{
+ constexpr const unsigned bufLen = 8000;
+ static char buf[bufLen];
+
+ unsigned nChar = 0;
+ char c;
+
+ str.clear();
+ while (is.get(c))
{
- t.setBad();
- }
- else if (token::compound::isCompound(val))
- {
- t = token::compound::New(val, *this).ptr();
- }
- else
- {
- t = std::move(val); // Move contents to token
+ if (c == token::HASH)
+ {
+ char nextC;
+ is.get(nextC);
+ if (nextC == token::END_BLOCK)
+ {
+ // Found closing "#}" sequence
+ str.append(buf, nChar);
+ return is;
+ }
+ else
+ {
+ // Re-analyze the character
+ is.putback(nextC);
+ }
+ }
+
+ buf[nChar++] = c;
+ if (nChar == bufLen) // Flush full buffer
+ {
+ str.append(buf, nChar);
+ nChar = 0;
+ }
}
+
+
+ // Abnormal exit of the loop
+ str.append(buf, nChar); // Finalize pending content
+ strncpy(buf, str.c_str(), errLen);
+ buf[errLen] = '\0';
+
+ FatalIOErrorInFunction(is)
+ << "Problem while reading verbatim \"" << buf
+ << "...\" [after " << str.length() << " chars]\n"
+ << exit(FatalIOError);
+
+ return is;
}
+// Read a variable or expression.
+// Handles "$var" and "${var}" forms, permits '/' scoping character.
+// Also handles "${{expr}}".
+//
+// Return the token type or ERROR
+//
+// The leading "${" or "$c" removed from stream prior to calling.
+static token::tokenType readVariable
+(
+ ISstream& is,
+ std::string& str,
+ char c // Next character after '$'
+)
+{
+ constexpr const unsigned bufLen = 1024;
+ static char buf[bufLen];
+
+ token::tokenType tokType(token::tokenType::VARIABLE);
+
+ // The first two characters are known:
+ buf[0] = token::DOLLAR;
+ buf[1] = c;
+
+ unsigned nChar = 2; // Starts with two characters
+ unsigned depth = 0; // Depth of {..} nesting
+
+ str.clear();
+ if (c == token::BEGIN_BLOCK)
+ {
+ // Processing '${variable}' or '${{expr}}'
+ ++depth;
+
+ int lookahead = is.peek();
+ if (lookahead == token::BEGIN_BLOCK)
+ {
+ // Looks like '${{expr...'
+ tokType = token::tokenType::EXPRESSION;
+ }
+ else if (lookahead == token::END_BLOCK)
+ {
+ // Looks like '${}'
+ IOWarningInFunction(is)
+ << "Ignoring empty ${}" << endl;
+ return token::tokenType::ERROR;
+ }
+
+ while (is.get(c))
+ {
+ buf[nChar++] = c;
+
+ if (c == token::BEGIN_BLOCK)
+ {
+ ++depth;
+ }
+ else if (c == token::END_BLOCK)
+ {
+ --depth;
+ if (!depth)
+ {
+ // Found closing '}' character
+ str.append(buf, nChar);
+ return tokType;
+ }
+ }
+ else if (c == '/' && tokType == token::tokenType::EXPRESSION)
+ {
+ // Strip C/C++ comments from expressions
+ // Note: could also peek instead of get/putback
+
+ if (!is.get(c))
+ {
+ break; // Premature end of stream
+ }
+ else if (c == '/')
+ {
+ --nChar; // Remove initial '/' from buffer
+
+ // C++ comment: discard through newline
+ (void) is.getLine(nullptr, '\n');
+ }
+ else if (c == '*')
+ {
+ --nChar; // Remove initial '/' from buffer
+
+ // C-style comment: seek "*/" ending
+ if (!is.seekCommentEnd_Cstyle())
+ {
+ break; // Premature end of stream
+ }
+ }
+ else
+ {
+ // Re-analyze the character
+ is.putback(c);
+ }
+ }
+
+ if (nChar == bufLen) // Flush full buffer
+ {
+ str.append(buf, nChar);
+ nChar = 0;
+ }
+ }
+
+
+ // Abnormal exit of the loop
+
+ str.append(buf, nChar); // Finalize pending content
+ strncpy(buf, str.c_str(), errLen);
+ buf[errLen] = '\0';
+
+ FatalIOErrorInFunction(is)
+ << "stream terminated while reading variable '" << buf
+ << "...' [after " << str.length() << " chars]\n"
+ << exit(FatalIOError);
+
+ return token::tokenType::ERROR;
+ }
+ else if (validVariableChar(c))
+ {
+ // Processing '$variable'
+
+ while (is.get(c))
+ {
+ if (!validVariableChar(c))
+ {
+ is.putback(c);
+ break;
+ }
+
+ if (c == token::BEGIN_LIST)
+ {
+ ++depth;
+ }
+ else if (c == token::END_LIST)
+ {
+ if (!depth)
+ {
+ // Closed ')' without opening '(':
+ // - don't consider it part of our input
+ is.putback(c);
+ break;
+ }
+ --depth;
+ }
+
+ buf[nChar++] = c;
+ if (nChar == bufLen) // Flush full buffer
+ {
+ str.append(buf, nChar);
+ nChar = 0;
+ }
+ }
+
+ str.append(buf, nChar); // Finalize pending content
+
+ if (depth)
+ {
+ strncpy(buf, str.c_str(), errLen);
+ buf[errLen] = '\0';
+
+ IOWarningInFunction(is)
+ << "Missing " << depth
+ << " closing ')' while parsing" << nl << nl
+ << buf << endl;
+ }
+
+ return tokType;
+ }
+ else
+ {
+ // Invalid character. Terminate string (for message)
+
+ buf[nChar--] = '\0';
+
+ IOWarningInFunction(is)
+ << "Ignoring bad variable name: " << buf << nl << endl;
+ }
+
+ return token::tokenType::ERROR;
+}
+
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
+
Foam::Istream& Foam::ISstream::read(token& t)
{
- constexpr const unsigned maxLen = 128; // Max length for labels/scalars
- static char buf[maxLen];
+ constexpr const unsigned bufLen = 128; // Max length for labels/scalars
+ static char buf[bufLen];
// Return the put back token if it exists
if (Istream::getBack(t))
@@ -199,8 +439,8 @@ Foam::Istream& Foam::ISstream::read(token& t)
case token::COLON :
case token::COMMA :
case token::ASSIGN :
- case token::ADD :
- // NB: token::SUBTRACT handled later as the possible start of a Number
+ case token::PLUS :
+ // NB: token::MINUS handled later as the possible start of a Number
case token::MULTIPLY :
case token::DIVIDE :
{
@@ -209,7 +449,7 @@ Foam::Istream& Foam::ISstream::read(token& t)
}
// String: enclosed by double quotes.
- case token::BEGIN_STRING :
+ case token::DQUOTE :
{
putback(c);
@@ -226,21 +466,21 @@ Foam::Istream& Foam::ISstream::read(token& t)
return *this;
}
- // Possible verbatim string or dictionary functionEntry
+ // Verbatim string '#{ .. #}' or dictionary '#directive'
case token::HASH :
{
char nextC;
- if (read(nextC).bad())
- {
- // Return lone '#' as word
- t = charToWord(c);
- }
- else if (nextC == token::BEGIN_BLOCK)
+ int lookahead = peek();
+
+ if (lookahead == token::BEGIN_BLOCK)
{
// Verbatim string: #{ ... #}
+ // Token stored without the surrounding delimiters
+
+ (void) get(nextC); // Discard '{' lookahead
string val;
- if (readVerbatim(val).bad())
+ if (readVerbatim(*this, val).bad())
{
t.setBad();
}
@@ -250,9 +490,14 @@ Foam::Istream& Foam::ISstream::read(token& t)
t.setType(token::tokenType::VERBATIM);
}
}
- else
+ else if (read(nextC).bad())
{
- // Word beginning with '#'. Eg, "#include"
+ // Return lone '#' as word
+ t = charToWord(c);
+ }
+ else if (word::valid(nextC))
+ {
+ // Directive (wordToken) beginning with '#'. Eg, "#include"
// Put back both so that '#...' is included in the directive
putback(nextC);
@@ -269,34 +514,44 @@ Foam::Istream& Foam::ISstream::read(token& t)
t.setType(token::tokenType::DIRECTIVE);
}
}
+ else
+ {
+ // '#' followed by non-word. Just ignore leading '#'?
+ putback(nextC);
+
+ IOWarningInFunction(*this)
+ << "Invalid sequence #" << char(nextC)
+ << " ... ignoring the leading '#'" << nl << endl;
+ }
return *this;
}
- // Dictionary variable (as rvalue)
+ // Dictionary variable or ${{ expression }}
case token::DOLLAR :
{
char nextC;
if (read(nextC).bad())
{
- // Return lone '$' as word
+ // Return lone '$' as word. Could also ignore
t = charToWord(c);
}
else
{
- // Put back both so that '$...' is included in the variable
- putback(nextC);
- putback(c);
+ // NB: the parser is slightly generous here.
+ // It will also accept '$ {' as input.
+ // - to be revisited (2021-05-17)
string val;
- if (readVariable(val).bad())
+ token::tokenType tokType = readVariable(*this, val, nextC);
+ if (tokType == token::tokenType::ERROR)
{
t.setBad();
}
else
{
t = std::move(val); // Move contents to token
- t.setType(token::tokenType::VARIABLE);
+ t.setType(tokType);
}
}
@@ -340,14 +595,14 @@ Foam::Istream& Foam::ISstream::read(token& t)
}
buf[nChar++] = c;
- if (nChar == maxLen)
+ if (nChar == bufLen)
{
// Runaway argument - avoid buffer overflow
- buf[maxLen-1] = '\0';
+ buf[bufLen-1] = '\0';
FatalIOErrorInFunction(*this)
- << "number '" << buf << "...'\n"
- << " is too long (max. " << maxLen << " characters)"
+ << "Number '" << buf << "...'\n"
+ << " is too long (max. " << bufLen << " characters)"
<< exit(FatalIOError);
t.setBad();
@@ -368,7 +623,7 @@ Foam::Istream& Foam::ISstream::read(token& t)
if (nChar == 1 && buf[0] == '-')
{
// A single '-' is punctuation
- t = token::punctuationToken(token::SUBTRACT);
+ t = token::punctuationToken(token::MINUS);
}
else if (labelVal && Foam::read(buf, labelVal))
{
@@ -397,7 +652,20 @@ Foam::Istream& Foam::ISstream::read(token& t)
default:
{
putback(c);
- readWordToken(t);
+
+ word val;
+ if (read(val).bad())
+ {
+ t.setBad();
+ }
+ else if (token::compound::isCompound(val))
+ {
+ t = token::compound::New(val, *this).ptr();
+ }
+ else
+ {
+ t = std::move(val); // Move contents to token
+ }
return *this;
}
@@ -414,20 +682,22 @@ Foam::Istream& Foam::ISstream::read(char& c)
Foam::Istream& Foam::ISstream::read(word& str)
{
- constexpr const unsigned maxLen = 1024;
- static char buf[maxLen];
+ constexpr const unsigned bufLen = 1024;
+ static char buf[bufLen];
unsigned nChar = 0;
- unsigned depth = 0; // Track depth of (..) nesting
+ unsigned depth = 0; // Depth of (..) nesting
char c;
- while
- (
- (nChar < maxLen)
- && get(c)
- && word::valid(c)
- )
+ str.clear();
+ while (get(c))
{
+ if (!word::valid(c))
+ {
+ putback(c);
+ break;
+ }
+
if (c == token::BEGIN_LIST)
{
++depth;
@@ -436,42 +706,40 @@ Foam::Istream& Foam::ISstream::read(word& str)
{
if (!depth)
{
- break; // Closed ')' without an opening '(' ? ... stop
+ // Closed ')' without opening '(':
+ // - don't consider it part of our input
+ putback(c);
+ break;
}
--depth;
}
buf[nChar++] = c;
+ if (nChar == bufLen) // Flush full buffer
+ {
+ str.append(buf, nChar);
+ nChar = 0;
+ }
}
- if (nChar >= maxLen)
- {
- buf[errLen] = '\0';
-
- FatalIOErrorInFunction(*this)
- << "word '" << buf << "...'\n"
- << " is too long (max. " << maxLen << " characters)"
- << exit(FatalIOError);
-
- return *this;
- }
-
- buf[nChar] = '\0'; // Terminate string
+ str.append(buf, nChar); // Finalize pending content
if (bad())
{
// Could probably skip this check
+
+ strncpy(buf, str.c_str(), errLen);
buf[errLen] = '\0';
FatalIOErrorInFunction(*this)
- << "Problem while reading word '" << buf << "...' after "
- << nChar << " characters\n"
+ << "Problem while reading word '" << buf
+ << "...' [after " << str.length() << " chars]\n"
<< exit(FatalIOError);
return *this;
}
- if (nChar == 0)
+ if (str.empty())
{
FatalIOErrorInFunction(*this)
<< "Invalid first character found : " << c
@@ -479,25 +747,25 @@ Foam::Istream& Foam::ISstream::read(word& str)
}
else if (depth)
{
+ strncpy(buf, str.c_str(), errLen);
+ buf[errLen] = '\0';
+
IOWarningInFunction(*this)
<< "Missing " << depth
<< " closing ')' while parsing" << nl << nl
<< buf << nl << endl;
}
- // Finalize: content already validated, assign without additional checks.
- str.assign(buf, nChar);
- putback(c);
-
return *this;
}
Foam::Istream& Foam::ISstream::read(string& str)
{
- constexpr const unsigned maxLen = 1024;
- static char buf[maxLen];
+ constexpr const unsigned bufLen = 1024;
+ static char buf[bufLen];
+ unsigned nChar = 0;
char c;
if (!get(c))
@@ -510,7 +778,7 @@ Foam::Istream& Foam::ISstream::read(string& str)
}
// Note, we could also handle single-quoted strings here (if desired)
- if (c != token::BEGIN_STRING)
+ if (c != token::DQUOTE)
{
FatalIOErrorInFunction(*this)
<< "Incorrect start of string character found : " << c
@@ -519,26 +787,25 @@ Foam::Istream& Foam::ISstream::read(string& str)
return *this;
}
- unsigned nChar = 0;
+ str.clear();
bool escaped = false;
-
- while
- (
- (nChar < maxLen)
- && get(c)
- )
+ while (get(c))
{
- if (c == token::END_STRING)
+ if (c == '\\')
+ {
+ escaped = !escaped; // Toggle state (retains backslashes)
+ }
+ else if (c == token::DQUOTE)
{
if (escaped)
{
escaped = false;
- --nChar; // Overwrite backslash
+ --nChar; // Overwrite backslash
}
else
{
// Done reading
- str.assign(buf, nChar);
+ str.append(buf, nChar);
return *this;
}
}
@@ -547,253 +814,44 @@ Foam::Istream& Foam::ISstream::read(string& str)
if (escaped)
{
escaped = false;
- --nChar; // Overwrite backslash
+ --nChar; // Overwrite backslash
}
else
{
- buf[errLen] = buf[nChar] = '\0';
+ str.append(buf, nChar); // Finalize pending content
+ strncpy(buf, str.c_str(), errLen);
+ buf[errLen] = '\0';
FatalIOErrorInFunction(*this)
- << "found '\\n' while reading string \""
- << buf << "...\""
+ << "Unescaped '\\n' while reading string \"" << buf
+ << "...\" [after " << str.length() << " chars]\n"
<< exit(FatalIOError);
return *this;
}
}
- else if (c == '\\')
- {
- escaped = !escaped; // toggle state (retains backslashes)
- }
else
{
escaped = false;
}
buf[nChar++] = c;
+ if (nChar == bufLen) // Flush full buffer
+ {
+ // Keep lookback character (eg, for backslash escaping)
+ str.append(buf, nChar-1);
+ nChar = 1;
+ buf[0] = c;
+ }
}
- if (nChar >= maxLen)
- {
- buf[errLen] = '\0';
-
- FatalIOErrorInFunction(*this)
- << "string \"" << buf << "...\"\n"
- << " is too long (max. " << maxLen << " characters)"
- << exit(FatalIOError);
-
- return *this;
- }
+ // Abnormal exit of the loop
// Don't worry about a dangling backslash if string terminated prematurely
- buf[errLen] = buf[nChar] = '\0';
- FatalIOErrorInFunction(*this)
- << "Problem while reading string \"" << buf << "...\""
- << exit(FatalIOError);
-
- return *this;
-}
-
-
-Foam::Istream& Foam::ISstream::readVariable(std::string& str)
-{
- constexpr const unsigned maxLen = 1024;
- static char buf[maxLen];
-
- unsigned nChar = 0;
- unsigned depth = 0; // Track depth of (..) or {..} nesting
- char c;
-
- // First character must be '$'
- if (!get(c) || c != token::DOLLAR)
- {
- FatalIOErrorInFunction(*this)
- << "Invalid first character found : " << c << nl
- << exit(FatalIOError);
- }
- buf[nChar++] = c;
-
- // Next character should also exist.
- // This should never fail, since it was checked before calling.
- if (!get(c))
- {
- str.assign(buf, nChar);
-
- IOWarningInFunction(*this)
- << "Truncated variable name : " << str << nl;
-
- return *this;
- }
- buf[nChar++] = c;
-
- str.clear();
- if (c == token::BEGIN_BLOCK)
- {
- // Processing ${...} style.
- ++depth;
-
- // Could check that the next char is good and not one of '{}'
- // since this would indicate "${}", "${{..." or truncated "${"
-
- while (get(c))
- {
- buf[nChar++] = c;
- if (nChar == maxLen)
- {
- str.append(buf, nChar);
- nChar = 0;
- }
- if (c == token::BEGIN_BLOCK)
- {
- ++depth;
- }
- else if (c == token::END_BLOCK)
- {
- --depth;
- if (!depth)
- {
- // Found closing '}' character
- str.append(buf, nChar);
- return *this;
- }
- }
- }
-
- // Should never reach here on normal input
-
- str.append(buf, nChar); // Finalize pending buffer input
-
- nChar = str.length();
- if (str.length() > errLen)
- {
- str.erase(errLen);
- }
-
- FatalIOErrorInFunction(*this)
- << "stream terminated while reading variable '"
- << str.c_str() << "...' [" << nChar << "]\n"
- << exit(FatalIOError);
-
- return *this;
- }
- else if (validVariableChar(c))
- {
- // Processing $var style
-
- while
- (
- (nChar < maxLen) && get(c)
- && (validVariableChar(c))
- )
- {
- if (c == token::BEGIN_LIST)
- {
- ++depth;
- }
- else if (c == token::END_LIST)
- {
- if (!depth)
- {
- break; // Closed ')' without an opening '(' ? ... stop
- }
- --depth;
- }
-
- buf[nChar++] = c;
- }
- }
- else
- {
- // Invalid character. Terminate string (for message) without
- // including the invalid character in the count.
-
- buf[nChar--] = '\0';
-
- IOWarningInFunction(*this)
- << "Bad variable name: " << buf << nl << endl;
- }
-
- if (nChar >= maxLen)
- {
- buf[errLen] = '\0';
-
- FatalIOErrorInFunction(*this)
- << "variable '" << buf << "...'\n"
- << " is too long (max. " << maxLen << " characters)"
- << exit(FatalIOError);
-
- return *this;
- }
-
- buf[nChar] = '\0'; // Terminate string
-
- if (bad())
- {
- // Could probably skip this check
- buf[errLen] = '\0';
-
- FatalIOErrorInFunction(*this)
- << "Problem while reading variable '" << buf << "...' after "
- << nChar << " characters\n"
- << exit(FatalIOError);
-
- return *this;
- }
-
- if (depth)
- {
- IOWarningInFunction(*this)
- << "Missing " << depth
- << " closing ')' while parsing" << nl << nl
- << buf << nl << endl;
- }
-
- // Finalize
- str.assign(buf, nChar);
- putback(c);
-
- return *this;
-}
-
-
-Foam::Istream& Foam::ISstream::readVerbatim(std::string& str)
-{
- constexpr const unsigned maxLen = 8000;
- static char buf[maxLen];
-
- unsigned nChar = 0;
- char c;
-
- str.clear();
- while (get(c))
- {
- if (c == token::HASH)
- {
- char nextC;
- get(nextC);
- if (nextC == token::END_BLOCK)
- {
- // Found closing "#}" sequence
- str.append(buf, nChar);
- return *this;
- }
- else
- {
- putback(nextC);
- }
- }
-
- buf[nChar++] = c;
- if (nChar == maxLen)
- {
- str.append(buf, nChar);
- nChar = 0;
- }
- }
-
- // Truncated terminated prematurely
- buf[errLen] = buf[nChar] = '\0';
+ str.append(buf, nChar); // Finalize pending content
+ strncpy(buf, str.c_str(), errLen);
+ buf[errLen] = '\0';
FatalIOErrorInFunction(*this)
<< "Problem while reading string \"" << buf << "...\""
diff --git a/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.H b/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.H
index 14f264595b..db8bba40fa 100644
--- a/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.H
+++ b/src/OpenFOAM/db/IOstreams/Sstreams/ISstream.H
@@ -69,18 +69,6 @@ class ISstream
//- Get the next valid character
char nextValid();
- //- Read a word token
- void readWordToken(token& t);
-
- //- Read a verbatim string (excluding block delimiters).
- // The leading "#{" has been removed prior to calling,
- // continues until the closing "#}" has been found.
- Istream& readVerbatim(std::string& str);
-
- //- Read a variable name starting with '$'.
- // Handles "$var" and "${var}" forms, permits '/' scoping character.
- Istream& readVariable(std::string& str);
-
//- No copy assignment
void operator=(const ISstream&) = delete;
@@ -137,6 +125,13 @@ public:
virtual ios_base::fmtflags flags() const;
+ // Special-purpose Functions
+
+ //- Discard until end of C-style comment '*/'
+ // \return False if stream exhausted before finding the comment end
+ bool seekCommentEnd_Cstyle();
+
+
// Read Functions
//- Raw, low-level get character function.
diff --git a/src/OpenFOAM/db/IOstreams/Sstreams/OSstream.C b/src/OpenFOAM/db/IOstreams/Sstreams/OSstream.C
index bf7e25c88a..78644b4e89 100644
--- a/src/OpenFOAM/db/IOstreams/Sstreams/OSstream.C
+++ b/src/OpenFOAM/db/IOstreams/Sstreams/OSstream.C
@@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
- Copyright (C) 2017-2020 OpenCFD Ltd.
+ Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@@ -47,27 +47,33 @@ bool Foam::OSstream::write(const token& tok)
case token::tokenType::DIRECTIVE :
{
- // The '#' sigil is already part of the wordToken
+ // Token stored with leading '#' sigil - output directly
write(tok.wordToken());
-
return true;
}
- case token::tokenType::VERBATIM :
+ case token::tokenType::EXPRESSION :
{
- // Surrounding '#{ .. #}' to be recognized as verbatim
- write(char(token::HASH));
- write(char(token::BEGIN_BLOCK));
+ // Token stored with surrounding '${{ .. }}' - output directly
writeQuoted(tok.stringToken(), false);
- write(char(token::HASH));
- write(char(token::END_BLOCK));
-
return true;
}
case token::tokenType::VARIABLE :
{
+ // Token stored with leading '$' sigil - output directly
writeQuoted(tok.stringToken(), false);
+ return true;
+ }
+
+ case token::tokenType::VERBATIM :
+ {
+ // Token stored without surrounding '#{ .. #}'. Add on output
+ write(char(token::HASH));
+ write(char(token::BEGIN_BLOCK));
+ writeQuoted(tok.stringToken(), false);
+ write(char(token::HASH));
+ write(char(token::END_BLOCK));
return true;
}
@@ -127,7 +133,7 @@ Foam::Ostream& Foam::OSstream::writeQuoted
// Output with surrounding quotes and backslash escaping
- os_ << token::BEGIN_STRING;
+ os_ << token::DQUOTE;
unsigned backslash = 0;
for (auto iter = str.cbegin(); iter != str.cend(); ++iter)
@@ -144,7 +150,7 @@ Foam::Ostream& Foam::OSstream::writeQuoted
++lineNumber_;
++backslash; // backslash escape for newline
}
- else if (c == token::END_STRING)
+ else if (c == token::DQUOTE)
{
++backslash; // backslash escape for quote
}
@@ -161,7 +167,7 @@ Foam::Ostream& Foam::OSstream::writeQuoted
// silently drop any trailing backslashes
// they would otherwise appear like an escaped end-quote
- os_ << token::END_STRING;
+ os_ << token::DQUOTE;
setState(os_.rdstate());
return *this;
diff --git a/src/OpenFOAM/db/IOstreams/token/token.H b/src/OpenFOAM/db/IOstreams/token/token.H
index eeb0d342ef..e1ccac5e9f 100644
--- a/src/OpenFOAM/db/IOstreams/token/token.H
+++ b/src/OpenFOAM/db/IOstreams/token/token.H
@@ -71,11 +71,13 @@ class token
public:
//- Enumeration defining the types of token.
- // Since these values are also used to tag content in Pstream,
- // the maximum number of types is limited to 30.
- enum tokenType
+ // Since the enumeration is used to tag content in Pstream, it is of
+ // type \c char and shall have values that do not overlap with regular
+ // punctuation characters.
+ enum tokenType : char
{
- UNDEFINED = 0, //!< An undefined token-type
+ UNDEFINED = '\0', //!< An undefined token-type
+ ERROR = '\x80', //!< Token error encountered
// Fundamental types
FLAG, //!< stream flag (1-byte bitmask)
@@ -86,14 +88,18 @@ public:
DOUBLE, //!< double (double-precision) type
// Pointer types
- WORD, //!< A Foam::word
- STRING, //!< A string (usually double-quoted)
- DIRECTIVE, //!< A dictionary \c \#directive (word variant)
- VARIABLE, //!< A dictionary \c \$variable (string variant)
- VERBATIM, //!< Verbatim string content
+ WORD, //!< Foam::word
+ STRING, //!< Foam::string (usually double-quoted)
COMPOUND, //!< Compound type such as \c List\