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 
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)
173  const char *data() const { return buffer(); }
174 
175  // Having said that, if you need a non-const pointer you must lock
176  // the string. This prohibits ANY update which changes the myLength
177  // variable (and thus potentially a realloc)
178  // You must release the buffer before any such changes.
179  // The work buffer continues to own the memory and will free it when
180  // it goes out of scope so don't think this is the same as a "steal"
181  // in UT_String.
182  // Currently, to ensure people couple their locks & releases,
183  // it asserts there is no unaccounted locks on death. This is so
184  // people who think it is steal find out otherwise.
185  // Offset is where in the string to get the pointer from.
186  // This is only to be used when absolutely necessary.
187  // When releasing, if you have a string buffer, and you have modified the
188  // length, you should set the recompute_length flag to 1. This will adjust
189  // the internal length variable so that further concatenations will work
190  // properly.
191  // The reserve_bytes parameter tells the lock to ensure that there are at
192  // least that many bytes in the locked buffer.
193  // NOTE: Unlike other UT_WorkBuffer functions, it is the user's
194  // responsibility to maintain a NUL termination guarantee when manipulating
195  // the raw buffer.
196  char *lock(exint offset = 0, exint reserve_bytes=0);
197  void release(bool recompute_length = false);
198  void releaseSetLength(exint new_length);
199 
201  exint getAllocatedSize() const { return myAllocatedSize; }
202  int64 getMemoryUsage(bool inclusive) const;
203 
204  /// Class to handle auto-locking of the UT_WorkBuffer. This is not related
205  /// to multi-threading, but to the lock/release methods above.
206  ///
207  /// You should never append data to a locked buffer.
208  class AutoLock
209  {
210  public:
213  : myBuffer(buf)
214  {
215  myString = myBuffer.lock();
216  }
219  {
220  release();
221  }
222  /// @{
223  /// Get access to the non-const buffer. This may return nullptr if the
224  /// lock has been released.
226  char *operator*() const { return myString; }
228  char *string() const { return myString; }
229  /// @}
230 
231  /// You can manually release the buffer
233  void release(bool recompute_length=false)
234  {
235  if (myString)
236  {
237  myBuffer.release(recompute_length);
238  myString = nullptr;
239  }
240  }
241  /// If you've manually released the lock, you can relock the buffer
243  void relock()
244  {
245  UT_ASSERT(!myString);
246  myString = myBuffer.lock();
247  }
248  private:
249  UT_WorkBuffer &myBuffer;
250  char *myString;
251  };
252 
253  void reserve(exint bytes=0);
254 
255  // This is a read only operator. We are avoiding the writeable
256  // versions as they lead to problems when people do a:
257  // foo[pastend] = foo(start)
258  // causing an implicit realloc.
260  char operator()(exint idx) const
261  {
262  // We allow an index at myLength as if we have a null
263  // terminated buffer that is the null termination.
264  UT_ASSERT_P(idx >= 0 && idx <= myLength);
265  return myBuffer[idx];
266  }
267 
268  // Returns last character. Only valid if !isEmpty()
270  char first() const
271  {
272  UT_ASSERT_P(myLength > 0);
273  return myBuffer[0];
274  }
275  // Returns last character. Only valid if !isEmpty()
277  char last() const
278  {
279  UT_ASSERT_P(myLength > 0);
280  return myBuffer[myLength - 1];
281  }
282 
283  // This should always be true. It's here to act as a sanity function.
284  int isNullTerminated() const;
285 
288  {
289  strcpy(other);
290  return *this;
291  }
293  UT_WorkBuffer &operator=(const char *str)
294  {
295  clear();
296  append(str);
297  return *this;
298  }
301  {
302  clear();
303  append(str.c_str(), str.length());
304  return *this;
305  }
306 
307  /// Comparison operator. Null strings are considered as empty strings.
308  /// @{
310  bool operator==(const char *str) const
311  {
312  if (!str)
313  return isEmpty();
314  return (::strcmp(str, myBuffer) == 0);
315  }
317  bool operator==(const UT_String &str) const
318  {
319  if (!(const char *)str)
320  return isEmpty();
321  return (::strcmp(str, myBuffer) == 0);
322  }
324  bool operator==(const UT_StringRef &str) const
325  {
326  if (length() != str.length())
327  return false;
328  return (::memcmp(myBuffer, str.c_str(), myLength) == 0);
329  }
331  bool operator==(const UT_WorkBuffer &buf) const
332  {
333  if (buf.isEmpty())
334  return isEmpty();
335  if (length() != buf.length())
336  return false;
337  return (::memcmp(myBuffer, buf.myBuffer, myLength) == 0);
338  }
340  bool operator!=(const char *str) const
341  {
342  return !(*this == str);
343  }
345  bool operator!=(const UT_String &str) const
346  {
347  return !(*this == str);
348  }
350  bool operator!=(const UT_StringRef &str) const
351  {
352  return !(*this == str);
353  }
355  bool operator!=(const UT_WorkBuffer &buf) const
356  {
357  return !(*this == buf);
358  }
359  /// @}
360 
361 private:
362  // Reallocate the buffer until the allocated size is >= the length. This
363  // private method needs to come first so it can be inlined.
364  void growBufferIfNeeded()
365  {
366  // Using a while loop instead of computing an accurate size the
367  // first time is slower, but most of the time the loop will execute
368  // at most once.
369  // We need to use myLength+1 as we need room for the null.
370  while (myLength+1 > myAllocatedSize) // false most of the time
371  reserve(myAllocatedSize * 2);
372  }
373 
374 public:
375  // These are standard string operators people tend to use:
377  void strcpy(const char *src)
378  {
379  clear();
380  append(src);
381  }
383  void strcpy(const UT_String &src)
384  {
385  clear();
386  append(src);
387  }
389  void strcpy(const UT_StringRef &src)
390  {
391  clear();
392  append(src);
393  }
395  void strcpy(const UT_WorkBuffer &src)
396  {
397  clear();
398  append(src);
399  }
401  void strcpy(const UT_StringView &src)
402  {
403  clear();
404  append(src);
405  }
406 
407  // NOTE: unlike strncpy(), maxlen does not include the null terminator.
409  void strncpy(const char *src, exint maxlen)
410  {
411  clear();
412  // Ensure we have enough room:
413  myLength = maxlen+1;
414  growBufferIfNeeded();
415  myLength = 0;
416  SYSstrlcpy(myBuffer, src, maxlen+1);
417  myLength = ::strlen(myBuffer);
418  }
419 
420  // Note we can't just return myLength as there may be embedded NULLs.
422  exint strlen() const
423  {
424  UT_ASSERT_P(isNullTerminated());
425  return ::strlen(myBuffer);
426  }
427 
429  exint length() const
430  {
431  return myLength;
432  }
433 
435  void strcat(const char *src)
436  {
437  append(src);
438  }
439 
440  // protectedStrcat() will quote the string in double quotes if required and
441  // protect any enclosed double quotes or backslashes in the source. It
442  // will not escape any other characters.
443  void protectedStrcat(const char *str, bool force_quote=false);
444 
445  // fullyProtected*Strcat() is similar to protectedStrcat, except it escapes
446  // any non-printable characters. It will not escape single quotes, and if
447  // force_quote is true, it will add double-quotes. It will work with
448  // arbitrary binary data and uses the \xNN syntax to encode bytes.
449  // UT_IStream::read() is capable of loading strings encoded with this
450  // method, and these strings can also be decoded in Python. If
451  // fullyProtectedBinaryStrcat is called, this method can handle data
452  // containing null characters.
453  void fullyProtectedStrcat(const char *str, bool force_quote=false);
454  void fullyProtectedBinaryStrcat(
455  const char *str, exint size, bool force_quote=false);
456 
457  /// Append a string of a given maximum length to the current string.
458  /// Unlike the POSIX's strncat(3), we ignore any NUL bytes in the current
459  /// string and blindly append at the end of the work buffer.
461  void strncat(const char *src, exint len)
462  {
463  if (!src)
464  return;
465  append(src, ::strnlen(src, len));
466  }
467 
468  // Extract the first argument from the src and append it to the work
469  // buffer. This does NOT handle quotes properly (i.e. if the first word
470  // is quoted with spaces).
471  void strcatFirstWord(const char *src);
472 
474  int strcmp(const char *src) const
475  {
476  UT_ASSERT_P(isNullTerminated());
477  return ::strcmp(myBuffer, src);
478  }
479 
481  int strncmp(const char *src, exint n) const
482  {
483  UT_ASSERT_P(isNullTerminated());
484  return ::strncmp(myBuffer, src, n);
485  }
486 
488  char *strdup() const
489  {
490  UT_ASSERT(isNullTerminated());
491  return ::strdup(myBuffer);
492  }
493 
494  // Reset the buffer to an empty buffer.
496  void clear()
497  {
498  if (myLockCount) { UT_ASSERT(0); return; }
499  myLength = 0;
500  myBuffer[0] = '\0';
501  }
502 
504  bool isEmpty() const
505  {
506  return (myLength == 0);
507  }
509  bool isstring() const
510  {
511  return !isEmpty();
512  }
513 
514  // Write into the buffer at a specific place.
515  // This WILL expand the buffer if it is required and keep it null
516  // terminated.
518  void write(exint offset, char c)
519  {
520  UT_ASSERT(offset >= 0);
521  if (offset < 0) return;
522  if (offset >= myLength)
523  {
524  if (myLockCount) { UT_ASSERT(0); return; }
525  myLength = offset+1;
526  growBufferIfNeeded();
527  myBuffer[myLength] = '\0';
528  }
529  myBuffer[offset] = c;
530  if (c == '\0')
531  myLength = offset;
532  }
533 
534  // This does NOT write out the trailing NULL of src, but the buffer will
535  // still be null-terminated.
536  void write(exint offset, const char *src)
537  {
538  while (*src)
539  {
540  write(offset, *src);
541  src++;
542  offset++;
543  }
544  }
545 
547  {
548  write(offset, src.c_str());
549  }
550 
551  /// Load an entire file into the buffer. Returns @b false if there was an
552  /// error reading the file
553  bool readFile(const char *filename);
554 
555  // Read a line from an istream -- no matter how long the line is
556  // Returns 0 if the stream read failed or 1 otherwise
557  bool getline(std::istream &is);
558  bool getline(FILE *fp);
559 
560  // Much like getline() except that it has more features. The string itself
561  // is tokenized which the UT_WorkArgs points into.
562  // line_num is incremented for each line read.
563  // comment_chars is list of characters to treat as comments.
564  // this can be NULL if we don't want this feature.
565  // Returns false if the stream read failed.
566  bool cmdGetLine(std::istream &is, UT_WorkArgs &args, int &line_num,
567  const char *comment_chars = "#",
568  const char *separators = " \t\n\r");
569  bool cmdGetLine(UT_IStream &is, UT_WorkArgs &args, int &line_num,
570  const char *comment_chars = "#",
571  const char *separators = " \t\n\r");
572  bool cmdGetLine(FILE *fp, UT_WorkArgs &args, int &line_num,
573  const char *comment_chars = "#",
574  const char *separators = " \t\n\r");
575 
576  /// Fast integer to string conversion.
577  /// @{
578  void itoa(int64 i);
579  void utoa(uint64 i);
580  /// @}
581 
582  /// Format using the system sprintf. See also printf() which uses UT_printf
583  /// which is type-safe and can print floating point using std::to_chars.
584  int sprintf(const char *fmt, ...)
586  int appendSprintf(const char *fmt, ...)
588  int vsprintf(const char *fmt, va_list ap);
589 
590  /// Replace the contents of the work buffer using the same formatting as
591  /// UTformat. Returns the resulting length in bytes.
592  /// If fmt is nullptr will space-separate the arguments like python print.
593  template<typename... Args>
594  size_t format(const char *fmt, const Args &...args)
595  {
596  clear();
597  return appendFormat(fmt, {args...});
598  }
599  /// Append to the work buffer using the same formatting as UTformat.
600  /// Returns the size of the appended portion, in bytes.
601  /// If fmt is nullptr will space-separate the arguments like python print.
602  /// @{
603  template<typename... Args>
604  size_t appendFormat(const char *fmt, const Args &...args)
605  {
606  return appendFormat(fmt, {args...});
607  }
608  size_t appendFormat(const char *fmt, std::initializer_list<UT::Format::ArgValue> args);
609  /// @}
610 
611  /// Like appendFormat() except it that uses an array of arguments
612  size_t appendFormatByArray(const char *fmt,
614  bool report_errors = true);
615 
616  // These tack stuff to the end of the buffer.
618  void append(char character)
619  {
620  if (myLockCount) { UT_ASSERT(0); return; }
621  UT_ASSERT_P(isNullTerminated());
622  myLength++;
623  growBufferIfNeeded();
624  myBuffer[myLength - 1] = character;
625  myBuffer[myLength] = '\0';
626  }
627 
628  void printMemory(int64 mem) { clear(); appendPrintMemory(mem); }
629  void appendPrintMemory(int64 mem);
630 
631  void append(exint n, char character)
632  {
633  if (myLockCount) { UT_ASSERT(0); return; }
634  UT_ASSERT_P(isNullTerminated());
635  myLength += n;
636  growBufferIfNeeded();
637  std::fill(myBuffer+myLength-n, myBuffer+myLength, character);
638  myBuffer[myLength] = '\0';
639  }
640 
641  /// Append a single Unicode code point, converted to UTF8
642  void append(utf32 cp)
643  {
645  int len = UT_Unicode::convert(cp, buf, sizeof(buf));
646  if (!len)
647  return;
648 
649  if (myLockCount) { UT_ASSERT(0); return; }
650  UT_ASSERT_P(isNullTerminated());
651  myLength += len;
652  growBufferIfNeeded();
653  ::memcpy(myBuffer + myLength - len, buf, len);
654  myBuffer[myLength] = '\0';
655  }
656 
657  void append(const char *data, exint size)
658  {
659  if (myLockCount) { UT_ASSERT(0); return; }
660  UT_ASSERT_P(data);
661  UT_ASSERT_P(isNullTerminated());
662  myLength += size;
663  growBufferIfNeeded();
664  ::memcpy(myBuffer + myLength - size, data, size);
665  myBuffer[myLength] = '\0';
666  }
667 
669  void append(const char *str)
670  {
671  if( UTisstring(str) )
672  append(str, ::strlen(str));
673  }
674 
676  void append(const UT_String &str)
677  {
678  if (str.isstring())
679  append((const char *)str);
680  }
681 
683  void append(const UT_StringRef &str)
684  {
685  if (str.isstring())
686  append(str.buffer(), str.length());
687  }
688 
690  void append(const UT_StringLit &str)
691  {
692  append(str.buffer(), str.length());
693  }
694 
695  void append(const UT_StringArray &strs, const UT_StringRef &sep);
696 
698  void append(const UT_WorkBuffer &wb)
699  {
700  append( wb.buffer(), wb.length() );
701  }
702 
704  void append(const UT_StringView &view)
705  {
706  // Avoid assertion if view is nullptr by testing for emptiness
707  if (!view.isEmpty())
708  append(view.data(), view.length());
709  }
710 
711  void append(const UT_Digits&);
712 
714  UT_WorkBuffer &operator+=(const char *str)
715  {
716  append(str);
717  return *this;
718  }
719 
722  {
723  append(str);
724  return *this;
725  }
726 
729  {
730  append(wb);
731  return *this;
732  }
733 
736  {
737  append(str);
738  return *this;
739  }
740 
743  {
744  append(str);
745  return *this;
746  }
747 
750  {
751  append(digits);
752  return *this;
753  }
754 
755  void prepend(char character)
756  {
757  if (myLockCount) { UT_ASSERT(0); return; }
758  UT_ASSERT_P(isNullTerminated());
759  myLength++;
760  growBufferIfNeeded();
761  ::memmove(myBuffer+1, myBuffer, myLength);
762  myBuffer[0] = character;
763  }
764  void prepend(const char *data, exint size)
765  {
766  if (myLockCount) { UT_ASSERT(0); return; }
767  UT_ASSERT_P(data);
768  UT_ASSERT_P(isNullTerminated());
769  myLength += size;
770  growBufferIfNeeded();
771  ::memmove(myBuffer+size, myBuffer, myLength+1 - size);
772  ::memcpy(myBuffer, data, size);
773  }
775  void prepend(const char *str)
776  {
777  UT_ASSERT_P(str);
778  prepend(str, ::strlen(str));
779  }
780 
782  void prepend(const UT_String &str)
783  {
784  if (str.isstring())
785  prepend((const char *)str);
786  }
788  void prepend(const UT_StringRef &str)
789  {
790  if (str)
791  prepend(str.buffer(), str.length());
792  }
793 
794  /// Insert @c slen characters from @c str, at location @c pos. If @c pos
795  /// exceeds the current length, the position is truncated and to an append.
796  void insert(exint pos, const char* str, exint slen);
797 
798  /// Erase @c len characters from location @c pos in the string.
799  void erase(exint pos, exint len);
800 
801  void rewind() { backup(myLength); }
802 
803  /// Rewind by the given length
805  void backup(exint by_length)
806  {
807  if (myLockCount) { UT_ASSERT(0); return; }
808  UT_ASSERT_P(isNullTerminated());
809  UT_ASSERT_P(by_length >= 0);
810  myLength -= by_length;
811  UT_ASSERT(myLength >= 0);
812  myBuffer[myLength] = '\0';
813  }
814 
815  /// Truncate the buffer to the specified length. Truncating to 0 is
816  /// identical to clear().
818  void truncate(exint new_length)
819  {
820  if (new_length >= myLength)
821  {
822  UT_ASSERT(0 && "Truncating beyond buffer extent");
823  return;
824  }
825  backup(myLength-new_length);
826  }
827 
828  // Delete characters off the end of the string until we hit the
829  // requested character.
830  void backupTo(char c)
831  {
832  if (myLockCount) { UT_ASSERT(0); return; }
833  UT_ASSERT_P(isNullTerminated());
834  while( myLength > 0 && myBuffer[myLength-1] != c )
835  myLength--;
836  myBuffer[myLength] = '\0';
837  }
838 
839  void advance(exint by_length)
840  {
841  if (myLockCount) { UT_ASSERT(0); return; }
842  UT_ASSERT_P(isNullTerminated());
843  UT_ASSERT_P(by_length >= 0);
844  myLength -= by_length;
845  UT_ASSERT(myLength >= 0);
846  for (int i=0; i<myLength; i++)
847  myBuffer[i] = myBuffer[by_length+i];
848  myBuffer[myLength] = '\0';
849  }
850 
851  // Finds the 'occurance_number'-th occurance of char c in the string.
853  const char *findChar(char c, int occurance_number = 1) const
854  {
855  return findCharFrom(c, 0, occurance_number);
856  }
857  // Same as findChar, but searches from the end of the string.
858  const char *lastChar(char c, int occurance_number = 1) const
859  {
860  if (myLockCount) { UT_ASSERT(0); return NULL; }
861 
862  UT_ASSERT_P(isNullTerminated());
863 
864  for (exint i = myLength; i --> 0;)
865  {
866  if(c == myBuffer[i])
867  {
868  occurance_number--;
869  if(occurance_number <= 0)
870  {
871  return (myBuffer + i);
872  }
873  }
874  }
875 
876  return NULL;
877  }
878  // Same and findChar, bu searches from given position in the string.
879  const char *findCharFrom(char c, exint position,
880  int occurance_number = 1) const
881  {
882  if (myLockCount) { UT_ASSERT(0); return NULL; }
883 
884  UT_ASSERT_P(isNullTerminated());
885 
886  if (position < 0 || position >= myLength) { return NULL; }
887 
888  for(exint i = position; i < myLength; ++i)
889  {
890  if(c == myBuffer[i])
891  {
892  occurance_number--;
893  if(occurance_number <= 0)
894  {
895  return (myBuffer + i);
896  }
897  }
898  }
899 
900  return NULL;
901  }
902 
903  /// Adopt a string from an outside source. The passed string is now
904  /// owned by the workbuffer.
905  void adoptFromMalloc(char* data, exint length);
906 
907  void adoptFromCharArray(UT_Array<char>& data);
908 
909  /// Count the occurrences of the text in the current string
910  exint count(const char *needle) const;
911 
912  // Get the next token pointed at by string and advance string past the
913  // token. Returns whether or not a token was retrieved successfully.
914  // Note that string is modified!!!
915  bool getNextToken(const char *(&string),
916  const UT_String separators = " \t\n");
917 
918  // Harden the contents of the buffer into a UT_String.
919  void copyIntoString(UT_String &str) const;
920 
921  // Copy the contents into a fixed length buffer.
922  // TODO: Get rid of this method, since it encourages fixed-length buffers.
923  void copyIntoString(char *str, exint max_length) const;
924 
925  // Steal the contents of this work buffer into the string.
926  void stealIntoString(UT_String &str);
927 
928  // Steal the contents of this work buffer into the string.
929  // NB: Use UT_StringHolder move constructor/assignment instead
930  // UT_StringHolder foo(std::move(buffer));
931  // foo = std::move(buffer);
932  SYS_DEPRECATED(19.0)
933  void stealIntoStringHolder(UT_StringHolder &str);
934 
935  // Return a string containing the contents of this work buffer, preserving
936  // any null characters in it.
937  std::string toStdString() const
938  { return std::string(buffer(), length()); }
939 
940  // Strips the characters after comment_char from the buffer. This method
941  // goes to some effort to enusre that the comment_char is not preceded by
942  // a backslash or is not in a quoted string. Returns true if it found a
943  // comment and modified the buffer, and false otherwise.
944  bool stripComments(char comment_char = '#');
945 
946  /// Strips out all characters found in 'chars'. The string length will be
947  /// reduced by the number of characters removed. The number of characters
948  /// removed is returned.
949  int strip(const char *chars);
950 
951  /// Remove trailing whitespace lines
952  void removeTrailingSpaceLines();
953 
954  /// Remove trailing whitespace, return true if whitespace was removed.
955  bool removeTrailingSpace();
956 
957  /// Remove leading white space, return true if whitespace was removed.
958  bool removeLeadingSpace();
959 
960  /// Remove trailing digits, return true if some were removed.
961  bool removeTrailingDigits();
962 
963  /// Convert string to lower case
964  void lower();
965 
966  /// Convert string to upper case
967  void upper();
968 
969  /// Create a string of tabs & spaces which represents the given indent
970  void makeIndentString(exint indent, exint tabstop=8);
971 
972  /// Remove the first n characters.
974  {
975  if (n < myLength)
976  {
977  myLength -= n;
978  ::memmove(myBuffer, myBuffer + n, myLength);
979  }
980  else
981  myLength = 0;
982 
983  myBuffer[myLength] = '\0';
984  }
985 
986  /// Replaces up to 'count' occurrences of 'find' with 'replacement',
987  /// and returns the number of substitutions that occurred.
988  /// If 'count' <= 0, all occurrences will be replaced.
989  int substitute(const char *find, const char *replacement, int count = -1);
990 
991  /// Convenience version of substitute() for all or single occurrence.
992  SYS_DEPRECATED_REPLACE(19.5, "Use 'count' variant")
993  int substitute(const char *find, const char *replacement, bool all)
994  {
995  return substitute(find, replacement, !all ? 1 : -1);
996  }
997 
998  /// Given from_name which is assumed to fit from_pattern, any assigned
999  /// wildcards are subsitituted in to_pattern, writing the result to this.
1000  /// The wildcards may also be indexed. For example:
1001  ///
1002  /// to_pattern = b* from_name = apple from_pattern = a*le
1003  /// ---> this = bpp
1004  ///
1005  /// to_pattern = *(1)_to_*(0) from_name = a_to_b from_pattern = *_to_*
1006  /// ---> this = b_to_a
1007  bool subPatterns(
1008  const char *to_pattern,
1009  const char *from_name,
1010  const char *from_pattern);
1011 
1012  /// UTF-16 / UTF-8 conversions.
1013 
1014  /// Set the work buffer to contain the UTF-8 representation of the incoming UTF-16 string.
1015  /// The UTF-16 string is assumed to be little-endian, unless prefixed with BOM that
1016  /// indicates endianness.
1017  /// The incoming string should be zero-word terminated.
1018  void setFromUTF16(const utf16 *str);
1019 
1020  /// Set the work buffer to contain a UTF-16LE (little endian) representation of the
1021  /// incoming UTF-8 string.
1022  /// The work buffer will be zero-word terminated.
1023  void setAsUTF16(const utf8 *str);
1024 
1025  /// Once set as UTF16-LE, get it back as such a pointer.
1027  const utf16* castToUTF16() const { return (const utf16*) myBuffer; }
1028 
1029  /// Lock buffer for `len` utf-16 characters.
1031  {
1032  return (utf16*)lock(offset, len*sizeof(utf16));
1033  }
1034 
1035  void swap(UT_WorkBuffer &other)
1036  {
1037  // Warn if we're about to swap locked buffers.
1038  UT_ASSERT(myLockCount==0);
1039 
1040  bool this_stack = (myBuffer == myStackBuffer);
1041  bool other_stack = (other.myBuffer == other.myStackBuffer);
1042 
1043  if (this_stack && other_stack)
1044  {
1045  // If both buffers are using the stack buffer, just swap the
1046  // buffer contents.
1047  size_t max_size = (myLength > other.myLength) ? myLength
1048  : other.myLength;
1049 
1050  UTswap(myStackBuffer, other.myStackBuffer, max_size + 1);
1051  }
1052  else if (this_stack && !other_stack)
1053  {
1054  ::memcpy(other.myStackBuffer, myStackBuffer, myLength + 1);
1055  myBuffer = other.myBuffer;
1056  other.myBuffer = other.myStackBuffer;
1057  }
1058  else if (!this_stack && other_stack)
1059  {
1060  ::memcpy(myStackBuffer, other.myStackBuffer, other.myLength + 1);
1061  other.myBuffer = myBuffer;
1062  myBuffer = myStackBuffer;
1063  }
1064  else
1065  UTswap(myBuffer, other.myBuffer);
1066  UTswap(myAllocatedSize, other.myAllocatedSize);
1067  UTswap(myLength, other.myLength);
1068  UTswap(myLockCount, other.myLockCount);
1069  }
1070 public:
1071  /// Iterator compatibility.
1073  const char *begin() const { return myBuffer; }
1075  const char *end() const { return myBuffer + myLength; }
1076 
1077 private:
1078 
1079  struct do_widen {};
1080  struct do_narrow {};
1081  /// Private constructors to allow for the Return Value Optimization
1082  /// @{
1084  UT_WorkBuffer(do_widen, const utf8 *str)
1085  : UT_WorkBuffer()
1086  {
1087  setAsUTF16(str);
1088  }
1090  UT_WorkBuffer(do_narrow, const utf16 *str)
1091  : UT_WorkBuffer()
1092  {
1093  setFromUTF16(str);
1094  }
1095  /// @}
1096 
1097  template <typename ListT, bool ReportErrorsT = true>
1098  size_t appendFormatImpl(const char *fmt, ListT args);
1099 
1100  friend UT_API std::ostream &operator<<(std::ostream &os,
1101  const UT_WorkBuffer &buffer);
1102 
1103 private: // Data:
1104 
1105  char *myBuffer = myStackBuffer;
1106  exint myAllocatedSize = UT_INITIAL_BUFFER_SIZE;
1107  exint myLength = 0;
1108  int myLockCount = 0;
1109  char myStackBuffer[UT_INITIAL_BUFFER_SIZE];
1110 };
1111 
1112 /// Direct equality operators for UT_WorkBuffer <> UT_StringLit for speed to
1113 /// avoid casting down to const char*.
1114 /// @{
1115 static SYS_FORCE_INLINE bool
1116 operator==(const UT_WorkBuffer &buf, const UT_StringLit &lit)
1117 {
1118  return buf.operator==(lit.asRef());
1119 }
1120 static SYS_FORCE_INLINE bool
1121 operator==(const UT_StringLit &lit, const UT_WorkBuffer &buf)
1122 {
1123  return buf.operator==(lit.asRef());
1124 }
1125 static SYS_FORCE_INLINE bool
1126 operator!=(const UT_WorkBuffer &buf, const UT_StringLit &lit)
1127 {
1128  return buf.operator!=(lit.asRef());
1129 }
1130 static SYS_FORCE_INLINE bool
1131 operator!=(const UT_StringLit &lit, const UT_WorkBuffer &buf)
1132 {
1133  return buf.operator!=(lit.asRef());
1134 }
1135 /// @}
1136 
1137 static inline size_t
1138 format(char *buffer, size_t buffer_size, const UT_WorkBuffer &v)
1139 {
1140  if (!buffer)
1141  return v.length();
1142  else
1143  {
1144  size_t len = std::min(size_t(v.length()), buffer_size);
1145  ::memcpy(buffer, v.buffer(), len);
1146  return len;
1147  }
1148 }
1149 
1150 #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:402
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)
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
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
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:3436
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:1262
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:39
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
Definition: core.h:760
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:447
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 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:357
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:395
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:609
auto vsprintf(const S &fmt, basic_format_args< basic_printf_context_t< type_identity_t< Char >>> args) -> std::basic_string< Char >
Definition: printf.h:554
Definition: core.h:982
bool isstring() const
Definition: UT_String.h:691
#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:574
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:895
Definition: format.h:2459
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
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2089
GLenum src
Definition: glcorearb.h:1793
SYS_FORCE_INLINE UT_WorkBuffer()
Definition: UT_WorkBuffer.h:80