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