HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_WorkBuffer.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  * NAME: UT_WorkBuffer.h ( Utility Library, C++ )
7  *
8  * COMMENTS:
9  * A growable string buffer that can be written into. A UT_String
10  * can be created with the contents of this buffer by calling
11  * copyIntoString().
12  *
13  * It's important that a non-const version of the raw buffer is not
14  * accessible since users could write past the end of the allocated
15  * buffer. Also note that the buffer location can change as it grows,
16  * so don't keep pointers to the buffer around.
17  *
18  * Most of the time, you want to allocate an object of this class on
19  * the stack and not on the heap.
20  *
21  * The buffer is kept null terminated by default. Functions exist
22  * to verify this. Note that the "length" of the buffer is the
23  * same as strlen - ie: it ignores the null termination!!!
24  *
25  * RELATION TO THE STL:
26  *
27  * Use UT_StringHolder, UT_WorkBuffer, etc., instead of std::string
28  * (see comments at the top of UT_StringHolder.h)
29  */
30 
31 #ifndef __UT_WorkBuffer_h__
32 #define __UT_WorkBuffer_h__
33 
34 #include "UT_API.h"
35 
36 #include "UT_Assert.h"
37 #include "UT_Format.h"
38 #include "UT_String.h"
39 #include "UT_StringHolder.h"
40 #include "UT_StringUtils.h"
41 #include "UT_StringView.h"
42 #include "UT_Swap.h"
43 #include "UT_Unicode.h"
44 
45 #include <SYS/SYS_Deprecated.h>
46 #include <SYS/SYS_Inline.h>
47 #include <SYS/SYS_String.h>
48 #include <SYS/SYS_Types.h>
49 
50 #include <iosfwd>
51 #include <string>
52 #include <utility>
53 #include <algorithm>
54 
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 
59 
60 // The default page size on most systems is 4K. We choose a default
61 // buffer size less than half of that in the hopes that if we have
62 // functions with 2 work buffers or additional variables on the stack that we
63 // may not have to allocate multiple stack pages.
64 #define UT_INITIAL_BUFFER_SIZE 2000
65 
66 class UT_StringArray;
67 class UT_WorkArgs;
68 class UT_IStream;
69 class UT_Digits;
70 
71 template <typename T>
72 class UT_Array;
73 
75 {
76 public:
77  typedef char value_type;
78 
81  {
82  myBuffer[0] = '\0';
83  }
84 
86  explicit UT_WorkBuffer(const char *str)
87  : UT_WorkBuffer()
88  {
89  append(str);
90  }
91 
93  explicit UT_WorkBuffer(const char *data, exint size)
94  : UT_WorkBuffer()
95  {
96  append(data, size);
97  }
98 
100  explicit UT_WorkBuffer(const UT_String &str)
101  : UT_WorkBuffer()
102  {
103  append(str);
104  }
105 
107  explicit UT_WorkBuffer(const UT_StringRef &str)
108  : UT_WorkBuffer()
109  {
110  append(str);
111  }
112 
114  explicit UT_WorkBuffer(const UT_StringLit &str)
115  : UT_WorkBuffer()
116  {
117  append(str);
118  }
119 
121  explicit UT_WorkBuffer(const UT_StringView &view)
122  : UT_WorkBuffer()
123  {
124  append(view);
125  }
126 
129  : UT_WorkBuffer()
130  {
131  append(other);
132  }
133 
136  {
137  if (myBuffer != myStackBuffer)
138  {
139  UT_ASSERT_P(myBuffer);
140  ::free(myBuffer);
141  }
142  }
143 
144  /// Create a work buffer to contain a UTF-16LE (little endian)
145  /// representation of the incoming UTF-8 string.
146  /// The work buffer will be zero-word terminated.
148  static UT_WorkBuffer
149  widen(const utf8 *str)
150  {
151  return UT_WorkBuffer(do_widen(), str);
152  }
153 
154  /// Create a work buffer to contain the UTF-8 representation of the
155  /// incoming UTF-16 string. The UTF-16 string is assumed to be
156  /// little-endian, unless prefixed with BOM that indicates endianness.
157  /// The incoming string should be zero-word terminated.
159  static UT_WorkBuffer
160  narrow(const utf16 *str)
161  {
162  return UT_WorkBuffer(do_narrow(), str);
163  }
164 
165  // It's important that there is no non-const access method to the buffer.
166  // Also note that the pointer to the buffer can change if the buffer
167  // grows.
169  const char *buffer() const { return myBuffer; }
170  /// Alias for the common string access across all string types (including
171  /// standard library)
172  /// @{
174  const char *data() const { return buffer(); }
176  const char *c_str() const { return buffer(); }
177  /// @}
178 
179  // Having said that, if you need a non-const pointer you must lock
180  // the string. This prohibits ANY update which changes the myLength
181  // variable (and thus potentially a realloc)
182  // You must release the buffer before any such changes.
183  // The work buffer continues to own the memory and will free it when
184  // it goes out of scope so don't think this is the same as a "steal"
185  // in UT_String.
186  // Currently, to ensure people couple their locks & releases,
187  // it asserts there is no unaccounted locks on death. This is so
188  // people who think it is steal find out otherwise.
189  // Offset is where in the string to get the pointer from.
190  // This is only to be used when absolutely necessary.
191  // When releasing, if you have a string buffer, and you have modified the
192  // length, you should set the recompute_length flag to 1. This will adjust
193  // the internal length variable so that further concatenations will work
194  // properly.
195  // The reserve_bytes parameter tells the lock to ensure that there are at
196  // least that many bytes in the locked buffer.
197  // NOTE: Unlike other UT_WorkBuffer functions, it is the user's
198  // responsibility to maintain a NUL termination guarantee when manipulating
199  // the raw buffer.
200  char *lock(exint offset = 0, exint reserve_bytes=0);
201  void release(bool recompute_length = false);
202  void releaseSetLength(exint new_length);
203 
205  exint getAllocatedSize() const { return myAllocatedSize; }
206  int64 getMemoryUsage(bool inclusive) const;
207 
208  /// Class to handle auto-locking of the UT_WorkBuffer. This is not related
209  /// to multi-threading, but to the lock/release methods above.
210  ///
211  /// You should never append data to a locked buffer.
212  class AutoLock
213  {
214  public:
217  : myBuffer(buf)
218  {
219  myString = myBuffer.lock();
220  }
223  {
224  release();
225  }
226  /// @{
227  /// Get access to the non-const buffer. This may return nullptr if the
228  /// lock has been released.
230  char *operator*() const { return myString; }
232  char *string() const { return myString; }
233  /// @}
234 
235  /// You can manually release the buffer
237  void release(bool recompute_length=false)
238  {
239  if (myString)
240  {
241  myBuffer.release(recompute_length);
242  myString = nullptr;
243  }
244  }
245  /// If you've manually released the lock, you can relock the buffer
247  void relock()
248  {
249  UT_ASSERT(!myString);
250  myString = myBuffer.lock();
251  }
252  private:
253  UT_WorkBuffer &myBuffer;
254  char *myString;
255  };
256 
257  void reserve(exint bytes=0);
258 
259  // This is a read only operator. We are avoiding the writeable
260  // versions as they lead to problems when people do a:
261  // foo[pastend] = foo(start)
262  // causing an implicit realloc.
264  char operator()(exint idx) const
265  {
266  // We allow an index at myLength as if we have a null
267  // terminated buffer that is the null termination.
268  UT_ASSERT_P(idx >= 0 && idx <= myLength);
269  return myBuffer[idx];
270  }
271 
272  // Returns last character. Only valid if !isEmpty()
274  char first() const
275  {
276  UT_ASSERT_P(myLength > 0);
277  return myBuffer[0];
278  }
279  // Returns last character. Only valid if !isEmpty()
281  char last() const
282  {
283  UT_ASSERT_P(myLength > 0);
284  return myBuffer[myLength - 1];
285  }
286 
287  // This should always be true. It's here to act as a sanity function.
288  int isNullTerminated() const;
289 
292  {
293  strcpy(other);
294  return *this;
295  }
297  UT_WorkBuffer &operator=(const char *str)
298  {
299  clear();
300  append(str);
301  return *this;
302  }
304  UT_WorkBuffer &operator=(const std::string &str)
305  {
306  clear();
307  append(str.c_str(), str.length());
308  return *this;
309  }
310 
311  /// Comparison operator. Null strings are considered as empty strings.
312  /// @{
314  bool operator==(const char *str) const
315  {
316  if (!str)
317  return isEmpty();
318  return (::strcmp(str, myBuffer) == 0);
319  }
321  bool operator==(const UT_String &str) const
322  {
323  if (!(const char *)str)
324  return isEmpty();
325  return (::strcmp(str, myBuffer) == 0);
326  }
328  bool operator==(const UT_StringRef &str) const
329  {
330  if (length() != str.length())
331  return false;
332  return (::memcmp(myBuffer, str.c_str(), myLength) == 0);
333  }
335  bool operator==(const UT_WorkBuffer &buf) const
336  {
337  if (buf.isEmpty())
338  return isEmpty();
339  if (length() != buf.length())
340  return false;
341  return (::memcmp(myBuffer, buf.myBuffer, myLength) == 0);
342  }
344  bool operator!=(const char *str) const
345  {
346  return !(*this == str);
347  }
349  bool operator!=(const UT_String &str) const
350  {
351  return !(*this == str);
352  }
354  bool operator!=(const UT_StringRef &str) const
355  {
356  return !(*this == str);
357  }
359  bool operator!=(const UT_WorkBuffer &buf) const
360  {
361  return !(*this == buf);
362  }
363  /// @}
364 
365 private:
366  // Reallocate the buffer until the allocated size is >= the length. This
367  // private method needs to come first so it can be inlined.
368  void growBufferIfNeeded()
369  {
370  // Using a while loop instead of computing an accurate size the
371  // first time is slower, but most of the time the loop will execute
372  // at most once.
373  // We need to use myLength+1 as we need room for the null.
374  while (myLength+1 > myAllocatedSize) // false most of the time
375  reserve(myAllocatedSize * 2);
376  }
377 
378 public:
379  // These are standard string operators people tend to use:
381  void strcpy(const char *src)
382  {
383  clear();
384  append(src);
385  }
387  void strcpy(const UT_String &src)
388  {
389  clear();
390  append(src);
391  }
393  void strcpy(const UT_StringRef &src)
394  {
395  clear();
396  append(src);
397  }
399  void strcpy(const UT_WorkBuffer &src)
400  {
401  clear();
402  append(src);
403  }
405  void strcpy(const UT_StringView &src)
406  {
407  clear();
408  append(src);
409  }
410 
411  // NOTE: unlike strncpy(), maxlen does not include the null terminator.
413  void strncpy(const char *src, exint maxlen)
414  {
415  clear();
416  // Ensure we have enough room:
417  myLength = maxlen+1;
418  growBufferIfNeeded();
419  myLength = 0;
420  SYSstrlcpy(myBuffer, src, maxlen+1);
421  myLength = ::strlen(myBuffer);
422  }
423 
424  // Note we can't just return myLength as there may be embedded NULLs.
426  exint strlen() const
427  {
428  UT_ASSERT_P(isNullTerminated());
429  return ::strlen(myBuffer);
430  }
431 
433  exint length() const
434  {
435  return myLength;
436  }
437 
439  void strcat(const char *src)
440  {
441  append(src);
442  }
443 
444  // protectedStrcat() will quote the string in double quotes if required and
445  // protect any enclosed double quotes or backslashes in the source. It
446  // will not escape any other characters.
447  void protectedStrcat(const char *str, bool force_quote=false);
448 
449  // fullyProtected*Strcat() is similar to protectedStrcat, except it escapes
450  // any non-printable characters. It will not escape single quotes, and if
451  // force_quote is true, it will add double-quotes. It will work with
452  // arbitrary binary data and uses the \xNN syntax to encode bytes.
453  // UT_IStream::read() is capable of loading strings encoded with this
454  // method, and these strings can also be decoded in Python. If
455  // fullyProtectedBinaryStrcat is called, this method can handle data
456  // containing null characters.
457  void fullyProtectedStrcat(const char *str, bool force_quote=false);
458  void fullyProtectedBinaryStrcat(
459  const char *str, exint size, bool force_quote=false);
460 
461  /// Append a string of a given maximum length to the current string.
462  /// Unlike the POSIX's strncat(3), we ignore any NUL bytes in the current
463  /// string and blindly append at the end of the work buffer.
465  void strncat(const char *src, exint len)
466  {
467  if (!src)
468  return;
469  append(src, ::strnlen(src, len));
470  }
471 
472  // Extract the first argument from the src and append it to the work
473  // buffer. This does NOT handle quotes properly (i.e. if the first word
474  // is quoted with spaces).
475  void strcatFirstWord(const char *src);
476 
478  int strcmp(const char *src) const
479  {
480  UT_ASSERT_P(isNullTerminated());
481  return ::strcmp(myBuffer, src);
482  }
483 
485  int strncmp(const char *src, exint n) const
486  {
487  UT_ASSERT_P(isNullTerminated());
488  return ::strncmp(myBuffer, src, n);
489  }
490 
492  char *strdup() const
493  {
494  UT_ASSERT(isNullTerminated());
495  return ::strdup(myBuffer);
496  }
497 
498  // Reset the buffer to an empty buffer.
500  void clear()
501  {
502  if (myLockCount) { UT_ASSERT(0); return; }
503  myLength = 0;
504  myBuffer[0] = '\0';
505  }
506 
508  bool isEmpty() const
509  {
510  return (myLength == 0);
511  }
513  bool isstring() const
514  {
515  return !isEmpty();
516  }
517 
518  // Write into the buffer at a specific place.
519  // This WILL expand the buffer if it is required and keep it null
520  // terminated.
522  void write(exint offset, char c)
523  {
524  UT_ASSERT(offset >= 0);
525  if (offset < 0) return;
526  if (offset >= myLength)
527  {
528  if (myLockCount) { UT_ASSERT(0); return; }
529  myLength = offset+1;
530  growBufferIfNeeded();
531  myBuffer[myLength] = '\0';
532  }
533  myBuffer[offset] = c;
534  if (c == '\0')
535  myLength = offset;
536  }
537 
538  // This does NOT write out the trailing NULL of src, but the buffer will
539  // still be null-terminated.
540  void write(exint offset, const char *src)
541  {
542  while (*src)
543  {
544  write(offset, *src);
545  src++;
546  offset++;
547  }
548  }
549 
551  {
552  write(offset, src.c_str());
553  }
554 
555  /// Load an entire file into the buffer. Returns @b false if there was an
556  /// error reading the file
557  bool readFile(const char *filename);
558 
559  // Read a line from an istream -- no matter how long the line is
560  // Returns 0 if the stream read failed or 1 otherwise
561  bool getline(std::istream &is);
562  bool getline(FILE *fp);
563 
564  // Much like getline() except that it has more features. The string itself
565  // is tokenized which the UT_WorkArgs points into.
566  // line_num is incremented for each line read.
567  // comment_chars is list of characters to treat as comments.
568  // this can be NULL if we don't want this feature.
569  // Returns false if the stream read failed.
570  bool cmdGetLine(std::istream &is, UT_WorkArgs &args, int &line_num,
571  const char *comment_chars = "#",
572  const char *separators = " \t\n\r");
573  bool cmdGetLine(UT_IStream &is, UT_WorkArgs &args, int &line_num,
574  const char *comment_chars = "#",
575  const char *separators = " \t\n\r");
576  bool cmdGetLine(FILE *fp, UT_WorkArgs &args, int &line_num,
577  const char *comment_chars = "#",
578  const char *separators = " \t\n\r");
579 
580  /// Fast integer to string conversion.
581  /// @{
582  void itoa(int64 i);
583  void utoa(uint64 i);
584  /// @}
585 
586  /// Format using the system sprintf. See also printf() which uses UT_printf
587  /// which is type-safe and can print floating point using std::to_chars.
588  int sprintf(const char *fmt, ...)
590  int appendSprintf(const char *fmt, ...)
592  int vsprintf(const char *fmt, va_list ap);
593 
594  /// Replace the contents of the work buffer using the same formatting as
595  /// UTformat. Returns the resulting length in bytes.
596  /// If fmt is nullptr will space-separate the arguments like python print.
597  template<typename... Args>
598  size_t format(const char *fmt, const Args &...args)
599  {
600  clear();
601  return appendFormat(fmt, {args...});
602  }
603  /// Append to the work buffer using the same formatting as UTformat.
604  /// Returns the size of the appended portion, in bytes.
605  /// If fmt is nullptr will space-separate the arguments like python print.
606  /// @{
607  template<typename... Args>
608  size_t appendFormat(const char *fmt, const Args &...args)
609  {
610  return appendFormat(fmt, {args...});
611  }
612  size_t appendFormat(const char *fmt, std::initializer_list<UT::Format::ArgValue> args);
613  /// @}
614 
615  /// Like appendFormat() except it that uses an array of arguments
616  size_t appendFormatByArray(const char *fmt,
618  bool report_errors = true);
619 
620  // These tack stuff to the end of the buffer.
622  void append(char character)
623  {
624  if (myLockCount) { UT_ASSERT(0); return; }
625  UT_ASSERT_P(isNullTerminated());
626  myLength++;
627  growBufferIfNeeded();
628  myBuffer[myLength - 1] = character;
629  myBuffer[myLength] = '\0';
630  }
631 
632  void printMemory(int64 mem) { clear(); appendPrintMemory(mem); }
633  void appendPrintMemory(int64 mem);
634 
635  void append(exint n, char character)
636  {
637  if (myLockCount) { UT_ASSERT(0); return; }
638  UT_ASSERT_P(isNullTerminated());
639  myLength += n;
640  growBufferIfNeeded();
641  std::fill(myBuffer+myLength-n, myBuffer+myLength, character);
642  myBuffer[myLength] = '\0';
643  }
644 
645  /// Append a single Unicode code point, converted to UTF8
646  void append(utf32 cp)
647  {
649  int len = UT_Unicode::convert(cp, buf, sizeof(buf));
650  if (!len)
651  return;
652 
653  if (myLockCount) { UT_ASSERT(0); return; }
654  UT_ASSERT_P(isNullTerminated());
655  myLength += len;
656  growBufferIfNeeded();
657  ::memcpy(myBuffer + myLength - len, buf, len);
658  myBuffer[myLength] = '\0';
659  }
660 
661  void append(const char *data, exint size)
662  {
663  if (myLockCount) { UT_ASSERT(0); return; }
664  UT_ASSERT_P(data);
665  UT_ASSERT_P(isNullTerminated());
666  myLength += size;
667  growBufferIfNeeded();
668  ::memcpy(myBuffer + myLength - size, data, size);
669  myBuffer[myLength] = '\0';
670  }
671 
673  void append(const char *str)
674  {
675  if( UTisstring(str) )
676  append(str, ::strlen(str));
677  }
678 
680  void append(const UT_String &str)
681  {
682  if (str.isstring())
683  append((const char *)str);
684  }
685 
687  void append(const UT_StringRef &str)
688  {
689  if (str.isstring())
690  append(str.buffer(), str.length());
691  }
692 
694  void append(const UT_StringLit &str)
695  {
696  append(str.buffer(), str.length());
697  }
698 
699  void append(const UT_StringArray &strs, const UT_StringRef &sep);
700 
702  void append(const UT_WorkBuffer &wb)
703  {
704  append( wb.buffer(), wb.length() );
705  }
706 
708  void append(const UT_StringView &view)
709  {
710  // Avoid assertion if view is nullptr by testing for emptiness
711  if (!view.isEmpty())
712  append(view.data(), view.length());
713  }
714 
715  void append(const UT_Digits&);
716 
718  UT_WorkBuffer &operator+=(const char *str)
719  {
720  append(str);
721  return *this;
722  }
723 
725  UT_WorkBuffer &operator+=(const std::string &str)
726  {
727  append(str);
728  return *this;
729  }
730 
733  {
734  append(wb);
735  return *this;
736  }
737 
740  {
741  append(str);
742  return *this;
743  }
744 
747  {
748  append(str);
749  return *this;
750  }
751 
754  {
755  append(digits);
756  return *this;
757  }
758 
759  void prepend(char character)
760  {
761  if (myLockCount) { UT_ASSERT(0); return; }
762  UT_ASSERT_P(isNullTerminated());
763  myLength++;
764  growBufferIfNeeded();
765  ::memmove(myBuffer+1, myBuffer, myLength);
766  myBuffer[0] = character;
767  }
768  void prepend(const char *data, exint size)
769  {
770  if (myLockCount) { UT_ASSERT(0); return; }
771  UT_ASSERT_P(data);
772  UT_ASSERT_P(isNullTerminated());
773  myLength += size;
774  growBufferIfNeeded();
775  ::memmove(myBuffer+size, myBuffer, myLength+1 - size);
776  ::memcpy(myBuffer, data, size);
777  }
779  void prepend(const char *str)
780  {
781  UT_ASSERT_P(str);
782  prepend(str, ::strlen(str));
783  }
784 
786  void prepend(const UT_String &str)
787  {
788  if (str.isstring())
789  prepend((const char *)str);
790  }
792  void prepend(const UT_StringRef &str)
793  {
794  if (str)
795  prepend(str.buffer(), str.length());
796  }
797 
798  /// Insert @c slen characters from @c str, at location @c pos. If @c pos
799  /// exceeds the current length, the position is truncated and to an append.
800  void insert(exint pos, const char* str, exint slen);
801 
802  /// Erase @c len characters from location @c pos in the string.
803  void erase(exint pos, exint len);
804 
805  void rewind() { backup(myLength); }
806 
807  /// Rewind by the given length
809  void backup(exint by_length)
810  {
811  if (myLockCount) { UT_ASSERT(0); return; }
812  UT_ASSERT_P(isNullTerminated());
813  UT_ASSERT_P(by_length >= 0);
814  myLength -= by_length;
815  UT_ASSERT(myLength >= 0);
816  myBuffer[myLength] = '\0';
817  }
818 
819  /// Truncate the buffer to the specified length. Truncating to 0 is
820  /// identical to clear().
822  void truncate(exint new_length)
823  {
824  if (new_length >= myLength)
825  {
826  // We can truncate to our existing length without asserting, but if
827  // new_length > myLength, then that's a problem.
828  UT_ASSERT(new_length == myLength
829  && "Truncating beyond buffer extent");
830  return;
831  }
832  backup(myLength-new_length);
833  }
834 
835  // Delete characters off the end of the string until we hit the
836  // requested character.
837  void backupTo(char c)
838  {
839  if (myLockCount) { UT_ASSERT(0); return; }
840  UT_ASSERT_P(isNullTerminated());
841  while( myLength > 0 && myBuffer[myLength-1] != c )
842  myLength--;
843  myBuffer[myLength] = '\0';
844  }
845 
846  void advance(exint by_length)
847  {
848  if (myLockCount) { UT_ASSERT(0); return; }
849  UT_ASSERT_P(isNullTerminated());
850  UT_ASSERT_P(by_length >= 0);
851  myLength -= by_length;
852  UT_ASSERT(myLength >= 0);
853  for (int i=0; i<myLength; i++)
854  myBuffer[i] = myBuffer[by_length+i];
855  myBuffer[myLength] = '\0';
856  }
857 
858  // Finds the 'occurance_number'-th occurance of char c in the string.
860  const char *findChar(char c, int occurance_number = 1) const
861  {
862  return findCharFrom(c, 0, occurance_number);
863  }
864  // Same as findChar, but searches from the end of the string.
865  const char *lastChar(char c, int occurance_number = 1) const
866  {
867  if (myLockCount) { UT_ASSERT(0); return NULL; }
868 
869  UT_ASSERT_P(isNullTerminated());
870 
871  for (exint i = myLength; i --> 0;)
872  {
873  if(c == myBuffer[i])
874  {
875  occurance_number--;
876  if(occurance_number <= 0)
877  {
878  return (myBuffer + i);
879  }
880  }
881  }
882 
883  return NULL;
884  }
885  // Same and findChar, bu searches from given position in the string.
886  const char *findCharFrom(char c, exint position,
887  int occurance_number = 1) const
888  {
889  if (myLockCount) { UT_ASSERT(0); return NULL; }
890 
891  UT_ASSERT_P(isNullTerminated());
892 
893  if (position < 0 || position >= myLength) { return NULL; }
894 
895  for(exint i = position; i < myLength; ++i)
896  {
897  if(c == myBuffer[i])
898  {
899  occurance_number--;
900  if(occurance_number <= 0)
901  {
902  return (myBuffer + i);
903  }
904  }
905  }
906 
907  return NULL;
908  }
909 
910  /// Adopt a string from an outside source. The passed string is now
911  /// owned by the workbuffer.
912  void adoptFromMalloc(char* data, exint length);
913 
914  void adoptFromCharArray(UT_Array<char>& data);
915 
916  /// Count the occurrences of the text in the current string
917  exint count(const char *needle) const;
918 
919  // Get the next token pointed at by string and advance string past the
920  // token. Returns whether or not a token was retrieved successfully.
921  // Note that string is modified!!!
922  bool getNextToken(const char *(&string),
923  const UT_String separators = " \t\n");
924 
925  // Harden the contents of the buffer into a UT_String.
926  void copyIntoString(UT_String &str) const;
927 
928  // Copy the contents into a fixed length buffer.
929  // TODO: Get rid of this method, since it encourages fixed-length buffers.
930  void copyIntoString(char *str, exint max_length) const;
931 
932  // Steal the contents of this work buffer into the string.
933  void stealIntoString(UT_String &str);
934 
935  // Steal the contents of this work buffer into the string.
936  // NB: Use UT_StringHolder move constructor/assignment instead
937  // UT_StringHolder foo(std::move(buffer));
938  // foo = std::move(buffer);
939  SYS_DEPRECATED(19.0)
940  void stealIntoStringHolder(UT_StringHolder &str);
941 
942  // Return a string containing the contents of this work buffer, preserving
943  // any null characters in it.
944  std::string toStdString() const
945  { return std::string(buffer(), length()); }
946 
947  // Strips the characters after comment_char from the buffer. This method
948  // goes to some effort to enusre that the comment_char is not preceded by
949  // a backslash or is not in a quoted string. Returns true if it found a
950  // comment and modified the buffer, and false otherwise.
951  bool stripComments(char comment_char = '#');
952 
953  /// Strips out all characters found in 'chars'. The string length will be
954  /// reduced by the number of characters removed. The number of characters
955  /// removed is returned.
956  int strip(const char *chars);
957 
958  /// Remove trailing whitespace lines
959  void removeTrailingSpaceLines();
960 
961  /// Remove trailing whitespace, return true if whitespace was removed.
962  bool removeTrailingSpace();
963 
964  /// Remove leading white space, return true if whitespace was removed.
965  bool removeLeadingSpace();
966 
967  /// Remove trailing digits, return true if some were removed.
968  bool removeTrailingDigits();
969 
970  /// Convert string to lower case
971  void lower();
972 
973  /// Convert string to upper case
974  void upper();
975 
976  /// Create a string of tabs & spaces which represents the given indent
977  void makeIndentString(exint indent, exint tabstop=8);
978 
979  /// Remove the first n characters.
981  {
982  if (n < myLength)
983  {
984  myLength -= n;
985  ::memmove(myBuffer, myBuffer + n, myLength);
986  }
987  else
988  myLength = 0;
989 
990  myBuffer[myLength] = '\0';
991  }
992 
993  /// Replaces up to 'count' occurrences of 'find' with 'replacement',
994  /// and returns the number of substitutions that occurred.
995  /// If 'count' <= 0, all occurrences will be replaced.
996  int substitute(const char *find, const char *replacement, int count = -1);
997 
998  /// Convenience version of substitute() for all or single occurrence.
999  SYS_DEPRECATED_REPLACE(19.5, "Use 'count' variant")
1000  int substitute(const char *find, const char *replacement, bool all)
1001  {
1002  return substitute(find, replacement, !all ? 1 : -1);
1003  }
1004 
1005  /// Given from_name which is assumed to fit from_pattern, any assigned
1006  /// wildcards are subsitituted in to_pattern, writing the result to this.
1007  /// The wildcards may also be indexed. For example:
1008  ///
1009  /// to_pattern = b* from_name = apple from_pattern = a*le
1010  /// ---> this = bpp
1011  ///
1012  /// to_pattern = *(1)_to_*(0) from_name = a_to_b from_pattern = *_to_*
1013  /// ---> this = b_to_a
1014  bool subPatterns(
1015  const char *to_pattern,
1016  const char *from_name,
1017  const char *from_pattern);
1018 
1019  /// UTF-16 / UTF-8 conversions.
1020 
1021  /// Set the work buffer to contain the UTF-8 representation of the incoming UTF-16 string.
1022  /// The UTF-16 string is assumed to be little-endian, unless prefixed with BOM that
1023  /// indicates endianness.
1024  /// The incoming string should be zero-word terminated.
1025  void setFromUTF16(const utf16 *str);
1026 
1027  /// Set the work buffer to contain a UTF-16LE (little endian) representation of the
1028  /// incoming UTF-8 string.
1029  /// The work buffer will be zero-word terminated.
1030  void setAsUTF16(const utf8 *str);
1031 
1032  /// Once set as UTF16-LE, get it back as such a pointer.
1034  const utf16* castToUTF16() const { return (const utf16*) myBuffer; }
1035 
1036  /// Lock buffer for `len` utf-16 characters.
1038  {
1039  return (utf16*)lock(offset, len*sizeof(utf16));
1040  }
1041 
1042  void swap(UT_WorkBuffer &other)
1043  {
1044  // Warn if we're about to swap locked buffers.
1045  UT_ASSERT(myLockCount==0);
1046 
1047  bool this_stack = (myBuffer == myStackBuffer);
1048  bool other_stack = (other.myBuffer == other.myStackBuffer);
1049 
1050  if (this_stack && other_stack)
1051  {
1052  // If both buffers are using the stack buffer, just swap the
1053  // buffer contents.
1054  size_t max_size = (myLength > other.myLength) ? myLength
1055  : other.myLength;
1056 
1057  UTswap(myStackBuffer, other.myStackBuffer, max_size + 1);
1058  }
1059  else if (this_stack && !other_stack)
1060  {
1061  ::memcpy(other.myStackBuffer, myStackBuffer, myLength + 1);
1062  myBuffer = other.myBuffer;
1063  other.myBuffer = other.myStackBuffer;
1064  }
1065  else if (!this_stack && other_stack)
1066  {
1067  ::memcpy(myStackBuffer, other.myStackBuffer, other.myLength + 1);
1068  other.myBuffer = myBuffer;
1069  myBuffer = myStackBuffer;
1070  }
1071  else
1072  UTswap(myBuffer, other.myBuffer);
1073  UTswap(myAllocatedSize, other.myAllocatedSize);
1074  UTswap(myLength, other.myLength);
1075  UTswap(myLockCount, other.myLockCount);
1076  }
1077 public:
1078  /// Iterator compatibility.
1080  const char *begin() const { return myBuffer; }
1082  const char *end() const { return myBuffer + myLength; }
1083 
1084 private:
1085 
1086  struct do_widen {};
1087  struct do_narrow {};
1088  /// Private constructors to allow for the Return Value Optimization
1089  /// @{
1091  UT_WorkBuffer(do_widen, const utf8 *str)
1092  : UT_WorkBuffer()
1093  {
1094  setAsUTF16(str);
1095  }
1097  UT_WorkBuffer(do_narrow, const utf16 *str)
1098  : UT_WorkBuffer()
1099  {
1100  setFromUTF16(str);
1101  }
1102  /// @}
1103 
1104  template <typename ListT, bool ReportErrorsT = true>
1105  size_t appendFormatImpl(const char *fmt, ListT args);
1106 
1107  friend UT_API std::ostream &operator<<(std::ostream &os,
1108  const UT_WorkBuffer &buffer);
1109 
1110 private: // Data:
1111 
1112  char *myBuffer = myStackBuffer;
1113  exint myAllocatedSize = UT_INITIAL_BUFFER_SIZE;
1114  exint myLength = 0;
1115  int myLockCount = 0;
1116  char myStackBuffer[UT_INITIAL_BUFFER_SIZE];
1117 };
1118 
1119 /// Direct equality operators for UT_WorkBuffer <> UT_StringLit for speed to
1120 /// avoid casting down to const char*.
1121 /// @{
1122 static SYS_FORCE_INLINE bool
1123 operator==(const UT_WorkBuffer &buf, const UT_StringLit &lit)
1124 {
1125  return buf.operator==(lit.asRef());
1126 }
1127 static SYS_FORCE_INLINE bool
1128 operator==(const UT_StringLit &lit, const UT_WorkBuffer &buf)
1129 {
1130  return buf.operator==(lit.asRef());
1131 }
1132 static SYS_FORCE_INLINE bool
1133 operator!=(const UT_WorkBuffer &buf, const UT_StringLit &lit)
1134 {
1135  return buf.operator!=(lit.asRef());
1136 }
1137 static SYS_FORCE_INLINE bool
1138 operator!=(const UT_StringLit &lit, const UT_WorkBuffer &buf)
1139 {
1140  return buf.operator!=(lit.asRef());
1141 }
1142 /// @}
1143 
1144 static inline size_t
1145 format(char *buffer, size_t buffer_size, const UT_WorkBuffer &v)
1146 {
1147  if (!buffer)
1148  return v.length();
1149  else
1150  {
1151  size_t len = std::min(size_t(v.length()), buffer_size);
1152  ::memcpy(buffer, v.buffer(), len);
1153  return len;
1154  }
1155 }
1156 
1157 #endif
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
SYS_FORCE_INLINE void append(const UT_StringRef &str)
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
std::string upper(string_view a)
Return an all-upper case version of a (locale-independent).
Definition: strutil.h:500
GT_API const UT_StringHolder filename
SYS_FORCE_INLINE exint length() const
#define SYS_DEPRECATED(__V__)
SYS_FORCE_INLINE constexpr exint length() const
SYS_FORCE_INLINE void strcpy(const UT_StringRef &src)
void write(exint offset, const UT_StringHolder &src)
SYS_FORCE_INLINE exint getAllocatedSize() const
SYS_FORCE_INLINE char * operator*() const
void UTswap(T &a, T &b)
Definition: UT_Swap.h:35
SYS_FORCE_INLINE bool operator==(const UT_StringRef &str) const
void
Definition: png.h:1083
SYS_FORCE_INLINE bool operator==(const UT_String &str) const
SYS_FORCE_INLINE UT_WorkBuffer(const char *data, exint size)
Definition: UT_WorkBuffer.h:93
const GLdouble * v
Definition: glcorearb.h:837
SYS_FORCE_INLINE void append(const UT_StringView &view)
SYS_FORCE_INLINE void strncat(const char *src, exint len)
unsigned short utf16
Definition: SYS_Types.h:56
SYS_FORCE_INLINE UT_WorkBuffer(const UT_StringRef &str)
SYS_FORCE_INLINE UT_WorkBuffer(const char *str)
Definition: UT_WorkBuffer.h:86
int64 exint
Definition: SYS_Types.h:125
void append(exint n, char character)
SYS_FORCE_INLINE const char * buffer() const
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:795
SYS_FORCE_INLINE void strcpy(const char *src)
SYS_FORCE_INLINE void release(bool recompute_length=false)
You can manually release the buffer.
#define UT_API
Definition: UT_API.h:14
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
const char * findCharFrom(char c, exint position, int occurance_number=1) const
SYS_FORCE_INLINE bool operator!=(const UT_StringRef &str) const
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2138
void append(const char *data, exint size)
const char * lastChar(char c, int occurance_number=1) const
unsigned long long uint64
Definition: SYS_Types.h:117
OIIO_FORCEINLINE vbool4 insert(const vbool4 &a, bool val)
Helper: substitute val for a[i].
Definition: simd.h:3556
SYS_FORCE_INLINE char last() const
utf16 * lockUTF16(exint offset=0, exint len=0)
Lock buffer for len utf-16 characters.
SYS_FORCE_INLINE void relock()
If you've manually released the lock, you can relock the buffer.
GLuint buffer
Definition: glcorearb.h:660
SYS_FORCE_INLINE void append(const UT_String &str)
FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t< Char > &fill) -> OutputIt
Definition: format.h:1860
SIM_API const UT_StringHolder all
SYS_FORCE_INLINE const char * data() const
SYS_FORCE_INLINE void append(const UT_StringLit &str)
void swap(UT_WorkBuffer &other)
void eraseHead(exint n)
Remove the first n characters.
SYS_FORCE_INLINE void append(const UT_WorkBuffer &wb)
SYS_FORCE_INLINE bool operator==(const UT_WorkBuffer &buf) const
#define SYS_DEPRECATED_REPLACE(__V__, __R__)
std::ostream & operator<<(std::ostream &ostr, const DataType &a)
Definition: DataType.h:133
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const UT_WorkBuffer &wb)
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE const char * data() const noexcept
Returns a pointer to the first character of a view.
SYS_FORCE_INLINE void append(const char *str)
A utility class to do read-only operations on a subset of an existing string.
Definition: UT_StringView.h:40
static const utf8 * convert(const utf8 *str, utf32 &cp)
size_t appendFormat(const char *fmt, const Args &...args)
#define UT_INITIAL_BUFFER_SIZE
Definition: UT_WorkBuffer.h:64
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE bool isEmpty() const
Returns true if the string is empty.
GLdouble n
Definition: glcorearb.h:2008
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE exint length() const
Returns the length of the string in bytes.
SYS_FORCE_INLINE void strcpy(const UT_WorkBuffer &src)
GLintptr offset
Definition: glcorearb.h:665
SYS_FORCE_INLINE void strcpy(const UT_StringView &src)
exint length() const
SYS_FORCE_INLINE const char * buffer() const
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const UT_Digits &digits)
SYS_FORCE_INLINE const char * end() const
SYS_FORCE_INLINE UT_WorkBuffer & operator=(const UT_WorkBuffer &other)
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
unsigned int utf32
Definition: SYS_Types.h:58
void printMemory(int64 mem)
#define SYS_PRINTF_CHECK_ATTRIBUTE(string_index, first_to_check)
Definition: SYS_Types.h:448
SYS_FORCE_INLINE const char * begin() const
Iterator compatibility.
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
GLint GLint GLsizei GLint GLenum format
Definition: glcorearb.h:108
SYS_FORCE_INLINE void prepend(const UT_StringRef &str)
SYS_FORCE_INLINE UT_WorkBuffer(const UT_StringView &view)
bool operator!=(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Inequality operator, does exact floating point comparisons.
Definition: Mat3.h:556
void prepend(char character)
SYS_FORCE_INLINE bool isEmpty() const
SYS_FORCE_INLINE char * strdup() const
long long int64
Definition: SYS_Types.h:116
static SYS_FORCE_INLINE UT_WorkBuffer widen(const utf8 *str)
SYS_FORCE_INLINE const char * findChar(char c, int occurance_number=1) const
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const UT_String &str)
SYS_FORCE_INLINE exint strlen() const
SYS_FORCE_INLINE bool operator!=(const UT_WorkBuffer &buf) const
SYS_FORCE_INLINE UT_WorkBuffer & operator=(const std::string &str)
SYS_FORCE_INLINE const char * c_str() const
SYS_FORCE_INLINE void strcpy(const UT_String &src)
#define UT_UTF8_MAX_ENCODING_LEN
Definition: UT_Unicode.h:19
size_t SYSstrlcpy(char *dest, const char *src, size_t size)
Definition: SYS_String.h:180
SYS_FORCE_INLINE char * string() const
SYS_FORCE_INLINE void prepend(const UT_String &str)
SYS_FORCE_INLINE char operator()(exint idx) const
SYS_FORCE_INLINE UT_WorkBuffer(const UT_WorkBuffer &other)
SYS_FORCE_INLINE void strcat(const char *src)
SYS_FORCE_INLINE const char * c_str() const
SYS_FORCE_INLINE void truncate(exint new_length)
SYS_FORCE_INLINE const utf16 * castToUTF16() const
Once set as UTF16-LE, get it back as such a pointer.
auto reserve(std::back_insert_iterator< Container > it, size_t n) -> checked_ptr< typename Container::value_type >
Definition: format.h:578
SYS_FORCE_INLINE const UT_StringRef & asRef() const
void append(utf32 cp)
Append a single Unicode code point, converted to UTF8.
SYS_FORCE_INLINE int strcmp(const char *src) const
static SYS_FORCE_INLINE UT_WorkBuffer narrow(const utf16 *str)
GLsizeiptr size
Definition: glcorearb.h:664
SYS_FORCE_INLINE UT_WorkBuffer & operator=(const char *str)
SYS_FORCE_INLINE bool isstring() const
SYS_FORCE_INLINE void backup(exint by_length)
Rewind by the given length.
void write(exint offset, const char *src)
SYS_FORCE_INLINE UT_WorkBuffer(const UT_String &str)
SYS_FORCE_INLINE AutoLock(UT_WorkBuffer &buf)
void backupTo(char c)
SYS_FORCE_INLINE bool operator==(const char *str) const
SYS_FORCE_INLINE UT_WorkBuffer(const UT_StringLit &str)
std::string lower(string_view a)
Return an all-upper case version of a (locale-independent).
Definition: strutil.h:493
void advance(exint by_length)
SYS_FORCE_INLINE bool operator!=(const char *str) const
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const char *str)
SIM_API const UT_StringHolder position
SYS_FORCE_INLINE bool UTisstring(const char *s)
SYS_FORCE_INLINE void append(char character)
Type-safe formatting, modeled on the Python str.format function.
void prepend(const char *data, exint size)
virtual bool readFile(GA_Detail &g, const char *filename, const GA_LoadOptions *opts, UT_StringArray *errors) const
Class which defines an I/O interface to save/load geometry.
**If you just want to fire and args
Definition: thread.h:618
auto vsprintf(const S &fmt, basic_format_args< basic_printf_context_t< type_identity_t< Char >>> args) -> std::basic_string< Char >
Definition: printf.h:597
bool isstring() const
Definition: UT_String.h:698
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
SYS_FORCE_INLINE ~UT_WorkBuffer()
SYS_FORCE_INLINE void clear()
char utf8
Definition: SYS_Types.h:52
SYS_FORCE_INLINE constexpr const char * buffer() const
SYS_FORCE_INLINE ~AutoLock()
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())
SYS_FORCE_INLINE char first() const
SYS_FORCE_INLINE bool operator!=(const UT_String &str) const
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const UT_StringRef &str)
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const std::string &str)
Converts a double or float or half to the shortest accurate decimal possible.
Definition: UT_Digits.h:22
bool operator==(const Mat3< T0 > &m0, const Mat3< T1 > &m1)
Equality operator, does exact floating point comparisons.
Definition: Mat3.h:542
SYS_FORCE_INLINE void write(exint offset, char c)
GLint GLsizei count
Definition: glcorearb.h:405
SYS_FORCE_INLINE bool isstring() const
Definition: format.h:1821
Definition: format.h:4365
SYS_FORCE_INLINE void prepend(const char *str)
SYS_FORCE_INLINE void strncpy(const char *src, exint maxlen)
SYS_FORCE_INLINE int strncmp(const char *src, exint n) const
GLenum src
Definition: glcorearb.h:1793
SYS_FORCE_INLINE UT_WorkBuffer()
Definition: UT_WorkBuffer.h:80