HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_String.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  *
7  * NAME: Utility Library (C++)
8  *
9  * COMMENTS: String class
10  *
11  */
12 
13 #ifndef __UT_String_h__
14 #define __UT_String_h__
15 
16 #include "UT_API.h"
17 
18 #include "UT_Assert.h"
19 #include "UT_VectorTypes.h"
20 #include "UT_StringView.h"
21 #include "UT_StringUtils.h"
22 
23 #include <SYS/SYS_Compiler.h>
24 #include <SYS/SYS_Deprecated.h>
25 #include <SYS/SYS_Inline.h>
26 #include <SYS/SYS_String.h>
27 #include <SYS/SYS_Types.h>
28 
29 #if __cplusplus >= 202002L
30  #include <concepts>
31 #endif
32 #include <iosfwd>
33 #include <string>
34 #include <utility>
35 
36 #include <ctype.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #ifdef WIN32
41  #define strcasecmp stricmp
42  #define strncasecmp strnicmp
43 #endif
44 
45 class UT_OStream;
46 class UT_String;
47 class UT_StringCshIO;
48 class UT_WorkArgs;
49 class UT_IStream;
50 class ut_PatternRecord;
51 class UT_StringMMPattern;
52 class UT_StringArray;
53 class UT_StringHolder;
54 class UT_StringRef;
55 
56 // The following lookup functions are used by cshParse. By default,
57 // varLookup simply uses getenv, exprLookup opens the command as
58 // a pipe and uses the result.
59 UT_API extern void UTvarLookup(const char *name, UT_String &result);
60 UT_API extern void UTexprLookup(const char *name, UT_String &result);
61 
62 /// @file
63 /// @class UT_String
64 ///
65 /// UT_String is a string class that support two different types of assignment
66 /// semantics:
67 /// - Shallow (default): Just reference the given string and NOT take
68 /// ownership.
69 /// - Deep: Make a copy of the given string, taking ownership in the
70 /// process (aka it making it "hard").
71 ///
72 /// If UT_String::harden() is called, or any other UT_String method that
73 /// requires modifying the string, it will make a copy of its reference pointer
74 /// (and take ownership) first.
75 ///
77 {
78 public:
79 
80  /// UT_String can be constructed with UT_String::ALWAYS_DEEP to create an
81  /// object that will always perform deep copies when assigned to.
82  enum UT_AlwaysDeepType { ALWAYS_DEEP };
83 
84  /// @brief Construct UT_String from a C string, using shallow semantics
85  ///
86  /// @param str The initial string.
88  UT_String(const char *str = nullptr)
89  : myData(SYSconst_cast(str))
90  , myIsReference(true)
91  , myIsAlwaysDeep(false)
92  {}
93 
94  /// @brief Construct UT_String from a C string, using shallow semantics
95  ///
96  /// @param str The initial string.
97  /// @param deep_copy If true, a copy of @em str will be used.
98  /// @param len Number of characters to use from @em str. Use -1 to
99  /// use the entire string. If len is non-negative, then
100  /// deepCopy will be implicitly set to true. If str is NULL
101  /// and len is non-negative, then it will be initialized
102  /// with "".
103  UT_String(const char *str, bool deep_copy, int len = -1);
104  // Prohibit accidents when converting to UT_StringHolder like:
105  // myString(buffer, /*deep*/1)
106  // where the 1 becomes a length. Note this also catches anyone who
107  // tried
108  // myString(buffer, UT_String::AlwaysDeep) as that should be first.
109  UT_String(const char *data, int bad) = delete;
110 
111 
112  /// @brief Construct UT_String from a std::string, always doing
113  /// a deep copy. The result will only be a UT_AlwaysDeep if the
114  /// appropriate version is used, however!
115  ///
116  /// NOTE: You cannot do:
117  /// UT_String foo;
118  /// std::string bar = "hello world";
119  /// foo = UT_String(bar.substr(2, 5));
120  ///
121  /// It provides an shortcut for constructing a UT_String from a function
122  /// that returns a std::string by value. For example, it lets you write
123  /// @code
124  /// UT_String str(func());
125  /// @endcode
126  /// instead of
127  /// @code
128  /// UT_String str(func().c_str(), /*harden=*/true);
129  /// @endcode
130  explicit UT_String(const std::string &str)
131  : myIsReference(false),
132  myIsAlwaysDeep(false)
133  { myData = strdup(str.c_str()); }
134 
135  /// @brief Construct UT_String from a UT_StringHolder.
136  /// This always duplicates and uses ALWAYS_DEEP semantics.
137  explicit UT_String(const UT_StringHolder &str);
138 
139  /// @brief Construct UT_String from a UT_StringHolder rvalue with
140  /// ALWAYS_DEEP semantics.
141  explicit UT_String(UT_StringHolder &&str);
142 
143 private:
144  /// This is intentionally not implemented - callers should choose between
145  /// the const char * and UT_StringHolder constructors, depending on whether
146  /// they want to make a deep copy.
147  /// @see UT_StringWrap.
148  UT_String(const UT_StringRef &);
149 
150 public:
151  /// @brief Construct UT_String from a UT_StringView.
152  /// This always duplicates and uses ALWAYS_DEEP semantics.
153  explicit UT_String(const UT_StringView &sv);
154 
155  /// @brief Construct UT_String from a C string, using ALWAYS_DEEP semantics
156  UT_String(UT_AlwaysDeepType, const char *str = nullptr)
157  : myIsReference(false),
158  myIsAlwaysDeep(true)
159  { myData = str ? strdup(str) : nullptr; }
160 
161  /// @brief Construct UT_String from a std::string, using ALWAYS_DEEP
162  /// semantics
163  UT_String(UT_AlwaysDeepType, const std::string &str)
164  : myIsReference(false),
165  myIsAlwaysDeep(true)
166  { myData = strdup(str.c_str()); }
167 
168  /// Copy constructor
169  ///
170  /// If the string we're copying from is ALWAYS_DEEP, then this object will
171  /// also become ALWAYS_DEEP. This way, you can pass/return a string by
172  /// value.
173  UT_String(const UT_String &str);
174 
175  ~UT_String();
176 
177  /// Move operators
178  /// @{
179  UT_String(UT_String &&str) noexcept
180  : myData(str.myData)
181  , myIsReference(str.myIsReference)
182  , myIsAlwaysDeep(str.myIsAlwaysDeep)
183  {
184  str.myData = nullptr;
185  str.myIsReference = !str.myIsAlwaysDeep;
186  }
187  UT_String &operator=(UT_String &&str) noexcept
188  {
189  freeData();
190  myData = str.myData;
191  myIsReference = str.myIsReference;
192  myIsAlwaysDeep = str.myIsAlwaysDeep;
193  str.myData = nullptr;
194  str.myIsReference = !str.myIsAlwaysDeep;
195  return *this;
196  }
197  /// @}
198 
199  /// Make a string always deep
200  void setAlwaysDeep(bool deep)
201  {
202  myIsAlwaysDeep = deep;
203  if (deep && myIsReference)
204  {
205  if (myData != nullptr)
206  harden();
207  else
208  {
209  // This takes the same semantic as
210  // str = NULL;
211  // where str is an always deep string
212  myIsReference = false;
213  }
214  }
215  }
216  bool isAlwaysDeep() const
217  {
218  return myIsAlwaysDeep;
219  }
220 
221  void swap( UT_String &other );
222 
223  /// Take shallow copy and make it deep.
224  // @{
225  void harden()
226  {
227  if (!myIsReference && myData)
228  return;
229  myData = strdup(myData ? myData : "");
230  myIsReference = false;
231  }
232 
233  void harden(const char *s, int len = -1);
235  {
236  if (myIsReference)
237  {
238  if (isstring())
239  harden();
240  else
241  *this = "";
242  }
243  }
244  void hardenIfNeeded(const char *s)
245  {
246  if (s && *s)
247  harden(s);
248  else
249  *this = "";
250  }
251  // @}
252 
253  /// Returns whether this string is hardened already.
254  bool isHard() const { return !myIsReference; }
255 
256  /// Give up ownership of string
257  ///
258  /// Take a hard reference and make it shallow. This method makes sure
259  /// it gives back something you can delete, because this UT_String is
260  /// taking its hands off the data. Use it with care since it may lead
261  /// to memory leaks if, for example, you harden it again later.
262  ///
263  /// In the case of ALWAYS_DEEP strings, this is disallowed so it will
264  /// just return a copy of the data.
265  char * steal()
266  {
267  if (!myIsAlwaysDeep)
268  {
269  if (myIsReference)
270  myData = strdup(myData ? myData : ""); // harden
271  myIsReference = true; // but say it's soft
272  return myData;
273  }
274  else
275  {
276  // return a new copy of the data without releasing
277  // ownership for always deep strings
278  return strdup(myData ? myData : "");
279  }
280  }
281 
282  /// Take ownership of given string
283  ///
284  /// adopt() is the opposite of steal(). Basically, you're giving
285  /// the UT_String ownership of the string.
286  // @{
287  void adopt(char *s)
288  {
289  if (!myIsReference)
290  {
291  if (s != myData)
292  utStrFree(myData);
293  }
294  myData = s;
295  myIsReference = false;
296  }
297  void adopt(UT_String &str)
298  {
299  adopt(str.steal());
300  }
301  void adopt(UT_StringHolder &holder);
302 
303  // @}
304 
305  /// Save string to binary stream.
306  void saveBinary(std::ostream &os) const { save(os, true); }
307 
308  /// Save string to ASCII stream. This will add double quotes and escape to
309  /// the stream if necessary (empty string or contains spaces).
310  void saveAscii(std::ostream &os) const { save(os, false); }
311  void saveAscii(UT_OStream &os) const { save(os, false); }
312 
313  /// Save string to stream. Saves as binary if @em binary is true.
314  void save(std::ostream &os, bool binary) const;
315  void save(UT_OStream &os, bool binary) const;
316 
317  /// Load string from stream. Use is.eof() to check eof status
318  bool load(UT_IStream &is);
319 
320  /// Reset the string to the default constructor.
321  void clear()
322  { *this = (const char *)nullptr; }
323 
324  /// Prepend a string (or character)
325  // @{
326  void prepend(const char *prefix);
327  void prepend(char ch);
328  // @}
329 
330  /// Append a character
331  void append(char ch);
332 
333  /// Append a string or a section of a string.
334  void append(const char *str, exint len = -1);
335 
336  /// Remove the last character
337  void removeLast() { truncate(length()-1); }
338  /// Truncate the string at the Nth character
339  void truncate(exint len);
340 
341  UT_String &operator=(const UT_String &str);
342  UT_String &operator=(const char *str);
343  UT_String &operator=(const std::string &str);
344  UT_String &operator=(const UT_StringHolder &str);
346  UT_String &operator=(const UT_StringView &str);
347 private:
348  /// Not implemented - see UT_String(const UT_StringRef &).
350 
351 public:
352  UT_String &operator+=(const char *str)
353  {
354  if (!isstring())
355  {
356  // We are an empty string, so we merely copy
357  // the incoming string rather than trying to append
358  // to it.
359  harden(str);
360  }
361  else
362  {
363  bool same = (str == myData);
364  harden();
365  if (str)
366  {
367  int mylen = (int)strlen(myData);
368  myData = (char *)realloc(myData,
369  mylen+strlen(str)+1);
370  if (!same)
371  {
372  strcpy(&myData[mylen], str);
373  }
374  else
375  {
376  memcpy(myData + mylen, myData, mylen);
377  myData[mylen * 2] = '\0';
378  }
379  }
380  }
381  return *this;
382  }
383 
385  {
386  *this += (const char *)str.myData;
387  return *this;
388  }
389  UT_String &operator+=(const UT_StringRef &str);
390 
391  // Basic equality functions and operators
392  int compare(const char *str, bool case_sensitive=true) const
393  {
394  // Unlike std::string, UT_String treats NULL and
395  // the empty string as distinct (empty has precedence).
396  if (myData == nullptr || str == nullptr)
397  {
398  if (myData) return 1;
399  if(str) return -1;
400  return 0;
401  }
402  if (case_sensitive)
403  return strcmp(myData, str);
404  return strcasecmp(myData, str);
405  }
406  int compare(const UT_String &str, bool case_sensitive=true) const
407  {
408  return compare(str.myData,case_sensitive);
409  }
410  int compare(const UT_StringRef &str, bool case_sensitive=true) const;
411 
412  bool equal(const char *str, bool case_sensitive=true) const
413  {
414  return compare(str,case_sensitive)==0;
415  }
416  bool equal(const UT_String &str, bool case_sensitive=true) const
417  {
418  return compare(str.myData,case_sensitive)==0;
419  }
420  bool equal(const UT_StringRef &str, bool case_sensitive=true) const
421  {
422  return compare(str,case_sensitive)==0;
423  }
424 
425  bool operator==(const char *str) const
426  {
427  return compare(str)==0;
428  }
429  bool operator==(const UT_String &str) const
430  {
431  return compare(str.myData)==0;
432  }
433  bool operator==(const UT_StringRef &str) const
434  {
435  return compare(str)==0;
436  }
437  bool operator!=(const char *str) const
438  {
439  return compare(str)!=0;
440  }
441  bool operator!=(const UT_String &str) const
442  {
443  return compare(str.myData)!=0;
444  }
445  bool operator!=(const UT_StringRef &str) const
446  {
447  return compare(str)!=0;
448  }
449  bool operator<(const char *str) const
450  {
451  return compare(str)<0;
452  }
453  bool operator<(const UT_String &str) const
454  {
455  return compare(str.myData)<0;
456  }
457  bool operator<(const UT_StringRef &str) const
458  {
459  return compare(str)<0;
460  }
461  bool operator<=(const char *str) const
462  {
463  return compare(str)<=0;
464  }
465  bool operator<=(const UT_String &str) const
466  {
467  return compare(str.myData)<=0;
468  }
469  bool operator<=(const UT_StringRef &str) const
470  {
471  return compare(str)<=0;
472  }
473  bool operator>(const char *str) const
474  {
475  return compare(str)>0;
476  }
477  bool operator>(const UT_String &str) const
478  {
479  return compare(str.myData)>0;
480  }
481  bool operator>(const UT_StringRef &str) const
482  {
483  return compare(str)>0;
484  }
485  bool operator>=(const char *str) const
486  {
487  return compare(str)>=0;
488  }
489  bool operator>=(const UT_String &str) const
490  {
491  return compare(str.myData)>=0;
492  }
493  bool operator>=(const UT_StringRef &str) const
494  {
495  return compare(str)>=0;
496  }
497 
498  /// Test whether the string is defined or not
499  explicit operator bool() const { return isstring(); }
500 
501  /// Return the edit distance between two strings.
502  /// See http://en.wikipedia.org/wiki/Levenshtein_distance for details.
503  /// allow_subst controls whether a substitution of a character with
504  /// another is a single operation, rather than two operations of
505  /// insert and delete.
506  int distance(const char *str,
507  bool case_sensitive = true,
508  bool allow_subst = true) const;
509 
510 #if __cplusplus >= 202002L
511  template <std::same_as<const char *> T>
512  operator T() const noexcept
513  { return (const char *)myData; }
514 #else
515  operator const char *() const
516  { return (const char *)myData; }
517 #endif
518  operator char *()
519  { return myData; }
520 
521  operator UT_StringView() const
522  { return UT_StringView(myData); }
523 
524  const char *c_str() const { return buffer(); }
525  const char *buffer() const { return myData; }
526  const char *data() const { return buffer(); }
527  const char *nonNullBuffer() const { return myData ? myData : ""; }
528 
529  const char &operator()(unsigned i) const
530  {
531  UT_ASSERT_P( isstring() );
532  UT_ASSERT_SLOW(i <= strlen(myData));
533  return myData[i];
534  }
535  // This doesn't work because C++20 compilers will find this ambiguous
536  // with the default conversion to const char *. Use operator() instead.
537  //char operator[](unsigned i) const { return (*this)(i); }
538 
539  char &operator()(unsigned i)
540  {
541  harden();
542  return myData[i];
543  }
544  // This is dangerous because it hardens the string resulting in different
545  // data. Use write() instead.
546  //char &operator[](unsigned i) { return (*this)(i); }
547 
548  // Prefer using write() since ideally the non-const operator() is removed
549  inline void write(unsigned i, char c)
550  {
551  hardenIfNeeded();
552  myData[i] = c;
553  }
554 
555  int toInt() const;
556  fpreal toFloat() const;
557 
558  /// Converts the contents of this UT_String to a std::string. Note that
559  /// std::string can't be constructed with a null pointer, so you can't
560  /// just write std::string s = ut_string.buffer();
561  std::string toStdString() const;
562 
563  //
564  // Here, we're finished with operators
565  //
566 
567  /// Return length of string
568  unsigned length() const
569  { return (myData) ? (unsigned)strlen(myData) : 0; }
570 
571  /// Return memory usage in bytes
572  int64 getMemoryUsage(bool inclusive=true) const
573  {
574  return (inclusive ? sizeof(*this) : 0)
575  + (!myIsReference ? (length() + 1)*sizeof(char) : 0);
576  }
577 
578  /// Find first occurrance of character. Returns NULL upon failure.
579  /// @{
580  char *findChar(int c)
581  { return myData ? strchr(myData, c) : nullptr; }
582  const char *findChar(int c) const
583  { return SYSconst_cast(*this).findChar(c); }
584  /// @}
585 
586  /// Find first occurrance of any character in @em str
587  /// @{
588  char *findChar(const char *str)
589  { return myData ? strpbrk(myData, str) : nullptr; }
590  const char *findChar(const char *str) const
591  { return SYSconst_cast(*this).findChar(str); }
592  /// @}
593 
594  /// Find last occurance of character
595  /// @{
596  char *lastChar(int c)
597  { return myData ? strrchr(myData, c) : nullptr; }
598  const char *lastChar(int c) const
599  { return SYSconst_cast(*this).lastChar(c); }
600  /// @}
601 
602  /// Return the number of occurrences of the specified character.
603  int countChar(int c) const;
604 
605  /// Count the occurrences of the string
606  int count(const char *str, bool case_sensitive = true) const;
607 
608  char *findNonSpace();
609  const char *findNonSpace() const;
610  const char *findWord(const char *word) const;
611  bool findString(const char *str, bool fullword,
612  bool usewildcards) const;
613  int changeWord(const char *from, const char *to, bool all = true);
614  int changeString(const char *from, const char *to, bool fullword);
615  int changeQuotedWord(const char *from, const char *to,
616  int quote = '`', bool all = true);
617 
618  int findLongestCommonSuffix( const char *with ) const;
619 
620  /// Perform deep copy of the substring starting from @em index
621  /// for @em len characters into the specified UT_String.
622  /// If @em len is too long, then a substring starting from @em index to
623  /// the end of the string is copied.
624  /// Returns the length of the copied substring.
625  int substr(UT_String &buf, int index, int len=0) const;
626 
627  /// Determine if string can be seen as a single floating point number
628  bool isFloat(bool skip_spaces = false,
629  bool loose = false,
630  bool allow_underscore = false) const;
631  /// Determine if string can be seen as a single integer number
632  bool isInteger(bool skip_spaces = false) const;
633 
634  void toUpper()
635  {
636  char *ptr;
637  harden();
638  for (ptr=myData; *ptr; ptr++)
639  *ptr = (char)toupper(*ptr);
640  }
641  void toLower()
642  {
643  char *ptr;
644  harden();
645  for (ptr=myData; *ptr; ptr++)
646  *ptr = (char)tolower(*ptr);
647  }
648 
649 
650  /// Return last component of forward slash separated path string
651  ///
652  /// If there is a slash in the string, fileName() returns the string
653  /// starting after the slash. Otherwise, it returns the contents of
654  /// this string. Note that it returns a pointer into this string.
655  const char *fileName() const
656  {
657  UT_StringView file_name = UTstringFileName(*this);
658  return file_name.begin();
659  }
660  /// Return the extension of a file path string
661  /// @{
663  {
665  if (extension.isEmpty())
666  return nullptr;
667  return myData + (extension.begin() - myData);
668  }
669  const char *fileExtension() const
670  {
671  return SYSconst_cast(*this).fileExtension();
672  }
673  /// @}
674 
675  /// Return whether the file extension matches. The extension passed in
676  /// should include the '.' separator. For example: @code
677  /// matchFileExtension(".jpg")
678  /// @endcode
679  bool matchFileExtension(const char *match_extension) const
680  {
681  return UTstringMatchFileExtension(*this, match_extension);
682  }
683  /// Return path terminated just before the extension.
684  /// If the filename starts with '.' and no path is provided,
685  /// returns NULL
686  UT_String pathUpToExtension() const;
687 
688  /// Replace the file extension and return the new string
689  UT_String replaceExtension(const UT_String &new_ext) const;
690 
691  /// Split a path into @em dir_name and @em file_name, where @em file_name
692  /// is everything after the final slash (i.e. the same as fileName()).
693  /// Either part may be empty. Note that if the string starts with / and
694  /// only contains that one slash, the @em dir_name will be / and not blank.
695  /// @em dir_name and @em file_name will either be set to hardened strings
696  /// or an empty string.
697  void splitPath(UT_String &dir_name, UT_String &file_name) const;
698 
699  /// Decompose a filename into various parts
700  ///
701  /// parseNumberedFileName will breakup a filename into its various
702  /// parts: file = prefix$Fsuffix (note: suffix is
703  /// not the same as file extension.) 0 is returned if there is
704  /// no frame number. 'negative' allows -[frame] to be interpreted as a
705  /// negative number. 'fractional' allows [frame].[number] to be interpreted
706  /// as a fractional frame.
707  int parseNumberedFilename(UT_String &prefix,
708  UT_String &frame,
709  UT_String &suff,
710  bool negative = true,
711  bool fractional = false) const;
712 
713  bool isstring() const
714  { return (myData && *myData); }
715 
716  /// trimSpace() will remove all space characters (leading and following)
717  /// from a string. If the string consists of multiple words, the words will
718  /// be collapsed. The function returns 1 if space was trimmed.
719  int trimSpace(bool leave_single_space_between_words = false);
720 
721  /// A version of trimSpace() that only removes leading and following spaces
722  /// from a string, leaving any between words intact.
723  int trimBoundingSpace();
724 
725  /// strips out all characters found in 'chars'. The string length will be
726  /// reduced by the number of characters removed. The number of characters
727  /// removed is returned.
728  int strip(const char *chars);
729 
730  /// protectString() will modify the existing string to escape double quotes
731  /// and backslashes. It will only wrap the string in double quotes if
732  /// it has spaces in it. If 'protect_empty' is true, the string will
733  /// become '""', otherwise it will stay empty.
734  void protectString(bool protect_empty=false);
735 
736  /// If the char is a quote character `"` or `'` then make sure to protect
737  /// it by adding '\' before the quote character. If the character is not
738  /// a quote character then the character is simply added to the ostream.
739  static void protectString(std::ostream& os, char c);
740 
741  /// protectPreQuotePythonStringLiteral() will modify the existing string
742  // to escape any non-printing characters, backslashes, and instances of the
743  /// specified delimiter. Unlike protectString(), it will not wrap the
744  /// string in quotes.
745  void protectPreQuotePythonStringLiteral(char delimiter='\'');
746 
747  /// returns true if the string begins and ends with a (non-escaped) quote
748  /// 'delimiter'.
749  bool isQuotedString(char delimiter='\'') const;
750 
751  /// makeQuotedString() is similar to protectString() except it returns a
752  /// new string instead of changing this string, it does wrap the string
753  /// in quotes, and it lets you use either ' or " as the delimiter.
754  /// The quoted string can also be optionally be made to escape non-printing
755  /// characters. The string that's returned is UT_String::ALWAYS_DEEP.
756  UT_String makeQuotedString(char delimiter='\'',
757  bool escape_nonprinting=false) const;
758 
759  /// makeSmartQuotedString() will use either ' or " as the delimiter to
760  /// avoid escaped quotes, using the default delimiter if it doesn't
761  /// matter. The quoted string can also be optionally be made to escape
762  /// non-printing characters. The string that's returned is
763  /// UT_String::ALWAYS_DEEP.
764  UT_String makeSmartQuotedString(char default_delimiter='\'',
765  bool escape_nonprinting=false) const;
766 
767  /// Expands standard control sequences ('\\n', '\\r', '\\t', '\\0') to their
768  /// corresponding ASCII values (10, 13, 9, 0, respectively).
769  /// If the expand_extended flag is enabled, an extended expansion is enabled
770  /// which adds hexadecimal, decimal and Unicode control sequence expansion.
771  /// Any values resulting from that expansion, which are outside the standard
772  /// ASCII range, will be encoded as UTF8-encoded control points.
773  void expandControlSequences(bool expand_extended = false);
774 
775  bool hasWhiteSpace() const;
776 
777  void removeTrailingSpace();
778  void removeTrailingChars(char chr);
779 
780  void removeTrailingDigits();
781 
782  /// Parse string into array of arguments similar to csh.
783  ///
784  /// cshParse() does not need to harden the string. It does very robust
785  /// parsing in the style of csh. It actually does better parsing than
786  /// csh. Variable expansion & backquote expansion are done in the
787  /// correct order for the correct arguments. One caveat is that the
788  /// string cannot have \0377 (0xff) as a character in it.
789  ///
790  /// If there is an error in parsing, the error flag (if passed in) will be
791  /// set to:
792  /// 0 = no error
793  /// 1 = line too long
794  ///
795  /// To reconstruct the command line, use UT_Args::fillCommandLine().
796  ///
797  /// @{
798  int cshParse(char *argv[], int max_args,
799  void (*vlookup)(const char *, UT_String&)=UTvarLookup,
800  void (*elookup)(const char *, UT_String&)=UTexprLookup,
801  int *error = nullptr,
802  UT_StringCshIO *io = nullptr);
803  int cshParse(UT_WorkArgs &argv,
804  void (*vlookup)(const char *, UT_String&)=UTvarLookup,
805  void (*elookup)(const char *, UT_String&)=UTexprLookup,
806  int *error = nullptr,
807  UT_StringCshIO *io = nullptr);
808  /// @}
809 
810  /// dosParse() uses the semi-braindead approach of ms-dos to argument
811  /// parsing. That is, arguments are separated by a double quote or space
812  /// (being a space or a tab). If 'preserve_backslashes' is set to
813  /// false (the default), back-slashes are passed through verbatim, unless
814  /// the following character is a double quote. Likewise, any pairs of
815  /// back-slashes preceding a double quote are turned into single
816  /// back-slashes.
817  ///
818  /// See also UTUTbuildDOSCommandLine() for reconstructing from arguments.
819  ///
820  /// @{
821  int dosParse(UT_WorkArgs &argv, bool preserve_backslashes=false);
822  int dosParse(char *argv[], int max_args,
823  bool preserve_backslashes=false);
824  /// Perform dos parsing modifying the buffer passed in. The args will be
825  /// stored as raw pointers into the given buffer
826  static int dosParse(char *buffer, UT_WorkArgs &args,
827  bool preserve_backslashes);
828  /// @}
829 
830  // parse will insert nulls into the string.
831  // NB: The argv array is null terminated, thus the effective
832  // maximum number of arguments is one less than maxArgs.
833  // NB: The maxArgs variants are all deprecated, use UT_WorkArgs
834  // instead.
835  int parse(char *argv[], int max_args,
836  const char *quotes = "\"'", bool keep_quotes = false)
837  {
838  harden();
839  return parseInPlace(argv, max_args, quotes, keep_quotes);
840  }
841  int parse(UT_WorkArgs &argv, int start_arg = 0,
842  const char *quotes = "\"'", bool keep_quotes = false)
843  {
844  harden();
845  return parseInPlace(argv, start_arg, quotes, keep_quotes);
846  }
847  int parse(UT_StringArray &argv, int start_arg = 0,
848  const char *quotes = "\"'", bool keep_quotes = false)
849  {
850  harden();
851  return parseInPlace(argv, start_arg, quotes, keep_quotes);
852  }
853  // Warning: the following methods insert nulls into the string without
854  // hardening.
855  int parseInPlace(char *argv[], int max_args,
856  const char *quotes = "\"'", bool keep_quotes = false);
857  int parseInPlace(UT_WorkArgs &argv, int start_arg = 0,
858  const char *quotes = "\"'", bool keep_quotes = false);
859  int parseInPlace(UT_StringArray &argv, int start_arg = 0,
860  const char *quotes = "\"'", bool keep_quotes = false);
861 
862  // Splits the string at specific separator characters. Unlike the parse
863  // methods, the tokenize methods ignore quoting completely.
864  int tokenize(char *argv[], int max_args, char separator)
865  {
866  harden();
867  return tokenizeInPlace(argv, max_args, separator);
868  }
869  int tokenizeInPlace(char *argv[], int max_args, char separator);
870  int tokenize(UT_WorkArgs &argv, char separator)
871  {
872  harden();
873  return tokenizeInPlace(argv, separator);
874  }
875  int tokenizeInPlace(UT_WorkArgs &argv, char separator);
876  int tokenize(char *argv[], int max_args,
877  const char *separators = " \t\n")
878  {
879  harden();
880  return tokenizeInPlace(argv, max_args, separators);
881  }
882  int tokenizeInPlace(char *argv[], int max_args,
883  const char *separators = " \t\n");
884  int tokenize(UT_WorkArgs &argv, const char *separators = " \t\n")
885  {
886  harden();
887  return tokenizeInPlace(argv, separators);
888  }
889  int tokenizeInPlace(UT_WorkArgs &argv,
890  const char *separators = " \t\n");
891 
892  template<typename T>
893  int tokenize(T &list, const char *separators = " \t\n")
894  {
895  harden();
896  return tokenizeInPlace(list, separators);
897  }
898 
899  template<typename T>
900  int tokenizeInPlace(T &list,
901  const char *separators = " \t\n")
902  {
903  char *token;
904  char *context;
905 
906  if (!isstring())
907  return 0;
908  if (!(token = SYSstrtok(myData, separators, &context)))
909  return 0;
910 
911  list.append(token);
912 
913  while ((token = SYSstrtok(nullptr, separators, &context))
914  != nullptr)
915  list.append(token);
916 
917  return list.entries();
918  }
919 
920 
921  // Replaces the contents with variables expanded.
922  void expandVariables();
923 
924  // Functions to hash a string
926  {
927  return hash(myData);
928  }
929 
930  // The code can be used for rudimentary hash chaining, but it is NOT
931  // the case that hash("def", hash("abc")) == hash("abcdef"), so there
932  // is little reason to use this rather than normal hash combiners.
933  static SYS_FORCE_INLINE uint32 hash(const char *str, uint32 code = 0)
934  {
935  return SYSstring_hashseed(
936  str, SYS_EXINT_MAX, code, /*allow_nulls*/ false);
937  }
938 
939  // This does pattern matching on a string. The pattern may include
940  // the following syntax:
941  // ? = match a single character
942  // * = match any number of characters
943  // [char_set] = matches any character in the set
944  bool match(const char *pattern, bool case_sensitive = true) const;
945 
946  // Similar to match() except it assumes that we're dealing with file paths
947  // so that it determines whether to do a case-sensitive match depending on
948  // the platform.
949  bool matchFile(const char *pattern) const;
950 
951  // Similar to match() but uses rsync style matching:
952  // * = match any number of characters up to a slash
953  // ** = match any number of characters, including a slash
954  bool matchPath(const char *pattern, bool case_sensitive = true,
955  bool *excludes_branch = nullptr) const;
956 
957  // multiMatch will actually check multiple patterns all separated
958  // by the separator character: i.e. geo1,geo2,foot*
959  //
960  // NOTE: No pattern or may contain the separator
961  bool multiMatch(const char *pattern,
962  bool case_sensitive, char separator) const;
963  bool multiMatch(const char *pattern, bool case_sensitive = true,
964  const char *separators = ", ",
965  bool *explicitly_excluded = nullptr,
966  int *match_index = nullptr,
967  ut_PatternRecord *pattern_record = nullptr) const;
968  bool multiMatch(const UT_StringMMPattern &pattern,
969  bool *explicitly_excluded = nullptr,
970  int *match_index = nullptr,
971  ut_PatternRecord *pattern_record = nullptr) const;
972 
973  // this method matches a pattern while recording any wildcard
974  // patterns used.
975  bool multiMatchRecord(const char *pattern, int maxpatterns,
976  char *singles, int &nsingles,
977  char **words, int &nwords,
978  bool case_sensitive = true,
979  const char *separators = ", ") const;
980  bool multiMatchRecord(const UT_StringMMPattern &pattern,
981  int maxpatterns,
982  char *singles, int &nsingles,
983  char **words, int &nwords) const;
984  bool multiMatchRecord(const char *pattern,
985  UT_StringHolder &singles,
986  UT_StringArray &words,
987  bool case_sensitive = true,
988  const char *separators = ", ") const;
989 
990  /// matchPattern(UT_WorkArgs &) assumes that the arguments contain the
991  /// components of a pattern to be matched against. The method returns
992  /// true if the pattern matches, false if it doesn't. This matching
993  /// process handles ^ expansion properly (and efficiently).
994  /// If the string doesn't match any components of the pattern, then the
995  /// assumed value is returned.
996  bool matchPattern(const UT_WorkArgs &pattern_args,
997  bool assume_match=false) const;
998 
999  static bool multiMatchCheck(const char *pattern);
1000  static bool wildcardMatchCheck(const char *pattern);
1001 
1002  // Same as match but equivalent to "*pattern*"
1003  bool contains(const char *pattern, bool case_sensitive=true) const;
1004 
1005  // Returns true if our string starts with the specified prefix.
1006  bool startsWith(const UT_StringView &prefix,
1007  bool case_sensitive = true) const;
1008 
1009  // Returns true if our string ends with the specified suffix.
1010  bool endsWith(const UT_StringView &suffix,
1011  bool case_sensitive = true) const;
1012 
1013  /// Pluralize an English noun ending (i.e. box->boxes or tube->tubes). The
1014  /// ending must be lower case to be processed properly.
1015  void pluralize();
1016 
1017  // Will parse strings like 1-10:2,3 and call func for every element
1018  // implied. It will stop when the func returns 0 or the parsing
1019  // is complete, in which case it returns 1.
1020  // Parsing also allows secondary elements to be specified eg 3.4 0.12
1021  // The secfunc is used to find the maximum index of secondary elements
1022  // for each compound num. The elements are assumed to be
1023  // non-negative integers.
1024  int traversePattern(int max, void *data,
1025  int (*func)(int num, int sec, void *data),
1026  unsigned int (*secfunc)(int num,void *data)
1027  = nullptr,
1028  int offset=0, bool invert=false) const;
1029 
1030  // Fast containment, assumes no special characters
1031  const char *fcontain(const char *pattern, bool case_sensitive=true) const
1032  {
1033  if (!myData)
1034  return nullptr;
1035  return case_sensitive ? strstr(myData, pattern)
1036  : SYSstrcasestr(myData, pattern);
1037  }
1038 
1039  // Given the match pattern which fits our contents, any assigned wildcards
1040  // are subsitituted. The wildcards may also be indexed.
1041  // Returns true if rename was successful.
1042  //
1043  // @note This code was adapted from CHOP_Rename::subPatterns() and
1044  // works the same way.
1045  //
1046  // eg. this = apple, match = a*le, replace = b* ---> bpp
1047  // this = a_to_b, match = *_to_*, replace = *(1)_to_*(0) ---> b_to_a
1048  bool patternRename(const char *match_pattern, const char *replace);
1049 
1050  // Given the name rule according to which a name consists of a base name
1051  // (char sequence ending in a non-digit) and a numerical suffix, the
1052  // following two methods return the base and the suffix respectively.
1053  // base() needs a string buffer and will return a const char* pointing to it.
1054  // base() always returns a non-zero pointer,
1055  // while suffix() returns 0 if no suffix is found.
1056  const char *base(UT_String &buf) const;
1057  const char *suffix() const;
1058 
1059  // incrementNumberedName will increment a name. If it has a numerical
1060  // suffix, that suffix is incremented. If not, "2" is appended to the
1061  // name. The preserve_padding parameter can be set to true so that zero
1062  // padding is preserved. Incrementing foo0009 will produce foo10 with
1063  // this parameter set to false, or foo0010 if it is set to true.
1064  void incrementNumberedName(bool preserve_padding = false);
1065 
1066  // setFormat is used to set how an outstream formats its ascii output.
1067  // So you can use printf style formatting. eg:
1068  // UT_String::setFormat(cout, "%08d") << 100;
1069  //
1070  // Note: Don't do:
1071  // cout << UT_String::setFormat(cout, "%08d") << 100;
1072  // ^^^^
1073  // Also: The formating changes (except for field width) are permanent,
1074  // so you'll have to reset them manually.
1075  //
1076  // TODO: A resetFormat, and a push/pop format pair.
1077  static std::ostream &setFormat(std::ostream &os, const char *fmt);
1078  std::ostream &setFormat(std::ostream &os);
1079 
1080  int replacePrefix(const char *oldpref,
1081  const char *newpref);
1082  int replaceSuffix(const char *oldsuffix,
1083  const char *newsuffix);
1084 
1085  // expandArrays will expand a series of tokens of the
1086  // form prefix[pattern]suffix into the names array
1087  //
1088  // Note: Each names[i] must be free'd after use
1089  // and label is used on the non-const parse method
1090  // NB: The max variants are all deprecated, use UT_WorkArgs
1091  // instead.
1092  int expandArrays(char *names[], int max);
1093 
1094  // This routine will ensure no line is over the specified
1095  // number of columns. Offending lines will be wrapped at
1096  // the first spaceChar or cut at exactly cols if spaceChar
1097  // is not found.
1098  // It returns one if any changes were done.
1099  // It currently treats tabs as single characters which should be
1100  // changed.
1101  // It will break words at hyphens if possible.
1102  int format(int cols);
1103 
1104  /// Replaces up to 'count' occurrences of 'find' with 'replacement',
1105  /// and returns the number of substitutions that occurred.
1106  /// If 'count' <= 0, all occurrences will be replaced.
1107  int substitute( const char *find, const char *replacement,
1108  exint count = -1);
1109 
1110  // This function replaces the character found with another character.
1111  int substitute( char find, char replacement, bool all = true );
1112 
1113  // this function removes the substring at pos and len, and inserts str
1114  // at pos. it returns the difference (new_length - old_length)
1115  int replace( int pos, int len, const char *str );
1116 
1117  // remove the first len characters of this string
1118  int eraseHead(int len)
1119  { return replace(0, len, ""); }
1120 
1121  // remove the last len characters of this string
1122  int eraseTail(int len)
1123  { return replace(length() - len, len, ""); }
1124 
1125  // remove the substring start at pos for len characters
1126  int erase(int pos = 0, int len = -1)
1127  {
1128  if (len < 0)
1129  len = length() - pos;
1130  return replace(pos, len, "");
1131  }
1132 
1133  // insert the given string at pos into this string
1134  int insert(int pos, const char *str)
1135  { return replace(pos, 0, str); }
1136 
1137  // Does a "smart" string compare which will sort based on numbered names.
1138  // That is "text20" is bigger than "text3". In a strictly alphanumeric
1139  // comparison, this would not be the case. Zero is only returned if both
1140  // strings are identical.
1141  static int compareNumberedString(const char *s1,
1142  const char *s2,
1143  bool case_sensitive=true,
1144  bool allow_negatives=false);
1145  static int qsortCmpNumberedString(const char *const*v1,
1146  const char *const*v2);
1147 
1148  // Like compare numbered strings, but it sorts better when there are
1149  // .ext extensions (i.e. it handles '.' as a special case)
1150  static int compareNumberedFilename(const char *s1,
1151  const char *s2,
1152  bool case_sensitive=false);
1153  static int qsortCmpNumberedFilename(const char *const*v1,
1154  const char *const*v2);
1155 
1156  // Like compare numbered strings, but allows special ordering of certain
1157  // characters that should always come first or last.
1158  static int compareNumberedStringWithExceptions(const char *s1,
1159  const char *s2,
1160  bool case_sensitive=false,
1161  bool allow_negatives=false,
1162  const char *sorted_first=nullptr,
1163  const char *sorted_last=nullptr);
1164 
1165  /// Compare two version strings which have numbered components separated by
1166  /// dots. eg. "X.Y.Z". Assumes the components go from most to least
1167  /// significant in left to right order.
1168  static int compareVersionString(const char *s1, const char *s2);
1169 
1170  /// Given a path, set the value of the string to the program name. For
1171  /// example: @code
1172  /// str.extractProgramName(argv[0]);
1173  /// str.extractProgramName("c:/Path/program.exe");
1174  /// str.extractProgramName("/usr/bin/program");
1175  /// @endcode
1176  /// This will extract the last path component. Program names may also have
1177  /// their extensions stripped. For example ".exe" on Windows and "-bin" to
1178  /// strip the Houdini wrappers on other platforms.
1179  ///
1180  /// @note The path should be normalized to have forward slashes as the path
1181  /// separator.
1182  void extractProgramName(const char *path,
1183  bool strip_extension=true,
1184  bool normalize_path=true);
1185 
1186  /// Given a path, check to see whether the program name matches the
1187  /// expected. For example: @code
1188  /// if (UT_String::matchProgramname(argv[0], "houdini"))
1189  /// if (UT_String::matchProgramname("c:/Path/houdini.exe", "houdini"))
1190  /// if (UT_String::matchProgramname("/usr/bin/houdini", "houdini"))
1191  /// @endcode
1192  /// The matching is always case-insensitive.
1193  ///
1194  /// @note The path should be normalized to have forward slashes as the path
1195  /// separator.
1196  static bool matchProgramName(const char *path, const char *expected,
1197  bool normalize_path=false);
1198 
1199  /// Convert a path to a "normalized" path. That is, all back-slashes will
1200  /// be converted to forward slashes. On some operating systems, this will
1201  /// leave the string unchanged.
1202  void normalizePath();
1203 
1204  // A very fast integer to string converter. This is faster (at least on
1205  // SGI) than using sprintf("%d"). About two to three times as fast. Both
1206  // of these methods return the length of the string generated.
1207  static int itoa(char *str, int64 i);
1208  static int utoa(char *str, uint64 i);
1209 
1210  // Versions of the above functions which set into this string object
1211  void itoa(int64 i);
1212  void utoa(uint64 i);
1213 
1214  // A reader-friendly version of itoa. This places commas appropriately
1215  // to ensure the person can pick out the kilo points easily.
1216  // This can handle numbers up to 999,999,999,999,999,999.
1217  void itoaPretty(int64 val);
1218 
1219  /// Convert the given time delta (in milliseconds)
1220  /// to a reader-friendly string in days, hours, minutes, and seconds.
1221  void timeDeltaToPrettyString(double time_ms);
1222 
1223  /// Convert the given time delta (in milliseconds)
1224  /// to a reader-friendly string in milliseconds.
1225  void timeDeltaToPrettyStringMS(double time_ms);
1226 
1227  // Do an sprintf into this string. This method will allocate exactly the
1228  // number of bytes required for the final string. If the format string is
1229  // bad, isstring() will return false afterwards.
1230  int sprintf(const char *fmt, ...) SYS_PRINTF_CHECK_ATTRIBUTE(2, 3);
1231 
1232  // This will change the string into a valid C style variable name.
1233  // All non-alpha numerics will be converted to _.
1234  // If the first letter is a digit, it is prefixed with an _.
1235  // This returns 0 if no changes occurred, 1 if something had to
1236  // be adjusted.
1237  // Note that this does NOT force the name to be non-zero in length.
1238  // The safechars parameter is a string containing extra characters
1239  // that should be considered safe. These characters are not
1240  // converted to underscores.
1241  int forceValidVariableName(const char *safechars = nullptr);
1242  // Returns true if the string matches a C-style variable name.
1243  // The safechars are not allowed to be the start.
1244  // Matching forceValid, empty strings are considered valid!
1245  bool isValidVariableName(const char *safechars = nullptr) const;
1246 
1247  // This will force all non-alphanumeric characters to be underscores.
1248  // Returns true if any changes were required.
1249  bool forceAlphaNumeric();
1250 
1251  // This function will calculate the relative path to get from src to dest.
1252  // If file_path is false, this method assume it is dealing with node paths.
1253  // If file_path is true, it will also deal with Windows drive letters and
1254  // UNC paths.
1255  //
1256  // If we are doing file path comparisons then the source and dest are
1257  // treated as files. So getting from /a/b to /a/c is just "c". But "/a/b/"
1258  // to "/a/c" is "../c", using the trailing slash on the source path to
1259  // indicate it specifies a directory instead of a file.
1260  void getRelativePath(const char *src_fullpath,
1261  const char *dest_fullpath,
1262  bool file_path = false,
1263  bool allow_relative_path_from_root = true);
1264 
1265  // This function takes two absolute paths and returns the length of the
1266  // longest common path prefix, up to and including the last '/'. This
1267  // means, for instance, that if fullpath1[len1-1] == '/' then all of
1268  // fullpath1 is eligible as a common prefix.
1269  // NB: This function DOES NOT handle NT style drive names! It is currently
1270  // only used for op paths. If you want to add support for this, you
1271  // should add another default parameter to do this.
1272  static int findLongestCommonPathPrefix(const char *fullpath1, int len1,
1273  const char *fullpath2, int len2);
1274 
1275  // This function tests whether we are an absolute path, and returns true or
1276  // false depending on whether we are.
1277  bool isAbsolutePath(bool file_path=false) const;
1278 
1279  // This function assumes that we are an absolute path and will remove all
1280  // un-necessary components from it as long as we remain an absolute path.
1281  // We return false if an error was encountered, in which case the results
1282  // are unpredictable.
1283  bool collapseAbsolutePath(bool file_path=false);
1284 
1285  // This function will make sure that the string is at most max_length
1286  // characters long. If the string is longer than that, it will
1287  // replace the middle of the string by "...". Returns true if the string
1288  // has changed and false otherwise. max_length must be greater than 3.
1289  bool truncateMiddle(int max_length);
1290 
1291  // This function is an abomination when you can just write:
1292  // UT_String foo("");
1293  // ...
1294  // if (foo.isstring())
1295  // ...
1296  // Avoid using it and do not write functions that return "const UT_String&"
1297  static const UT_String &getEmptyString();
1298 
1299  /// Count the number of valid characters in the : modifier for variable
1300  /// expansion. For example, the string ":r" will return 2, the string
1301  /// ":r:t" will return 4, the string ":z" will return 0. These use the csh
1302  /// expansion modifiers.
1303  ///
1304  /// If the string doesn't start with a ':', the method will return 0.
1305  static int countCshModifiers(const char *src);
1306 
1307  /// Applies a "csh" style modifier string to this string. For example, a
1308  /// modifier string of ":e" would replace the string with the file
1309  /// extension of the string.
1310  ///
1311  /// Returns true if any modifications were performed
1312  bool applyCshModifiers(const char *modifiers);
1313 
1314 
1315  /// This will remove the range from a string of the form foo$Fbar.ext (#-#)
1316  /// and return the first number from the range. If there is only 1 range
1317  /// number, it will be returned. If there is no range, 0 is returned.
1318  /// The returned string is hardened.
1319  UT_String removeRange ();
1320 
1321  /// This will format a value to represent a given size in bytes, kilobytes,
1322  /// megabytes, etc.
1323  void formatByteSize(exint size, int digits=2);
1324 
1325  // UTF-8 helpers
1326 
1327  /// Returns the number of Unicode codepoints in the string, assuming it's
1328  /// encoded as UTF-8.
1329  int getCodePointCount() const;
1330 
1331  /// Returns a list of Unicode code points from this string.
1332  void getAsCodePoints(UT_Int32Array &cp_list) const;
1333 
1334  /// Friend specialization of std::swap() to use UT_String::swap()
1335  /// @internal This is needed because standard std::swap() implementations
1336  /// will try to copy the UT_String objects, causing hardened strings to
1337  /// become weak.
1338  friend void swap(UT_String& a, UT_String& b) { a.swap(b); }
1339 
1340  /// expandArrays will expand a series of tokens of the
1341  /// form prefix[pattern]suffix into the names UT_StringArray
1342  /// @param tokens is will store the parsed tokens without expansion
1343  /// @param names is will store the parsed tokens with expansion
1344  /// This doesn't need a max argument like:
1345  /// int expandArrays(char *names[], int max)
1346  int expandArrays(UT_StringArray &tokens, UT_StringArray &names);
1347 
1348 private:
1349  template <typename OSTREAM>
1350  void saveInternal(OSTREAM &os, bool binary) const;
1351 
1352  void freeData();
1353 
1354  /// implements a few csh-style modifiers.
1355  /// @param mod pointer to a string starting with the modifier to apply.
1356  /// so, to apply a global substitute modifier :gs/l/r/
1357  /// mod should be: s/l/r
1358  /// @param all True if all possible modifications should be
1359  /// (recursively) performed.
1360  /// Otherwise, at most one modification is applied.
1361  /// @return whether any modification was performed
1362  bool applyNextModifier(const char *mod, bool all);
1363 
1364 
1365  /// Sets myIsReference to false and copies the other_string into myData,
1366  /// but attempts to avoid unnecessary memory reallocations. Frees up
1367  /// any previous data, if necessary. If other_string is NULL, the call
1368  /// is equivalent to freeData().
1369  void doSmartCopyFrom(const char* other_string);
1370 
1371  static int compareNumberedStringInternal(const char *s1, const char *s2,
1372  bool case_sensitive,
1373  bool allow_negatives,
1374  const char *sorted_first,
1375  const char *sorted_last);
1376 
1377  static SYS_FORCE_INLINE void utStrFree(char *str)
1378  {
1379 #if defined(UT_DEBUG) && !defined(_WIN32)
1380  if (str)
1381  ::memset((void *)str, 0xDD, ::strlen(str) + 1);
1382 #endif
1383  ::free((void *)str);
1384  }
1385 
1386  char *myData;
1387  bool myIsReference:1,
1388  myIsAlwaysDeep:1;
1389 
1390  /// This operator saves the string to the stream via the string's
1391  /// saveAscii() method, protecting any whitespace (by adding quotes),
1392  /// backslashes or quotes in the string.
1393  friend UT_API std::ostream &operator<<(std::ostream &os, const UT_String &d);
1394  friend UT_API UT_OStream &operator<<(UT_OStream &os, const UT_String &d);
1395 
1396  friend class UT_API UT_StringRef;
1397 };
1398 
1399 /// Creates a shallow wrapper around a string for calling UT_String's many
1400 /// const algorithms.
1402 {
1403 public:
1404  // We only have a single constructor which is always shallow.
1406  UT_StringWrap(const char *str)
1407  : UT_String(str)
1408  {}
1409  // It seems necessary on MSVC to forceinline the empty constructor in order
1410  // to have it inlined.
1413  {}
1414 
1415  UT_StringWrap(const UT_StringWrap &) = delete;
1416  UT_StringWrap &operator=(const UT_StringWrap &) = delete;
1417 
1418  // Manually wrap methods that have non-const overloads or return non-const
1419  // pointers.
1420  char operator()(unsigned i) const { return UT_String::operator()(i); }
1421  const char *findChar(int c) const { return UT_String::findChar(c); }
1422  const char *findChar(const char *str) const { return UT_String::findChar(str); }
1423  const char *findNonSpace() const { return UT_String::findNonSpace(); }
1424  const char *lastChar(int c) const { return UT_String::lastChar(c); }
1425 
1426  using UT_String::operator==;
1427  using UT_String::operator!=;
1428  using UT_String::c_str;
1429  using UT_String::length;
1430 
1431  using UT_String::base;
1432  using UT_String::compare;
1433  using UT_String::contains;
1434  using UT_String::count;
1435  using UT_String::countChar;
1436  using UT_String::distance;
1437  using UT_String::endsWith;
1438  using UT_String::equal;
1439  using UT_String::fcontain;
1441  using UT_String::fileName;
1442  using UT_String::findWord;
1443  using UT_String::findString;
1446  using UT_String::isFloat;
1447  using UT_String::isInteger;
1449  using UT_String::isstring;
1450  using UT_String::match;
1451  using UT_String::matchFile;
1453  using UT_String::matchPath;
1455  using UT_String::multiMatch;
1460  using UT_String::save;
1461  using UT_String::saveAscii;
1462  using UT_String::saveBinary;
1463  using UT_String::splitPath;
1464  using UT_String::startsWith;
1465  using UT_String::substr;
1466  using UT_String::suffix;
1467  using UT_String::toFloat;
1468  using UT_String::toInt;
1469 };
1470 
1471 inline
1473  : myIsReference(false)
1474  , myIsAlwaysDeep(true)
1475  , myData(nullptr)
1476 {
1477  *this = str;
1478 }
1479 
1480 inline
1482  : myIsReference(false)
1483  , myIsAlwaysDeep(true)
1484  , myData(nullptr)
1485 {
1486  *this = std::move(str);
1487 }
1488 
1489 inline UT_String &
1491 {
1492  adopt(str);
1493  myIsAlwaysDeep = true; // matches copy constructor behaviour
1494  return *this;
1495 }
1496 
1499 {
1500  if (!myIsReference && myData)
1501  utStrFree(myData);
1502 }
1503 
1505 void
1506 UT_String::freeData()
1507 {
1508  if (myData)
1509  {
1510  if (!myIsReference)
1511  utStrFree(myData);
1512  myData = nullptr;
1513  }
1514 }
1515 
1516 inline void
1518 {
1519  // We can't use UTswap because it doesn't work with bit fields.
1520  bool temp = myIsReference;
1521  myIsReference = other.myIsReference;
1522  other.myIsReference = temp;
1523 
1524  char *tmp_data = myData;
1525  myData = other.myData;
1526  other.myData = tmp_data;
1527 
1528  if (myIsAlwaysDeep)
1529  harden();
1530 
1531  if (other.myIsAlwaysDeep)
1532  other.harden();
1533 }
1534 
1536 {
1537 public:
1538  UT_String myOut; // Points to argument following '>'
1539  UT_String myErr; // Points to argument following '>&'
1540  UT_String myIn; // Points to argument following '<'
1541  short myDoubleOut; // If the argument is '>>' or '>>&'
1542  short myDoubleIn; // If the argument is '<<'
1543 };
1544 
1545 UT_API std::ostream & do_setformat(std::ostream &os, const char fmt[]);
1546 
1547 /// Does a "smart" string compare which will sort based on numbered names.
1548 /// That is "text20" is bigger than "text3". In a strictly alphanumeric
1549 /// comparison, this would not be the case.
1551 {
1552  bool operator()(const char *s1, const char *s2) const
1553  {
1554  return UT_String::compareNumberedString(s1, s2) < 0;
1555  }
1556 
1557  bool operator()(const std::string &s1, const std::string &s2) const
1558  {
1559  return operator()(s1.c_str(), s2.c_str());
1560  }
1561 };
1562 
1563 #endif
bool match(const char *pattern, bool case_sensitive=true) const
int tokenize(char *argv[], int max_args, const char *separators=" \t\n")
Definition: UT_String.h:876
UT_String & operator+=(const char *str)
Definition: UT_String.h:352
static SYS_FORCE_INLINE uint32 hash(const char *str, uint32 code=0)
Definition: UT_String.h:933
int distance(const char *str, bool case_sensitive=true, bool allow_subst=true) const
char * lastChar(int c)
Definition: UT_String.h:596
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
bool isValidVariableName(const char *safechars=nullptr) const
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
bool operator!=(const char *str) const
Definition: UT_String.h:437
UT_String & operator+=(const UT_String &str)
Definition: UT_String.h:384
UT_API void normalizePath(UT_String &file_path, bool want_marker=false, bool always_want_expanded_path=false)
bool operator>=(const UT_StringRef &str) const
Definition: UT_String.h:493
int count(const char *str, bool case_sensitive=true) const
Count the occurrences of the string.
T mod(T x, int y)
Definition: chrono.h:1648
bool matchFileExtension(const char *match_extension) const
Definition: UT_String.h:679
void swap(UT_String &other)
Definition: UT_String.h:1517
void saveAscii(UT_OStream &os) const
Definition: UT_String.h:311
bool operator()(const char *s1, const char *s2) const
Definition: UT_String.h:1552
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:139
GLboolean invert
Definition: glcorearb.h:549
const char * lastChar(int c) const
Definition: UT_String.h:1424
bool isInteger(bool skip_spaces=false) const
Determine if string can be seen as a single integer number.
that also have some descendant prim *whose name begins with which in turn has a child named baz where *the predicate and *a name There is also one special expression _ which means *the weaker expression when composing expressions together See with
bool operator<=(const char *str) const
Definition: UT_String.h:461
UT_String myIn
Definition: UT_String.h:1540
fpreal toFloat() const
bool operator==(const char *str) const
Definition: UT_String.h:425
bool operator<=(const UT_String &str) const
Definition: UT_String.h:465
int toInt() const
char * fileExtension()
Definition: UT_String.h:662
CompareResults OIIO_API compare(const ImageBuf &A, const ImageBuf &B, float failthresh, float warnthresh, float failrelative, float warnrelative, ROI roi={}, int nthreads=0)
const GLuint GLenum const void * binary
Definition: glcorearb.h:1924
bool isHard() const
Returns whether this string is hardened already.
Definition: UT_String.h:254
GLsizei const GLchar *const * path
Definition: glcorearb.h:3341
SYS_FORCE_INLINE T * SYSconst_cast(const T *foo)
Definition: SYS_Types.h:136
UT_String makeQuotedString(char delimiter='\'', bool escape_nonprinting=false) const
const char * findChar(const char *str) const
Definition: UT_String.h:590
int64 exint
Definition: SYS_Types.h:125
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
GLdouble s
Definition: glad.h:3009
void swap(T &lhs, T &rhs)
Definition: pugixml.cpp:7440
void write(unsigned i, char c)
Definition: UT_String.h:549
bool operator==(const UT_String &str) const
Definition: UT_String.h:429
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:795
#define UT_API
Definition: UT_API.h:14
const char * fileExtension() const
Definition: UT_String.h:669
const char * data() const
Definition: UT_String.h:526
bool isAbsolutePath(bool file_path=false) const
bool findString(const char *str, bool fullword, bool usewildcards) const
**But if you need a result
Definition: thread.h:622
char * findChar(int c)
Definition: UT_String.h:580
#define SYS_EXINT_MAX
Definition: SYS_Types.h:181
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2138
char & operator()(unsigned i)
Definition: UT_String.h:539
bool equal(const char *str, bool case_sensitive=true) const
Definition: UT_String.h:412
GLfloat GLfloat GLfloat v2
Definition: glcorearb.h:818
const char * findNonSpace() const
Definition: UT_String.h:1423
unsigned long long uint64
Definition: SYS_Types.h:117
int compare(const char *str, bool case_sensitive=true) const
Definition: UT_String.h:392
GLuint buffer
Definition: glcorearb.h:660
void clear()
Reset the string to the default constructor.
Definition: UT_String.h:321
bool isAlwaysDeep() const
Definition: UT_String.h:216
const char * c_str() const
Definition: UT_String.h:524
OutGridT const XformOp bool bool
SYS_FORCE_INLINE UT_String(const char *str=nullptr)
Construct UT_String from a C string, using shallow semantics.
Definition: UT_String.h:88
bool matchPath(const char *pattern, bool case_sensitive=true, bool *excludes_branch=nullptr) const
SIM_API const UT_StringHolder all
unsigned length() const
Return length of string.
Definition: UT_String.h:568
int compare(const UT_String &str, bool case_sensitive=true) const
Definition: UT_String.h:406
< returns > If no error
Definition: snippets.dox:2
const char * suffix() const
bool operator<(const char *str) const
Definition: UT_String.h:449
bool operator<(const UT_StringRef &str) const
Definition: UT_String.h:457
UT_API void UTexprLookup(const char *name, UT_String &result)
bool contains(const char *pattern, bool case_sensitive=true) const
int tokenize(UT_WorkArgs &argv, const char *separators=" \t\n")
Definition: UT_String.h:884
std::ostream & operator<<(std::ostream &ostr, const DataType &a)
Definition: DataType.h:133
UT_String(UT_AlwaysDeepType, const std::string &str)
Construct UT_String from a std::string, using ALWAYS_DEEP semantics.
Definition: UT_String.h:163
void hardenIfNeeded(const char *s)
Take shallow copy and make it deep.
Definition: UT_String.h:244
const char * buffer() const
Definition: UT_String.h:525
A utility class to do read-only operations on a subset of an existing string.
Definition: UT_StringView.h:40
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE bool isEmpty() const
Returns true if the string is empty.
SYS_FORCE_INLINE uint32 hash() const
Definition: UT_String.h:925
bool operator==(const UT_StringRef &str) const
Definition: UT_String.h:433
GLintptr offset
Definition: glcorearb.h:665
char operator()(unsigned i) const
Definition: UT_String.h:1420
int tokenize(char *argv[], int max_args, char separator)
Definition: UT_String.h:864
bool operator>=(const char *str) const
Definition: UT_String.h:485
SYS_NO_DISCARD_RESULT UT_StringView UTstringFileName(const StringT &str)
int tokenizeInPlace(T &list, const char *separators=" \t\n")
Definition: UT_String.h:900
bool operator!=(const UT_String &str) const
Definition: UT_String.h:441
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:164
bool operator>=(const UT_String &str) const
Definition: UT_String.h:489
#define SYS_PRINTF_CHECK_ATTRIBUTE(string_index, first_to_check)
Definition: SYS_Types.h:453
char * findNonSpace()
std::string OIIO_UTIL_API replace(string_view str, string_view pattern, string_view replacement, bool global=false)
UT_String(UT_AlwaysDeepType, const char *str=nullptr)
Construct UT_String from a C string, using ALWAYS_DEEP semantics.
Definition: UT_String.h:156
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
GLint GLint GLsizei GLint GLenum format
Definition: glcorearb.h:108
bool matchPattern(const UT_WorkArgs &pattern_args, bool assume_match=false) const
bool operator>(const UT_String &str) const
Definition: UT_String.h:477
char * SYSstrtok(char *string, const char *delimit, char **context)
Definition: SYS_String.h:151
char * findChar(const char *str)
Definition: UT_String.h:588
#define UT_ASSERT_SLOW(ZZ)
Definition: UT_Assert.h:163
const char * findChar(int c) const
Definition: UT_String.h:582
void harden()
Take shallow copy and make it deep.
Definition: UT_String.h:225
void saveAscii(std::ostream &os) const
Definition: UT_String.h:310
bool equal(const UT_StringRef &str, bool case_sensitive=true) const
Definition: UT_String.h:420
UT_String(UT_String &&str) noexcept
Definition: UT_String.h:179
long long int64
Definition: SYS_Types.h:116
bool equal(const UT_String &str, bool case_sensitive=true) const
Definition: UT_String.h:416
void setAlwaysDeep(bool deep)
Make a string always deep.
Definition: UT_String.h:200
bool operator>(const UT_StringRef &str) const
Definition: UT_String.h:481
const char * findChar(const char *str) const
Definition: UT_String.h:1422
bool matchFile(const char *pattern) const
bool operator()(const std::string &s1, const std::string &s2) const
Definition: UT_String.h:1557
GLuint const GLchar * name
Definition: glcorearb.h:786
int eraseHead(int len)
Definition: UT_String.h:1118
GLushort pattern
Definition: glad.h:2583
void toUpper()
Definition: UT_String.h:634
void adopt(UT_String &str)
Definition: UT_String.h:297
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
SYS_FORCE_INLINE ~UT_StringWrap()
Definition: UT_String.h:1412
const char * findWord(const char *word) const
bool operator>(const char *str) const
Definition: UT_String.h:473
int64 getMemoryUsage(bool inclusive=true) const
Return memory usage in bytes.
Definition: UT_String.h:572
void saveBinary(std::ostream &os) const
Save string to binary stream.
Definition: UT_String.h:306
bool isFloat(bool skip_spaces=false, bool loose=false, bool allow_underscore=false) const
Determine if string can be seen as a single floating point number.
static int compareNumberedString(const char *s1, const char *s2, bool case_sensitive=true, bool allow_negatives=false)
short myDoubleIn
Definition: UT_String.h:1542
void adopt(char *s)
Definition: UT_String.h:287
GLsizeiptr size
Definition: glcorearb.h:664
UT_String pathUpToExtension() const
const char & operator()(unsigned i) const
Definition: UT_String.h:529
__hostdev__ bool isInteger(GridType gridType)
Return true if the GridType maps to a POD integer type.
Definition: NanoVDB.h:820
SYS_NO_DISCARD_RESULT UT_StringView UTstringFileExtension(const StringT &str)
GLenum func
Definition: glcorearb.h:783
int substr(UT_String &buf, int index, int len=0) const
SYS_NO_DISCARD_RESULT bool UTstringMatchFileExtension(const StringT &str, const char *extension)
void save(std::ostream &os, bool binary) const
Save string to stream. Saves as binary if binary is true.
short myDoubleOut
Definition: UT_String.h:1541
fpreal64 fpreal
Definition: SYS_Types.h:283
int parse(UT_StringArray &argv, int start_arg=0, const char *quotes="\"'", bool keep_quotes=false)
Definition: UT_String.h:847
bool multiMatch(const char *pattern, bool case_sensitive, char separator) const
LeafData & operator=(const LeafData &)=delete
char * steal()
Definition: UT_String.h:265
char * SYSstrcasestr(const char *haystack, const char *needle)
Replacement for strcasestr, since no equivalent exists on Win32.
Definition: SYS_String.h:335
GLuint index
Definition: glcorearb.h:786
bool multiMatchRecord(const char *pattern, int maxpatterns, char *singles, int &nsingles, char **words, int &nwords, bool case_sensitive=true, const char *separators=", ") const
int parseNumberedFilename(UT_String &prefix, UT_String &frame, UT_String &suff, bool negative=true, bool fractional=false) const
UT_AlwaysDeepType
Definition: UT_String.h:82
GLfloat GLfloat v1
Definition: glcorearb.h:817
auto ptr(T p) -> const void *
Definition: format.h:4331
GLuint GLfloat * val
Definition: glcorearb.h:1608
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
**If you just want to fire and args
Definition: thread.h:618
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE const_iterator begin() const
Returns a constant iterator pointing to the beginning of the string.
unsigned int uint32
Definition: SYS_Types.h:40
const char * lastChar(int c) const
Definition: UT_String.h:598
UT_String myOut
Definition: UT_String.h:1538
UT_String myErr
Definition: UT_String.h:1539
bool isstring() const
Definition: UT_String.h:713
int findLongestCommonSuffix(const char *with) const
void hardenIfNeeded()
Take shallow copy and make it deep.
Definition: UT_String.h:234
const char * findChar(int c) const
Definition: UT_String.h:1421
int parse(char *argv[], int max_args, const char *quotes="\"'", bool keep_quotes=false)
Definition: UT_String.h:835
bool operator<(const UT_String &str) const
Definition: UT_String.h:453
int erase(int pos=0, int len=-1)
Definition: UT_String.h:1126
int tokenize(UT_WorkArgs &argv, char separator)
Definition: UT_String.h:870
auto sprintf(const S &fmt, const T &...args) -> std::basic_string< Char >
Definition: printf.h:617
string_view OIIO_UTIL_API strip(string_view str, string_view chars=string_view())
SIM_API const UT_StringHolder distance
bool operator<=(const UT_StringRef &str) const
Definition: UT_String.h:469
bool startsWith(const UT_StringView &prefix, bool case_sensitive=true) const
void splitPath(UT_String &dir_name, UT_String &file_name) const
bool OIIO_UTIL_API contains(string_view a, string_view b)
Does 'a' contain the string 'b' within it?
int parse(UT_WorkArgs &argv, int start_arg=0, const char *quotes="\"'", bool keep_quotes=false)
Definition: UT_String.h:841
const char * base(UT_String &buf) const
UT_String & operator=(UT_String &&str) noexcept
Definition: UT_String.h:187
void removeLast()
Remove the last character.
Definition: UT_String.h:337
UT_API void UTvarLookup(const char *name, UT_String &result)
SYS_FORCE_INLINE UT_StringWrap(const char *str)
Definition: UT_String.h:1406
bool endsWith(const UT_StringView &suffix, bool case_sensitive=true) const
UT_String(const std::string &str)
Construct UT_String from a std::string, always doing a deep copy. The result will only be a UT_Always...
Definition: UT_String.h:130
int eraseTail(int len)
Definition: UT_String.h:1122
const char * fileName() const
Definition: UT_String.h:655
OIIO_UTIL_API std::string extension(string_view filepath, bool include_dot=true) noexcept
GLint GLsizei count
Definition: glcorearb.h:405
Definition: format.h:1821
int countChar(int c) const
Return the number of occurrences of the specified character.
UT_API std::ostream & do_setformat(std::ostream &os, const char fmt[])
int tokenize(T &list, const char *separators=" \t\n")
Definition: UT_String.h:893
const char * nonNullBuffer() const
Definition: UT_String.h:527
void toLower()
Definition: UT_String.h:641
GLenum src
Definition: glcorearb.h:1793
int insert(int pos, const char *str)
Definition: UT_String.h:1134
const char * fcontain(const char *pattern, bool case_sensitive=true) const
Definition: UT_String.h:1031
bool operator!=(const UT_StringRef &str) const
Definition: UT_String.h:445