]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/include/SString.h
wxMGL fixes (patch #884758)
[wxWidgets.git] / src / stc / scintilla / include / SString.h
1 // SciTE - Scintilla based Text Editor
2 /** @file SString.h
3 ** A simple string class.
4 **/
5 // Copyright 1998-2001 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.
12 int CompareCaseInsensitive(const char *a, const char *b);
13 int CompareNCaseInsensitive(const char *a, const char *b, size_t len);
14 bool 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 * @brief A simple string class.
22 *
23 * Hold the length of the string for quick operations,
24 * can have a buffer bigger than the string to avoid too many memory allocations and copies.
25 * May have embedded zeroes as a result of @a substitute, but relies too heavily on C string
26 * functions to allow reliable manipulations of these strings, other than simple appends, etc.
27 **/
28 class SString {
29 public:
30 /** Type of string lengths (sizes) and positions (indexes). */
31 typedef size_t lenpos_t;
32 /** Out of bounds value indicating that the string argument should be measured. */
33 enum { measure_length=0xffffffffU};
34
35 private:
36 char *s; ///< The C string
37 lenpos_t sSize; ///< The size of the buffer, less 1: ie. the maximum size of the string
38 lenpos_t sLen; ///< The size of the string in s
39 lenpos_t sizeGrowth; ///< Minimum growth size when appending strings
40 enum { sizeGrowthDefault = 64 };
41 bool grow(lenpos_t lenNew) {
42 while (sizeGrowth * 6 < lenNew) {
43 sizeGrowth *= 2;
44 }
45 char *sNew = new char[lenNew + sizeGrowth + 1];
46 if (sNew) {
47 if (s) {
48 memcpy(sNew, s, sLen);
49 delete []s;
50 }
51 s = sNew;
52 s[sLen] = '\0';
53 sSize = lenNew + sizeGrowth;
54 }
55 return sNew != 0;
56 }
57
58 SString &assign(const char *sOther, lenpos_t sSize_=measure_length) {
59 if (!sOther) {
60 sSize_ = 0;
61 } else if (sSize_ == measure_length) {
62 sSize_ = strlen(sOther);
63 }
64 if (sSize > 0 && sSize_ <= sSize) { // Does not allocate new buffer if the current is big enough
65 if (s && sSize_) {
66 memcpy(s, sOther, sSize_);
67 }
68 s[sSize_] = '\0';
69 sLen = sSize_;
70 } else {
71 delete []s;
72 s = StringAllocate(sOther, sSize_);
73 if (s) {
74 sSize = sSize_; // Allow buffer bigger than real string, thus providing space to grow
75 sLen = strlen(s);
76 } else {
77 sSize = sLen = 0;
78 }
79 }
80 return *this;
81 }
82
83 public:
84 SString() : s(0), sSize(0), sLen(0), sizeGrowth(sizeGrowthDefault) {
85 }
86 SString(const SString &source) : sizeGrowth(sizeGrowthDefault) {
87 s = StringAllocate(source.s);
88 sSize = sLen = (s) ? strlen(s) : 0;
89 }
90 SString(const char *s_) : sizeGrowth(sizeGrowthDefault) {
91 s = StringAllocate(s_);
92 sSize = sLen = (s) ? strlen(s) : 0;
93 }
94 SString(const char *s_, lenpos_t first, lenpos_t last) : sizeGrowth(sizeGrowthDefault) {
95 // note: expects the "last" argument to point one beyond the range end (a la STL iterators)
96 s = StringAllocate(s_ + first, last - first);
97 sSize = sLen = (s) ? strlen(s) : 0;
98 }
99 SString(int i) : sizeGrowth(sizeGrowthDefault) {
100 char number[32];
101 sprintf(number, "%0d", i);
102 s = StringAllocate(number);
103 sSize = sLen = (s) ? strlen(s) : 0;
104 }
105 SString(double d, int precision) : sizeGrowth(sizeGrowthDefault) {
106 char number[32];
107 sprintf(number, "%.*f", precision, d);
108 s = StringAllocate(number);
109 sSize = sLen = (s) ? strlen(s) : 0;
110 }
111 ~SString() {
112 delete []s;
113 s = 0;
114 sSize = 0;
115 sLen = 0;
116 }
117 void clear() {
118 if (s) {
119 *s = '\0';
120 }
121 sLen = 0;
122 }
123 /** Size of buffer. */
124 lenpos_t size() const {
125 if (s)
126 return sSize;
127 else
128 return 0;
129 }
130 /** Size of string in buffer. */
131 lenpos_t length() const {
132 return sLen;
133 }
134 SString &operator=(const char *source) {
135 return assign(source);
136 }
137 SString &operator=(const SString &source) {
138 if (this != &source) {
139 assign(source.c_str());
140 }
141 return *this;
142 }
143 bool operator==(const SString &sOther) const {
144 if ((s == 0) && (sOther.s == 0))
145 return true;
146 if ((s == 0) || (sOther.s == 0))
147 return false;
148 return strcmp(s, sOther.s) == 0;
149 }
150 bool operator!=(const SString &sOther) const {
151 return !operator==(sOther);
152 }
153 bool operator==(const char *sOther) const {
154 if ((s == 0) && (sOther == 0))
155 return true;
156 if ((s == 0) || (sOther == 0))
157 return false;
158 return strcmp(s, sOther) == 0;
159 }
160 bool operator!=(const char *sOther) const {
161 return !operator==(sOther);
162 }
163 bool contains(char ch) {
164 if (s && *s)
165 return strchr(s, ch) != 0;
166 else
167 return false;
168 }
169 void setsizegrowth(lenpos_t sizeGrowth_) {
170 sizeGrowth = sizeGrowth_;
171 }
172 const char *c_str() const {
173 if (s)
174 return s;
175 else
176 return "";
177 }
178 /** Give ownership of buffer to caller which must use delete[] to free buffer. */
179 char *detach() {
180 char *sRet = s;
181 s = 0;
182 sSize = 0;
183 sLen = 0;
184 return sRet;
185 }
186 char operator[](lenpos_t i) const {
187 if (s && i < sSize) // Or < sLen? Depends on the use, both are OK
188 return s[i];
189 else
190 return '\0';
191 }
192 SString substr(lenpos_t subPos, lenpos_t subLen=measure_length) const {
193 if (subPos >= sLen) {
194 return SString(); // return a null string if start index is out of bounds
195 }
196 if ((subLen == measure_length) || (subPos + subLen > sLen)) {
197 subLen = sLen - subPos; // can't substr past end of source string
198 }
199 return SString(s, subPos, subPos + subLen);
200 }
201 SString &lowercase(lenpos_t subPos = 0, lenpos_t subLen=measure_length) {
202 if ((subLen == measure_length) || (subPos + subLen > sLen)) {
203 subLen = sLen - subPos; // don't apply past end of string
204 }
205 for (lenpos_t i = subPos; i < subPos + subLen; i++) {
206 if (s[i] < 'A' || s[i] > 'Z')
207 continue;
208 else
209 s[i] = static_cast<char>(s[i] - 'A' + 'a');
210 }
211 return *this;
212 }
213 SString &append(const char *sOther, lenpos_t sLenOther=measure_length, char sep = '\0') {
214 if (!sOther) {
215 return *this;
216 }
217 if (sLenOther == measure_length) {
218 sLenOther = strlen(sOther);
219 }
220 int lenSep = 0;
221 if (sLen && sep) { // Only add a separator if not empty
222 lenSep = 1;
223 }
224 lenpos_t lenNew = sLen + sLenOther + lenSep;
225 // Conservative about growing the buffer: don't do it, unless really needed
226 if ((lenNew + 1 < sSize) || (grow(lenNew))) {
227 if (lenSep) {
228 s[sLen] = sep;
229 sLen++;
230 }
231 memcpy(&s[sLen], sOther, sLenOther);
232 sLen += sLenOther;
233 s[sLen] = '\0';
234 }
235 return *this;
236 }
237 SString &operator+=(const char *sOther) {
238 return append(sOther, static_cast<lenpos_t>(measure_length));
239 }
240 SString &operator+=(const SString &sOther) {
241 return append(sOther.s, sOther.sLen);
242 }
243 SString &operator+=(char ch) {
244 return append(&ch, 1);
245 }
246 SString &appendwithseparator(const char *sOther, char sep) {
247 return append(sOther, strlen(sOther), sep);
248 }
249 SString &insert(lenpos_t pos, const char *sOther, lenpos_t sLenOther=measure_length) {
250 if (!sOther) {
251 return *this;
252 }
253 if (sLenOther == measure_length) {
254 sLenOther = strlen(sOther);
255 }
256 lenpos_t lenNew = sLen + sLenOther;
257 // Conservative about growing the buffer: don't do it, unless really needed
258 if ((lenNew + 1 < sSize) || grow(lenNew)) {
259 lenpos_t moveChars = sLen - pos + 1;
260 for (lenpos_t i = moveChars; i > 0; i--) {
261 s[pos + sLenOther + i - 1] = s[pos + i - 1];
262 }
263 memcpy(s + pos, sOther, sLenOther);
264 sLen = lenNew;
265 }
266 return *this;
267 }
268 /** Remove @a len characters from the @a pos position, included.
269 * Characters at pos + len and beyond replace characters at pos.
270 * If @a len is 0, or greater than the length of the string
271 * starting at @a pos, the string is just truncated at @a pos.
272 */
273 void remove(lenpos_t pos, lenpos_t len) {
274 if (len < 1 || pos + len >= sLen) {
275 s[pos] = '\0';
276 sLen = pos;
277 } else {
278 for (lenpos_t i = pos; i < sLen - len + 1; i++) {
279 s[i] = s[i+len];
280 }
281 sLen -= len;
282 }
283 }
284 SString &change(lenpos_t pos, char ch) {
285 if (pos >= sLen) { // character changed must be in string bounds
286 return *this;
287 }
288 *(s + pos) = ch;
289 return *this;
290 }
291 /** Read an integral numeric value from the string. */
292 int value() const {
293 if (s)
294 return atoi(s);
295 else
296 return 0;
297 }
298 int search(const char *sFind, lenpos_t start=0) const {
299 if (start < sLen) {
300 const char *sFound = strstr(s + start, sFind);
301 if (sFound) {
302 return sFound - s;
303 }
304 }
305 return -1;
306 }
307 bool contains(const char *sFind) {
308 return search(sFind) >= 0;
309 }
310 int substitute(char chFind, char chReplace) {
311 int c = 0;
312 char *t = s;
313 while (t) {
314 t = strchr(t, chFind);
315 if (t) {
316 *t = chReplace;
317 t++;
318 c++;
319 }
320 }
321 return c;
322 }
323 int substitute(const char *sFind, const char *sReplace) {
324 int c = 0;
325 lenpos_t lenFind = strlen(sFind);
326 lenpos_t lenReplace = strlen(sReplace);
327 int posFound = search(sFind);
328 while (posFound >= 0) {
329 remove(posFound, lenFind);
330 insert(posFound, sReplace, lenReplace);
331 posFound = search(sFind, posFound + lenReplace);
332 c++;
333 }
334 return c;
335 }
336 int remove(const char *sFind) {
337 return substitute(sFind, "");
338 }
339 /**
340 * Duplicate a C string.
341 * Allocate memory of the given size, or big enough to fit the string if length isn't given;
342 * then copy the given string in the allocated memory.
343 * @return the pointer to the new string
344 */
345 static char *StringAllocate(
346 const char *s, ///< The string to duplicate
347 lenpos_t len=measure_length) ///< The length of memory to allocate. Optional.
348 {
349 if (s == 0) {
350 return 0;
351 }
352 if (len == measure_length) {
353 len = strlen(s);
354 }
355 char *sNew = new char[len + 1];
356 if (sNew) {
357 memcpy(sNew, s, len);
358 sNew[len] = '\0';
359 }
360 return sNew;
361 }
362 };
363
364 /**
365 * Duplicate a C string.
366 * Allocate memory of the given size, or big enough to fit the string if length isn't given;
367 * then copy the given string in the allocated memory.
368 * @return the pointer to the new string
369 */
370 inline char *StringDup(
371 const char *s, ///< The string to duplicate
372 SString::lenpos_t len=SString::measure_length) ///< The length of memory to allocate. Optional.
373 {
374 return SString::StringAllocate(s, len);
375 }
376
377 #endif