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-2020 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  // Single warning (on master) with guard to avoid Pstream::master()
165  // when Pstream has not yet been initialized
166  if (UPstream::parRun() ? UPstream::master() : true)
167  {
168  std::cerr
169  << nl
170  << "--> FOAM Warning :" << nl
171  << " Found [v" << version << "] '"
172  << "~OpenFOAM" << "' string expansion instead of '"
173  << "<etc>" << "' in string\n\"" << s << "\"\n" << nl
174  << std::endl;
175 
176  error::warnAboutAge("expansion", version);
177  }
178 
179  s = findEtcFile(file);
180  }
181  else
182  {
183  s = home(user)/file;
184  }
185 }
186 
187 
188 // Expand leading contents: "./", "~..", "<tag>/"
189 static void expandLeading(std::string& s)
190 {
191  if (s.empty())
192  {
193  return;
194  }
195 
196  switch (s[0])
197  {
198  case '.':
199  {
200  // Expand a lone '.' and an initial './' into cwd
201  if (s.size() == 1)
202  {
203  s = cwd();
204  }
205  else if (s[1] == '/')
206  {
207  s.replace(0, 1, cwd());
208  }
209  break;
210  }
211  case '<':
212  {
213  expandLeadingTag(s, '<', '>');
214  break;
215  }
216  case '~':
217  {
219  break;
220  }
221  }
222 }
223 
224 
225 // Serialize an entry (primitive or dictionary) with special treatment
226 // for primitive entries that are already a string-type.
227 static inline std::string entryToString
228 (
229  const entry* eptr,
230  const bool allowSubDict
231 )
232 {
233  std::string str;
234 
235  if (eptr)
236  {
237  OStringStream buf;
238  // Force floating point numbers to be printed with at least
239  // some decimal digits.
240  buf << fixed;
242 
243  if (allowSubDict && eptr->isDict())
244  {
245  eptr->dict().write(buf, false);
246  str = buf.str();
247  }
248  else
249  {
250  // Fail for non-primitiveEntry
251  const primitiveEntry& pe =
252  dynamicCast<const primitiveEntry>(*eptr);
253 
254  if (pe.size() == 1 && pe[0].isStringType())
255  {
256  // Already a string-type (WORD, STRING, ...). Just copy.
257  str = pe[0].stringToken();
258  }
259  else
260  {
261  pe.write(buf, true);
262  str = buf.str();
263  }
264  }
265  }
266 
267  return str;
268 }
269 
270 } // End namespace Foam
271 
272 
273 // Details for handling dictionary expansion
274 
275 namespace
276 {
277 
278 // Acceptable values for $variable names.
279 //
280 // Similar to word::valid(), except we don't have the benefit of a parser
281 // to filter out other unacceptable entries for us.
282 //
283 // Does not currently accept '/' in a variable name.
284 // We would like "$file/$name" to expand as two variables.
285 static inline bool validVariableChar(char c)
286 {
287  return
288  (
289  std::isalnum(c)
290  || c == '.'
291  || c == ':'
292  || c == '_'
293  );
294 }
295 
296 
297 // Find the type/position of the ":-" or ":+" alternative values
298 // Returns 0, '-', '+' corresponding to not-found or ':-' or ':+'
299 static inline int findParameterAlternative
300 (
301  const std::string& s,
304 )
305 {
306  while (pos != std::string::npos)
307  {
308  pos = s.find(':', pos);
309  if (pos != std::string::npos)
310  {
311  if (pos < endPos)
312  {
313  // in-range: check for '+' or '-' following the ':'
314  const int altType = s[pos+1];
315  if (altType == '+' || altType == '-')
316  {
317  return altType;
318  }
319 
320  ++pos; // unknown/unsupported - continue at next position
321  }
322  else
323  {
324  // out-of-range: abort
325  pos = std::string::npos;
326  }
327  }
328  }
329 
330  return 0;
331 }
332 
333 
334 // For input string of "$variable with other" return the length of
335 // the variable.
336 //
337 // Intentionally will not capture ':+', ':-' alterations. Use ${ .. } for that
338 static inline std::string::size_type findVariableLen
339 (
340  const std::string& s,
342  const char sigil = '$'
343 )
344 {
345  std::string::size_type len = 0;
346 
347  if (pos < s.length())
348  {
349  if (s[pos] == sigil)
350  {
351  // Skip leading '$' in the count!
352  ++pos;
353  }
354 
355  for
356  (
357  auto iter = s.cbegin() + pos;
358  iter != s.cend() && validVariableChar(*iter);
359  ++iter
360  )
361  {
362  ++len;
363  }
364  }
365 
366  return len;
367 }
368 
369 } // End namespace anonymous
370 
371 
372 namespace Foam
373 {
374 
375 // Get dictionary or (optionally) environment variable
376 //
377 // Handles default and alternative values as per the POSIX shell.
378 // \code
379 // ${parameter:-defValue}
380 // ${parameter:+altValue}
381 // \endcode
383 (
384  const word& name,
385  const dictionary* dictptr,
386  const bool allowEnv,
387  const bool allowEmpty,
388  const bool allowSubDict
389 )
390 {
391  // The type/position of the ":-" or ":+" alternative values
392  std::string::size_type altPos = 0;
393 
394  // Check for parameter:-word or parameter:+word
395  const int altType =
396  findParameterAlternative(name, altPos, name.size()-1);
397 
398  const word lookupName =
399  (altType ? word(name.substr(0,altPos), false) : name);
400 
401  const entry* eptr =
402  (
403  (dictptr != nullptr)
404  ? dictptr->findScoped(lookupName, keyType::LITERAL_RECURSIVE)
405  : nullptr
406  );
407 
408  string value;
409  if (eptr)
410  {
411  value = entryToString(eptr, allowSubDict);
412  }
413  else if (allowEnv || dictptr == nullptr)
414  {
415  value = Foam::getEnv(lookupName);
416  }
417 
418  if (value.empty() ? (altType == '-') : (altType == '+'))
419  {
420  // Not found or empty: use ":-" alternative value
421  // Found and not empty: use ":+" alternative value
422  value = name.substr(altPos + 2);
423  }
424 
425  if (!allowEmpty && value.empty())
426  {
427  if (dictptr != nullptr)
428  {
429  auto& err =
430  FatalIOErrorInFunction(*dictptr)
431  << "Cannot find dictionary entry ";
432 
433  if (allowEnv)
434  {
435  err << "or environment ";
436  }
437 
438  err << "variable '" << lookupName << "'" << nl
439  << exit(FatalIOError);
440  }
441  else
442  {
444  << "Unknown variable '" << lookupName << "'" << nl
445  << exit(FatalError);
446  }
447  }
448 
449  return value;
450 }
451 
452 
453 // Recursively expands (dictionary or environment) variable
454 // starting at index in string. Updates index.
455 //
456 // String: "abc ${var} def",
457 // Receive: "var} def"
458 //
459 // String: "abc ${{expr}} def"
460 // Receive: "{expr}} def"
461 //
462 // On return, the index will be adjust to be AFTER the closing '}'
464 (
465  const std::string& s,
466  std::string::size_type& index,
467  const dictionary* dictptr,
468  const bool allowEnv,
469  const bool allowEmpty,
470  const bool allowSubDict
471 )
472 {
474 
475  // Track ${{ expr }} expressions
476  const bool isExpr = (index < s.size() && s[index] == '{');
477 
478  if (isExpr)
479  {
480  ++index;
481  }
482 
483  // Initially called for a ${variable}, not ${{expr}}
484  bool isVar = !isExpr;
485 
486  string out;
487 
488  for (/*nil*/; index < s.size(); ++index)
489  {
491  if (s[index] == '$')
492  {
493  if (s[index+1] == '{')
494  {
495  // Recurse to parse variable name
496  index += 2;
497 
498  string val =
500  (
501  s,
502  index,
503  dictptr,
504  allowEnv,
505  allowEmpty,
506  allowSubDict
507  );
508 
509  out.append(val); // Append content
510 
512 
513  // Already skipped past '}' terminator?
514  if (s[index-1] == '}')
515  {
516  --index;
517  }
518  }
519  else if (validVariableChar(s[index+1]))
520  {
521  // A regular $var expansion without a surrounding {}.
522 
523  const auto varLen = findVariableLen(s, index);
524  const word varName(s.substr(index+1, varLen), false);
525  index += varLen;
526 
527  string val =
529  (
530  varName,
531  dictptr,
532  allowEnv,
533  allowEmpty,
534  allowSubDict
535  );
536 
537  out.append(val); // Append content
538  }
539  else
540  {
541  // Something like '$()', '$[]', etc - pass through
542  out += s[index]; // Append char
543  }
544  }
545  else if (s[index] == '}')
546  {
547  // Closing an expression or variable
548 
549  if (isExpr)
550  {
551  // Closes with '}}'
552  ++index; // Index past closing '}'
553 
554  if (s[index] == '}')
555  {
556  ++index; // Index past closing '}'
557  }
558  else if (dictptr != nullptr)
559  {
560  // Missing '}'? - Warn/error/ignore
561  FatalIOErrorInFunction(*dictptr)
562  << "Expansion ${{ is missing a closing '}}'\n"
563  << exit(FatalIOError);
564  }
565  else
566  {
568  << "Expansion ${{ is missing a closing '}}'\n"
569  << exit(FatalIOError);
570  }
571 
573 
574  // Even with allow empty, expressions may need content
575 
576  string val(stringOps::evaluate(out));
578 
579  return val;
580  }
581  else if (isVar)
582  {
583  // Variable - closes with '}'
584 
585  ++index; // Index past closing '}'
586 
587  return
589  (
590  out,
591  dictptr,
592  allowEnv,
593  allowEmpty,
594  allowSubDict
595  );
596  }
597  else
598  {
599  // Stray '}'? - Leave on output
600 
601  out += s[index]; // append char
602  }
603  }
604  else
605  {
606  out += s[index]; // append char
607  }
608  }
609 
610  return out;
611 }
612 
613 
614 static void expandString
615 (
616  std::string& s,
617  const dictionary* dictptr,
618  const bool allowEnv,
619  const bool allowEmpty,
620  const bool allowSubDict,
621  const char sigil
622 )
623 {
624  std::string::size_type varBeg = 0;
625 
626  // Expand $VAR, ${VAR} or ${{EXPR}}
627  // Repeat until nothing more is found
628  while
629  (
630  (varBeg = s.find(sigil, varBeg)) != std::string::npos
631  && varBeg < s.size()-1
632  )
633  {
634  if (varBeg == 0 || s[varBeg-1] != '\\')
635  {
636  if (s[varBeg+1] == '{')
637  {
638  // Recursive variable expansion mode: '${' or '${{'
639  const auto replaceBeg = varBeg;
640 
641  varBeg += 2;
642  string varValue
643  (
645  (
646  s,
647  varBeg,
648  dictptr,
649  allowEnv,
650  allowEmpty,
651  allowSubDict
652  )
653  );
654 
655  s.replace(replaceBeg, varBeg - replaceBeg, varValue);
656  varBeg = replaceBeg+varValue.size();
657  }
658  else if (validVariableChar(s[varBeg+1]))
659  {
660  // A regular $var expansion without surrounding {}.
661  const auto varLen(findVariableLen(s, varBeg, sigil));
662  const word varName(s.substr(varBeg+1, varLen), false);
663 
664  string varValue
665  (
667  (
668  varName,
669  dictptr,
670  allowEnv,
671  allowEmpty,
672  allowSubDict
673  )
674  );
675 
676  s.replace(varBeg, varName.size()+1, varValue);
677  varBeg += varValue.size();
678  }
679  else
680  {
681  ++varBeg;
682  }
683  }
684  else
685  {
686  ++varBeg;
687  }
688  }
689 
690  expandLeading(s);
691 }
692 
693 } // End namespace Foam
694 
695 
696 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
697 
699 (
700  const std::string& s,
701  const char c
702 )
703 {
704  return std::count(s.cbegin(), s.cend(), c);
705 }
706 
707 
709 {
710  return
711  (
712  s == nullptr
713  ? 0
714  : std::count(s, (s + std::char_traits<char>::length(s)), c)
715  );
716 }
717 
718 
720 (
721  const std::string& s,
723  const char sigil
724 )
725 {
726  string out(s);
727  inplaceExpand(out, mapping);
728  return out;
729 }
730 
731 
733 (
734  std::string& s,
736  const char sigil
737 )
738 {
739  std::string::size_type varBeg = 0;
740 
741  // Expand $VAR or ${VAR}
742  // Repeat until nothing more is found
743  while
744  (
745  (varBeg = s.find(sigil, varBeg)) != std::string::npos
746  && varBeg < s.size()-1
747  )
748  {
749  if (varBeg == 0 || s[varBeg-1] != '\\')
750  {
751  // Find end of first occurrence
752  std::string::size_type varEnd = varBeg;
753  std::string::size_type delim = 0;
754 
755  // The type/position of the ":-" or ":+" alternative values
756  int altType = 0;
757  auto altPos = std::string::npos;
758 
759  if (s[varBeg+1] == '{')
760  {
761  varEnd = s.find('}', varBeg);
762  delim = 1;
763 
764  // Check for ${parameter:-word} or ${parameter:+word}
765  if (varEnd != std::string::npos)
766  {
767  altPos = varBeg;
768  altType = findParameterAlternative(s, altPos, varEnd);
769  }
770  }
771  else
772  {
773  varEnd += findVariableLen(s, varBeg, sigil);
774  }
775 
776  if (varEnd == std::string::npos)
777  {
778  // Likely parsed '${...' without closing '}' - abort
779  break;
780  }
781  else if (varEnd == varBeg)
782  {
783  // Something like '$()', '$[]', etc - pass through
784  ++varBeg;
785  }
786  else
787  {
788  const word varName
789  (
790  s.substr
791  (
792  varBeg + 1 + delim,
793  (
794  (altPos == std::string::npos ? varEnd : altPos)
795  - varBeg - 2*delim
796  )
797  ),
798  false
799  );
800 
801  std::string altValue;
802  if (altPos != std::string::npos)
803  {
804  // Had ":-" or ":+" alternative value
805  altValue = s.substr
806  (
807  altPos + 2,
808  varEnd - altPos - 2*delim
809  );
810  }
811 
812 
813  const auto fnd = mapping.cfind(varName);
814 
815  if (fnd.found() ? (altType == '+') : (altType == '-'))
816  {
817  // Found and ":+" alternative
818  // Not-found and ":-" alternative
819 
820  s.replace(varBeg, varEnd - varBeg + 1, altValue);
821  varBeg += altValue.size();
822  }
823  else if (fnd.found())
824  {
825  // Found: use value
826  s.replace(varBeg, varEnd - varBeg + 1, *fnd);
827  varBeg += (*fnd).size();
828  }
829  else
830  {
831  // Not-found: empty value
832  s.erase(varBeg, varEnd - varBeg + 1);
833  }
834  }
835  }
836  else
837  {
838  ++varBeg;
839  }
840  }
841 }
842 
843 
845 (
846  const std::string& s,
847  const dictionary& dict,
848  const char sigil
849 )
850 {
851  string out(s);
852  inplaceExpand(out, dict, sigil);
853  return out;
854 }
855 
856 
858 (
859  std::string& s,
860  const dictionary& dict,
861  const bool allowEnv,
862  const bool allowEmpty,
863  const bool allowSubDict,
864  const char sigil
865 )
866 {
867  expandString(s, &dict, allowEnv, allowEmpty, allowSubDict, sigil);
868 }
869 
870 
872 (
873  std::string& s,
874  const dictionary& dict,
875  const char sigil
876 )
877 {
878  // Allow everything, including subDict expansions
879  // env=true, empty=true, subDict=true
880  expandString(s, &dict, true, true, true, sigil);
881 }
882 
883 
885 (
886  const std::string& s,
887  const bool allowEmpty
888 )
889 {
890  string out(s);
891  inplaceExpand(out, allowEmpty);
892  return out;
893 }
894 
895 
897 (
898  std::string& s,
899  const bool allowEmpty
900 )
901 {
902  // Expand without a dictionary context
903  // allowEnv=true, allowSubDict=N/A
904  expandString(s, nullptr, true, allowEmpty, false, '$');
905 }
906 
907 
908 bool Foam::stringOps::inplaceReplaceVar(std::string& s, const word& varName)
909 {
910  if (s.empty() || varName.empty())
911  {
912  return false;
913  }
914 
915  const string content(Foam::getEnv(varName));
916  if (content.empty())
917  {
918  return false;
919  }
920 
921  const auto i = s.find(content);
922  if (i == std::string::npos)
923  {
924  return false;
925  }
926 
927  s.replace(i, content.size(), string("${" + varName + "}"));
928  return true;
929 }
930 
931 
933 {
934  if (!s.empty())
935  {
937  const auto end = s.length();
938 
939  while (pos < end && std::isspace(s[pos]))
940  {
941  ++pos;
942  }
943 
944  if (pos)
945  {
946  return s.substr(pos);
947  }
948  }
949 
950  return s;
951 }
952 
953 
955 {
956  if (!s.empty())
957  {
959  const auto end = s.length();
960 
961  while (pos < end && std::isspace(s[pos]))
962  {
963  ++pos;
964  }
965 
966  if (pos)
967  {
968  s.erase(0, pos);
969  }
970  }
971 }
972 
973 
975 {
976  if (!s.empty())
977  {
978  auto end = s.length();
979  while (end && std::isspace(s[end-1]))
980  {
981  --end;
982  }
983 
984  if (end < s.length())
985  {
986  return s.substr(0, end);
987  }
988  }
989 
990  return s;
991 }
992 
993 
995 {
996  if (!s.empty())
997  {
998  auto end = s.length();
999  while (end && std::isspace(s[end-1]))
1000  {
1001  --end;
1002  }
1003 
1004  s.erase(end);
1005  }
1006 }
1007 
1008 
1009 std::pair<std::size_t, std::size_t>
1011 (
1012  const std::string& s,
1013  std::size_t pos,
1014  std::size_t len
1015 )
1016 {
1017  size_t end = s.length();
1018  if (pos >= end)
1019  {
1020  pos = end;
1021  }
1022  else if (len != std::string::npos)
1023  {
1024  len += pos;
1025 
1026  if (len < end)
1027  {
1028  end = len;
1029  }
1030  }
1031 
1032  // Right = last
1033  while (pos < end && std::isspace(s[end-1]))
1034  {
1035  --end;
1036  }
1037 
1038  // Left = first
1039  while (pos < end && std::isspace(s[pos]))
1040  {
1041  ++pos;
1042  }
1043 
1044  return std::pair<std::size_t, std::size_t>(pos, end);
1045 }
1046 
1047 
1049 {
1051  std::string::size_type end = s.length();
1052 
1053  // Right
1054  while (pos < end && std::isspace(s[end-1]))
1055  {
1056  --end;
1057  }
1058 
1059  // Left
1060  while (pos < end && std::isspace(s[pos]))
1061  {
1062  ++pos;
1063  }
1064 
1065  return s.substr(pos, end-pos);
1066 }
1067 
1068 
1070 {
1072  inplaceTrimLeft(s);
1073 }
1074 
1075 
1077 {
1078  s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
1079 }
1080 
1081 
1083 {
1084  string out(s);
1085  inplaceRemoveComments(out);
1086  return out;
1087 }
1088 
1089 
1091 {
1092  const auto len = s.length();
1093 
1094  if (len < 2)
1095  {
1096  return;
1097  }
1098 
1100 
1101  for (std::string::size_type i = 0; i < len; ++i)
1102  {
1103  char c = s[i];
1104 
1105  if (n != i)
1106  {
1107  s[n] = c;
1108  }
1109  ++n;
1110 
1111  // The start of a C/C++ comment?
1112  if (c == '/')
1113  {
1114  ++i;
1115 
1116  if (i == len)
1117  {
1118  // No further characters
1119  break;
1120  }
1121 
1122  c = s[i];
1123 
1124  if (c == '/')
1125  {
1126  // C++ comment - remove to end-of-line
1127 
1128  --n;
1129  s[n] = '\n';
1130 
1131  // Backtrack to eliminate leading spaces,
1132  // up to the previous newline
1133 
1134  while (n && std::isspace(s[n-1]))
1135  {
1136  --n;
1137 
1138  if (s[n] == '\n')
1139  {
1140  break;
1141  }
1142 
1143  s[n] = '\n';
1144  }
1145 
1146  i = s.find('\n', ++i);
1147 
1148  if (i == std::string::npos)
1149  {
1150  // Truncated - done
1151  break;
1152  }
1153 
1154  ++n; // Include newline in output
1155  }
1156  else if (c == '*')
1157  {
1158  // C comment - search for '*/'
1159  --n;
1160  i = s.find("*/", ++i, 2);
1161 
1162  if (i == std::string::npos)
1163  {
1164  // Truncated - done
1165  break;
1166  }
1167 
1168  ++i; // Index past first of "*/", loop increment does the rest
1169  }
1170  else
1171  {
1172  // Not a C/C++ comment
1173  if (n != i)
1174  {
1175  s[n] = c;
1176  }
1177  ++n;
1178  }
1179  }
1180  }
1181 
1182  s.erase(n);
1183 }
1184 
1185 
1187 {
1188  string out;
1189  out.resize(s.length());
1190 
1191  std::transform(s.begin(), s.end(), out.begin(), ::tolower);
1192  return out;
1193 }
1194 
1195 
1197 {
1198  std::transform(s.begin(), s.end(), s.begin(), ::tolower);
1199 }
1200 
1201 
1203 {
1204  string out;
1205  out.resize(s.length());
1206 
1207  std::transform(s.begin(), s.end(), out.begin(), ::toupper);
1208  return out;
1209 }
1210 
1211 
1213 {
1214  std::transform(s.begin(), s.end(), s.begin(), ::toupper);
1215 }
1216 
1217 
1220  OSstream& os,
1221  const std::string& str,
1222  const std::string::size_type width,
1224  const bool escape
1225 )
1226 {
1227  const auto len = str.length();
1228 
1230 
1231  // Handle leading newlines
1232  while (str[pos] == '\n' && pos < len)
1233  {
1234  os << '\n';
1235  ++pos;
1236  }
1237 
1238  while (pos < len)
1239  {
1240  // Potential end point and next point
1241  std::string::size_type end = pos + width - 1;
1242  std::string::size_type eol = str.find('\n', pos);
1243  std::string::size_type next = string::npos;
1244 
1245  if (end >= len)
1246  {
1247  // No more wrapping needed
1248  end = len;
1249 
1250  if (std::string::npos != eol && eol <= end)
1251  {
1252  // Manual '\n' break, next follows it (default behaviour)
1253  end = eol;
1254  }
1255  }
1256  else if (std::string::npos != eol && eol <= end)
1257  {
1258  // Manual '\n' break, next follows it (default behaviour)
1259  end = eol;
1260  }
1261  else if (isspace(str[end]))
1262  {
1263  // Ended on a space - can use this directly
1264  next = str.find_first_not_of(" \t\n", end); // Next non-space
1265  }
1266  else if (isspace(str[end+1]))
1267  {
1268  // The next one is a space - so we are okay
1269  ++end; // Otherwise the length is wrong
1270  next = str.find_first_not_of(" \t\n", end); // Next non-space
1271  }
1272  else
1273  {
1274  // Line break will be mid-word
1275  auto prev = str.find_last_of(" \t\n", end); // Prev word break
1276 
1277  if (std::string::npos != prev && prev > pos)
1278  {
1279  end = prev;
1280  next = prev + 1; // Continue from here
1281  }
1282  }
1283 
1284  // The next position to continue from
1285  if (std::string::npos == next)
1286  {
1287  next = end + 1;
1288  }
1289 
1290  // Has a length
1291  if (end > pos)
1292  {
1293  // Indent following lines.
1294  // The first one was already done prior to calling this routine.
1295  if (pos)
1296  {
1297  for (std::string::size_type i = 0; i < indent; ++i)
1298  {
1299  os <<' ';
1300  }
1301  }
1302 
1303  while (pos < end)
1304  {
1305  const char c = str[pos];
1306 
1307  if (escape && c == '\\')
1308  {
1309  os << '\\';
1310  }
1311  os << c;
1312 
1313  ++pos;
1314  }
1315  os << nl;
1316  }
1317 
1318  pos = next;
1319  }
1320 }
1321 
1322 
1323 // ************************************************************************* //
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:78
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:994
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
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:1219
typeInfo.H
UPstream.H
Foam::stringOps::inplaceTrim
void inplaceTrim(std::string &s)
Trim leading and trailing whitespace inplace.
Definition: stringOps.C:1069
Foam::stringOps::inplaceReplaceVar
bool inplaceReplaceVar(std::string &s, const word &varName)
Replace environment variable contents with its name.
Definition: stringOps.C:908
Foam::getVariable
static Foam::string getVariable(const word &name, const dictionary *dictptr, const bool allowEnv, const bool allowEmpty, const bool allowSubDict)
Definition: stringOps.C:383
Foam::UPstream::parRun
static bool & parRun()
Test if this a parallel run, or allow modify access.
Definition: UPstream.H:434
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:1048
Foam::UPstream::master
static bool master(const label communicator=worldComm)
Am I the master process.
Definition: UPstream.H:458
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:350
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:300
Foam::string
A class for handling character strings derived from std::string.
Definition: string.H:73
Foam::stringOps::trimLeft
string trimLeft(const std::string &s)
Return string trimmed of leading whitespace.
Definition: stringOps.C:932
Foam::transform
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:519
Foam::stringOps::inplaceRemoveComments
void inplaceRemoveComments(std::string &s)
Remove C/C++ comments inplace.
Definition: stringOps.C:1090
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
Foam::stringOps::expand
string expand(const std::string &s, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Definition: stringOps.C:720
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::stringOps::lower
string lower(const std::string &s)
Return string copy transformed with std::tolower on each character.
Definition: stringOps.C:1186
Foam::constant::physicoChemical::b
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
Foam::entry::isDict
virtual bool isDict() const
Return true if this entry is a dictionary.
Definition: entry.H:222
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::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::entryToString
static std::string entryToString(const entry *eptr, const bool allowSubDict)
Definition: stringOps.C:228
Foam::stringOps::inplaceExpand
void inplaceExpand(std::string &s, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Definition: stringOps.C:733
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:615
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:449
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:121
Foam::stringOps::trimRight
string trimRight(const std::string &s)
Return string trimmed of trailing whitespace.
Definition: stringOps.C:974
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:320
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:189
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:320
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:1196
Foam::Detail::StringStreamAllocator::str
Foam::string str() const
Get the string - as Foam::string rather than std::string.
Definition: StringStream.H:91
Foam::stringOps::inplaceTrimLeft
void inplaceTrimLeft(std::string &s)
Trim leading whitespace inplace.
Definition: stringOps.C:954
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:381
Foam::error::warnAboutAge
static void warnAboutAge(const char *what, const int version)
Emit warning on stderr about something being old.
Definition: error.C:41
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: dictionary.C:394
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:385
Foam::IOstream::defaultPrecision
static unsigned int defaultPrecision()
Return the default precision.
Definition: IOstream.H:333
Foam::stringOps::inplaceRemoveSpace
void inplaceRemoveSpace(std::string &s)
Eliminate whitespace inplace.
Definition: stringOps.C:1076
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.
Definition: StringStream.H:196
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::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:401
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:699
Foam::stringOps::upper
string upper(const std::string &s)
Return string copy transformed with std::toupper on each character.
Definition: stringOps.C:1202
Foam::stringOps::removeComments
string removeComments(const std::string &s)
Return string with C/C++ comments removed.
Definition: stringOps.C:1082
Foam::stringOps::inplaceUpper
void inplaceUpper(std::string &s)
Inplace transform string with std::toupper on each character.
Definition: stringOps.C:1212
stringOps.H
Foam::isspace
bool isspace(char c)
Test for horizontal whitespace.
Definition: char.H:63
findParameterAlternative
static int findParameterAlternative(const std::string &s, std::string::size_type &pos, std::string::size_type endPos=std::string::npos)
Definition: primitiveEntry.C:39
Foam::stringOps::evaluate
string evaluate(const std::string &s, size_t pos=0, size_t len=std::string::npos)
Definition: stringOpsEvaluate.C:37
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:464
OSstream.H
Foam::pos
dimensionedScalar pos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:177