]> git.saurik.com Git - wxWidgets.git/blobdiff - src/stc/scintilla/include/SString.h
wxMGL fixes (patch #884758)
[wxWidgets.git] / src / stc / scintilla / include / SString.h
index aeb5940502e7c8df95efdcd8b5024e002be56e39..01602df7816fbc65d28c4fd4f7af1e4b6423fd09 100644 (file)
 #ifndef SSTRING_H
 #define SSTRING_H
 
-// These functions are implemented because each platform calls them something different
+// These functions are implemented because each platform calls them something different.
 int CompareCaseInsensitive(const char *a, const char *b);
-int CompareNCaseInsensitive(const char *a, const char *b, int len);
+int CompareNCaseInsensitive(const char *a, const char *b, size_t len);
 bool EqualCaseInsensitive(const char *a, const char *b);
 
 // Define another string class.
 // While it would be 'better' to use std::string, that doubles the executable size.
 // An SString may contain embedded nul characters.
 
-/**
- * Duplicate a C string.
- * Allocate memory of the given size, or big enough to fit the string if length isn't given;
- * then copy the given string in the allocated memory.
- * @return the pointer to the new string
- */
-inline char *StringDup(
-       const char *s,  ///< The string to duplicate
-       int len=-1)             ///< The length of memory to allocate. Optional.
-{
-       if (!s)
-               return 0;
-       if (len == -1)
-               len = strlen(s);
-       char *sNew = new char[len + 1];
-       if (sNew) {
-               strncpy(sNew, s, len);
-               sNew[len] = '\0';
-       }
-       return sNew;
-}
-
 /**
  * @brief A simple string class.
+ *
  * Hold the length of the string for quick operations,
  * can have a buffer bigger than the string to avoid too many memory allocations and copies.
- * May have embedded zeroes as a result of @a substitute, but rely too heavily on C string
- * functions to allow reliable manipulations of these strings.
+ * May have embedded zeroes as a result of @a substitute, but relies too heavily on C string
+ * functions to allow reliable manipulations of these strings, other than simple appends, etc.
  **/
 class SString {
-       char *s;                        ///< The C string
-       int sSize;      ///< The size of the buffer, less 1: ie. the maximum size of the string
-       int sLen;       ///< The size of the string in s
-       int sizeGrowth; ///< Minimum growth size when appending strings
+public:
+       /** Type of string lengths (sizes) and positions (indexes). */
+       typedef size_t lenpos_t;
+       /** Out of bounds value indicating that the string argument should be measured. */
+       enum { measure_length=0xffffffffU};
+
+private:
+       char *s;                                ///< The C string
+       lenpos_t sSize;                 ///< The size of the buffer, less 1: ie. the maximum size of the string
+       lenpos_t sLen;                  ///< The size of the string in s
+       lenpos_t sizeGrowth;    ///< Minimum growth size when appending strings
        enum { sizeGrowthDefault = 64 };
+       bool grow(lenpos_t lenNew) {
+               while (sizeGrowth * 6 < lenNew) {
+                       sizeGrowth *= 2;
+               }
+               char *sNew = new char[lenNew + sizeGrowth + 1];
+               if (sNew) {
+                       if (s) {
+                               memcpy(sNew, s, sLen);
+                               delete []s;
+                       }
+                       s = sNew;
+                       s[sLen] = '\0';
+                       sSize = lenNew + sizeGrowth;
+               }
+               return sNew != 0;
+       }
 
-public:
-       typedef int size_type;
+       SString &assign(const char *sOther, lenpos_t sSize_=measure_length) {
+               if (!sOther) {
+                       sSize_ = 0;
+               } else if (sSize_ == measure_length) {
+                       sSize_ = strlen(sOther);
+               }
+               if (sSize > 0 && sSize_ <= sSize) {     // Does not allocate new buffer if the current is big enough
+                       if (s && sSize_) {
+                               memcpy(s, sOther, sSize_);
+                       }
+                       s[sSize_] = '\0';
+                       sLen = sSize_;
+               } else {
+                       delete []s;
+                       s = StringAllocate(sOther, sSize_);
+                       if (s) {
+                               sSize = sSize_; // Allow buffer bigger than real string, thus providing space to grow
+                               sLen = strlen(s);
+                       } else {
+                               sSize = sLen = 0;
+                       }
+               }
+               return *this;
+       }
 
+public:
        SString() : s(0), sSize(0), sLen(0), sizeGrowth(sizeGrowthDefault) {
        }
        SString(const SString &source) : sizeGrowth(sizeGrowthDefault) {
-               s = StringDup(source.s);
+               s = StringAllocate(source.s);
                sSize = sLen = (s) ? strlen(s) : 0;
        }
        SString(const char *s_) : sizeGrowth(sizeGrowthDefault) {
-               s = StringDup(s_);
+               s = StringAllocate(s_);
                sSize = sLen = (s) ? strlen(s) : 0;
        }
-       SString(const char *s_, int first, int last) : sizeGrowth(sizeGrowthDefault) {
-               s = StringDup(s_ + first, last - first);
+       SString(const char *s_, lenpos_t first, lenpos_t last) : sizeGrowth(sizeGrowthDefault) {
+               // note: expects the "last" argument to point one beyond the range end (a la STL iterators)
+               s = StringAllocate(s_ + first, last - first);
                sSize = sLen = (s) ? strlen(s) : 0;
        }
        SString(int i) : sizeGrowth(sizeGrowthDefault) {
                char number[32];
                sprintf(number, "%0d", i);
-               s = StringDup(number);
+               s = StringAllocate(number);
+               sSize = sLen = (s) ? strlen(s) : 0;
+       }
+       SString(double d, int precision) : sizeGrowth(sizeGrowthDefault) {
+               char number[32];
+               sprintf(number, "%.*f", precision, d);
+               s = StringAllocate(number);
                sSize = sLen = (s) ? strlen(s) : 0;
        }
        ~SString() {
@@ -82,51 +114,23 @@ public:
                sSize = 0;
                sLen = 0;
        }
-       void clear(void) {
+       void clear() {
                if (s) {
                        *s = '\0';
                }
                sLen = 0;
        }
        /** Size of buffer. */
-       size_type size(void) const {    ///<
+       lenpos_t size() const {
                if (s)
                        return sSize;
                else
                        return 0;
        }
        /** Size of string in buffer. */
-       int length() const {
+       lenpos_t length() const {
                return sLen;
        }
-       SString &assign(const char* sOther, int sSize_ = -1) {
-               if (!sOther) {
-                       sSize_ = 0;
-               }
-               if (sSize_ < 0) {
-                       sSize_ = strlen(sOther);
-               }
-               if (sSize > 0 && sSize_ <= sSize) {     // Does not allocate new buffer if the current is big enough
-                       if (s && sSize_) {
-                               strncpy(s, sOther, sSize_);
-                       }
-                       s[sSize_] = '\0';
-                       sLen = sSize_;
-               } else {
-                       delete []s;
-                       s = StringDup(sOther, sSize_);
-                       if (s) {
-                               sSize = sSize_; // Allow buffer bigger than real string, thus providing space to grow
-                               sLen = strlen(s);
-                       } else {
-                               sSize = sLen = 0;
-                       }
-               }
-               return *this;
-       }
-       SString &assign(const SString& sOther, int sSize_ = -1) {
-               return assign(sOther.s, sSize_);
-       }
        SString &operator=(const char *source) {
                return assign(source);
        }
@@ -162,7 +166,7 @@ public:
                else
                        return false;
        }
-       void setsizegrowth(int sizeGrowth_) {
+       void setsizegrowth(lenpos_t sizeGrowth_) {
                sizeGrowth = sizeGrowth_;
        }
        const char *c_str() const {
@@ -179,77 +183,195 @@ public:
                sLen = 0;
                return sRet;
        }
-       char operator[](int i) const {
+       char operator[](lenpos_t i) const {
                if (s && i < sSize)     // Or < sLen? Depends on the use, both are OK
                        return s[i];
                else
                        return '\0';
        }
-       SString &append(const char* sOther, int sLenOther=-1, char sep=0) {
-               if (sLenOther < 0)
+       SString substr(lenpos_t subPos, lenpos_t subLen=measure_length) const {
+               if (subPos >= sLen) {
+                       return SString();                                       // return a null string if start index is out of bounds
+               }
+               if ((subLen == measure_length) || (subPos + subLen > sLen)) {
+                       subLen = sLen - subPos;         // can't substr past end of source string
+               }
+               return SString(s, subPos, subPos + subLen);
+       }
+       SString &lowercase(lenpos_t subPos = 0, lenpos_t subLen=measure_length) {
+               if ((subLen == measure_length) || (subPos + subLen > sLen)) {
+                       subLen = sLen - subPos;         // don't apply past end of string
+               }
+               for (lenpos_t i = subPos; i < subPos + subLen; i++) {
+                       if (s[i] < 'A' || s[i] > 'Z')
+                               continue;
+                       else
+                               s[i] = static_cast<char>(s[i] - 'A' + 'a');
+               }
+               return *this;
+       }
+       SString &append(const char *sOther, lenpos_t sLenOther=measure_length, char sep = '\0') {
+               if (!sOther) {
+                       return *this;
+               }
+               if (sLenOther == measure_length) {
                        sLenOther = strlen(sOther);
+               }
                int lenSep = 0;
-               if (sLen && sep)        // Only add a separator if not empty
+               if (sLen && sep) {      // Only add a separator if not empty
                        lenSep = 1;
-               int lenNew = sLen + sLenOther + lenSep;
-               if (lenNew + 1 < sSize) {
-                       // Conservative about growing the buffer: don't do it, unless really needed
+               }
+               lenpos_t lenNew = sLen + sLenOther + lenSep;
+               // Conservative about growing the buffer: don't do it, unless really needed
+               if ((lenNew + 1 < sSize) || (grow(lenNew))) {
                        if (lenSep) {
                                s[sLen] = sep;
                                sLen++;
                        }
-                       strncpy(&s[sLen], sOther, sLenOther);
-                       s[sLen + sLenOther] = '\0';
+                       memcpy(&s[sLen], sOther, sLenOther);
                        sLen += sLenOther;
-               } else {
-                       // Grow the buffer bigger than really needed, to have room for other appends
-                       char *sNew = new char[lenNew + sizeGrowth + 1];
-                       if (sNew) {
-                               if (s) {
-                                       memcpy(sNew, s, sLen);
-                                       delete []s;
-                               }
-                               s = sNew;
-                               sSize = lenNew + sizeGrowth;
-                               if (lenSep) {
-                                       s[sLen] = sep;
-                                       sLen++;
-                               }
-                               strncpy(&s[sLen], sOther, sLenOther);
-                               sNew[sLen + sLenOther] = '\0';
-                               sLen += sLenOther;
-                       }
+                       s[sLen] = '\0';
                }
                return *this;
        }
-       SString &operator +=(const char *sOther) {
-               return append(sOther, -1);
+       SString &operator+=(const char *sOther) {
+               return append(sOther, static_cast<lenpos_t>(measure_length));
        }
-       SString &operator +=(const SString &sOther) {
-               return append(sOther.s, sOther.sSize);
+       SString &operator+=(const SString &sOther) {
+               return append(sOther.s, sOther.sLen);
        }
-       SString &operator +=(char ch) {
+       SString &operator+=(char ch) {
                return append(&ch, 1);
        }
-       SString &appendwithseparator(const charsOther, char sep) {
+       SString &appendwithseparator(const char *sOther, char sep) {
                return append(sOther, strlen(sOther), sep);
        }
+       SString &insert(lenpos_t pos, const char *sOther, lenpos_t sLenOther=measure_length) {
+               if (!sOther) {
+                       return *this;
+               }
+               if (sLenOther == measure_length) {
+                       sLenOther = strlen(sOther);
+               }
+               lenpos_t lenNew = sLen + sLenOther;
+               // Conservative about growing the buffer: don't do it, unless really needed
+               if ((lenNew + 1 < sSize) || grow(lenNew)) {
+                       lenpos_t moveChars = sLen - pos + 1;
+                       for (lenpos_t i = moveChars; i > 0; i--) {
+                               s[pos + sLenOther + i - 1] = s[pos + i - 1];
+                       }
+                       memcpy(s + pos, sOther, sLenOther);
+                       sLen = lenNew;
+               }
+               return *this;
+       }
+       /** Remove @a len characters from the @a pos position, included.
+        * Characters at pos + len and beyond replace characters at pos.
+        * If @a len is 0, or greater than the length of the string
+        * starting at @a pos, the string is just truncated at @a pos.
+        */
+       void remove(lenpos_t pos, lenpos_t len) {
+               if (len < 1 || pos + len >= sLen) {
+                       s[pos] = '\0';
+                       sLen = pos;
+               } else {
+                       for (lenpos_t i = pos; i < sLen - len + 1; i++) {
+                               s[i] = s[i+len];
+                       }
+                       sLen -= len;
+               }
+       }
+       SString &change(lenpos_t pos, char ch) {
+               if (pos >= sLen) {                                      // character changed must be in string bounds
+                       return *this;
+               }
+               *(s + pos) = ch;
+               return *this;
+       }
+       /** Read an integral numeric value from the string. */
        int value() const {
                if (s)
                        return atoi(s);
                else
                        return 0;
        }
-       void substitute(char find, char replace) {
+       int search(const char *sFind, lenpos_t start=0) const {
+               if (start < sLen) {
+                       const char *sFound = strstr(s + start, sFind);
+                       if (sFound) {
+                               return sFound - s;
+                       }
+               }
+               return -1;
+       }
+       bool contains(const char *sFind) {
+               return search(sFind) >= 0;
+       }
+       int substitute(char chFind, char chReplace) {
+               int c = 0;
                char *t = s;
                while (t) {
-                       t = strchr(t, find);
+                       t = strchr(t, chFind);
                        if (t) {
-                               *t = replace;
+                               *t = chReplace;
                                t++;
+                               c++;
                        }
                }
+               return c;
+       }
+       int substitute(const char *sFind, const char *sReplace) {
+               int c = 0;
+               lenpos_t lenFind = strlen(sFind);
+               lenpos_t lenReplace = strlen(sReplace);
+               int posFound = search(sFind);
+               while (posFound >= 0) {
+                       remove(posFound, lenFind);
+                       insert(posFound, sReplace, lenReplace);
+                       posFound = search(sFind, posFound + lenReplace);
+                       c++;
+               }
+               return c;
+       }
+       int remove(const char *sFind) {
+               return substitute(sFind, "");
+       }
+       /**
+        * Duplicate a C string.
+        * Allocate memory of the given size, or big enough to fit the string if length isn't given;
+        * then copy the given string in the allocated memory.
+        * @return the pointer to the new string
+        */
+       static char *StringAllocate(
+               const char *s,                  ///< The string to duplicate
+               lenpos_t len=measure_length)    ///< The length of memory to allocate. Optional.
+       {
+               if (s == 0) {
+                       return 0;
+               }
+               if (len == measure_length) {
+                       len = strlen(s);
+               }
+               char *sNew = new char[len + 1];
+               if (sNew) {
+                       memcpy(sNew, s, len);
+                       sNew[len] = '\0';
+               }
+               return sNew;
        }
 };
 
+/**
+ * Duplicate a C string.
+ * Allocate memory of the given size, or big enough to fit the string if length isn't given;
+ * then copy the given string in the allocated memory.
+ * @return the pointer to the new string
+ */
+inline char *StringDup(
+       const char *s,                  ///< The string to duplicate
+       SString::lenpos_t len=SString::measure_length)  ///< The length of memory to allocate. Optional.
+{
+       return SString::StringAllocate(s, len);
+}
+
 #endif