stringOps.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-2021 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 "stringOps.H"
30#include "typeInfo.H"
31#include "etcFiles.H"
32#include "UPstream.H"
33#include "StringStream.H"
34#include "OSstream.H"
35#include "OSspecific.H"
36#include <algorithm>
37#include <cctype>
38
39// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
40
41namespace Foam
42{
43
44// Return the file location mode (string) as a numerical value.
45//
46// - u : location mask 0700
47// - g : location mask 0070
48// - o : location mask 0007
49// - a : location mask 0777
50//
51static inline unsigned short modeToLocation
52(
53 const std::string& mode,
54 std::size_t pos = 0
55)
56{
57 unsigned short where(0);
58
59 if (std::string::npos != mode.find('u', pos)) { where |= 0700; } // User
60 if (std::string::npos != mode.find('g', pos)) { where |= 0070; } // Group
61 if (std::string::npos != mode.find('o', pos)) { where |= 0007; } // Other
62 if (std::string::npos != mode.find('a', pos)) { where |= 0777; } // All
63
64 return where;
65}
66
67
68// Expand a leading <tag>/
69// Convenient for frequently used directories
70//
71// <etc>/ => user/group/other etc - findEtcEntry()
72// <etc(:[ugoa]+)?>/ => user/group/other etc - findEtcEntry()
73// <case>/ => FOAM_CASE directory
74// <constant>/ => FOAM_CASE/constant directory
75// <system>/ => FOAM_CASE/system directory
76static void expandLeadingTag(std::string& s, const char b, const char e)
77{
78 if (s[0] != b)
79 {
80 return;
81 }
82
83 auto delim = s.find(e);
84 if (std::string::npos == delim)
85 {
86 return; // Error: no closing delim - ignore expansion
87 }
88
89 fileName file;
90
91 const char nextC = s[++delim];
92
93 // Require the following character to be '/' or the end of string.
94 if (nextC)
95 {
96 if (nextC != '/')
97 {
98 return;
99 }
100
101 file.assign(s.substr(delim + 1));
102 }
103
104 const std::string tag(s, 1, delim-2);
105 const auto tagLen = tag.length();
106
107 // Note that file is also allowed to be an empty string.
108
109 if (tag == "etc")
110 {
111 s = findEtcEntry(file);
112 }
113 else if (tag == "case")
114 {
115 s = fileName(Foam::getEnv("FOAM_CASE"))/file;
116 }
117 else if (tag == "constant" || tag == "system")
118 {
119 s = fileName(Foam::getEnv("FOAM_CASE"))/tag/file;
120 }
121 else if (tagLen >= 4 && tag.compare(0, 4, "etc:") == 0)
122 {
123 // <etc:[ugoa]+> type of tag - convert "ugo" to numeric
124
125 s = findEtcEntry(file, modeToLocation(tag,4));
126 }
127}
128
129
130// Expand a leading tilde
131// ~/ => home directory
132// ~user => home directory for specified user
133// Deprecated ~OpenFOAM => <etc> instead
134static void expandLeadingTilde(std::string& s)
135{
136 if (s[0] != '~')
137 {
138 return;
139 }
140
141 std::string user;
142 fileName file;
143
144 const auto slash = s.find('/');
145 if (slash == std::string::npos)
146 {
147 user = s.substr(1);
148 }
149 else
150 {
151 user = s.substr(1, slash - 1);
152 file = s.substr(slash + 1);
153 }
154
155 // NB: be a bit lazy and expand ~unknownUser as an
156 // empty string rather than leaving it untouched.
157 // otherwise add extra test
158
159 if (user == "OpenFOAM")
160 {
161 // Compat Warning
162 const int version(1806);
163
164 if (error::master())
165 {
166 std::cerr
167 << nl
168 << "--> FOAM Warning :" << nl
169 << " Found [v" << version << "] '"
170 << "~OpenFOAM" << "' string expansion instead of '"
171 << "<etc>" << "' in string\n\"" << s << "\"\n" << nl
172 << std::endl;
173
174 error::warnAboutAge("expansion", version);
175 }
176
177 s = findEtcFile(file);
178 }
179 else
180 {
181 s = home(user)/file;
182 }
183}
184
185
186// Expand leading contents: "./", "~..", "<tag>/"
187static void expandLeading(std::string& s)
188{
189 if (s.empty())
190 {
191 return;
192 }
193
194 switch (s[0])
195 {
196 case '.':
197 {
198 // Expand a lone '.' and an initial './' into cwd
199 if (s.size() == 1)
200 {
201 s = cwd();
202 }
203 else if (s[1] == '/')
204 {
205 s.replace(0, 1, cwd());
206 }
207 break;
208 }
209 case '<':
210 {
211 expandLeadingTag(s, '<', '>');
212 break;
213 }
214 case '~':
215 {
217 break;
218 }
219 }
220}
221
222
223// Serialize an entry (primitive or dictionary) with special treatment
224// for primitive entries that are already a string-type.
225static inline std::string entryToString
226(
227 const entry* eptr,
228 const bool allowSubDict
229)
230{
231 std::string str;
232
233 if (eptr)
234 {
235 OStringStream buf;
236 // Force floating point numbers to be printed with at least
237 // some decimal digits.
238 buf << fixed;
240
241 if (allowSubDict && eptr->isDict())
242 {
243 eptr->dict().write(buf, false);
244 str = buf.str();
245 }
246 else
247 {
248 // Fail for non-primitiveEntry
249 const primitiveEntry& pe =
250 dynamicCast<const primitiveEntry>(*eptr);
251
252 if (pe.size() == 1 && pe[0].isStringType())
253 {
254 // Already a string-type (WORD, STRING, ...). Just copy.
255 str = pe[0].stringToken();
256 }
257 else
258 {
259 pe.write(buf, true);
260 str = buf.str();
261 }
262 }
263 }
264
265 return str;
266}
267
268} // End namespace Foam
269
270
271// Details for handling dictionary expansion
272
273namespace
274{
275
276// Acceptable values for $variable names.
277//
278// Similar to word::valid(), except we don't have the benefit of a parser
279// to filter out other unacceptable entries for us.
280//
281// Does not currently accept '/' in a variable name.
282// We would like "$file/$name" to expand as two variables.
283static inline bool validVariableChar(char c)
284{
285 return
286 (
287 std::isalnum(c)
288 || c == '.'
289 || c == ':'
290 || c == '_'
291 );
292}
293
294
295// Find the type/position of the ":-" or ":+" alternative values
296// Returns 0, '-', '+' corresponding to not-found or ':-' or ':+'
297static inline int findParameterAlternative
298(
299 const std::string& s,
300 std::string::size_type& pos,
301 std::string::size_type endPos
302)
303{
304 while (pos != std::string::npos)
305 {
306 pos = s.find(':', pos);
307 if (pos != std::string::npos)
308 {
309 if (pos < endPos)
310 {
311 // in-range: check for '+' or '-' following the ':'
312 const int altType = s[pos+1];
313 if (altType == '+' || altType == '-')
314 {
315 return altType;
316 }
317
318 ++pos; // unknown/unsupported - continue at next position
319 }
320 else
321 {
322 // out-of-range: abort
323 pos = std::string::npos;
324 }
325 }
326 }
327
328 return 0;
329}
330
331
332// For input string of "$variable with other" return the length of
333// the variable.
334//
335// Intentionally will not capture ':+', ':-' alterations. Use ${ .. } for that
336static inline std::string::size_type findVariableLen
337(
338 const std::string& s,
339 std::string::size_type pos,
340 const char sigil = '$'
341)
342{
343 std::string::size_type len = 0;
344
345 if (pos < s.length())
346 {
347 if (s[pos] == sigil)
348 {
349 // Skip leading '$' in the count!
350 ++pos;
351 }
352
353 for
354 (
355 auto iter = s.cbegin() + pos;
356 iter != s.cend() && validVariableChar(*iter);
357 ++iter
358 )
359 {
360 ++len;
361 }
362 }
363
364 return len;
365}
366
367} // End namespace anonymous
368
369
370namespace Foam
371{
372
373// Get dictionary or (optionally) environment variable
374//
375// Handles default and alternative values as per the POSIX shell.
376// \code
377// ${parameter:-defValue}
378// ${parameter:+altValue}
379// \endcode
381(
382 const word& name,
383 const dictionary* dictptr,
384 const bool allowEnv,
385 const bool allowEmpty,
386 const bool allowSubDict
387)
388{
389 // The type/position of the ":-" or ":+" alternative values
390 std::string::size_type altPos = 0;
391
392 // Check for parameter:-word or parameter:+word
393 const int altType =
394 findParameterAlternative(name, altPos, name.size()-1);
395
396 const word lookupName =
397 (altType ? word(name.substr(0,altPos), false) : name);
398
399 const entry* eptr =
400 (
401 (dictptr != nullptr)
402 ? dictptr->findScoped(lookupName, keyType::LITERAL_RECURSIVE)
403 : nullptr
404 );
405
406 string value;
407 if (eptr)
408 {
409 value = entryToString(eptr, allowSubDict);
410 }
411 else if (allowEnv || dictptr == nullptr)
412 {
413 value = Foam::getEnv(lookupName);
414 }
415
416 if (value.empty() ? (altType == '-') : (altType == '+'))
417 {
418 // Not found or empty: use ":-" alternative value
419 // Found and not empty: use ":+" alternative value
420 value = name.substr(altPos + 2);
421 }
422
423 if (!allowEmpty && value.empty())
424 {
425 if (dictptr != nullptr)
426 {
427 auto& err =
428 FatalIOErrorInFunction(*dictptr)
429 << "Cannot find dictionary entry ";
430
431 if (allowEnv)
432 {
433 err << "or environment ";
434 }
435
436 err << "variable '" << lookupName << "'" << nl
437 << exit(FatalIOError);
438 }
439 else
440 {
442 << "Unknown variable '" << lookupName << "'" << nl
443 << exit(FatalError);
444 }
445 }
446
447 return value;
448}
449
450
451// Recursively expands (dictionary or environment) variable
452// starting at index in string. Updates index.
453//
454// String: "abc ${var} def",
455// Receive: "var} def"
456//
457// String: "abc ${{expr}} def"
458// Receive: "{expr}} def"
459//
460// On return, the index will be adjust to be AFTER the closing '}'
462(
463 const std::string& s,
464 std::string::size_type& index,
465 const dictionary* dictptr,
466 const bool allowEnv,
467 const bool allowEmpty,
468 const bool allowSubDict
469)
470{
472
473 // Track ${{ expr }} expressions
474 const bool isExpr = (index < s.size() && s[index] == '{');
475
476 if (isExpr)
477 {
478 ++index;
479 }
480
481 // Initially called for a ${variable}, not ${{expr}}
482 bool isVar = !isExpr;
483
484 string out;
485
486 for (/*nil*/; index < s.size(); ++index)
487 {
489 if (s[index] == '$')
490 {
491 if (s[index+1] == '{')
492 {
493 // Recurse to parse variable name
494 index += 2;
495
496 string val =
498 (
499 s,
500 index,
501 dictptr,
502 allowEnv,
503 allowEmpty,
504 allowSubDict
505 );
506
507 out.append(val); // Append content
508
510
511 // Already skipped past '}' terminator?
512 if (s[index-1] == '}')
513 {
514 --index;
515 }
516 }
517 else if (validVariableChar(s[index+1]))
518 {
519 // A regular $var expansion without a surrounding {}.
520
521 const auto varLen = findVariableLen(s, index);
522 const word varName(s.substr(index+1, varLen), false);
523 index += varLen;
524
525 string val =
527 (
528 varName,
529 dictptr,
530 allowEnv,
531 allowEmpty,
532 allowSubDict
533 );
534
535 out.append(val); // Append content
536 }
537 else
538 {
539 // Something like '$()', '$[]', etc - pass through
540 out += s[index]; // Append char
541 }
542 }
543 else if (s[index] == '}')
544 {
545 // Closing an expression or variable
546
547 if (isExpr)
548 {
549 // Closes with '}}'
550 ++index; // Index past closing '}'
551
552 if (s[index] == '}')
553 {
554 ++index; // Index past closing '}'
555 }
556 else if (dictptr != nullptr)
557 {
558 // Missing '}'? - Warn/error/ignore
559 FatalIOErrorInFunction(*dictptr)
560 << "Expansion ${{ is missing a closing '}}'\n"
561 << exit(FatalIOError);
562 }
563 else
564 {
566 << "Expansion ${{ is missing a closing '}}'\n"
567 << exit(FatalError);
568 }
569
571
572 // Even with allow empty, expressions may need content
573
574 string val(stringOps::evaluate(out));
576
577 return val;
578 }
579 else if (isVar)
580 {
581 // Variable - closes with '}'
582
583 ++index; // Index past closing '}'
584
585 return
587 (
588 out,
589 dictptr,
590 allowEnv,
591 allowEmpty,
592 allowSubDict
593 );
594 }
595 else
596 {
597 // Stray '}'? - Leave on output
598
599 out += s[index]; // append char
600 }
601 }
602 else
603 {
604 out += s[index]; // append char
605 }
606 }
607
608 return out;
609}
610
611
612static void expandString
613(
614 std::string& s,
615 const dictionary* dictptr,
616 const bool allowEnv,
617 const bool allowEmpty,
618 const bool allowSubDict,
619 const char sigil
620)
621{
622 std::string::size_type varBeg = 0;
623
624 // Expand $VAR, ${VAR} or ${{EXPR}}
625 // Repeat until nothing more is found
626 while
627 (
628 (varBeg = s.find(sigil, varBeg)) != std::string::npos
629 && varBeg < s.size()-1
630 )
631 {
632 if (varBeg == 0 || s[varBeg-1] != '\\')
633 {
634 if (s[varBeg+1] == '{')
635 {
636 // Recursive variable expansion mode: '${' or '${{'
637 const auto replaceBeg = varBeg;
638
639 varBeg += 2;
640 string varValue
641 (
643 (
644 s,
645 varBeg,
646 dictptr,
647 allowEnv,
648 allowEmpty,
649 allowSubDict
650 )
651 );
652
653 s.replace(replaceBeg, varBeg - replaceBeg, varValue);
654 varBeg = replaceBeg+varValue.size();
655 }
656 else if (validVariableChar(s[varBeg+1]))
657 {
658 // A regular $var expansion without surrounding {}.
659 const auto varLen(findVariableLen(s, varBeg, sigil));
660 const word varName(s.substr(varBeg+1, varLen), false);
661
662 string varValue
663 (
665 (
666 varName,
667 dictptr,
668 allowEnv,
669 allowEmpty,
670 allowSubDict
671 )
672 );
673
674 s.replace(varBeg, varName.size()+1, varValue);
675 varBeg += varValue.size();
676 }
677 else
678 {
679 ++varBeg;
680 }
681 }
682 else
683 {
684 ++varBeg;
685 }
686 }
687
689}
690
691} // End namespace Foam
692
693
694// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
695
696std::string::size_type Foam::stringOps::count
697(
698 const std::string& s,
699 const char c
700)
701{
702 return std::count(s.cbegin(), s.cend(), c);
703}
704
705
706std::string::size_type Foam::stringOps::count(const char* s, const char c)
707{
708 return
709 (
710 s == nullptr
711 ? 0
712 : std::count(s, (s + std::char_traits<char>::length(s)), c)
713 );
714}
715
716
718(
719 const std::string& s,
720 const HashTable<string>& mapping,
721 const char sigil
722)
723{
724 string out(s);
725 inplaceExpand(out, mapping);
726 return out;
727}
728
729
731(
732 std::string& s,
733 const HashTable<string>& mapping,
734 const char sigil
735)
736{
737 std::string::size_type varBeg = 0;
738
739 // Expand $VAR or ${VAR}
740 // Repeat until nothing more is found
741 while
742 (
743 (varBeg = s.find(sigil, varBeg)) != std::string::npos
744 && varBeg < s.size()-1
745 )
746 {
747 if (varBeg == 0 || s[varBeg-1] != '\\')
748 {
749 // Find end of first occurrence
750 std::string::size_type varEnd = varBeg;
751 std::string::size_type delim = 0;
752
753 // The type/position of the ":-" or ":+" alternative values
754 int altType = 0;
755 auto altPos = std::string::npos;
756
757 if (s[varBeg+1] == '{')
758 {
759 varEnd = s.find('}', varBeg);
760 delim = 1;
761
762 // Check for ${parameter:-word} or ${parameter:+word}
763 if (varEnd != std::string::npos)
764 {
765 altPos = varBeg;
766 altType = findParameterAlternative(s, altPos, varEnd);
767 }
768 }
769 else
770 {
771 varEnd += findVariableLen(s, varBeg, sigil);
772 }
773
774 if (varEnd == std::string::npos)
775 {
776 // Likely parsed '${...' without closing '}' - abort
777 break;
778 }
779 else if (varEnd == varBeg)
780 {
781 // Something like '$()', '$[]', etc - pass through
782 ++varBeg;
783 }
784 else
785 {
786 const word varName
787 (
788 s.substr
789 (
790 varBeg + 1 + delim,
791 (
792 (altPos == std::string::npos ? varEnd : altPos)
793 - varBeg - 2*delim
794 )
795 ),
796 false
797 );
798
799 std::string altValue;
800 if (altPos != std::string::npos)
801 {
802 // Had ":-" or ":+" alternative value
803 altValue = s.substr
804 (
805 altPos + 2,
806 varEnd - altPos - 2*delim
807 );
808 }
809
810
811 const auto fnd = mapping.cfind(varName);
812
813 if (fnd.found() ? (altType == '+') : (altType == '-'))
814 {
815 // Found and ":+" alternative
816 // Not-found and ":-" alternative
817
818 s.replace(varBeg, varEnd - varBeg + 1, altValue);
819 varBeg += altValue.size();
820 }
821 else if (fnd.found())
822 {
823 // Found: use value
824 s.replace(varBeg, varEnd - varBeg + 1, *fnd);
825 varBeg += (*fnd).size();
826 }
827 else
828 {
829 // Not-found: empty value
830 s.erase(varBeg, varEnd - varBeg + 1);
831 }
832 }
833 }
834 else
835 {
836 ++varBeg;
837 }
838 }
839}
840
841
843(
844 const std::string& s,
845 const dictionary& dict,
846 const char sigil
847)
848{
849 string out(s);
850 inplaceExpand(out, dict, sigil);
851 return out;
852}
853
854
856(
857 std::string& s,
858 const dictionary& dict,
859 const bool allowEnv,
860 const bool allowEmpty,
861 const bool allowSubDict,
862 const char sigil
863)
864{
865 expandString(s, &dict, allowEnv, allowEmpty, allowSubDict, sigil);
866}
867
868
870(
871 std::string& s,
872 const dictionary& dict,
873 const char sigil
874)
875{
876 // Allow everything, including subDict expansions
877 // env=true, empty=true, subDict=true
878 expandString(s, &dict, true, true, true, sigil);
879}
880
881
883(
884 const std::string& s,
885 const bool allowEmpty
886)
887{
888 string out(s);
889 inplaceExpand(out, allowEmpty);
890 return out;
891}
892
893
895(
896 std::string& s,
897 const bool allowEmpty
898)
899{
900 // Expand without a dictionary context
901 // allowEnv=true, allowSubDict=N/A
902 expandString(s, nullptr, true, allowEmpty, false, '$');
903}
904
905
906bool Foam::stringOps::inplaceReplaceVar(std::string& s, const word& varName)
907{
908 if (s.empty() || varName.empty())
909 {
910 return false;
911 }
912
913 const string content(Foam::getEnv(varName));
914 if (content.empty())
915 {
916 return false;
917 }
918
919 const auto i = s.find(content);
920 if (i == std::string::npos)
921 {
922 return false;
923 }
924
925 s.replace(i, content.size(), string("${" + varName + "}"));
926 return true;
927}
928
929
931{
932 if (!s.empty())
933 {
934 std::string::size_type pos = 0;
935 const auto end = s.length();
936
937 while (pos < end && std::isspace(s[pos]))
938 {
939 ++pos;
940 }
941
942 if (pos)
943 {
944 return s.substr(pos);
945 }
946 }
947
948 return s;
949}
950
951
953{
954 if (!s.empty())
955 {
956 std::string::size_type pos = 0;
957 const auto end = s.length();
958
959 while (pos < end && std::isspace(s[pos]))
960 {
961 ++pos;
962 }
963
964 if (pos)
965 {
966 s.erase(0, pos);
967 }
968 }
969}
970
971
973{
974 if (!s.empty())
975 {
976 auto end = s.length();
977 while (end && std::isspace(s[end-1]))
978 {
979 --end;
980 }
981
982 if (end < s.length())
983 {
984 return s.substr(0, end);
985 }
986 }
987
988 return s;
989}
990
991
993{
994 if (!s.empty())
995 {
996 auto end = s.length();
997 while (end && std::isspace(s[end-1]))
998 {
999 --end;
1000 }
1001
1002 s.erase(end);
1003 }
1004}
1005
1006
1007std::pair<std::size_t, std::size_t>
1009(
1010 const std::string& s,
1011 std::size_t pos,
1012 std::size_t len
1013)
1014{
1015 size_t end = s.length();
1016 if (pos >= end)
1017 {
1018 pos = end;
1019 }
1020 else if (len != std::string::npos)
1021 {
1022 len += pos;
1023
1024 if (len < end)
1025 {
1026 end = len;
1027 }
1028 }
1029
1030 // Right = last
1031 while (pos < end && std::isspace(s[end-1]))
1032 {
1033 --end;
1034 }
1035
1036 // Left = first
1037 while (pos < end && std::isspace(s[pos]))
1038 {
1039 ++pos;
1040 }
1041
1042 return std::pair<std::size_t, std::size_t>(pos, end);
1043}
1044
1045
1047{
1048 std::string::size_type pos = 0;
1049 std::string::size_type end = s.length();
1050
1051 // Right
1052 while (pos < end && std::isspace(s[end-1]))
1053 {
1054 --end;
1055 }
1056
1057 // Left
1058 while (pos < end && std::isspace(s[pos]))
1059 {
1060 ++pos;
1061 }
1062
1063 return s.substr(pos, end-pos);
1064}
1065
1066
1068{
1071}
1072
1073
1075{
1076 s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
1077}
1078
1079
1081{
1082 string out(s);
1084 return out;
1085}
1086
1087
1089{
1090 const auto len = s.length();
1091
1092 if (len < 2)
1093 {
1094 return;
1095 }
1096
1097 std::string::size_type n = 0;
1098
1099 for (std::string::size_type i = 0; i < len; ++i)
1100 {
1101 char c = s[i];
1102
1103 if (n != i)
1104 {
1105 s[n] = c;
1106 }
1107 ++n;
1108
1109 // The start of a C/C++ comment?
1110 if (c == '/')
1111 {
1112 ++i;
1113
1114 if (i == len)
1115 {
1116 // No further characters
1117 break;
1118 }
1119
1120 c = s[i];
1121
1122 if (c == '/')
1123 {
1124 // C++ comment - remove to end-of-line
1125
1126 --n;
1127 s[n] = '\n';
1128
1129 // Backtrack to eliminate leading spaces,
1130 // up to the previous newline
1131
1132 while (n && std::isspace(s[n-1]))
1133 {
1134 --n;
1135
1136 if (s[n] == '\n')
1137 {
1138 break;
1139 }
1140
1141 s[n] = '\n';
1142 }
1143
1144 i = s.find('\n', ++i);
1145
1146 if (i == std::string::npos)
1147 {
1148 // Truncated - done
1149 break;
1150 }
1151
1152 ++n; // Include newline in output
1153 }
1154 else if (c == '*')
1155 {
1156 // C comment - search for '*/'
1157 --n;
1158 i = s.find("*/", ++i, 2);
1159
1160 if (i == std::string::npos)
1161 {
1162 // Truncated - done
1163 break;
1164 }
1165
1166 ++i; // Index past first of "*/", loop increment does the rest
1167 }
1168 else
1169 {
1170 // Not a C/C++ comment
1171 if (n != i)
1172 {
1173 s[n] = c;
1174 }
1175 ++n;
1176 }
1177 }
1178 }
1179
1180 s.erase(n);
1181}
1182
1183
1185{
1186 string out;
1187 out.resize(s.length());
1188
1189 std::transform(s.begin(), s.end(), out.begin(), ::tolower);
1190 return out;
1191}
1192
1193
1195{
1196 std::transform(s.begin(), s.end(), s.begin(), ::tolower);
1197}
1198
1199
1201{
1202 string out;
1203 out.resize(s.length());
1204
1205 std::transform(s.begin(), s.end(), out.begin(), ::toupper);
1206 return out;
1207}
1208
1209
1211{
1212 std::transform(s.begin(), s.end(), s.begin(), ::toupper);
1213}
1214
1215
1217(
1218 OSstream& os,
1219 const std::string& str,
1220 const std::string::size_type width,
1221 const std::string::size_type indent,
1222 const bool escape
1223)
1224{
1225 const auto len = str.length();
1226
1227 std::string::size_type pos = 0;
1228
1229 // Handle leading newlines
1230 while (str[pos] == '\n' && pos < len)
1231 {
1232 os << '\n';
1233 ++pos;
1234 }
1235
1236 while (pos < len)
1237 {
1238 // Potential end point and next point
1239 std::string::size_type end = pos + width - 1;
1240 std::string::size_type eol = str.find('\n', pos);
1241 std::string::size_type next = string::npos;
1242
1243 if (end >= len)
1244 {
1245 // No more wrapping needed
1246 end = len;
1247
1248 if (std::string::npos != eol && eol <= end)
1249 {
1250 // Manual '\n' break, next follows it (default behaviour)
1251 end = eol;
1252 }
1253 }
1254 else if (std::string::npos != eol && eol <= end)
1255 {
1256 // Manual '\n' break, next follows it (default behaviour)
1257 end = eol;
1258 }
1259 else if (isspace(str[end]))
1260 {
1261 // Ended on a space - can use this directly
1262 next = str.find_first_not_of(" \t\n", end); // Next non-space
1263 }
1264 else if (isspace(str[end+1]))
1265 {
1266 // The next one is a space - so we are okay
1267 ++end; // Otherwise the length is wrong
1268 next = str.find_first_not_of(" \t\n", end); // Next non-space
1269 }
1270 else
1271 {
1272 // Line break will be mid-word
1273 auto prev = str.find_last_of(" \t\n", end); // Prev word break
1274
1275 if (std::string::npos != prev && prev > pos)
1276 {
1277 end = prev;
1278 next = prev + 1; // Continue from here
1279 }
1280 }
1281
1282 // The next position to continue from
1283 if (std::string::npos == next)
1284 {
1285 next = end + 1;
1286 }
1287
1288 // Has a length
1289 if (end > pos)
1290 {
1291 // Indent following lines.
1292 // The first one was already done prior to calling this routine.
1293 if (pos)
1294 {
1295 for (std::string::size_type i = 0; i < indent; ++i)
1296 {
1297 os <<' ';
1298 }
1299 }
1300
1301 while (pos < end)
1302 {
1303 const char c = str[pos];
1304
1305 if (escape && c == '\\')
1306 {
1307 os << '\\';
1308 }
1309 os << c;
1310
1311 ++pos;
1312 }
1313 os << nl;
1314 }
1315
1316 pos = next;
1317 }
1318}
1319
1320
1321// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Input/output from string buffers.
label n
Foam::string str() const
Get the string - as Foam::string rather than std::string.
Definition: StringStream.H:88
A HashTable similar to std::unordered_map.
Definition: HashTable.H:123
const_iterator cfind(const Key &key) const
Find and return an const_iterator set at the hashed entry.
Definition: HashTableI.H:141
static unsigned int defaultPrecision() noexcept
Return the default precision.
Definition: IOstream.H:342
Generic output stream using a standard (STL) stream.
Definition: OSstream.H:57
virtual int precision() const
Get precision of output field.
Definition: OSstream.C:326
Output to string buffer, using a OSstream. Always UNCOMPRESSED.
Definition: StringStream.H:231
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
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:117
void write(Ostream &os, const bool subDict=true) const
Write dictionary, normally with sub-dictionary formatting.
Definition: dictionaryIO.C:206
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:70
virtual bool isDict() const noexcept
Return true if this entry is a dictionary.
Definition: entry.H:233
virtual const dictionary & dict() const =0
Return dictionary, if entry is a dictionary.
static bool warnAboutAge(const int version) noexcept
Test if an age warning should be emitted.
Definition: error.C:55
A class for handling file names.
Definition: fileName.H:76
bool assign(const token &tok)
Assign from word or string token.
Definition: fileNameIO.C:42
@ LITERAL_RECURSIVE
Definition: keyType.H:86
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read,...
virtual void write(Ostream &os) const
Write.
splitCell * master() const
Definition: splitCell.H:113
A class for handling character strings derived from std::string.
Definition: string.H:79
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Functions to search 'etc' directories for configuration files etc.
OBJstream os(runTime.globalPath()/outputName)
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))
void inplaceLower(std::string &s)
Inplace transform string with std::tolower on each character.
Definition: stringOps.C:1194
string removeComments(const std::string &s)
Return string with C/C++ comments removed.
Definition: stringOps.C:1080
string evaluate(label fieldWidth, const std::string &s, size_t pos=0, size_t len=std::string::npos)
String evaluation with specified (positive, non-zero) field width.
void inplaceRemoveComments(std::string &s)
Remove C/C++ comments inplace.
Definition: stringOps.C:1088
string lower(const std::string &s)
Return string copy transformed with std::tolower on each character.
Definition: stringOps.C:1184
bool inplaceReplaceVar(std::string &s, const word &varName)
Replace environment variable contents with its name.
Definition: stringOps.C:906
void writeWrapped(OSstream &os, const std::string &str, const std::string::size_type width, const std::string::size_type indent=0, const bool escape=false)
Output string with text wrapping.
Definition: stringOps.C:1217
string trim(const std::string &s)
Return string trimmed of leading and trailing whitespace.
Definition: stringOps.C:1046
void inplaceUpper(std::string &s)
Inplace transform string with std::toupper on each character.
Definition: stringOps.C:1210
std::pair< size_t, size_t > findTrim(const std::string &s, size_t pos=0, size_t len=std::string::npos)
Find (first, last) non-space locations in string or sub-string.
void inplaceExpand(std::string &s, const HashTable< string > &mapping, const char sigil='$')
Definition: stringOps.C:731
void inplaceTrimLeft(std::string &s)
Trim leading whitespace inplace.
Definition: stringOps.C:952
std::string::size_type count(const std::string &s, const char c)
Count the number of occurrences of the specified character.
Definition: stringOps.C:697
void inplaceTrim(std::string &s)
Trim leading and trailing whitespace inplace.
Definition: stringOps.C:1067
string trimLeft(const std::string &s)
Return string trimmed of leading whitespace.
Definition: stringOps.C:930
string upper(const std::string &s)
Return string copy transformed with std::toupper on each character.
Definition: stringOps.C:1200
string trimRight(const std::string &s)
Return string trimmed of trailing whitespace.
Definition: stringOps.C:972
void inplaceTrimRight(std::string &s)
Trim trailing whitespace inplace.
Definition: stringOps.C:992
string expand(const std::string &s, const HashTable< string > &mapping, const char sigil='$')
Definition: stringOps.C:718
void inplaceRemoveSpace(std::string &s)
Eliminate whitespace inplace.
Definition: stringOps.C:1074
Namespace for OpenFOAM.
fileName cwd()
The physical or logical current working directory path name.
Definition: MSwindows.C:476
static std::string entryToString(const entry *eptr, const bool allowSubDict)
Definition: stringOps.C:226
dimensionedScalar pos(const dimensionedScalar &ds)
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: MSwindows.C:371
IOstream & fixed(IOstream &io)
Definition: IOstream.H:458
bool isspace(char c) noexcept
Test for whitespace (C-locale)
Definition: char.H:65
mode_t mode(const fileName &name, const bool followLink=true)
Return the file mode, normally following symbolic links.
Definition: MSwindows.C:572
static Foam::string recursiveExpand(const std::string &s, std::string::size_type &index, const dictionary *dictptr, const bool allowEnv, const bool allowEmpty, const bool allowSubDict)
Definition: stringOps.C:462
fileName findEtcFile(const fileName &name, const bool mandatory=false, unsigned short location=0777)
Search for a single FILE within the etc directories.
Definition: etcFiles.C:446
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:342
static Foam::string getVariable(const word &name, const dictionary *dictptr, const bool allowEnv, const bool allowEmpty, const bool allowSubDict)
Definition: stringOps.C:381
IOerror FatalIOError
static void expandLeading(std::string &s)
Definition: stringOps.C:187
static void expandString(std::string &s, const dictionary *dictptr, const bool allowEnv, const bool allowEmpty, const bool allowSubDict, const char sigil)
Definition: stringOps.C:613
static unsigned short modeToLocation(const std::string &mode, std::size_t pos=0)
Definition: stringOps.C:52
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
static void expandLeadingTag(std::string &s, const char b, const char e)
Definition: stringOps.C:76
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
fileName home()
Return home directory path name for the current user.
Definition: MSwindows.C:457
fileName findEtcEntry(const fileName &name, unsigned short location=0777, const fileName::Type typeRequired=fileName::Type::UNDEFINED)
Search for a single FILE or DIRECTORY within the etc directories.
Definition: etcFiles.C:415
static void expandLeadingTilde(std::string &s)
Definition: stringOps.C:134
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:158
static char findParameterAlternative(const std::string &s, std::string::size_type &pos, std::string::size_type endPos=std::string::npos)
dictionary dict
volScalarField & b
Definition: createFields.H:27
volScalarField & e
Definition: createFields.H:11