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