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 -------------------------------------------------------------------------------
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 "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 
41 namespace 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 //
51 static 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
76 static 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
134 static 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>/"
187 static 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.
225 static 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 
273 namespace
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.
283 static 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 ':+'
297 static inline int findParameterAlternative
298 (
299  const std::string& s,
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
336 static inline std::string::size_type findVariableLen
337 (
338  const std::string& s,
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 
370 namespace 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 
612 static 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 
688  expandLeading(s);
689 }
690 
691 } // End namespace Foam
692 
693 
694 // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
695 
697 (
698  const std::string& s,
699  const char c
700 )
701 {
702  return std::count(s.cbegin(), s.cend(), c);
703 }
704 
705 
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 
906 bool 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  {
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  {
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 
1007 std::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 {
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 {
1070  inplaceTrimLeft(s);
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);
1083  inplaceRemoveComments(out);
1084  return out;
1085 }
1086 
1087 
1089 {
1090  const auto len = s.length();
1091 
1092  if (len < 2)
1093  {
1094  return;
1095  }
1096 
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 
1218  OSstream& os,
1219  const std::string& str,
1220  const std::string::size_type width,
1222  const bool escape
1223 )
1224 {
1225  const auto len = str.length();
1226 
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 // ************************************************************************* //
Foam::entry
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:67
OSspecific.H
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Foam::keyType::LITERAL_RECURSIVE
Definition: keyType.H:86
Foam::expandLeadingTag
static void expandLeadingTag(std::string &s, const char b, const char e)
Definition: stringOps.C:76
Foam::primitiveEntry
A keyword and a list of tokens comprise a primitiveEntry. A primitiveEntry can be read,...
Definition: primitiveEntry.H:63
Foam::stringOps::inplaceTrimRight
void inplaceTrimRight(std::string &s)
Trim trailing whitespace inplace.
Definition: stringOps.C:992
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:65
Foam::fileName
A class for handling file names.
Definition: fileName.H:73
s
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))
Definition: gmvOutputSpray.H:25
Foam::stringOps::writeWrapped
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
typeInfo.H
Foam::isspace
bool isspace(char c) noexcept
Test for whitespace (C-locale)
Definition: char.H:65
UPstream.H
Foam::stringOps::inplaceTrim
void inplaceTrim(std::string &s)
Trim leading and trailing whitespace inplace.
Definition: stringOps.C:1067
Foam::stringOps::inplaceReplaceVar
bool inplaceReplaceVar(std::string &s, const word &varName)
Replace environment variable contents with its name.
Definition: stringOps.C:906
Foam::entry::isDict
virtual bool isDict() const noexcept
Return true if this entry is a dictionary.
Definition: entry.H:233
Foam::getVariable
static Foam::string getVariable(const word &name, const dictionary *dictptr, const bool allowEnv, const bool allowEmpty, const bool allowSubDict)
Definition: stringOps.C:381
Foam::findEtcEntry
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
Foam::stringOps::trim
string trim(const std::string &s)
Return string trimmed of leading and trailing whitespace.
Definition: stringOps.C:1046
StringStream.H
Input/output from string buffers.
Foam::FatalIOError
IOerror FatalIOError
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::expandLeadingTilde
static void expandLeadingTilde(std::string &s)
Definition: stringOps.C:134
Foam::primitiveEntry::write
virtual void write(Ostream &os) const
Write.
Definition: primitiveEntryIO.C:304
Foam::string
A class for handling character strings derived from std::string.
Definition: string.H:76
Foam::stringOps::trimLeft
string trimLeft(const std::string &s)
Return string trimmed of leading whitespace.
Definition: stringOps.C:930
Foam::transform
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:521
Foam::stringOps::inplaceRemoveComments
void inplaceRemoveComments(std::string &s)
Remove C/C++ comments inplace.
Definition: stringOps.C:1088
Foam::getEnv
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: MSwindows.C:371
Foam::mode
mode_t mode(const fileName &name, const bool followLink=true)
Return the file mode, normally following symbolic links.
Definition: MSwindows.C:564
findParameterAlternative
static char findParameterAlternative(const std::string &s, std::string::size_type &pos, std::string::size_type endPos=std::string::npos)
Definition: primitiveEntry.C:39
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::stringOps::inplaceExpand
void inplaceExpand(std::string &s, const HashTable< string > &mapping, const char sigil='$')
Definition: stringOps.C:731
Foam::stringOps::lower
string lower(const std::string &s)
Return string copy transformed with std::tolower on each character.
Definition: stringOps.C:1184
Foam::constant::physicoChemical::b
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
Foam::findEtcFile
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
Foam::entryToString
static std::string entryToString(const entry *eptr, const bool allowSubDict)
Definition: stringOps.C:226
Foam::stringOps::findTrim
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.
Foam::expandString
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
Foam::OSstream
Generic output stream using a standard (STL) stream.
Definition: OSstream.H:54
size_type
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:76
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::fixed
IOstream & fixed(IOstream &io)
Definition: IOstream.H:458
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
Foam::stringOps::trimRight
string trimRight(const std::string &s)
Return string trimmed of trailing whitespace.
Definition: stringOps.C:972
os
OBJstream os(runTime.globalPath()/outputName)
stdFoam::end
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:121
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::modeToLocation
static unsigned short modeToLocation(const std::string &mode, std::size_t pos=0)
Definition: stringOps.C:52
Foam::entry::dict
virtual const dictionary & dict() const =0
Return dictionary, if entry is a dictionary.
Foam::indent
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:339
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::foamVersion::version
const std::string version
OpenFOAM version (name or stringified number) as a std::string.
Foam::expandLeading
static void expandLeading(std::string &s)
Definition: stringOps.C:187
Foam::HashTable
A HashTable similar to std::unordered_map.
Definition: HashTable.H:105
Foam::OSstream::precision
virtual int precision() const
Get precision of output field.
Definition: OSstream.C:326
etcFiles.H
Functions to search 'etc' directories for configuration files etc.
Foam::stringOps::inplaceLower
void inplaceLower(std::string &s)
Inplace transform string with std::tolower on each character.
Definition: stringOps.C:1194
Foam::Detail::StringStreamAllocator::str
Foam::string str() const
Get the string - as Foam::string rather than std::string.
Definition: StringStream.H:88
Foam::IOstream::defaultPrecision
static unsigned int defaultPrecision() noexcept
Return the default precision.
Definition: IOstream.H:342
Foam::stringOps::inplaceTrimLeft
void inplaceTrimLeft(std::string &s)
Trim leading whitespace inplace.
Definition: stringOps.C:952
Foam::home
fileName home()
Return home directory path name for the current user.
Definition: MSwindows.C:449
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::dictionary::findScoped
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
Foam::HashTable::cfind
const_iterator cfind(const Key &key) const
Find and return an const_iterator set at the hashed entry.
Definition: HashTableI.H:141
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::stringOps::inplaceRemoveSpace
void inplaceRemoveSpace(std::string &s)
Eliminate whitespace inplace.
Definition: stringOps.C:1074
Foam::BitOps::count
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition: BitOps.H:77
Foam::dictionary::write
void write(Ostream &os, const bool subDict=true) const
Write dictionary, normally with sub-dictionary formatting.
Definition: dictionaryIO.C:206
Foam::OStringStream
Output to string buffer, using a OSstream. Always UNCOMPRESSED.
Definition: StringStream.H:227
Foam::error::master
static bool master(const label communicator=-1)
Definition: error.C:41
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::constant::universal::c
const dimensionedScalar c
Speed of light in a vacuum.
Foam::name
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
Foam::error::warnAboutAge
static bool warnAboutAge(const int version) noexcept
Test if an age warning should be emitted.
Definition: error.C:55
Foam::cwd
fileName cwd()
The physical or logical current working directory path name.
Definition: MSwindows.C:468
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
Foam::stringOps::count
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
Foam::fileName::assign
bool assign(const token &tok)
Assign from word or string token.
Definition: fileNameIO.C:42
Foam::stringOps::upper
string upper(const std::string &s)
Return string copy transformed with std::toupper on each character.
Definition: stringOps.C:1200
Foam::stringOps::removeComments
string removeComments(const std::string &s)
Return string with C/C++ comments removed.
Definition: stringOps.C:1080
Foam::stringOps::inplaceUpper
void inplaceUpper(std::string &s)
Inplace transform string with std::toupper on each character.
Definition: stringOps.C:1210
Foam::stringOps::expand
string expand(const std::string &s, const HashTable< string > &mapping, const char sigil='$')
Definition: stringOps.C:718
stringOps.H
Foam::recursiveExpand
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
OSstream.H
Foam::stringOps::evaluate
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.
Definition: stringOpsEvaluate.C:37
Foam::pos
dimensionedScalar pos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:177