]> git.saurik.com Git - wxWidgets.git/blame - src/stc/scintilla/include/SString.h
wxMGL fixes (patch #884758)
[wxWidgets.git] / src / stc / scintilla / include / SString.h
CommitLineData
65ec6247
RD
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
1a2fb4cd 11// These functions are implemented because each platform calls them something different.
65ec6247 12int CompareCaseInsensitive(const char *a, const char *b);
a834585d 13int CompareNCaseInsensitive(const char *a, const char *b, size_t len);
65ec6247
RD
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
65ec6247
RD
20/**
21 * @brief A simple string class.
1a2fb4cd 22 *
65ec6247
RD
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.
a834585d
RD
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.
65ec6247
RD
27 **/
28class SString {
1a2fb4cd
RD
29public:
30 /** Type of string lengths (sizes) and positions (indexes). */
a834585d 31 typedef size_t lenpos_t;
1a2fb4cd
RD
32 /** Out of bounds value indicating that the string argument should be measured. */
33 enum { measure_length=0xffffffffU};
34
35private:
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
65ec6247 40 enum { sizeGrowthDefault = 64 };
1a2fb4cd
RD
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 }
65ec6247 57
1a2fb4cd
RD
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_) {
a834585d 66 memcpy(s, sOther, sSize_);
1a2fb4cd
RD
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 }
65ec6247 82
1a2fb4cd 83public:
65ec6247
RD
84 SString() : s(0), sSize(0), sLen(0), sizeGrowth(sizeGrowthDefault) {
85 }
86 SString(const SString &source) : sizeGrowth(sizeGrowthDefault) {
1a2fb4cd 87 s = StringAllocate(source.s);
65ec6247
RD
88 sSize = sLen = (s) ? strlen(s) : 0;
89 }
90 SString(const char *s_) : sizeGrowth(sizeGrowthDefault) {
1a2fb4cd 91 s = StringAllocate(s_);
65ec6247
RD
92 sSize = sLen = (s) ? strlen(s) : 0;
93 }
1a2fb4cd 94 SString(const char *s_, lenpos_t first, lenpos_t last) : sizeGrowth(sizeGrowthDefault) {
a834585d 95 // note: expects the "last" argument to point one beyond the range end (a la STL iterators)
1a2fb4cd 96 s = StringAllocate(s_ + first, last - first);
65ec6247
RD
97 sSize = sLen = (s) ? strlen(s) : 0;
98 }
99 SString(int i) : sizeGrowth(sizeGrowthDefault) {
100 char number[32];
101 sprintf(number, "%0d", i);
1a2fb4cd
RD
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);
65ec6247
RD
109 sSize = sLen = (s) ? strlen(s) : 0;
110 }
111 ~SString() {
112 delete []s;
113 s = 0;
114 sSize = 0;
115 sLen = 0;
116 }
1a2fb4cd 117 void clear() {
65ec6247
RD
118 if (s) {
119 *s = '\0';
120 }
121 sLen = 0;
122 }
123 /** Size of buffer. */
1a2fb4cd 124 lenpos_t size() const {
65ec6247
RD
125 if (s)
126 return sSize;
127 else
128 return 0;
129 }
130 /** Size of string in buffer. */
1a2fb4cd 131 lenpos_t length() const {
65ec6247
RD
132 return sLen;
133 }
65ec6247
RD
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 }
1a2fb4cd 169 void setsizegrowth(lenpos_t sizeGrowth_) {
65ec6247
RD
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 }
1a2fb4cd 186 char operator[](lenpos_t i) const {
65ec6247
RD
187 if (s && i < sSize) // Or < sLen? Depends on the use, both are OK
188 return s[i];
189 else
190 return '\0';
191 }
a834585d
RD
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 }
1a2fb4cd
RD
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) {
65ec6247 218 sLenOther = strlen(sOther);
1a2fb4cd 219 }
65ec6247 220 int lenSep = 0;
1a2fb4cd 221 if (sLen && sep) { // Only add a separator if not empty
65ec6247 222 lenSep = 1;
1a2fb4cd
RD
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))) {
65ec6247
RD
227 if (lenSep) {
228 s[sLen] = sep;
229 sLen++;
230 }
a834585d 231 memcpy(&s[sLen], sOther, sLenOther);
65ec6247 232 sLen += sLenOther;
1a2fb4cd 233 s[sLen] = '\0';
65ec6247
RD
234 }
235 return *this;
236 }
1a2fb4cd
RD
237 SString &operator+=(const char *sOther) {
238 return append(sOther, static_cast<lenpos_t>(measure_length));
65ec6247 239 }
1a2fb4cd 240 SString &operator+=(const SString &sOther) {
9e730a78 241 return append(sOther.s, sOther.sLen);
65ec6247 242 }
1a2fb4cd 243 SString &operator+=(char ch) {
65ec6247
RD
244 return append(&ch, 1);
245 }
1a2fb4cd 246 SString &appendwithseparator(const char *sOther, char sep) {
65ec6247
RD
247 return append(sOther, strlen(sOther), sep);
248 }
1a2fb4cd
RD
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 }
a834585d
RD
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 }
1a2fb4cd 291 /** Read an integral numeric value from the string. */
65ec6247
RD
292 int value() const {
293 if (s)
294 return atoi(s);
295 else
296 return 0;
297 }
a834585d 298 int search(const char *sFind, lenpos_t start=0) const {
1a2fb4cd
RD
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;
65ec6247
RD
312 char *t = s;
313 while (t) {
1a2fb4cd 314 t = strchr(t, chFind);
65ec6247 315 if (t) {
1a2fb4cd 316 *t = chReplace;
65ec6247 317 t++;
1a2fb4cd 318 c++;
65ec6247
RD
319 }
320 }
1a2fb4cd
RD
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) {
a834585d 357 memcpy(sNew, s, len);
1a2fb4cd
RD
358 sNew[len] = '\0';
359 }
360 return sNew;
65ec6247
RD
361 }
362};
363
1a2fb4cd
RD
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 */
370inline char *StringDup(
371 const char *s, ///< The string to duplicate
9e730a78 372 SString::lenpos_t len=SString::measure_length) ///< The length of memory to allocate. Optional.
1a2fb4cd
RD
373{
374 return SString::StringAllocate(s, len);
375}
376
65ec6247 377#endif