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