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  void fullyProtectedUtf8ToPythonStrcat(const char *str);
461 
462  /// Append a string of a given maximum length to the current string.
463  /// Unlike the POSIX's strncat(3), we ignore any NUL bytes in the current
464  /// string and blindly append at the end of the work buffer.
466  void strncat(const char *src, exint len)
467  {
468  if (!src)
469  return;
470  append(src, ::strnlen(src, len));
471  }
472 
473  // Extract the first argument from the src and append it to the work
474  // buffer. This does NOT handle quotes properly (i.e. if the first word
475  // is quoted with spaces).
476  void strcatFirstWord(const char *src);
477 
479  int strcmp(const char *src) const
480  {
481  UT_ASSERT_P(isNullTerminated());
482  return ::strcmp(myBuffer, src);
483  }
484 
486  int strncmp(const char *src, exint n) const
487  {
488  UT_ASSERT_P(isNullTerminated());
489  return ::strncmp(myBuffer, src, n);
490  }
491 
493  char *strdup() const
494  {
495  UT_ASSERT(isNullTerminated());
496  return ::strdup(myBuffer);
497  }
498 
499  // Reset the buffer to an empty buffer.
501  void clear()
502  {
503  if (myLockCount) { UT_ASSERT(0); return; }
504  myLength = 0;
505  myBuffer[0] = '\0';
506  }
507 
509  bool isEmpty() const
510  {
511  return (myLength == 0);
512  }
514  bool isstring() const
515  {
516  return !isEmpty();
517  }
518 
519  // Write into the buffer at a specific place.
520  // This WILL expand the buffer if it is required and keep it null
521  // terminated.
523  void write(exint offset, char c)
524  {
525  UT_ASSERT(offset >= 0);
526  if (offset < 0) return;
527  if (offset >= myLength)
528  {
529  if (myLockCount) { UT_ASSERT(0); return; }
530  myLength = offset+1;
531  growBufferIfNeeded();
532  myBuffer[myLength] = '\0';
533  }
534  myBuffer[offset] = c;
535  if (c == '\0')
536  myLength = offset;
537  }
538 
539  // This does NOT write out the trailing NULL of src, but the buffer will
540  // still be null-terminated.
541  void write(exint offset, const char *src)
542  {
543  while (*src)
544  {
545  write(offset, *src);
546  src++;
547  offset++;
548  }
549  }
550 
552  {
553  write(offset, src.c_str());
554  }
555 
556  /// Load an entire file into the buffer. Returns @b false if there was an
557  /// error reading the file
558  bool readFile(const char *filename);
559 
560  // Read a line from an istream -- no matter how long the line is
561  // Returns 0 if the stream read failed or 1 otherwise
562  bool getline(std::istream &is);
563  bool getline(FILE *fp);
564 
565  // Much like getline() except that it has more features. The string itself
566  // is tokenized which the UT_WorkArgs points into.
567  // line_num is incremented for each line read.
568  // comment_chars is list of characters to treat as comments.
569  // this can be NULL if we don't want this feature.
570  // Returns false if the stream read failed.
571  bool cmdGetLine(std::istream &is, UT_WorkArgs &args, int &line_num,
572  const char *comment_chars = "#",
573  const char *separators = " \t\n\r");
574  bool cmdGetLine(UT_IStream &is, UT_WorkArgs &args, int &line_num,
575  const char *comment_chars = "#",
576  const char *separators = " \t\n\r");
577  bool cmdGetLine(FILE *fp, UT_WorkArgs &args, int &line_num,
578  const char *comment_chars = "#",
579  const char *separators = " \t\n\r");
580 
581  /// Fast integer to string conversion.
582  /// @{
583  void itoa(int64 i);
584  void utoa(uint64 i);
585  /// @}
586 
587  /// Format using the system sprintf. See also printf() which uses UT_printf
588  /// which is type-safe and can print floating point using std::to_chars.
589  int sprintf(const char *fmt, ...)
591  int appendSprintf(const char *fmt, ...)
593  int vsprintf(const char *fmt, va_list ap);
594 
595  /// Replace the contents of the work buffer using the same formatting as
596  /// UTformat. Returns the resulting length in bytes.
597  /// If fmt is nullptr will space-separate the arguments like python print.
598  template<typename... Args>
599  size_t format(const char *fmt, const Args &...args)
600  {
601  clear();
602  return appendFormat(fmt, {args...});
603  }
604  /// Append to the work buffer using the same formatting as UTformat.
605  /// Returns the size of the appended portion, in bytes.
606  /// If fmt is nullptr will space-separate the arguments like python print.
607  /// @{
608  template<typename... Args>
609  size_t appendFormat(const char *fmt, const Args &...args)
610  {
611  return appendFormat(fmt, {args...});
612  }
613  size_t appendFormat(const char *fmt, std::initializer_list<UT::Format::ArgValue> args);
614  /// @}
615 
616  /// Like appendFormat() except it that uses an array of arguments
617  size_t appendFormatByArray(const char *fmt,
619  bool report_errors = true);
620 
621  // These tack stuff to the end of the buffer.
623  void append(char character)
624  {
625  if (myLockCount) { UT_ASSERT(0); return; }
626  UT_ASSERT_P(isNullTerminated());
627  myLength++;
628  growBufferIfNeeded();
629  myBuffer[myLength - 1] = character;
630  myBuffer[myLength] = '\0';
631  }
632 
633  void printMemory(int64 mem) { clear(); appendPrintMemory(mem); }
634  void appendPrintMemory(int64 mem);
635 
636  void append(exint n, char character)
637  {
638  if (myLockCount) { UT_ASSERT(0); return; }
639  UT_ASSERT_P(isNullTerminated());
640  myLength += n;
641  growBufferIfNeeded();
642  std::fill(myBuffer+myLength-n, myBuffer+myLength, character);
643  myBuffer[myLength] = '\0';
644  }
645 
646  /// Append a single Unicode code point, converted to UTF8
647  void append(utf32 cp)
648  {
650  int len = UT_Unicode::convert(cp, buf, sizeof(buf));
651  if (!len)
652  return;
653 
654  if (myLockCount) { UT_ASSERT(0); return; }
655  UT_ASSERT_P(isNullTerminated());
656  myLength += len;
657  growBufferIfNeeded();
658  ::memcpy(myBuffer + myLength - len, buf, len);
659  myBuffer[myLength] = '\0';
660  }
661 
662  void append(const char *data, exint size)
663  {
664  if (myLockCount) { UT_ASSERT(0); return; }
665  UT_ASSERT_P(data);
666  UT_ASSERT_P(isNullTerminated());
667  myLength += size;
668  growBufferIfNeeded();
669  ::memcpy(myBuffer + myLength - size, data, size);
670  myBuffer[myLength] = '\0';
671  }
672 
674  void append(const char *str)
675  {
676  if( UTisstring(str) )
677  append(str, ::strlen(str));
678  }
679 
681  void append(const UT_String &str)
682  {
683  if (str.isstring())
684  append((const char *)str);
685  }
686 
688  void append(const UT_StringRef &str)
689  {
690  if (str.isstring())
691  append(str.buffer(), str.length());
692  }
693 
695  void append(const UT_StringLit &str)
696  {
697  append(str.buffer(), str.length());
698  }
699 
700  void append(const UT_StringArray &strs, const UT_StringRef &sep);
701 
703  void append(const UT_WorkBuffer &wb)
704  {
705  append( wb.buffer(), wb.length() );
706  }
707 
709  void append(const UT_StringView &view)
710  {
711  // Avoid assertion if view is nullptr by testing for emptiness
712  if (!view.isEmpty())
713  append(view.data(), view.length());
714  }
715 
716  void append(const UT_Digits&);
717 
719  UT_WorkBuffer &operator+=(const char *str)
720  {
721  append(str);
722  return *this;
723  }
724 
726  UT_WorkBuffer &operator+=(const std::string &str)
727  {
728  append(str);
729  return *this;
730  }
731 
734  {
735  append(wb);
736  return *this;
737  }
738 
741  {
742  append(str);
743  return *this;
744  }
745 
748  {
749  append(str);
750  return *this;
751  }
752 
755  {
756  append(digits);
757  return *this;
758  }
759 
760  void prepend(char character)
761  {
762  if (myLockCount) { UT_ASSERT(0); return; }
763  UT_ASSERT_P(isNullTerminated());
764  myLength++;
765  growBufferIfNeeded();
766  ::memmove(myBuffer+1, myBuffer, myLength);
767  myBuffer[0] = character;
768  }
769  void prepend(const char *data, exint size)
770  {
771  if (myLockCount) { UT_ASSERT(0); return; }
772  UT_ASSERT_P(data);
773  UT_ASSERT_P(isNullTerminated());
774  myLength += size;
775  growBufferIfNeeded();
776  ::memmove(myBuffer+size, myBuffer, myLength+1 - size);
777  ::memcpy(myBuffer, data, size);
778  }
780  void prepend(const char *str)
781  {
782  UT_ASSERT_P(str);
783  prepend(str, ::strlen(str));
784  }
785 
787  void prepend(const UT_String &str)
788  {
789  if (str.isstring())
790  prepend((const char *)str);
791  }
793  void prepend(const UT_StringRef &str)
794  {
795  if (str)
796  prepend(str.buffer(), str.length());
797  }
798 
799  /// Insert @c slen characters from @c str, at location @c pos. If @c pos
800  /// exceeds the current length, the position is truncated and to an append.
801  void insert(exint pos, const char* str, exint slen);
802 
803  /// Erase @c len characters from location @c pos in the string.
804  void erase(exint pos, exint len);
805 
806  void rewind() { backup(myLength); }
807 
808  /// Rewind by the given length
810  void backup(exint by_length)
811  {
812  if (myLockCount) { UT_ASSERT(0); return; }
813  UT_ASSERT_P(isNullTerminated());
814  UT_ASSERT_P(by_length >= 0);
815  myLength -= by_length;
816  UT_ASSERT(myLength >= 0);
817  myBuffer[myLength] = '\0';
818  }
819 
820  /// Truncate the buffer to the specified length. Truncating to 0 is
821  /// identical to clear().
823  void truncate(exint new_length)
824  {
825  if (new_length >= myLength)
826  {
827  // We can truncate to our existing length without asserting, but if
828  // new_length > myLength, then that's a problem.
829  UT_ASSERT(new_length == myLength
830  && "Truncating beyond buffer extent");
831  return;
832  }
833  backup(myLength-new_length);
834  }
835 
836  // Delete characters off the end of the string until we hit the
837  // requested character.
838  void backupTo(char c)
839  {
840  if (myLockCount) { UT_ASSERT(0); return; }
841  UT_ASSERT_P(isNullTerminated());
842  while( myLength > 0 && myBuffer[myLength-1] != c )
843  myLength--;
844  myBuffer[myLength] = '\0';
845  }
846 
847  void advance(exint by_length)
848  {
849  if (myLockCount) { UT_ASSERT(0); return; }
850  UT_ASSERT_P(isNullTerminated());
851  UT_ASSERT_P(by_length >= 0);
852  myLength -= by_length;
853  UT_ASSERT(myLength >= 0);
854  for (int i=0; i<myLength; i++)
855  myBuffer[i] = myBuffer[by_length+i];
856  myBuffer[myLength] = '\0';
857  }
858 
859  // Finds the 'occurance_number'-th occurance of char c in the string.
861  const char *findChar(char c, int occurance_number = 1) const
862  {
863  return findCharFrom(c, 0, occurance_number);
864  }
865  // Same as findChar, but searches from the end of the string.
866  const char *lastChar(char c, int occurance_number = 1) const
867  {
868  if (myLockCount) { UT_ASSERT(0); return NULL; }
869 
870  UT_ASSERT_P(isNullTerminated());
871 
872  for (exint i = myLength; i --> 0;)
873  {
874  if(c == myBuffer[i])
875  {
876  occurance_number--;
877  if(occurance_number <= 0)
878  {
879  return (myBuffer + i);
880  }
881  }
882  }
883 
884  return NULL;
885  }
886  // Same and findChar, bu searches from given position in the string.
887  const char *findCharFrom(char c, exint position,
888  int occurance_number = 1) const
889  {
890  if (myLockCount) { UT_ASSERT(0); return NULL; }
891 
892  UT_ASSERT_P(isNullTerminated());
893 
894  if (position < 0 || position >= myLength) { return NULL; }
895 
896  for(exint i = position; i < myLength; ++i)
897  {
898  if(c == myBuffer[i])
899  {
900  occurance_number--;
901  if(occurance_number <= 0)
902  {
903  return (myBuffer + i);
904  }
905  }
906  }
907 
908  return NULL;
909  }
910 
911  /// Adopt a string from an outside source. The passed string is now
912  /// owned by the workbuffer.
913  void adoptFromMalloc(char* data, exint length);
914 
915  void adoptFromCharArray(UT_Array<char>& data);
916 
917  /// Count the occurrences of the text in the current string
918  exint count(const char *needle) const;
919 
920  // Get the next token pointed at by string and advance string past the
921  // token. Returns whether or not a token was retrieved successfully.
922  // Note that string is modified!!!
923  bool getNextToken(const char *(&string),
924  const UT_String separators = " \t\n");
925 
926  // Harden the contents of the buffer into a UT_String.
927  void copyIntoString(UT_String &str) const;
928 
929  // Copy the contents into a fixed length buffer.
930  // TODO: Get rid of this method, since it encourages fixed-length buffers.
931  void copyIntoString(char *str, exint max_length) const;
932 
933  // Steal the contents of this work buffer into the string.
934  void stealIntoString(UT_String &str);
935 
936  // Steal the contents of this work buffer into the string.
937  // NB: Use UT_StringHolder move constructor/assignment instead
938  // UT_StringHolder foo(std::move(buffer));
939  // foo = std::move(buffer);
940  SYS_DEPRECATED(19.0)
941  void stealIntoStringHolder(UT_StringHolder &str);
942 
943  // Return a string containing the contents of this work buffer, preserving
944  // any null characters in it.
945  std::string toStdString() const
946  { return std::string(buffer(), length()); }
947 
948  // Strips the characters after comment_char from the buffer. This method
949  // goes to some effort to enusre that the comment_char is not preceded by
950  // a backslash or is not in a quoted string. Returns true if it found a
951  // comment and modified the buffer, and false otherwise.
952  bool stripComments(char comment_char = '#');
953 
954  /// Strips out all characters found in 'chars'. The string length will be
955  /// reduced by the number of characters removed. The number of characters
956  /// removed is returned.
957  int strip(const char *chars);
958 
959  /// Remove trailing whitespace lines
960  void removeTrailingSpaceLines();
961 
962  /// Remove trailing whitespace, return true if whitespace was removed.
963  bool removeTrailingSpace();
964 
965  /// Remove leading white space, return true if whitespace was removed.
966  bool removeLeadingSpace();
967 
968  /// Remove trailing digits, return true if some were removed.
969  bool removeTrailingDigits();
970 
971  /// Convert string to lower case
972  void lower();
973 
974  /// Convert string to upper case
975  void upper();
976 
977  /// Create a string of tabs & spaces which represents the given indent
978  void makeIndentString(exint indent, exint tabstop=8);
979 
980  /// Remove the first n characters.
982  {
983  if (n < myLength)
984  {
985  myLength -= n;
986  ::memmove(myBuffer, myBuffer + n, myLength);
987  }
988  else
989  myLength = 0;
990 
991  myBuffer[myLength] = '\0';
992  }
993 
994  /// Replaces up to 'count' occurrences of 'find' with 'replacement',
995  /// and returns the number of substitutions that occurred.
996  /// If 'count' <= 0, all occurrences will be replaced.
997  int substitute(const char *find, const char *replacement, int count = -1);
998 
999  /// Convenience version of substitute() for all or single occurrence.
1000  SYS_DEPRECATED_REPLACE(19.5, "Use 'count' variant")
1001  int substitute(const char *find, const char *replacement, bool all)
1002  {
1003  return substitute(find, replacement, !all ? 1 : -1);
1004  }
1005 
1006  /// Given from_name which is assumed to fit from_pattern, any assigned
1007  /// wildcards are subsitituted in to_pattern, writing the result to this.
1008  /// The wildcards may also be indexed. For example:
1009  ///
1010  /// to_pattern = b* from_name = apple from_pattern = a*le
1011  /// ---> this = bpp
1012  ///
1013  /// to_pattern = *(1)_to_*(0) from_name = a_to_b from_pattern = *_to_*
1014  /// ---> this = b_to_a
1015  bool subPatterns(
1016  const char *to_pattern,
1017  const char *from_name,
1018  const char *from_pattern);
1019 
1020  /// UTF-16 / UTF-8 conversions.
1021 
1022  /// Set the work buffer to contain the UTF-8 representation of the incoming UTF-16 string.
1023  /// The UTF-16 string is assumed to be little-endian, unless prefixed with BOM that
1024  /// indicates endianness.
1025  /// The incoming string should be zero-word terminated.
1026  void setFromUTF16(const utf16 *str);
1027 
1028  /// Set the work buffer to contain a UTF-16LE (little endian) representation of the
1029  /// incoming UTF-8 string.
1030  /// The work buffer will be zero-word terminated.
1031  void setAsUTF16(const utf8 *str);
1032 
1033  /// Once set as UTF16-LE, get it back as such a pointer.
1035  const utf16* castToUTF16() const { return (const utf16*) myBuffer; }
1036 
1037  /// Lock buffer for `len` utf-16 characters.
1039  {
1040  return (utf16*)lock(offset, len*sizeof(utf16));
1041  }
1042 
1043  void swap(UT_WorkBuffer &other)
1044  {
1045  // Warn if we're about to swap locked buffers.
1046  UT_ASSERT(myLockCount==0);
1047 
1048  bool this_stack = (myBuffer == myStackBuffer);
1049  bool other_stack = (other.myBuffer == other.myStackBuffer);
1050 
1051  if (this_stack && other_stack)
1052  {
1053  // If both buffers are using the stack buffer, just swap the
1054  // buffer contents.
1055  size_t max_size = (myLength > other.myLength) ? myLength
1056  : other.myLength;
1057 
1058  UTswap(myStackBuffer, other.myStackBuffer, max_size + 1);
1059  }
1060  else if (this_stack && !other_stack)
1061  {
1062  ::memcpy(other.myStackBuffer, myStackBuffer, myLength + 1);
1063  myBuffer = other.myBuffer;
1064  other.myBuffer = other.myStackBuffer;
1065  }
1066  else if (!this_stack && other_stack)
1067  {
1068  ::memcpy(myStackBuffer, other.myStackBuffer, other.myLength + 1);
1069  other.myBuffer = myBuffer;
1070  myBuffer = myStackBuffer;
1071  }
1072  else
1073  UTswap(myBuffer, other.myBuffer);
1074  UTswap(myAllocatedSize, other.myAllocatedSize);
1075  UTswap(myLength, other.myLength);
1076  UTswap(myLockCount, other.myLockCount);
1077  }
1078 public:
1079  /// Iterator compatibility.
1081  const char *begin() const { return myBuffer; }
1083  const char *end() const { return myBuffer + myLength; }
1084 
1085 private:
1086 
1087  struct do_widen {};
1088  struct do_narrow {};
1089  /// Private constructors to allow for the Return Value Optimization
1090  /// @{
1092  UT_WorkBuffer(do_widen, const utf8 *str)
1093  : UT_WorkBuffer()
1094  {
1095  setAsUTF16(str);
1096  }
1098  UT_WorkBuffer(do_narrow, const utf16 *str)
1099  : UT_WorkBuffer()
1100  {
1101  setFromUTF16(str);
1102  }
1103  /// @}
1104 
1105  template <typename ListT, bool ReportErrorsT = true>
1106  size_t appendFormatImpl(const char *fmt, ListT args);
1107 
1108  friend UT_API std::ostream &operator<<(std::ostream &os,
1109  const UT_WorkBuffer &buffer);
1110 
1111 private: // Data:
1112 
1113  char *myBuffer = myStackBuffer;
1114  exint myAllocatedSize = UT_INITIAL_BUFFER_SIZE;
1115  exint myLength = 0;
1116  int myLockCount = 0;
1117  char myStackBuffer[UT_INITIAL_BUFFER_SIZE];
1118 };
1119 
1120 /// Direct equality operators for UT_WorkBuffer <> UT_StringLit for speed to
1121 /// avoid casting down to const char*.
1122 /// @{
1123 static SYS_FORCE_INLINE bool
1124 operator==(const UT_WorkBuffer &buf, const UT_StringLit &lit)
1125 {
1126  return buf.operator==(lit.asRef());
1127 }
1128 static SYS_FORCE_INLINE bool
1129 operator==(const UT_StringLit &lit, const UT_WorkBuffer &buf)
1130 {
1131  return buf.operator==(lit.asRef());
1132 }
1133 static SYS_FORCE_INLINE bool
1134 operator!=(const UT_WorkBuffer &buf, const UT_StringLit &lit)
1135 {
1136  return buf.operator!=(lit.asRef());
1137 }
1138 static SYS_FORCE_INLINE bool
1139 operator!=(const UT_StringLit &lit, const UT_WorkBuffer &buf)
1140 {
1141  return buf.operator!=(lit.asRef());
1142 }
1143 /// @}
1144 
1145 static inline size_t
1146 format(char *buffer, size_t buffer_size, const UT_WorkBuffer &v)
1147 {
1148  if (!buffer)
1149  return v.length();
1150  else
1151  {
1152  size_t len = std::min(size_t(v.length()), buffer_size);
1153  ::memcpy(buffer, v.buffer(), len);
1154  return len;
1155  }
1156 }
1157 
1158 #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