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 
26 #ifndef __UT_WorkBuffer_h__
27 #define __UT_WorkBuffer_h__
28 
29 #include "UT_API.h"
30 
31 #include "UT_Assert.h"
32 #include "UT_Defines.h"
33 #include "UT_Format.h"
34 #include "UT_NonCopyable.h"
35 #include "UT_String.h"
36 #include "UT_StringArray.h"
37 #include "UT_StringHolder.h"
38 #include "UT_Swap.h"
39 #include "UT_Unicode.h"
40 
41 #include <SYS/SYS_Inline.h>
42 #include <SYS/SYS_Types.h>
43 
44 #include <iosfwd>
45 
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49 
50 
51 // The default page size on most systems is 4K. We choose a default
52 // buffer size less than half of that in the hopes that if we have
53 // functions with 2 work buffers or additional variables on the stack that we
54 // may not have to allocate multiple stack pages.
55 #define UT_INITIAL_BUFFER_SIZE 2000
56 
57 class UT_WorkArgs;
58 class UT_IStream;
59 
61 {
62 public:
63  typedef char value_type;
64 
67  : myBuffer(myStackBuffer)
68  {
69  // Default termination.
70  myBuffer[0] = '\0';
71  }
72 
74  explicit UT_WorkBuffer(const char *str)
75  : myBuffer(myStackBuffer)
76  {
77  myBuffer[0] = '\0';
78  append(str);
79  }
80 
82  explicit UT_WorkBuffer(const char *data, exint size)
83  : myBuffer(myStackBuffer)
84  {
85  myBuffer[0] = '\0';
86  append(data, size);
87  }
88 
90  explicit UT_WorkBuffer(const UT_String &str)
91  : myBuffer(myStackBuffer)
92  {
93  myBuffer[0] = '\0';
94  append(str);
95  }
96 
98  explicit UT_WorkBuffer(const UT_StringRef &str)
99  : myBuffer(myStackBuffer)
100  {
101  myBuffer[0] = '\0';
102  append(str);
103  }
104 
107  : myBuffer(myStackBuffer)
108  {
109  myBuffer[0] = '\0';
110  append(other);
111  }
112 
115  {
116  if (myBuffer != myStackBuffer)
117  {
118  UT_ASSERT(myBuffer);
119  ::free(myBuffer);
120  }
121  }
122 
123  /// Create a work buffer to contain a UTF-16LE (little endian)
124  /// representation of the incoming UTF-8 string.
125  /// The work buffer will be zero-word terminated.
127  static UT_WorkBuffer
128  widen(const utf8 *str)
129  {
130  return UT_WorkBuffer(do_widen(), str);
131  }
132 
133  /// Create a work buffer to contain the UTF-8 representation of the
134  /// incoming UTF-16 string. The UTF-16 string is assumed to be
135  /// little-endian, unless prefixed with BOM that indicates endianness.
136  /// The incoming string should be zero-word terminated.
138  static UT_WorkBuffer
139  narrow(const utf16 *str)
140  {
141  return UT_WorkBuffer(do_narrow(), str);
142  }
143 
144  // It's important that there is no non-const access method to the buffer.
145  // Also note that the pointer to the buffer can change if the buffer
146  // grows.
148  const char *buffer() const { return myBuffer; }
149 
150  // Having said that, if you need a non-const pointer you must lock
151  // the string. This prohibits ANY update which changes the myLength
152  // variable (and thus potentially a realloc)
153  // You must release the buffer before any such changes.
154  // The work buffer continues to own the memory and will free it when
155  // it goes out of scope so don't think this is the same as a "steal"
156  // in UT_String.
157  // Currently, to ensure people couple their locks & releases,
158  // it asserts there is no unaccounted locks on death. This is so
159  // people who think it is steal find out otherwise.
160  // Offset is where in the string to get the pointer from.
161  // This is only to be used when absolutely necessary.
162  // When releasing, if you have a string buffer, and you have modified the
163  // length, you should set the recomputeLength flag to 1. This will adjust
164  // the internal length variable so that further concatenations will work
165  // properly.
166  // The reserve_bytes parameter tells the lock to ensure that there are at
167  // least that many bytes in the locked buffer.
168  // NOTE: Unlike other UT_WorkBuffer functions, it is the user's
169  // responsibility to maintain a NUL termination guarantee when manipulating
170  // the raw buffer.
171  char *lock(exint offset = 0, exint reserve_bytes=0);
172  void release(int recomputeLength=0);
173  void releaseSetLength(exint new_length);
174 
176  exint getAllocatedSize() const { return myAllocatedSize; }
177 
178  /// Class to handle auto-locking of the UT_WorkBuffer. This is not related
179  /// to multi-threading, but to the lock/release methods above.
180  ///
181  /// You should never append data to a locked buffer.
182  class AutoLock
183  {
184  public:
187  : myBuffer(buf)
188  {
189  myString = myBuffer.lock();
190  }
193  {
194  release();
195  }
196  /// @{
197  /// Get access to the non-const buffer. This may return nullptr if the
198  /// lock has been released.
200  char *operator*() const { return myString; }
202  char *string() const { return myString; }
203  /// @}
204 
205  /// You can manually release the buffer
207  void release(bool recompute_length=false)
208  {
209  if (myString)
210  {
211  myBuffer.release(recompute_length);
212  myString = nullptr;
213  }
214  }
215  /// If you've manually released the lock, you can relock the buffer
217  void relock()
218  {
219  UT_ASSERT(!myString);
220  myString = myBuffer.lock();
221  }
222  private:
223  UT_WorkBuffer &myBuffer;
224  char *myString;
225  };
226 
227  void reserve(exint bytes=0);
228 
229  // This is a read only operator. We are avoiding the writeable
230  // versions as they lead to problems when people do a:
231  // foo[pastend] = foo(start)
232  // causing an implicit realloc.
234  char operator()(exint idx) const
235  {
236  // We allow an index at myLength as if we have a null
237  // terminated buffer that is the null termination.
238  UT_ASSERT_P(idx >= 0 && idx <= myLength);
239  return myBuffer[idx];
240  }
241 
242  // Returns last character. Only valid if !isEmpty()
244  char first() const
245  {
246  UT_ASSERT_P(myLength > 0);
247  return myBuffer[0];
248  }
249  // Returns last character. Only valid if !isEmpty()
251  char last() const
252  {
253  UT_ASSERT_P(myLength > 0);
254  return myBuffer[myLength - 1];
255  }
256 
257  // This should always be true. It's here to act as a sanity function.
258  int isNullTerminated() const;
259 
262  {
263  strcpy(other);
264  return *this;
265  }
267  UT_WorkBuffer &operator=(const char *str)
268  {
269  clear();
270  append(str);
271  return *this;
272  }
275  {
276  clear();
277  append(str.c_str(), str.length());
278  return *this;
279  }
280 
281  /// Comparison operator. Null strings are considered as empty strings.
282  /// @{
284  bool operator==(const char *str) const
285  {
286  if (!str)
287  return isEmpty();
288  return (::strcmp(str, myBuffer) == 0);
289  }
291  bool operator==(const UT_String &str) const
292  {
293  if (!(const char *)str)
294  return isEmpty();
295  return (::strcmp(str, myBuffer) == 0);
296  }
298  bool operator==(const UT_WorkBuffer &buf) const
299  {
300  if (buf.isEmpty())
301  return isEmpty();
302  if (length() != buf.length())
303  return false;
304  return (::memcmp(myBuffer, buf.myBuffer, myLength) == 0);
305  }
307  bool operator!=(const char *str) const
308  {
309  return !(*this == str);
310  }
312  bool operator!=(const UT_String &str) const
313  {
314  return !(*this == str);
315  }
317  bool operator!=(const UT_WorkBuffer &buf) const
318  {
319  return !(*this == buf);
320  }
321  /// @}
322 
323 private:
324  // Reallocate the buffer until the allocated size is >= the length. This
325  // private method needs to come first so it can be inlined.
326  void growBufferIfNeeded()
327  {
328  // Using a while loop instead of computing an accurate size the
329  // first time is slower, but most of the time the loop will execute
330  // at most once.
331  // We need to use myLength+1 as we need room for the null.
332  while (myLength+1 > myAllocatedSize) // false most of the time
333  reserve(myAllocatedSize * 2);
334  }
335 
336 public:
337  // These are standard string operators people tend to use:
339  void strcpy(const char *src)
340  {
341  clear();
342  append(src);
343  }
345  void strcpy(const UT_String &src)
346  {
347  clear();
348  append(src);
349  }
351  void strcpy(const UT_StringRef &src)
352  {
353  clear();
354  append(src);
355  }
357  void strcpy(const UT_WorkBuffer &src)
358  {
359  clear();
360  append(src);
361  }
362 
363  // NOTE: unlike strncpy(), maxlen does not include the null terminator.
365  void strncpy(const char *src, exint maxlen)
366  {
367  clear();
368  // Ensure we have enough room:
369  myLength = maxlen+1;
370  growBufferIfNeeded();
371  myLength = 0;
372  SYSstrlcpy(myBuffer, src, maxlen+1);
373  myLength = ::strlen(myBuffer);
374  }
375 
376  // Note we can't just return myLength as there may be embedded NULLs.
378  exint strlen() const
379  {
380  UT_ASSERT_P(isNullTerminated());
381  return ::strlen(myBuffer);
382  }
383 
385  exint length() const
386  {
387  return myLength;
388  }
389 
391  void strcat(const char *src)
392  {
393  append(src);
394  }
395 
396  // protectedStrcat() will quote the string in double quotes if required and
397  // protect any enclosed double quotes or backslashes in the source. It
398  // will not escape any other characters.
399  void protectedStrcat(const char *str, bool force_quote=false);
400 
401  // fullyProtected*Strcat() is similar to protectedStrcat, except it escapes
402  // any non-printable characters. It will not escape single quotes, and if
403  // force_quote is true, it will add double-quotes. It will work with
404  // arbitrary binary data and uses the \xNN syntax to encode bytes.
405  // UT_IStream::read() is capable of loading strings encoded with this
406  // method, and these strings can also be decoded in Python. If
407  // fullyProtectedBinaryStrcat is called, this method can handle data
408  // containing null characters.
409  void fullyProtectedStrcat(const char *str, bool force_quote=false);
410  void fullyProtectedBinaryStrcat(
411  const char *str, exint size, bool force_quote=false);
412 
413  /// Append a string of a given maximum length to the current string.
414  /// Unlike the POSIX's strncat(3), we ignore any NUL bytes in the current
415  /// string and blindly append at the end of the work buffer.
417  void strncat(const char *src, exint len)
418  {
419  if (!src)
420  return;
421  append(src, ::strnlen(src, len));
422  }
423 
424  // Extract the first argument from the src and append it to the work
425  // buffer. This does NOT handle quotes properly (i.e. if the first word
426  // is quoted with spaces).
427  void strcatFirstWord(const char *src);
428 
430  int strcmp(const char *src) const
431  {
432  UT_ASSERT_P(isNullTerminated());
433  return ::strcmp(myBuffer, src);
434  }
435 
437  int strncmp(const char *src, exint n) const
438  {
439  UT_ASSERT_P(isNullTerminated());
440  return ::strncmp(myBuffer, src, n);
441  }
442 
444  char *strdup() const
445  {
446  UT_ASSERT(isNullTerminated());
447  return ::strdup(myBuffer);
448  }
449 
450  // Reset the buffer to an empty buffer.
452  void clear()
453  {
454  if (myLockCount) { UT_ASSERT(0); return; }
455  myLength = 0;
456  myBuffer[0] = '\0';
457  }
458 
460  bool isEmpty() const
461  {
462  return (myLength == 0);
463  }
465  bool isstring() const
466  {
467  return !isEmpty();
468  }
469 
470  // Write into the buffer at a specific place.
471  // This WILL expand the buffer if it is required and keep it null
472  // terminated.
474  void write(exint offset, char c)
475  {
476  UT_ASSERT(offset >= 0);
477  if (offset < 0) return;
478  if (offset >= myLength)
479  {
480  if (myLockCount) { UT_ASSERT(0); return; }
481  myLength = offset+1;
482  growBufferIfNeeded();
483  myBuffer[myLength] = '\0';
484  }
485  myBuffer[offset] = c;
486  if (c == '\0')
487  myLength = offset;
488  }
489 
490  // This does NOT write out the trailing NULL of src, but the buffer will
491  // still be null-terminated.
492  void write(exint offset, const char *src)
493  {
494  while (*src)
495  {
496  write(offset, *src);
497  src++;
498  offset++;
499  }
500  }
501 
503  {
504  write(offset, src.c_str());
505  }
506 
507  /// Load an entire file into the buffer. Returns @b false if there was an
508  /// error reading the file
509  bool readFile(const char *filename);
510 
511  // Read a line from an istream -- no matter how long the line is
512  // Returns 0 if the stream read failed or 1 otherwise
513  bool getline(std::istream &is);
514  bool getline(FILE *fp);
515 
516  // Much like getline() except that it has more features. The string itself
517  // is tokenized which the UT_WorkArgs points into.
518  // line_num is incremented for each line read.
519  // comment_chars is list of characters to treat as comments.
520  // this can be NULL if we don't want this feature.
521  // Returns false if the stream read failed.
522  bool cmdGetLine(std::istream &is, UT_WorkArgs &args, int &line_num,
523  const char *comment_chars = "#",
524  const char *separators = " \t\n\r");
525  bool cmdGetLine(UT_IStream &is, UT_WorkArgs &args, int &line_num,
526  const char *comment_chars = "#",
527  const char *separators = " \t\n\r");
528  bool cmdGetLine(FILE *fp, UT_WorkArgs &args, int &line_num,
529  const char *comment_chars = "#",
530  const char *separators = " \t\n\r");
531 
532  int sprintf(const char *fmt, ...)
534  int appendSprintf(const char *fmt, ...)
536 
537  int vsprintf(const char *fmt, va_list ap);
538 
539  /// Replace the contents of the work buffer using the same formatting as
540  /// UTformat.
541  /// Returns the size of the appended portion, in bytes.
542  template<typename... Args>
543  size_t format(const char *fmt, const Args &...args)
544  {
545  clear();
546  return appendFormat(fmt, args...);
547  }
548 
549  /// Append to the work buffer using the same formatting as UTformat.
550  /// Returns the size of the appended portion, in bytes.
551  template<typename... Args>
552  size_t appendFormat(const char *fmt, const Args &...args)
553  {
554  if (myLockCount) { UT_ASSERT(0); return 0; }
555  UT_ASSERT_P(isNullTerminated());
556 
557  using namespace UT::Format;
558  Writer w;
560  size_t nb_needed = f.format(w, fmt, {args...});
561 
562  myLength += nb_needed;
563  growBufferIfNeeded();
564 
565  // Format again, this time to fill in the buffer.
566  w.setBuffer(myBuffer + myLength - nb_needed, nb_needed);
567  f.format(w, fmt, {args...});
568 
569  myBuffer[myLength] = '\0';
570  return nb_needed;
571  }
572 
573  /// Replace the contents of the work buffer using UTformat formatting
574  /// with an implicit "{} " for each argument, giving a Python-style
575  /// print result.
576  template<typename... Args>
577  size_t print(const Args &...args)
578  {
579  clear();
580  return appendPrint(args...);
581  }
582 
583  /// Append to the work buffer using the UTformat with an implicit "{} "
584  /// format for each parameter.
585  /// Returns the size of the appended portion, in bytes.
586  template<typename... Args>
587  size_t appendPrint()
588  {
589  return 0;
590  }
591  template<typename T, typename... Args>
592  size_t appendPrint(const T &value, const Args &...args)
593  {
594  size_t newbytes;
595  newbytes = appendFormat("{} ", value);
596  newbytes += appendPrint(args...);
597  return newbytes;
598  }
599 
600  // These tack stuff to the end of the buffer.
602  void append(char character)
603  {
604  if (myLockCount) { UT_ASSERT(0); return; }
605  UT_ASSERT_P(isNullTerminated());
606  myLength++;
607  growBufferIfNeeded();
608  myBuffer[myLength - 1] = character;
609  myBuffer[myLength] = '\0';
610  }
611 
612  void printMemory(int64 mem) { clear(); appendPrintMemory(mem); }
613  void appendPrintMemory(int64 mem);
614 
615  void append(exint n, char character)
616  {
617  if (myLockCount) { UT_ASSERT(0); return; }
618  UT_ASSERT_P(isNullTerminated());
619  myLength += n;
620  growBufferIfNeeded();
621  for (int i = n; i > 0; i--)
622  myBuffer[myLength - i] = character;
623  myBuffer[myLength] = '\0';
624  }
625 
626  /// Append a single Unicode code point, converted to UTF8
627  void append(utf32 cp)
628  {
630  int len = UT_Unicode::convert(cp, buf, sizeof(buf));
631  if (!len)
632  return;
633 
634  if (myLockCount) { UT_ASSERT(0); return; }
635  UT_ASSERT_P(isNullTerminated());
636  myLength += len;
637  growBufferIfNeeded();
638  ::memcpy(myBuffer + myLength - len, buf, len);
639  myBuffer[myLength] = '\0';
640  }
641 
642  void append(const char *data, exint size)
643  {
644  if (myLockCount) { UT_ASSERT(0); return; }
645  UT_ASSERT_P(data);
646  UT_ASSERT_P(isNullTerminated());
647  myLength += size;
648  growBufferIfNeeded();
649  ::memcpy(myBuffer + myLength - size, data, size);
650  myBuffer[myLength] = '\0';
651  }
652 
654  void append(const char *str)
655  {
656  if( UTisstring(str) )
657  append(str, ::strlen(str));
658  }
659 
661  void append(const UT_String &str)
662  {
663  if (str.isstring())
664  append((const char *)str);
665  }
666 
668  void append(const UT_StringRef &str)
669  {
670  if (str.isstring())
671  append(str.buffer(), str.length());
672  }
673 
674  void append(const UT_StringArray &strs, const UT_StringRef &sep)
675  {
676  for (exint i = 0; i < strs.entries(); i++)
677  {
678  append(strs(i));
679  if (i+1 < strs.entries())
680  append(sep);
681  }
682  }
683 
685  void append(const UT_WorkBuffer &wb)
686  {
687  append( wb.buffer(), wb.length() );
688  }
689 
691  UT_WorkBuffer &operator+=(const char *str)
692  {
693  append(str);
694  return *this;
695  }
696 
699  {
700  append(str);
701  return *this;
702  }
703 
706  {
707  append(wb);
708  return *this;
709  }
710 
713  {
714  append(str);
715  return *this;
716  }
717 
720  {
721  append(str);
722  return *this;
723  }
724 
725  void prepend(char character)
726  {
727  if (myLockCount) { UT_ASSERT(0); return; }
728  UT_ASSERT_P(isNullTerminated());
729  myLength++;
730  growBufferIfNeeded();
731  ::memmove(myBuffer+1, myBuffer, myLength);
732  myBuffer[0] = character;
733  }
734  void prepend(const char *data, exint size)
735  {
736  if (myLockCount) { UT_ASSERT(0); return; }
737  UT_ASSERT_P(data);
738  UT_ASSERT_P(isNullTerminated());
739  myLength += size;
740  growBufferIfNeeded();
741  ::memmove(myBuffer+size, myBuffer, myLength+1 - size);
742  ::memcpy(myBuffer, data, size);
743  }
745  void prepend(const char *str)
746  {
747  UT_ASSERT_P(str);
748  prepend(str, ::strlen(str));
749  }
750 
752  void prepend(const UT_String &str)
753  {
754  if (str.isstring())
755  prepend((const char *)str);
756  }
757 
758  /// Insert @c slen characters from @c str, at location @c pos. If @c pos
759  /// exceeds the current length, the position is truncated and to an append.
760  void insert(exint pos, const char* str, exint slen);
761 
762  /// Erase @c len characters from location @c pos in the string.
763  void erase(exint pos, exint len);
764 
765  void rewind() { backup(myLength); }
766 
767  /// Rewind by the given length
769  void backup(exint by_length)
770  {
771  if (myLockCount) { UT_ASSERT(0); return; }
772  UT_ASSERT_P(isNullTerminated());
773  UT_ASSERT_P(by_length >= 0);
774  myLength -= by_length;
775  UT_ASSERT(myLength >= 0);
776  myBuffer[myLength] = '\0';
777  }
778 
779  /// Truncate the buffer to the specified length. Truncating to 0 is
780  /// identical to clear().
782  void truncate(exint new_length)
783  {
784  if (new_length >= myLength)
785  {
786  UT_ASSERT(0 && "Truncating beyond buffer extent");
787  return;
788  }
789  backup(myLength-new_length);
790  }
791 
792  // Delete characters off the end of the string until we hit the
793  // requested character.
794  void backupTo(char c)
795  {
796  if (myLockCount) { UT_ASSERT(0); return; }
797  UT_ASSERT_P(isNullTerminated());
798  while( myLength > 0 && myBuffer[myLength-1] != c )
799  myLength--;
800  myBuffer[myLength] = '\0';
801  }
802 
803  void advance(exint by_length)
804  {
805  if (myLockCount) { UT_ASSERT(0); return; }
806  UT_ASSERT_P(isNullTerminated());
807  UT_ASSERT_P(by_length >= 0);
808  myLength -= by_length;
809  UT_ASSERT(myLength >= 0);
810  for (int i=0; i<myLength; i++)
811  myBuffer[i] = myBuffer[by_length+i];
812  myBuffer[myLength] = '\0';
813  }
814 
815  // Finds the 'occurance_number'-th occurance of char c in the string.
817  const char *findChar(char c, int occurance_number = 1) const
818  {
819  return findCharFrom(c, 0, occurance_number);
820  }
821  // Same as findChar, but searches from the end of the string.
822  const char *lastChar(char c, int occurance_number = 1) const
823  {
824  if (myLockCount) { UT_ASSERT(0); return NULL; }
825 
826  UT_ASSERT_P(isNullTerminated());
827 
828  for (exint i = myLength; i --> 0;)
829  {
830  if(c == myBuffer[i])
831  {
832  occurance_number--;
833  if(occurance_number <= 0)
834  {
835  return (myBuffer + i);
836  }
837  }
838  }
839 
840  return NULL;
841  }
842  // Same and findChar, bu searches from given position in the string.
843  const char *findCharFrom(char c, exint position,
844  int occurance_number = 1) const
845  {
846  if (myLockCount) { UT_ASSERT(0); return NULL; }
847 
848  UT_ASSERT_P(isNullTerminated());
849 
850  if (position < 0 || position >= myLength) { return NULL; }
851 
852  for(exint i = position; i < myLength; ++i)
853  {
854  if(c == myBuffer[i])
855  {
856  occurance_number--;
857  if(occurance_number <= 0)
858  {
859  return (myBuffer + i);
860  }
861  }
862  }
863 
864  return NULL;
865  }
866 
867  /// Count the occurrences of the text in the current string
868  exint count(const char *needle) const;
869 
870  // Get the next token pointed at by string and advance string past the
871  // token. Returns whether or not a token was retrieved successfully.
872  // Note that string is modified!!!
873  bool getNextToken(const char *(&string),
874  const UT_String separators = " \t\n");
875 
876  // Harden the contents of the buffer into a UT_String.
877  void copyIntoString(UT_String &str) const;
878 
879  // Copy the contents into a fixed length buffer.
880  // TODO: Get rid of this method, since it encourages fixed-length buffers.
881  void copyIntoString(char *str, exint max_length) const;
882 
883  // Steal the contents of this work buffer into the string.
884  void stealIntoString(UT_String &str);
885 
886  // Steal the contents of this work buffer into the string.
887  void stealIntoStringHolder(UT_StringHolder &str);
888 
889  // Return a string containing the contents of this work buffer, preserving
890  // any null characters in it.
892  { return std::string(buffer(), length()); }
893 
894  // Strips the characters after comment_char from the buffer. This method
895  // goes to some effort to enusre that the comment_char is not preceded by
896  // a backslash or is not in a quoted string. Returns true if it found a
897  // comment and modified the buffer, and false otherwise.
898  bool stripComments(char comment_char = '#');
899 
900  /// Strips out all characters found in 'chars'. The string length will be
901  /// reduced by the number of characters removed. The number of characters
902  /// removed is returned.
903  int strip(const char *chars);
904 
905  /// Remove trailing whitespace lines
906  void removeTrailingSpaceLines();
907 
908  /// Remove trailing whitespace, return true if whitespace was removed.
909  bool removeTrailingSpace();
910 
911  /// Remove leading white space, return true if whitespace was removed.
912  bool removeLeadingSpace();
913 
914  /// Remove trailing digits, return true if some were removed.
915  bool removeTrailingDigits();
916 
917  /// Convert string to lower case
918  void lower();
919 
920  /// Convert string to upper case
921  void upper();
922 
923  /// Create a string of tabs & spaces which represents the given indent
924  void makeIndentString(exint indent, exint tabstop=8);
925 
926  /// Remove the first n characters.
928  {
929  if (n < myLength)
930  {
931  myLength -= n;
932  ::memmove(myBuffer, myBuffer + n, myLength);
933  }
934  else
935  myLength = 0;
936 
937  myBuffer[myLength] = '\0';
938  }
939 
940  /// Replace all occurances of 'find' with 'replacement'
941  void substitute(const char *find, const char *replacement,
942  bool all = true);
943 
944  /// Given from_name which is assumed to fit from_pattern, any assigned
945  /// wildcards are subsitituted in to_pattern, writing the result to this.
946  /// The wildcards may also be indexed. For example:
947  ///
948  /// to_pattern = b* from_name = apple from_pattern = a*le
949  /// ---> this = bpp
950  ///
951  /// to_pattern = *(1)_to_*(0) from_name = a_to_b from_pattern = *_to_*
952  /// ---> this = b_to_a
953  bool subPatterns(
954  const char *to_pattern,
955  const char *from_name,
956  const char *from_pattern);
957 
958  /// UTF-16 / UTF-8 conversions.
959 
960  /// Set the work buffer to contain the UTF-8 representation of the incoming UTF-16 string.
961  /// The UTF-16 string is assumed to be little-endian, unless prefixed with BOM that
962  /// indicates endianness.
963  /// The incoming string should be zero-word terminated.
964  void setFromUTF16(const utf16 *str);
965 
966  /// Set the work buffer to contain a UTF-16LE (little endian) representation of the
967  /// incoming UTF-8 string.
968  /// The work buffer will be zero-word terminated.
969  void setAsUTF16(const utf8 *str);
970 
971 
972  void swap(UT_WorkBuffer &other)
973  {
974  // Warn if we're about to swap locked buffers.
975  UT_ASSERT(myLockCount==0);
976 
977  bool this_stack = (myBuffer == myStackBuffer);
978  bool other_stack = (other.myBuffer == other.myStackBuffer);
979 
980  if (this_stack && other_stack)
981  {
982  // If both buffers are using the stack buffer, just swap the
983  // buffer contents.
984  size_t max_size = (myLength > other.myLength) ? myLength
985  : other.myLength;
986 
987  UTswap(myStackBuffer, other.myStackBuffer, max_size + 1);
988  }
989  else if (this_stack && !other_stack)
990  {
991  ::memcpy(other.myStackBuffer, myStackBuffer, myLength + 1);
992  myBuffer = other.myBuffer;
993  other.myBuffer = other.myStackBuffer;
994  }
995  else if (!this_stack && other_stack)
996  {
997  ::memcpy(myStackBuffer, other.myStackBuffer, other.myLength + 1);
998  other.myBuffer = myBuffer;
999  myBuffer = myStackBuffer;
1000  }
1001  else
1002  UTswap(myBuffer, other.myBuffer);
1003  UTswap(myAllocatedSize, other.myAllocatedSize);
1004  UTswap(myLength, other.myLength);
1005  UTswap(myLockCount, other.myLockCount);
1006  }
1007 
1008 public:
1009  /// Iterator compatibility.
1011  const char *begin() const { return myBuffer; }
1013  const char *end() const { return myBuffer + myLength; }
1014 
1015 private:
1016 
1017  struct do_widen {};
1018  struct do_narrow {};
1019  /// Private constructors to allow for the Return Value Optimization
1020  /// @{
1022  UT_WorkBuffer(do_widen, const utf8 *str)
1023  : myBuffer(myStackBuffer)
1024  , myAllocatedSize(UT_INITIAL_BUFFER_SIZE)
1025  , myLength(0)
1026  , myLockCount(0)
1027  {
1028  setAsUTF16(str);
1029  }
1031  UT_WorkBuffer(do_narrow, const utf16 *str)
1032  : myBuffer(myStackBuffer)
1033  , myAllocatedSize(UT_INITIAL_BUFFER_SIZE)
1034  , myLength(0)
1035  , myLockCount(0)
1036  {
1037  setFromUTF16(str);
1038  }
1039  /// @}
1040 
1041  friend UT_API std::ostream &operator<<(std::ostream &os,
1042  const UT_WorkBuffer &buffer);
1043 
1044 private: // Data:
1045 
1046  char *myBuffer; // Do not make an access method to the data
1047  exint myAllocatedSize = UT_INITIAL_BUFFER_SIZE;
1048  exint myLength = 0;
1049  int myLockCount = 0;
1050  char myStackBuffer[UT_INITIAL_BUFFER_SIZE];
1051 };
1052 
1053 
1054 static inline size_t
1055 format(char *buffer, size_t buffer_size, const UT_WorkBuffer &v)
1056 {
1057  if (!buffer)
1058  return v.length();
1059  else
1060  {
1061  size_t len = std::min(size_t(v.length()), buffer_size);
1062  ::memcpy(buffer, v.buffer(), len);
1063  return len;
1064  }
1065 }
1066 
1067 
1068 #endif
size_t print(const Args &...args)
vbool4 insert(const vbool4 &a, bool val)
Helper: substitute val for a[i].
Definition: simd.h:3340
std::string sprintf(const char *fmt, const Args &...args)
Definition: strutil.h:136
SYS_FORCE_INLINE void append(const UT_StringRef &str)
string_view OIIO_API strip(string_view str, string_view chars=string_view())
GT_API const UT_StringHolder filename
GLsizeiptr size
Definition: glew.h:1681
GLenum src
Definition: glew.h:2410
SYS_FORCE_INLINE exint length() const
char utf8
Definition: SYS_Types.h:51
unsigned int utf32
Definition: SYS_Types.h:53
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
const Args & args
Definition: printf.h:628
SYS_FORCE_INLINE bool operator==(const UT_String &str) const
SYS_FORCE_INLINE UT_WorkBuffer(const char *data, exint size)
Definition: UT_WorkBuffer.h:82
SYS_FORCE_INLINE void strncat(const char *src, exint len)
SYS_FORCE_INLINE UT_WorkBuffer(const UT_StringRef &str)
Definition: UT_WorkBuffer.h:98
SYS_FORCE_INLINE UT_WorkBuffer(const char *str)
Definition: UT_WorkBuffer.h:74
void append(exint n, char character)
SYS_FORCE_INLINE const char * buffer() const
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:13
const GLdouble * v
Definition: glew.h:1391
const char * findCharFrom(char c, exint position, int occurance_number=1) const
void append(const char *data, exint size)
const char * lastChar(char c, int occurance_number=1) const
size_t appendPrint()
SYS_FORCE_INLINE char last() const
SYS_FORCE_INLINE void relock()
If you've manually released the lock, you can relock the buffer.
SYS_FORCE_INLINE void append(const UT_String &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
std::ostream & operator<<(std::ostream &ostr, const DataType &a)
Definition: DataType.h:133
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const UT_WorkBuffer &wb)
long long int64
Definition: SYS_Types.h:111
SYS_FORCE_INLINE void append(const char *str)
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:55
SYS_FORCE_INLINE void strcpy(const UT_WorkBuffer &src)
GLclampf f
Definition: glew.h:3499
exint length() const
SYS_FORCE_INLINE const char * buffer() const
std::enable_if< is_contiguous< Container >::value, typename checked< typename Container::value_type >::type >::type reserve(std::back_insert_iterator< Container > &it, std::size_t n)
Definition: format.h:593
SYS_FORCE_INLINE const char * end() const
int64 exint
Definition: SYS_Types.h:120
GLuint buffer
Definition: glew.h:1680
GLint GLenum GLsizei GLint GLsizei const void * data
Definition: glew.h:1379
SYS_FORCE_INLINE UT_WorkBuffer & operator=(const UT_WorkBuffer &other)
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:134
void printMemory(int64 mem)
#define SYS_PRINTF_CHECK_ATTRIBUTE(string_index, first_to_check)
Definition: SYS_Types.h:432
SYS_FORCE_INLINE const char * begin() const
Iterator compatibility.
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1890
GLsizei n
Definition: glew.h:4040
const GLfloat * c
Definition: glew.h:16296
GLuint GLsizei GLsizei * length
Definition: glew.h:1825
void prepend(char character)
SYS_FORCE_INLINE bool isEmpty() const
SYS_FORCE_INLINE char * strdup() const
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:18
size_t SYSstrlcpy(char *dest, const char *src, size_t size)
Definition: SYS_String.h:187
std::string toStdString() const
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)
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:453
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)
SYS_FORCE_INLINE UT_WorkBuffer & operator=(const char *str)
GLsizei const GLchar *const * string
Definition: glew.h:1844
std::basic_string< Char > vsprintf(const S &format, basic_format_args< typename basic_printf_context_t< internal::basic_buffer< Char >>::type > args)
Definition: printf.h:609
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)
Definition: UT_WorkBuffer.h:90
SYS_FORCE_INLINE AutoLock(UT_WorkBuffer &buf)
void backupTo(char c)
size_t appendPrint(const T &value, const Args &...args)
SYS_FORCE_INLINE bool operator==(const char *str) const
SYS_FORCE_INLINE bool UTisstring(const char *s)
Definition: UT_String.h:57
void advance(exint by_length)
SYS_FORCE_INLINE bool operator!=(const char *str) const
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: glew.h:1254
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const char *str)
FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr &out)
Definition: format.h:2104
SYS_FORCE_INLINE void append(char character)
GLuint GLuint GLsizei count
Definition: glew.h:1253
Type-safe formatting, modeled on the Python str.format function.
void prepend(const char *data, exint size)
unsigned short utf16
Definition: SYS_Types.h:52
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.
void append(const UT_StringArray &strs, const UT_StringRef &sep)
bool isstring() const
Definition: UT_String.h:705
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:135
SYS_FORCE_INLINE ~UT_WorkBuffer()
SYS_FORCE_INLINE void clear()
SYS_FORCE_INLINE ~AutoLock()
#define const
Definition: zconf.h:214
SYS_FORCE_INLINE char first() const
vint4 min(const vint4 &a, const vint4 &b)
Definition: simd.h:4694
void write(T &out, bool v)
Definition: ImfXdr.h:332
GLenum GLuint GLsizei const GLchar * buf
Definition: glew.h:2580
SYS_FORCE_INLINE bool operator!=(const UT_String &str) const
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const UT_StringRef &str)
bool all(const vbool4 &v)
Definition: simd.h:3371
SYS_FORCE_INLINE UT_WorkBuffer & operator+=(const std::string &str)
GLsizei const GLfloat * value
Definition: glew.h:1849
SYS_FORCE_INLINE void write(exint offset, char c)
SYS_FORCE_INLINE bool isstring() const
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 GLsizei len
Definition: glew.h:7752
GLintptr offset
Definition: glew.h:1682
SYS_FORCE_INLINE UT_WorkBuffer()
Definition: UT_WorkBuffer.h:66