1// SciTE - Scintilla based Text Editor 2/** @file SString.h 3 ** A simple string class. 4 **/ 5// Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org> 6// The License.txt file describes the conditions under which this software may be distributed. 7 8#ifndef SSTRING_H 9#define SSTRING_H 10 11// These functions are implemented because each platform calls them something different. 12int CompareCaseInsensitive(const char *a, const char *b); 13int CompareNCaseInsensitive(const char *a, const char *b, size_t len); 14bool EqualCaseInsensitive(const char *a, const char *b); 15 16// Define another string class. 17// While it would be 'better' to use std::string, that doubles the executable size. 18// An SString may contain embedded nul characters. 19 20/** 21 * Base class from which the two other classes (SBuffer & SString) 22 * are derived. 23 */ 24class SContainer { 25public: 26 /** Type of string lengths (sizes) and positions (indexes). */ 27 typedef size_t lenpos_t; 28 /** Out of bounds value indicating that the string argument should be measured. */ 29 enum { measure_length=0xffffffffU}; 30 31protected: 32 char *s; ///< The C string 33 lenpos_t sSize; ///< The size of the buffer, less 1: ie. the maximum size of the string 34 35 SContainer() : s(0), sSize(0) {} 36 ~SContainer() { 37 delete []s; // Suppose it was allocated using StringAllocate 38 s = 0; 39 sSize = 0; 40 } 41 /** Size of buffer. */ 42 lenpos_t size() const { 43 if (s) { 44 return sSize; 45 } else { 46 return 0; 47 } 48 } 49public: 50 /** 51 * Allocate uninitialized memory big enough to fit a string of the given length. 52 * @return the pointer to the new string 53 */ 54 static char *StringAllocate(lenpos_t len); 55 /** 56 * Duplicate a buffer/C string. 57 * Allocate memory of the given size, or big enough to fit the string if length isn't given; 58 * then copy the given string in the allocated memory. 59 * @return the pointer to the new string 60 */ 61 static char *StringAllocate( 62 const char *s, ///< The string to duplicate 63 lenpos_t len=measure_length); ///< The length of memory to allocate. Optional. 64}; 65 66 67/** 68 * @brief A string buffer class. 69 * 70 * Main use is to ask an API the length of a string it can provide, 71 * then to allocate a buffer of the given size, and to provide this buffer 72 * to the API to put the string. 73 * This class is intended to be shortlived, to be transformed as SString 74 * as soon as it holds the string, so it has little members. 75 * Note: we assume the buffer is filled by the API. If the length can be shorter, 76 * we should set sLen to strlen(sb.ptr()) in related SString constructor and assignment. 77 */ 78class SBuffer : protected SContainer { 79public: 80 SBuffer(lenpos_t len) { 81 s = StringAllocate(len); 82 if (s) { 83 *s = '\0'; 84 sSize = len; 85 } else { 86 sSize = 0; 87 } 88 } 89private: 90 /// Copy constructor 91 // Here only to be on the safe size, user should avoid returning SBuffer values. 92 SBuffer(const SBuffer &source) : SContainer() { 93 s = StringAllocate(source.s, source.sSize); 94 sSize = (s) ? source.sSize : 0; 95 } 96 /// Default assignment operator 97 // Same here, shouldn't be used 98 SBuffer &operator=(const SBuffer &source) { 99 if (this != &source) { 100 delete []s; 101 s = StringAllocate(source.s, source.sSize); 102 sSize = (s) ? source.sSize : 0; 103 } 104 return *this; 105 } 106public: 107 /** Provide direct read/write access to buffer. */ 108 char *ptr() { 109 return s; 110 } 111 /** Ownership of the buffer have been taken, so release it. */ 112 void reset() { 113 s = 0; 114 sSize = 0; 115 } 116 /** Size of buffer. */ 117 lenpos_t size() const { 118 return SContainer::size(); 119 } 120}; 121 122 123/** 124 * @brief A simple string class. 125 * 126 * Hold the length of the string for quick operations, 127 * can have a buffer bigger than the string to avoid too many memory allocations and copies. 128 * May have embedded zeroes as a result of @a substitute, but relies too heavily on C string 129 * functions to allow reliable manipulations of these strings, other than simple appends, etc. 130 */ 131class SString : protected SContainer { 132 lenpos_t sLen; ///< The size of the string in s 133 lenpos_t sizeGrowth; ///< Minimum growth size when appending strings 134 enum { sizeGrowthDefault = 64 }; 135 136 bool grow(lenpos_t lenNew); 137 SString &assign(const char *sOther, lenpos_t sSize_=measure_length); 138 139public: 140 SString() : sLen(0), sizeGrowth(sizeGrowthDefault) {} 141 SString(const SString &source) : SContainer(), sizeGrowth(sizeGrowthDefault) { 142 s = StringAllocate(source.s, source.sLen); 143 sSize = sLen = (s) ? source.sLen : 0; 144 } 145 SString(const char *s_) : sizeGrowth(sizeGrowthDefault) { 146 s = StringAllocate(s_); 147 sSize = sLen = (s) ? strlen(s) : 0; 148 } 149 SString(SBuffer &buf) : sizeGrowth(sizeGrowthDefault) { 150 s = buf.ptr(); 151 sSize = sLen = buf.size(); 152 // Consumes the given buffer! 153 buf.reset(); 154 } 155 SString(const char *s_, lenpos_t first, lenpos_t last) : sizeGrowth(sizeGrowthDefault) { 156 // note: expects the "last" argument to point one beyond the range end (a la STL iterators) 157 s = StringAllocate(s_ + first, last - first); 158 sSize = sLen = (s) ? last - first : 0; 159 } 160 SString(int i); 161 SString(double d, int precision); 162 ~SString() { 163 sLen = 0; 164 } 165 void clear() { 166 if (s) { 167 *s = '\0'; 168 } 169 sLen = 0; 170 } 171 /** Size of buffer. */ 172 lenpos_t size() const { 173 return SContainer::size(); 174 } 175 /** Size of string in buffer. */ 176 lenpos_t length() const { 177 return sLen; 178 } 179 /** Read access to a character of the string. */ 180 char operator[](lenpos_t i) const { 181 return (s && i < sSize) ? s[i] : '\0'; 182 } 183 SString &operator=(const char *source) { 184 return assign(source); 185 } 186 SString &operator=(const SString &source) { 187 if (this != &source) { 188 assign(source.s, source.sLen); 189 } 190 return *this; 191 } 192 bool operator==(const SString &sOther) const; 193 bool operator!=(const SString &sOther) const { 194 return !operator==(sOther); 195 } 196 bool operator==(const char *sOther) const; 197 bool operator!=(const char *sOther) const { 198 return !operator==(sOther); 199 } 200 bool contains(char ch) const { 201 return (s && *s) ? strchr(s, ch) != 0 : false; 202 } 203 void setsizegrowth(lenpos_t sizeGrowth_) { 204 sizeGrowth = sizeGrowth_; 205 } 206 const char *c_str() const { 207 return s ? s : ""; 208 } 209 /** Give ownership of buffer to caller which must use delete[] to free buffer. */ 210 char *detach() { 211 char *sRet = s; 212 s = 0; 213 sSize = 0; 214 sLen = 0; 215 return sRet; 216 } 217 SString substr(lenpos_t subPos, lenpos_t subLen=measure_length) const; 218 SString &lowercase(lenpos_t subPos = 0, lenpos_t subLen=measure_length); 219 SString &uppercase(lenpos_t subPos = 0, lenpos_t subLen=measure_length); 220 SString &append(const char *sOther, lenpos_t sLenOther=measure_length, char sep = '\0'); 221 SString &operator+=(const char *sOther) { 222 return append(sOther, static_cast<lenpos_t>(measure_length)); 223 } 224 SString &operator+=(const SString &sOther) { 225 return append(sOther.s, sOther.sLen); 226 } 227 SString &operator+=(char ch) { 228 return append(&ch, 1); 229 } 230 SString &appendwithseparator(const char *sOther, char sep) { 231 return append(sOther, strlen(sOther), sep); 232 } 233 SString &insert(lenpos_t pos, const char *sOther, lenpos_t sLenOther=measure_length); 234 235 /** 236 * Remove @a len characters from the @a pos position, included. 237 * Characters at pos + len and beyond replace characters at pos. 238 * If @a len is 0, or greater than the length of the string 239 * starting at @a pos, the string is just truncated at @a pos. 240 */ 241 void remove(lenpos_t pos, lenpos_t len); 242 243 SString &change(lenpos_t pos, char ch) { 244 if (pos < sLen) { // character changed must be in string bounds 245 *(s + pos) = ch; 246 } 247 return *this; 248 } 249 /** Read an integral numeric value from the string. */ 250 int value() const { 251 return s ? atoi(s) : 0; 252 } 253 bool startswith(const char *prefix); 254 bool endswith(const char *suffix); 255 int search(const char *sFind, lenpos_t start=0) const; 256 bool contains(const char *sFind) const { 257 return search(sFind) >= 0; 258 } 259 int substitute(char chFind, char chReplace); 260 int substitute(const char *sFind, const char *sReplace); 261 int remove(const char *sFind) { 262 return substitute(sFind, ""); 263 } 264}; 265 266 267/** 268 * Duplicate a C string. 269 * Allocate memory of the given size, or big enough to fit the string if length isn't given; 270 * then copy the given string in the allocated memory. 271 * @return the pointer to the new string 272 */ 273inline char *StringDup( 274 const char *s, ///< The string to duplicate 275 SContainer::lenpos_t len=SContainer::measure_length) ///< The length of memory to allocate. Optional. 276{ 277 return SContainer::StringAllocate(s, len); 278} 279 280#endif 281