]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | * Duplicate a C string. | |
22 | * Allocate memory of the given size, or big enough to fit the string if length isn't given; | |
23 | * then copy the given string in the allocated memory. | |
24 | * @return the pointer to the new string | |
25 | */ | |
26 | inline char *StringDup( | |
27 | const char *s, ///< The string to duplicate | |
28 | int len=-1) ///< The length of memory to allocate. Optional. | |
29 | { | |
30 | if (!s) | |
31 | return 0; | |
32 | if (len == -1) | |
33 | len = strlen(s); | |
34 | char *sNew = new char[len + 1]; | |
35 | if (sNew) { | |
36 | strncpy(sNew, s, len); | |
37 | sNew[len] = '\0'; | |
38 | } | |
39 | return sNew; | |
40 | } | |
41 | ||
42 | /** | |
43 | * @brief A simple string class. | |
44 | * Hold the length of the string for quick operations, | |
45 | * can have a buffer bigger than the string to avoid too many memory allocations and copies. | |
46 | * May have embedded zeroes as a result of @a substitute, but rely too heavily on C string | |
47 | * functions to allow reliable manipulations of these strings. | |
48 | **/ | |
49 | class SString { | |
50 | char *s; ///< The C string | |
51 | int sSize; ///< The size of the buffer, less 1: ie. the maximum size of the string | |
52 | int sLen; ///< The size of the string in s | |
53 | int sizeGrowth; ///< Minimum growth size when appending strings | |
54 | enum { sizeGrowthDefault = 64 }; | |
55 | ||
56 | public: | |
57 | typedef int size_type; | |
58 | ||
59 | SString() : s(0), sSize(0), sLen(0), sizeGrowth(sizeGrowthDefault) { | |
60 | } | |
61 | SString(const SString &source) : sizeGrowth(sizeGrowthDefault) { | |
62 | s = StringDup(source.s); | |
63 | sSize = sLen = (s) ? strlen(s) : 0; | |
64 | } | |
65 | SString(const char *s_) : sizeGrowth(sizeGrowthDefault) { | |
66 | s = StringDup(s_); | |
67 | sSize = sLen = (s) ? strlen(s) : 0; | |
68 | } | |
69 | SString(const char *s_, int first, int last) : sizeGrowth(sizeGrowthDefault) { | |
70 | s = StringDup(s_ + first, last - first); | |
71 | sSize = sLen = (s) ? strlen(s) : 0; | |
72 | } | |
73 | SString(int i) : sizeGrowth(sizeGrowthDefault) { | |
74 | char number[32]; | |
75 | sprintf(number, "%0d", i); | |
76 | s = StringDup(number); | |
77 | sSize = sLen = (s) ? strlen(s) : 0; | |
78 | } | |
79 | ~SString() { | |
80 | delete []s; | |
81 | s = 0; | |
82 | sSize = 0; | |
83 | sLen = 0; | |
84 | } | |
85 | void clear(void) { | |
86 | if (s) { | |
87 | *s = '\0'; | |
88 | } | |
89 | sLen = 0; | |
90 | } | |
91 | /** Size of buffer. */ | |
92 | size_type size(void) const { ///< | |
93 | if (s) | |
94 | return sSize; | |
95 | else | |
96 | return 0; | |
97 | } | |
98 | /** Size of string in buffer. */ | |
99 | int length() const { | |
100 | return sLen; | |
101 | } | |
102 | SString &assign(const char* sOther, int sSize_ = -1) { | |
103 | if (!sOther) { | |
104 | sSize_ = 0; | |
105 | } | |
106 | if (sSize_ < 0) { | |
107 | sSize_ = strlen(sOther); | |
108 | } | |
109 | if (sSize > 0 && sSize_ <= sSize) { // Does not allocate new buffer if the current is big enough | |
110 | if (s && sSize_) { | |
111 | strncpy(s, sOther, sSize_); | |
112 | } | |
113 | s[sSize_] = '\0'; | |
114 | sLen = sSize_; | |
115 | } else { | |
116 | delete []s; | |
117 | s = StringDup(sOther, sSize_); | |
118 | if (s) { | |
119 | sSize = sSize_; // Allow buffer bigger than real string, thus providing space to grow | |
120 | sLen = strlen(s); | |
121 | } else { | |
122 | sSize = sLen = 0; | |
123 | } | |
124 | } | |
125 | return *this; | |
126 | } | |
127 | SString &assign(const SString& sOther, int sSize_ = -1) { | |
128 | return assign(sOther.s, sSize_); | |
129 | } | |
130 | SString &operator=(const char *source) { | |
131 | return assign(source); | |
132 | } | |
133 | SString &operator=(const SString &source) { | |
134 | if (this != &source) { | |
135 | assign(source.c_str()); | |
136 | } | |
137 | return *this; | |
138 | } | |
139 | bool operator==(const SString &sOther) const { | |
140 | if ((s == 0) && (sOther.s == 0)) | |
141 | return true; | |
142 | if ((s == 0) || (sOther.s == 0)) | |
143 | return false; | |
144 | return strcmp(s, sOther.s) == 0; | |
145 | } | |
146 | bool operator!=(const SString &sOther) const { | |
147 | return !operator==(sOther); | |
148 | } | |
149 | bool operator==(const char *sOther) const { | |
150 | if ((s == 0) && (sOther == 0)) | |
151 | return true; | |
152 | if ((s == 0) || (sOther == 0)) | |
153 | return false; | |
154 | return strcmp(s, sOther) == 0; | |
155 | } | |
156 | bool operator!=(const char *sOther) const { | |
157 | return !operator==(sOther); | |
158 | } | |
159 | bool contains(char ch) { | |
160 | if (s && *s) | |
161 | return strchr(s, ch) != 0; | |
162 | else | |
163 | return false; | |
164 | } | |
165 | void setsizegrowth(int sizeGrowth_) { | |
166 | sizeGrowth = sizeGrowth_; | |
167 | } | |
168 | const char *c_str() const { | |
169 | if (s) | |
170 | return s; | |
171 | else | |
172 | return ""; | |
173 | } | |
174 | /** Give ownership of buffer to caller which must use delete[] to free buffer. */ | |
175 | char *detach() { | |
176 | char *sRet = s; | |
177 | s = 0; | |
178 | sSize = 0; | |
179 | sLen = 0; | |
180 | return sRet; | |
181 | } | |
182 | char operator[](int i) const { | |
183 | if (s && i < sSize) // Or < sLen? Depends on the use, both are OK | |
184 | return s[i]; | |
185 | else | |
186 | return '\0'; | |
187 | } | |
188 | SString &append(const char* sOther, int sLenOther=-1, char sep=0) { | |
189 | if (sLenOther < 0) | |
190 | sLenOther = strlen(sOther); | |
191 | int lenSep = 0; | |
192 | if (sLen && sep) // Only add a separator if not empty | |
193 | lenSep = 1; | |
194 | int lenNew = sLen + sLenOther + lenSep; | |
195 | if (lenNew + 1 < sSize) { | |
196 | // Conservative about growing the buffer: don't do it, unless really needed | |
197 | if (lenSep) { | |
198 | s[sLen] = sep; | |
199 | sLen++; | |
200 | } | |
201 | strncpy(&s[sLen], sOther, sLenOther); | |
202 | s[sLen + sLenOther] = '\0'; | |
203 | sLen += sLenOther; | |
204 | } else { | |
205 | // Grow the buffer bigger than really needed, to have room for other appends | |
206 | char *sNew = new char[lenNew + sizeGrowth + 1]; | |
207 | if (sNew) { | |
208 | if (s) { | |
209 | memcpy(sNew, s, sLen); | |
210 | delete []s; | |
211 | } | |
212 | s = sNew; | |
213 | sSize = lenNew + sizeGrowth; | |
214 | if (lenSep) { | |
215 | s[sLen] = sep; | |
216 | sLen++; | |
217 | } | |
218 | strncpy(&s[sLen], sOther, sLenOther); | |
219 | sNew[sLen + sLenOther] = '\0'; | |
220 | sLen += sLenOther; | |
221 | } | |
222 | } | |
223 | return *this; | |
224 | } | |
225 | SString &operator +=(const char *sOther) { | |
226 | return append(sOther, -1); | |
227 | } | |
228 | SString &operator +=(const SString &sOther) { | |
229 | return append(sOther.s, sOther.sSize); | |
230 | } | |
231 | SString &operator +=(char ch) { | |
232 | return append(&ch, 1); | |
233 | } | |
234 | SString &appendwithseparator(const char* sOther, char sep) { | |
235 | return append(sOther, strlen(sOther), sep); | |
236 | } | |
237 | int value() const { | |
238 | if (s) | |
239 | return atoi(s); | |
240 | else | |
241 | return 0; | |
242 | } | |
243 | void substitute(char find, char replace) { | |
244 | char *t = s; | |
245 | while (t) { | |
246 | t = strchr(t, find); | |
247 | if (t) { | |
248 | *t = replace; | |
249 | t++; | |
250 | } | |
251 | } | |
252 | } | |
253 | }; | |
254 | ||
255 | #endif |