]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/include/SString.h
Same typo.
[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, int 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 rely too heavily on C string
26 * functions to allow reliable manipulations of these strings.
27 **/
28 class SString {
29 public:
30 /** Type of string lengths (sizes) and positions (indexes). */
31 typedef unsigned int 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 strncpy(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 s = StringAllocate(s_ + first, last - first);
96 sSize = sLen = (s) ? strlen(s) : 0;
97 }
98 SString(int i) : sizeGrowth(sizeGrowthDefault) {
99 char number[32];
100 sprintf(number, "%0d", i);
101 s = StringAllocate(number);
102 sSize = sLen = (s) ? strlen(s) : 0;
103 }
104 SString(double d, int precision) : sizeGrowth(sizeGrowthDefault) {
105 char number[32];
106 sprintf(number, "%.*f", precision, d);
107 s = StringAllocate(number);
108 sSize = sLen = (s) ? strlen(s) : 0;
109 }
110 ~SString() {
111 delete []s;
112 s = 0;
113 sSize = 0;
114 sLen = 0;
115 }
116 void clear() {
117 if (s) {
118 *s = '\0';
119 }
120 sLen = 0;
121 }
122 /** Size of buffer. */
123 lenpos_t size() const {
124 if (s)
125 return sSize;
126 else
127 return 0;
128 }
129 /** Size of string in buffer. */
130 lenpos_t length() const {
131 return sLen;
132 }
133 SString &operator=(const char *source) {
134 return assign(source);
135 }
136 SString &operator=(const SString &source) {
137 if (this != &source) {
138 assign(source.c_str());
139 }
140 return *this;
141 }
142 bool operator==(const SString &sOther) const {
143 if ((s == 0) && (sOther.s == 0))
144 return true;
145 if ((s == 0) || (sOther.s == 0))
146 return false;
147 return strcmp(s, sOther.s) == 0;
148 }
149 bool operator!=(const SString &sOther) const {
150 return !operator==(sOther);
151 }
152 bool operator==(const char *sOther) const {
153 if ((s == 0) && (sOther == 0))
154 return true;
155 if ((s == 0) || (sOther == 0))
156 return false;
157 return strcmp(s, sOther) == 0;
158 }
159 bool operator!=(const char *sOther) const {
160 return !operator==(sOther);
161 }
162 bool contains(char ch) {
163 if (s && *s)
164 return strchr(s, ch) != 0;
165 else
166 return false;
167 }
168 void setsizegrowth(lenpos_t sizeGrowth_) {
169 sizeGrowth = sizeGrowth_;
170 }
171 const char *c_str() const {
172 if (s)
173 return s;
174 else
175 return "";
176 }
177 /** Give ownership of buffer to caller which must use delete[] to free buffer. */
178 char *detach() {
179 char *sRet = s;
180 s = 0;
181 sSize = 0;
182 sLen = 0;
183 return sRet;
184 }
185 char operator[](lenpos_t i) const {
186 if (s && i < sSize) // Or < sLen? Depends on the use, both are OK
187 return s[i];
188 else
189 return '\0';
190 }
191 SString &append(const char *sOther, lenpos_t sLenOther=measure_length, char sep = '\0') {
192 if (!sOther) {
193 return *this;
194 }
195 if (sLenOther == measure_length) {
196 sLenOther = strlen(sOther);
197 }
198 int lenSep = 0;
199 if (sLen && sep) { // Only add a separator if not empty
200 lenSep = 1;
201 }
202 lenpos_t lenNew = sLen + sLenOther + lenSep;
203 // Conservative about growing the buffer: don't do it, unless really needed
204 if ((lenNew + 1 < sSize) || (grow(lenNew))) {
205 if (lenSep) {
206 s[sLen] = sep;
207 sLen++;
208 }
209 strncpy(&s[sLen], sOther, sLenOther);
210 sLen += sLenOther;
211 s[sLen] = '\0';
212 }
213 return *this;
214 }
215 SString &operator+=(const char *sOther) {
216 return append(sOther, static_cast<lenpos_t>(measure_length));
217 }
218 SString &operator+=(const SString &sOther) {
219 return append(sOther.s, sOther.sSize);
220 }
221 SString &operator+=(char ch) {
222 return append(&ch, 1);
223 }
224 SString &appendwithseparator(const char *sOther, char sep) {
225 return append(sOther, strlen(sOther), sep);
226 }
227 SString &insert(lenpos_t pos, const char *sOther, lenpos_t sLenOther=measure_length) {
228 if (!sOther) {
229 return *this;
230 }
231 if (sLenOther == measure_length) {
232 sLenOther = strlen(sOther);
233 }
234 lenpos_t lenNew = sLen + sLenOther;
235 // Conservative about growing the buffer: don't do it, unless really needed
236 if ((lenNew + 1 < sSize) || grow(lenNew)) {
237 lenpos_t moveChars = sLen - pos + 1;
238 for (lenpos_t i = moveChars; i > 0; i--) {
239 s[pos + sLenOther + i - 1] = s[pos + i - 1];
240 }
241 memcpy(s + pos, sOther, sLenOther);
242 sLen = lenNew;
243 }
244 return *this;
245 }
246 /** Remove @a len characters from the @a pos position, included.
247 * Characters at pos + len and beyond replace characters at pos.
248 * If @a len is 0, or greater than the length of the string
249 * starting at @a pos, the string is just truncated at @a pos.
250 */
251 void remove(lenpos_t pos, lenpos_t len) {
252 if (len < 1 || pos + len >= sLen) {
253 s[pos] = '\0';
254 sLen = pos;
255 } else {
256 for (lenpos_t i = pos; i < sLen - len + 1; i++) {
257 s[i] = s[i+len];
258 }
259 sLen -= len;
260 }
261 }
262 /** Read an integral numeric value from the string. */
263 int value() const {
264 if (s)
265 return atoi(s);
266 else
267 return 0;
268 }
269 int search(const char *sFind, lenpos_t start=0) {
270 if (start < sLen) {
271 const char *sFound = strstr(s + start, sFind);
272 if (sFound) {
273 return sFound - s;
274 }
275 }
276 return -1;
277 }
278 bool contains(const char *sFind) {
279 return search(sFind) >= 0;
280 }
281 int substitute(char chFind, char chReplace) {
282 int c = 0;
283 char *t = s;
284 while (t) {
285 t = strchr(t, chFind);
286 if (t) {
287 *t = chReplace;
288 t++;
289 c++;
290 }
291 }
292 return c;
293 }
294 int substitute(const char *sFind, const char *sReplace) {
295 int c = 0;
296 lenpos_t lenFind = strlen(sFind);
297 lenpos_t lenReplace = strlen(sReplace);
298 int posFound = search(sFind);
299 while (posFound >= 0) {
300 remove(posFound, lenFind);
301 insert(posFound, sReplace, lenReplace);
302 posFound = search(sFind, posFound + lenReplace);
303 c++;
304 }
305 return c;
306 }
307 int remove(const char *sFind) {
308 return substitute(sFind, "");
309 }
310 /**
311 * Duplicate a C string.
312 * Allocate memory of the given size, or big enough to fit the string if length isn't given;
313 * then copy the given string in the allocated memory.
314 * @return the pointer to the new string
315 */
316 static char *StringAllocate(
317 const char *s, ///< The string to duplicate
318 lenpos_t len=measure_length) ///< The length of memory to allocate. Optional.
319 {
320 if (s == 0) {
321 return 0;
322 }
323 if (len == measure_length) {
324 len = strlen(s);
325 }
326 char *sNew = new char[len + 1];
327 if (sNew) {
328 strncpy(sNew, s, len);
329 sNew[len] = '\0';
330 }
331 return sNew;
332 }
333 };
334
335 /**
336 * Duplicate a C string.
337 * Allocate memory of the given size, or big enough to fit the string if length isn't given;
338 * then copy the given string in the allocated memory.
339 * @return the pointer to the new string
340 */
341 inline char *StringDup(
342 const char *s, ///< The string to duplicate
343 SString::lenpos_t len=SString::measure_length) ///< The length of memory to allocate. Optional.
344 {
345 return SString::StringAllocate(s, len);
346 }
347
348 #endif