]> git.saurik.com Git - wxWidgets.git/blame - src/stc/scintilla/include/SString.h
Committing in .
[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
RD
12int CompareCaseInsensitive(const char *a, const char *b);
13int CompareNCaseInsensitive(const char *a, const char *b, int 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
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.
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 **/
28class SString {
1a2fb4cd
RD
29public:
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
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_) {
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 }
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
RD
94 SString(const char *s_, lenpos_t first, lenpos_t last) : sizeGrowth(sizeGrowthDefault) {
95 s = StringAllocate(s_ + first, last - first);
65ec6247
RD
96 sSize = sLen = (s) ? strlen(s) : 0;
97 }
98 SString(int i) : sizeGrowth(sizeGrowthDefault) {
99 char number[32];
100 sprintf(number, "%0d", i);
1a2fb4cd
RD
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);
65ec6247
RD
108 sSize = sLen = (s) ? strlen(s) : 0;
109 }
110 ~SString() {
111 delete []s;
112 s = 0;
113 sSize = 0;
114 sLen = 0;
115 }
1a2fb4cd 116 void clear() {
65ec6247
RD
117 if (s) {
118 *s = '\0';
119 }
120 sLen = 0;
121 }
122 /** Size of buffer. */
1a2fb4cd 123 lenpos_t size() const {
65ec6247
RD
124 if (s)
125 return sSize;
126 else
127 return 0;
128 }
129 /** Size of string in buffer. */
1a2fb4cd 130 lenpos_t length() const {
65ec6247
RD
131 return sLen;
132 }
65ec6247
RD
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 }
1a2fb4cd 168 void setsizegrowth(lenpos_t sizeGrowth_) {
65ec6247
RD
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 }
1a2fb4cd 185 char operator[](lenpos_t i) const {
65ec6247
RD
186 if (s && i < sSize) // Or < sLen? Depends on the use, both are OK
187 return s[i];
188 else
189 return '\0';
190 }
1a2fb4cd
RD
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) {
65ec6247 196 sLenOther = strlen(sOther);
1a2fb4cd 197 }
65ec6247 198 int lenSep = 0;
1a2fb4cd 199 if (sLen && sep) { // Only add a separator if not empty
65ec6247 200 lenSep = 1;
1a2fb4cd
RD
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))) {
65ec6247
RD
205 if (lenSep) {
206 s[sLen] = sep;
207 sLen++;
208 }
209 strncpy(&s[sLen], sOther, sLenOther);
65ec6247 210 sLen += sLenOther;
1a2fb4cd 211 s[sLen] = '\0';
65ec6247
RD
212 }
213 return *this;
214 }
1a2fb4cd
RD
215 SString &operator+=(const char *sOther) {
216 return append(sOther, static_cast<lenpos_t>(measure_length));
65ec6247 217 }
1a2fb4cd 218 SString &operator+=(const SString &sOther) {
65ec6247
RD
219 return append(sOther.s, sOther.sSize);
220 }
1a2fb4cd 221 SString &operator+=(char ch) {
65ec6247
RD
222 return append(&ch, 1);
223 }
1a2fb4cd 224 SString &appendwithseparator(const char *sOther, char sep) {
65ec6247
RD
225 return append(sOther, strlen(sOther), sep);
226 }
1a2fb4cd
RD
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. */
65ec6247
RD
263 int value() const {
264 if (s)
265 return atoi(s);
266 else
267 return 0;
268 }
1a2fb4cd
RD
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;
65ec6247
RD
283 char *t = s;
284 while (t) {
1a2fb4cd 285 t = strchr(t, chFind);
65ec6247 286 if (t) {
1a2fb4cd 287 *t = chReplace;
65ec6247 288 t++;
1a2fb4cd 289 c++;
65ec6247
RD
290 }
291 }
1a2fb4cd
RD
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;
65ec6247
RD
332 }
333};
334
1a2fb4cd
RD
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 */
341inline 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
65ec6247 348#endif