Sun, 02 Feb 2014 18:07:06 +0200
- blargh. buffers weren't initialized properly
88 | 1 | /* |
2 | Copyright 2012-2014 Santeri Piippo | |
3 | All rights reserved. | |
4 | ||
5 | Redistribution and use in source and binary forms, with or without | |
6 | modification, are permitted provided that the following conditions | |
7 | are met: | |
8 | ||
9 | 1. Redistributions of source code must retain the above copyright | |
10 | notice, this list of conditions and the following disclaimer. | |
11 | 2. Redistributions in binary form must reproduce the above copyright | |
12 | notice, this list of conditions and the following disclaimer in the | |
13 | documentation and/or other materials provided with the distribution. | |
14 | 3. The name of the author may not be used to endorse or promote products | |
15 | derived from this software without specific prior written permission. | |
16 | ||
17 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
18 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
19 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
20 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
22 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | |
28 | ||
29 | #include <cstring> | |
30 | #include "Main.h" | |
31 | #include "String.h" | |
32 | ||
33 | // ============================================================================= | |
34 | // | |
35 | int String::Compare (const String& other) const | |
36 | { | |
37 | return mString.compare (other.STDString()); | |
38 | } | |
39 | ||
40 | // ============================================================================= | |
41 | // | |
42 | void String::Trim (int n) | |
43 | { | |
44 | if (n > 0) | |
45 | mString = Mid (0, Length() - n).STDString(); | |
46 | else | |
47 | mString = Mid (n, -1).STDString(); | |
48 | } | |
49 | ||
50 | // ============================================================================= | |
51 | // | |
52 | String String::Strip (const List< char >& unwanted) | |
53 | { | |
54 | String copy (mString); | |
55 | ||
56 | for (char c : unwanted) | |
57 | for (int i = 0; i < copy.Length(); ++i) | |
58 | if (copy[i] == c) | |
59 | copy.RemoveAt (i); | |
60 | ||
61 | /* | |
89
029a330a9bef
- blargh. buffers weren't initialized properly
Teemu Piippo <crimsondusk64@gmail.com>
parents:
88
diff
changeset
|
62 | int pos = 0; |
029a330a9bef
- blargh. buffers weren't initialized properly
Teemu Piippo <crimsondusk64@gmail.com>
parents:
88
diff
changeset
|
63 | while ((pos = copy.First (c)) != -1) |
029a330a9bef
- blargh. buffers weren't initialized properly
Teemu Piippo <crimsondusk64@gmail.com>
parents:
88
diff
changeset
|
64 | copy.RemoveAt (pos--); |
88 | 65 | */ |
66 | ||
67 | return copy; | |
68 | } | |
69 | ||
70 | // ============================================================================= | |
71 | // | |
72 | String String::ToUppercase() const | |
73 | { | |
74 | String newstr = mString; | |
75 | ||
89
029a330a9bef
- blargh. buffers weren't initialized properly
Teemu Piippo <crimsondusk64@gmail.com>
parents:
88
diff
changeset
|
76 | for (char& c : newstr) |
88 | 77 | if (c >= 'a' && c <= 'z') |
78 | c -= 'a' - 'A'; | |
79 | ||
80 | return newstr; | |
81 | } | |
82 | ||
83 | // ============================================================================= | |
84 | // | |
85 | String String::ToLowercase() const | |
86 | { | |
87 | String newstr = mString; | |
88 | ||
89 | for (char & c : newstr) | |
90 | if (c >= 'A' && c <= 'Z') | |
91 | c += 'a' - 'A'; | |
92 | ||
93 | return newstr; | |
94 | } | |
95 | ||
96 | // ============================================================================= | |
97 | // | |
98 | StringList String::Split (char del) const | |
99 | { | |
100 | String delimstr; | |
101 | delimstr += del; | |
102 | return Split (delimstr); | |
103 | } | |
104 | ||
105 | // ============================================================================= | |
106 | // | |
107 | StringList String::Split (String del) const | |
108 | { | |
109 | StringList res; | |
110 | long a = 0; | |
111 | ||
112 | // Find all separators and store the text left to them. | |
113 | for (;;) | |
114 | { | |
115 | long b = FirstIndexOf (del, a); | |
116 | ||
117 | if (b == -1) | |
118 | break; | |
119 | ||
120 | String sub = Mid (a, b); | |
121 | ||
122 | if (sub.Length() > 0) | |
123 | res.Append (Mid (a, b)); | |
124 | ||
125 | a = b + del.Length(); | |
126 | } | |
127 | ||
128 | // Add the string at the right of the last separator | |
129 | if (a < (int) Length()) | |
130 | res.Append (Mid (a, Length())); | |
131 | ||
132 | return res; | |
133 | } | |
134 | ||
135 | // ============================================================================= | |
136 | // | |
137 | void String::Replace (const char* a, const char* b) | |
138 | { | |
139 | long pos; | |
140 | ||
141 | while ( (pos = FirstIndexOf (a)) != -1) | |
142 | mString = mString.replace (pos, strlen (a), b); | |
143 | } | |
144 | ||
145 | // ============================================================================= | |
146 | // | |
147 | int String::Count (char needle) const | |
148 | { | |
149 | int needles = 0; | |
150 | ||
151 | for (const char & c : mString) | |
152 | if (c == needle) | |
153 | needles++; | |
154 | ||
155 | return needles; | |
156 | } | |
157 | ||
158 | // ============================================================================= | |
159 | // | |
160 | String String::Mid (long a, long b) const | |
161 | { | |
162 | if (b == -1) | |
163 | b = Length(); | |
164 | ||
165 | if (b == a) | |
166 | return ""; | |
167 | ||
168 | if (b < a) | |
169 | { | |
170 | // Swap the variables | |
171 | int c = a; | |
172 | a = b; | |
173 | b = c; | |
174 | } | |
175 | ||
176 | char* newstr = new char[b - a + 1]; | |
177 | strncpy (newstr, mString.c_str() + a, b - a); | |
178 | newstr[b - a] = '\0'; | |
179 | ||
180 | String other (newstr); | |
181 | delete[] newstr; | |
182 | return other; | |
183 | } | |
184 | ||
185 | // ============================================================================= | |
186 | // | |
187 | int String::WordPosition (int n) const | |
188 | { | |
189 | int count = 0; | |
190 | ||
191 | for (int i = 0; i < Length(); ++i) | |
192 | { | |
193 | if (mString[i] != ' ') | |
194 | continue; | |
195 | ||
196 | if (++count < n) | |
197 | continue; | |
198 | ||
199 | return i; | |
200 | } | |
201 | ||
202 | return -1; | |
203 | } | |
204 | ||
205 | // ============================================================================= | |
206 | // | |
207 | int String::FirstIndexOf (const char* c, int a) const | |
208 | { | |
209 | for (; a < Length(); a++) | |
210 | if (mString[a] == c[0] && strncmp (mString.c_str() + a, c, strlen (c)) == 0) | |
211 | return a; | |
212 | ||
213 | return -1; | |
214 | } | |
215 | ||
216 | // ============================================================================= | |
217 | // | |
218 | int String::LastIndexOf (const char* c, int a) const | |
219 | { | |
220 | if (a == -1 || a >= Length()) | |
221 | a = Length() - 1; | |
222 | ||
223 | for (; a > 0; a--) | |
224 | if (mString[a] == c[0] && strncmp (mString.c_str() + a, c, strlen (c)) == 0) | |
225 | return a; | |
226 | ||
227 | return -1; | |
228 | } | |
229 | ||
230 | // ============================================================================= | |
231 | // | |
232 | void String::Dump() const | |
233 | { | |
234 | Print ("`%1`:\n", CString()); | |
235 | int i = 0; | |
236 | ||
237 | for (char u : mString) | |
238 | Print ("\t%1. [%d2] `%3`\n", i++, u, String (u)); | |
239 | } | |
240 | ||
241 | // ============================================================================= | |
242 | // | |
243 | long String::ToLong (bool* ok, int base) const | |
244 | { | |
245 | errno = 0; | |
246 | char* endptr; | |
247 | long i = strtol (mString.c_str(), &endptr, base); | |
248 | ||
249 | if (ok) | |
250 | *ok = (errno == 0 && *endptr == '\0'); | |
251 | ||
252 | return i; | |
253 | } | |
254 | ||
255 | // ============================================================================= | |
256 | // | |
257 | float String::ToFloat (bool* ok) const | |
258 | { | |
259 | errno = 0; | |
260 | char* endptr; | |
261 | float i = strtof (mString.c_str(), &endptr); | |
262 | ||
263 | if (ok) | |
264 | *ok = (errno == 0 && *endptr == '\0'); | |
265 | ||
266 | return i; | |
267 | } | |
268 | ||
269 | // ============================================================================= | |
270 | // | |
271 | double String::ToDouble (bool* ok) const | |
272 | { | |
273 | errno = 0; | |
274 | char* endptr; | |
275 | double i = strtod (mString.c_str(), &endptr); | |
276 | ||
277 | if (ok) | |
278 | *ok = (errno == 0 && *endptr == '\0'); | |
279 | ||
280 | return i; | |
281 | } | |
282 | ||
283 | // ============================================================================= | |
284 | // | |
285 | String String::operator+ (const String& data) const | |
286 | { | |
287 | String newString = *this; | |
288 | newString.Append (data); | |
289 | return newString; | |
290 | } | |
291 | ||
292 | // ============================================================================= | |
293 | // | |
294 | String String::operator+ (const char* data) const | |
295 | { | |
296 | String newstr = *this; | |
297 | newstr.Append (data); | |
298 | return newstr; | |
299 | } | |
300 | ||
301 | // ============================================================================= | |
302 | // | |
303 | bool String::IsNumeric() const | |
304 | { | |
305 | bool gotDot = false; | |
306 | ||
307 | for (const char & c : mString) | |
308 | { | |
309 | // Allow leading hyphen for negatives | |
310 | if (&c == &mString[0] && c == '-') | |
311 | continue; | |
312 | ||
313 | // Check for decimal point | |
314 | if (!gotDot && c == '.') | |
315 | { | |
316 | gotDot = true; | |
317 | continue; | |
318 | } | |
319 | ||
320 | if (c >= '0' && c <= '9') | |
321 | continue; // Digit | |
322 | ||
323 | // If the above cases didn't catch this character, it was | |
324 | // illegal and this is therefore not a number. | |
325 | return false; | |
326 | } | |
327 | ||
328 | return true; | |
329 | } | |
330 | ||
331 | // ============================================================================= | |
332 | // | |
333 | bool String::EndsWith (const String& other) | |
334 | { | |
335 | if (Length() < other.Length()) | |
336 | return false; | |
337 | ||
338 | const int ofs = Length() - other.Length(); | |
339 | return strncmp (CString() + ofs, other.CString(), other.Length()) == 0; | |
340 | } | |
341 | ||
342 | // ============================================================================= | |
343 | // | |
344 | bool String::StartsWith (const String& other) | |
345 | { | |
346 | if (Length() < other.Length()) | |
347 | return false; | |
348 | ||
349 | return strncmp (CString(), other.CString(), other.Length()) == 0; | |
350 | } | |
351 | ||
352 | // ============================================================================= | |
353 | // | |
354 | void String::SPrintf (const char* fmtstr, ...) | |
355 | { | |
356 | char* buf; | |
357 | int bufsize = 256; | |
358 | va_list va; | |
359 | va_start (va, fmtstr); | |
360 | ||
361 | do | |
362 | buf = new char[bufsize]; | |
363 | while (vsnprintf (buf, bufsize, fmtstr, va) >= bufsize); | |
364 | ||
365 | va_end (va); | |
366 | mString = buf; | |
367 | delete[] buf; | |
368 | } | |
369 | ||
370 | // ============================================================================= | |
371 | // | |
372 | String StringList::Join (const String& delim) | |
373 | { | |
374 | String result; | |
375 | ||
376 | for (const String& it : GetDeque()) | |
377 | { | |
378 | if (result.IsEmpty() == false) | |
379 | result += delim; | |
380 | ||
381 | result += it; | |
382 | } | |
383 | ||
384 | return result; | |
385 | } | |
386 | ||
387 | // ============================================================================= | |
388 | // | |
389 | bool String::MaskAgainst (const String& pattern) const | |
390 | { | |
391 | // Elevate to uppercase for case-insensitive matching | |
392 | String pattern_upper = pattern.ToUppercase(); | |
393 | String this_upper = ToUppercase(); | |
394 | const char* maskstring = pattern_upper.CString(); | |
395 | const char* mptr = &maskstring[0]; | |
396 | ||
397 | for (const char* sptr = this_upper.CString(); *sptr != '\0'; sptr++) | |
398 | { | |
399 | if (*mptr == '?') | |
400 | { | |
401 | if (*(sptr + 1) == '\0') | |
402 | { | |
403 | // ? demands that there's a character here and there wasn't. | |
404 | // Therefore, mask matching fails | |
405 | return false; | |
406 | } | |
407 | } | |
408 | elif (*mptr == '*') | |
409 | { | |
410 | char end = *(++mptr); | |
411 | ||
412 | // If '*' is the final character of the message, all of the remaining | |
413 | // string matches against the '*'. We don't need to bother checking | |
414 | // the string any further. | |
415 | if (end == '\0') | |
416 | return true; | |
417 | ||
418 | // Skip to the end character | |
419 | while (*sptr != end && *sptr != '\0') | |
420 | sptr++; | |
421 | ||
422 | // String ended while the mask still had stuff | |
423 | if (*sptr == '\0') | |
424 | return false; | |
425 | } | |
426 | elif (*sptr != *mptr) | |
427 | return false; | |
428 | ||
429 | mptr++; | |
430 | } | |
431 | ||
432 | return true; | |
433 | } | |
434 | ||
435 | // ============================================================================= | |
436 | // | |
437 | String String::FromNumber (int a) | |
438 | { | |
439 | char buf[32]; | |
440 | sprintf (buf, "%d", a); | |
441 | return String (buf); | |
442 | } | |
443 | ||
444 | // ============================================================================= | |
445 | // | |
446 | String String::FromNumber (long a) | |
447 | { | |
448 | char buf[32]; | |
449 | sprintf (buf, "%ld", a); | |
450 | return String (buf); | |
451 | } |