sources/mystring.cpp

changeset 1
4dd5bde4e777
child 5
146825d63b9a
equal deleted inserted replaced
0:792876306489 1:4dd5bde4e777
1 /*
2 Copyright 2014 Teemu 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. Neither the name of the copyright holder nor the names of its
15 contributors may be used to endorse or promote products derived from
16 this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
22 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <cstring>
32 #include "main.h"
33 #include "mystring.h"
34 #include "format.h"
35
36 // -------------------------------------------------------------------------------------------------
37
38 METHOD
39 String::compare (const String& other) const -> int
40 {
41 return m_string.compare (other.std_string());
42 }
43
44 // -------------------------------------------------------------------------------------------------
45
46 METHOD
47 String::trim (int n) -> void
48 {
49 if (n > 0)
50 m_string = mid (0, length() - n).std_string();
51 else
52 m_string = mid (n, -1).std_string();
53 }
54
55 // -------------------------------------------------------------------------------------------------
56
57 METHOD
58 String::strip (const List<char>& unwanted) -> String
59 {
60 String copy (m_string);
61
62 for (char c : unwanted)
63 {
64 for (int pos = 0; (pos = copy.find (String (c))) != -1;)
65 copy.remove (pos--);
66 }
67
68 return copy;
69 }
70
71 // -------------------------------------------------------------------------------------------------
72
73 METHOD
74 String::to_uppercase() const -> String
75 {
76 String newstr (m_string);
77
78 for (char& c : newstr)
79 {
80 if (c >= 'a' and c <= 'z')
81 c -= 'a' - 'A';
82 }
83
84 return newstr;
85 }
86
87 // -------------------------------------------------------------------------------------------------
88
89 METHOD
90 String::to_lowercase() const -> String
91 {
92 String newstr (m_string);
93
94 for (char& c : newstr)
95 {
96 if (c >= 'A' and c <= 'Z')
97 c += 'a' - 'A';
98 }
99
100 return newstr;
101 }
102
103 // -------------------------------------------------------------------------------------------------
104
105 METHOD
106 String::split (char del) const -> StringList
107 {
108 String delimstr;
109 delimstr += del;
110 return split (delimstr);
111 }
112
113 // -------------------------------------------------------------------------------------------------
114
115 METHOD
116 String::split (const String& del) const -> StringList
117 {
118 StringList res;
119 int a = 0;
120 int b;
121
122 // Find all separators and store the text left to them.
123 while ((b = find (del, a)) != -1)
124 {
125 String sub = mid (a, b);
126
127 if (sub.length() > 0)
128 res << sub;
129
130 a = b + del.length();
131 }
132
133 // Add the string at the right of the last separator
134 if (a < (int) length())
135 res.append (mid (a, length()));
136
137 return res;
138 }
139
140 // -------------------------------------------------------------------------------------------------
141
142 METHOD
143 String::replace (const char* a, const char* b) -> void
144 {
145 long pos;
146
147 while ((pos = find (a)) != -1)
148 m_string = m_string.replace (pos, strlen (a), b);
149 }
150
151 // -------------------------------------------------------------------------------------------------
152
153 METHOD
154 String::count (char needle) const -> int
155 {
156 int needles = 0;
157
158 for (const char & c : m_string)
159 if (c == needle)
160 needles++;
161
162 return needles;
163 }
164
165 // -------------------------------------------------------------------------------------------------
166
167 METHOD
168 String::mid (long a, long b) const -> String
169 {
170 if (b == -1 or b > length())
171 b = length();
172
173 if (b == a)
174 return "";
175
176 if (b < a)
177 swap (a, b);
178
179 if (a == 0 and b == length())
180 return *this;
181
182 char* newstr = new char[b - a + 1];
183 strncpy (newstr, chars() + a, b - a);
184 newstr[b - a] = '\0';
185 String other (newstr);
186 delete[] newstr;
187 return other;
188 }
189
190 // -------------------------------------------------------------------------------------------------
191
192 METHOD
193 String::word_position (int n) const -> int
194 {
195 int count = 0;
196
197 for (int i = 0; i < length(); ++i)
198 {
199 if (m_string[i] != ' ')
200 continue;
201
202 if (++count < n)
203 continue;
204
205 return i;
206 }
207
208 return -1;
209 }
210
211 // -------------------------------------------------------------------------------------------------
212
213 METHOD
214 String::find (const char* c, int a) const -> int
215 {
216 int pos = m_string.find (c, a);
217
218 if (pos == int (std::string::npos))
219 return -1;
220
221 return pos;
222 }
223
224 // -------------------------------------------------------------------------------------------------
225
226 METHOD
227 String::find_last (const char* c, int a) const -> int
228 {
229 if (a == -1 or a >= length())
230 a = length() - 1;
231
232 for (; a > 0; a--)
233 if (m_string[a] == c[0] and strncmp (chars() + a, c, strlen (c)) == 0)
234 return a;
235
236 return -1;
237 }
238
239 // -------------------------------------------------------------------------------------------------
240
241 METHOD
242 String::to_int (bool* ok, int base) const -> long
243 {
244 errno = 0;
245 char* endptr;
246 long i = strtol (chars(), &endptr, base);
247
248 if (ok)
249 *ok = (errno == 0 and *endptr == '\0');
250
251 return i;
252 }
253
254 // -------------------------------------------------------------------------------------------------
255
256 METHOD
257 String::to_float (bool* ok) const -> float
258 {
259 errno = 0;
260 char* endptr;
261 float i = strtof (chars(), &endptr);
262
263 if (ok != nullptr)
264 *ok = (errno == 0 and *endptr == '\0');
265
266 return i;
267 }
268
269 // -------------------------------------------------------------------------------------------------
270
271 METHOD
272 String::to_double (bool* ok) const -> double
273 {
274 errno = 0;
275 char* endptr;
276 double i = strtod (chars(), &endptr);
277
278 if (ok != nullptr)
279 *ok = (errno == 0 and *endptr == '\0');
280
281 return i;
282 }
283
284 // -------------------------------------------------------------------------------------------------
285
286 METHOD
287 String::operator+ (const String& data) const -> String
288 {
289 String newString = *this;
290 newString.append (data);
291 return newString;
292 }
293
294 // -------------------------------------------------------------------------------------------------
295
296 METHOD
297 String::operator+ (const char* data) const -> String
298 {
299 String newstr = *this;
300 newstr.append (data);
301 return newstr;
302 }
303
304 // -------------------------------------------------------------------------------------------------
305
306 METHOD
307 String::is_numeric() const -> bool
308 {
309 bool gotDot = false;
310
311 for (const char & c : m_string)
312 {
313 // Allow leading hyphen for negatives
314 if (&c == &m_string[0] and c == '-')
315 continue;
316
317 // Check for decimal point
318 if (!gotDot and c == '.')
319 {
320 gotDot = true;
321 continue;
322 }
323
324 if (c >= '0' and c <= '9')
325 continue; // Digit
326
327 // If the above cases didn't catch this character, it was
328 // illegal and this is therefore not a number.
329 return false;
330 }
331
332 return true;
333 }
334
335 // -------------------------------------------------------------------------------------------------
336
337 METHOD
338 String::ends_with (const String& other) -> bool
339 {
340 if (length() < other.length())
341 return false;
342
343 const int ofs = length() - other.length();
344 return strncmp (chars() + ofs, other.chars(), other.length()) == 0;
345 }
346
347 // -------------------------------------------------------------------------------------------------
348
349 METHOD
350 String::starts_with (const String& other) -> bool
351 {
352 if (length() < other.length())
353 return false;
354
355 return strncmp (chars(), other.chars(), other.length()) == 0;
356 }
357
358 // -------------------------------------------------------------------------------------------------
359
360 METHOD
361 String::sprintf (const char* fmtstr, ...) -> void
362 {
363 char* buf;
364 int bufsize = 256;
365 va_list va;
366 va_start (va, fmtstr);
367
368 do
369 buf = new char[bufsize];
370 while (vsnprintf (buf, bufsize, fmtstr, va) >= bufsize);
371
372 va_end (va);
373 m_string = buf;
374 delete[] buf;
375 }
376
377 // -------------------------------------------------------------------------------------------------
378
379 METHOD
380 StringList::join (const String& delim) -> String
381 {
382 String result;
383
384 for (const String& it : container())
385 {
386 if (result.is_empty() == false)
387 result += delim;
388
389 result += it;
390 }
391
392 return result;
393 }
394
395 // -------------------------------------------------------------------------------------------------
396
397 METHOD
398 String::mask_against (const String& pattern) const -> bool
399 {
400 // Elevate to uppercase for case-insensitive matching
401 String pattern_upper = pattern.to_uppercase();
402 String this_upper = to_uppercase();
403 const char* maskstring = pattern_upper.chars();
404 const char* mptr = &maskstring[0];
405
406 for (const char* sptr = this_upper.chars(); *sptr != '\0'; sptr++)
407 {
408 if (*mptr == '?')
409 {
410 if (*(sptr + 1) == '\0')
411 {
412 // ? demands that there's a character here and there wasn't.
413 // Therefore, mask matching fails
414 return false;
415 }
416 }
417 else if (*mptr == '*')
418 {
419 char end = *(++mptr);
420
421 // If '*' is the final character of the message, all of the remaining
422 // string matches against the '*'. We don't need to bother checking
423 // the string any further.
424 if (end == '\0')
425 return true;
426
427 // Skip to the end character
428 while (*sptr != end and *sptr != '\0')
429 sptr++;
430
431 // String ended while the mask still had stuff
432 if (*sptr == '\0')
433 return false;
434 }
435 else if (*sptr != *mptr)
436 return false;
437
438 mptr++;
439 }
440
441 return true;
442 }
443
444 // -------------------------------------------------------------------------------------------------
445
446 METHOD
447 String::from_number (int a) -> String
448 {
449 char buf[32];
450 ::sprintf (buf, "%d", a);
451 return String (buf);
452 }
453
454 // -------------------------------------------------------------------------------------------------
455
456 METHOD
457 String::from_number (long a) -> String
458 {
459 char buf[32];
460 ::sprintf (buf, "%ld", a);
461 return String (buf);
462 }
463
464 // -------------------------------------------------------------------------------------------------
465
466 METHOD
467 String::from_number (unsigned long a) -> String
468 {
469 char buf[32];
470 ::sprintf (buf, "%lu", a);
471 return String (buf);
472 }
473
474 // -------------------------------------------------------------------------------------------------
475
476 METHOD
477 String::from_number (double a) -> String
478 {
479 char buf[64];
480 ::sprintf (buf, "%f", a);
481 return String (buf);
482 }

mercurial