src/str.cc

changeset 88
5def6ff8b466
parent 87
8f65914e7046
child 89
029a330a9bef
equal deleted inserted replaced
87:8f65914e7046 88:5def6ff8b466
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 "str.h"
32
33 // =============================================================================
34 //
35 int string::compare (const string& other) const
36 {
37 return m_string.compare (other.std_string());
38 }
39
40 // =============================================================================
41 //
42 void string::trim (string::length_type n)
43 {
44 if (n > 0)
45 m_string = substring (0, length() - n).std_string();
46 else
47 m_string = substring (n, -1).std_string();
48 }
49
50 // =============================================================================
51 //
52 string string::strip (list<char> unwanted)
53 {
54 string copy (m_string);
55
56 for (char c : unwanted)
57 for (int i = 0; i < copy.length(); ++i)
58 if (copy[i] == c)
59 copy.erase (i);
60
61 /*
62 while(( pos = copy.first( c )) != -1 )
63 copy.erase( pos );
64 */
65
66 return copy;
67 }
68
69 // =============================================================================
70 //
71 string string::to_uppercase() const
72 {
73 string newstr = m_string;
74
75 for (char& c : newstr)
76 if (c >= 'a' && c <= 'z')
77 c -= 'a' - 'A';
78
79 return newstr;
80 }
81
82 // =============================================================================
83 //
84 string string::to_lowercase() const
85 {
86 string newstr = m_string;
87
88 for (char & c : newstr)
89 if (c >= 'A' && c <= 'Z')
90 c += 'a' - 'A';
91
92 return newstr;
93 }
94
95 // =============================================================================
96 //
97 string_list string::split (char del) const
98 {
99 string delimstr;
100 delimstr += del;
101 return split (delimstr);
102 }
103
104 // =============================================================================
105 //
106 string_list string::split (string del) const
107 {
108 string_list res;
109 long a = 0;
110
111 // Find all separators and store the text left to them.
112 for (;;)
113 {
114 long b = first (del, a);
115
116 if (b == -1)
117 break;
118
119 string sub = substring (a, b);
120
121 if (sub.length() > 0)
122 res.push_back (substring (a, b));
123
124 a = b + strlen (del);
125 }
126
127 // Add the string at the right of the last separator
128 if (a < (int) length())
129 res.push_back (substring (a, length()));
130
131 return res;
132 }
133
134 // =============================================================================
135 //
136 void string::replace (const char* a, const char* b)
137 {
138 long pos;
139
140 while ( (pos = first (a)) != -1)
141 m_string = m_string.replace (pos, strlen (a), b);
142 }
143
144 // =============================================================================
145 //
146 int string::count (const char needle) const
147 {
148 int needles = 0;
149
150 for (const char & c : m_string)
151 if (c == needle)
152 needles++;
153
154 return needles;
155 }
156
157 // =============================================================================
158 //
159 string string::substring (long a, long b) const
160 {
161 if (b == -1)
162 b = length();
163
164 if (b == a)
165 return "";
166
167 if (b < a)
168 {
169 // Swap the variables
170 int c = a;
171 a = b;
172 b = c;
173 }
174
175 char* newstr = new char[b - a + 1];
176 strncpy (newstr, m_string.c_str() + a, b - a);
177 newstr[b - a] = '\0';
178
179 string other (newstr);
180 delete[] newstr;
181 return other;
182 }
183
184 // =============================================================================
185 //
186 string::length_type string::posof (int n) const
187 {
188 int count = 0;
189
190 for (int i = 0; i < length(); ++i)
191 {
192 if (m_string[i] != ' ')
193 continue;
194
195 if (++count < n)
196 continue;
197
198 return i;
199 }
200
201 return -1;
202 }
203
204 // =============================================================================
205 //
206 int string::first (const char* c, string::length_type a) const
207 {
208 for (; a < length(); a++)
209 if (m_string[a] == c[0] && strncmp (m_string.c_str() + a, c, strlen (c)) == 0)
210 return a;
211
212 return -1;
213 }
214
215 // =============================================================================
216 //
217 int string::last (const char* c, string::length_type a) const
218 {
219 if (a == -1 || a >= length())
220 a = length() - 1;
221
222 for (; a > 0; a--)
223 if (m_string[a] == c[0] && strncmp (m_string.c_str() + a, c, strlen (c)) == 0)
224 return a;
225
226 return -1;
227 }
228
229 // =============================================================================
230 //
231 void string::dump() const
232 {
233 print ("`%1`:\n", chars());
234 int i = 0;
235
236 for (char u : m_string)
237 print ("\t%1. [%d2] `%3`\n", i++, u, string (u));
238 }
239
240 // =============================================================================
241 //
242 long string::to_long (bool* ok, int base) const
243 {
244 errno = 0;
245 char* endptr;
246 long i = strtol (m_string.c_str(), &endptr, base);
247
248 if (ok)
249 *ok = (errno == 0 && *endptr == '\0');
250
251 return i;
252 }
253
254 // =============================================================================
255 //
256 float string::to_float (bool* ok) const
257 {
258 errno = 0;
259 char* endptr;
260 float i = strtof (m_string.c_str(), &endptr);
261
262 if (ok)
263 *ok = (errno == 0 && *endptr == '\0');
264
265 return i;
266 }
267
268 // =============================================================================
269 //
270 double string::to_double (bool* ok) const
271 {
272 errno = 0;
273 char* endptr;
274 double i = strtod (m_string.c_str(), &endptr);
275
276 if (ok)
277 *ok = (errno == 0 && *endptr == '\0');
278
279 return i;
280 }
281
282 // =============================================================================
283 //
284 bool operator== (const char* a, const string& b)
285 {
286 return b == a;
287 }
288
289 // =============================================================================
290 //
291 string operator+ (const char* a, const string& b)
292 {
293 return string (a) + b;
294 }
295
296 // =============================================================================
297 //
298 string string::operator+ (const string& data) const
299 {
300 string newString = *this;
301 newString += data;
302 return newString;
303 }
304
305 // =============================================================================
306 //
307 string string::operator+ (const char* data) const
308 {
309 string newstr = *this;
310 newstr += data;
311 return newstr;
312 }
313
314 // =============================================================================
315 //
316 string string::operator+ (int num) const
317 {
318 string newstr = *this;
319 string numstr;
320 numstr.sprintf ("%d", num);
321 newstr += numstr;
322 return newstr;
323 }
324
325 // =============================================================================
326 //
327 string& string::operator+= (const string data)
328 {
329 append (data);
330 return *this;
331 }
332
333 // =============================================================================
334 //
335 string& string::operator+= (const char* data)
336 {
337 append (data);
338 return *this;
339 }
340
341 // =============================================================================
342 //
343 string& string::operator+= (int num)
344 {
345 string numstr;
346 numstr.sprintf ("%d", num);
347 return operator+= (numstr);
348 }
349
350 // =============================================================================
351 //
352 bool string::is_numeric() const
353 {
354 bool gotDot = false;
355
356 for (const char & c : m_string)
357 {
358 // Allow leading hyphen for negatives
359 if (&c == &m_string[0] && c == '-')
360 continue;
361
362 // Check for decimal point
363 if (!gotDot && c == '.')
364 {
365 gotDot = true;
366 continue;
367 }
368
369 if (c >= '0' && c <= '9')
370 continue; // Digit
371
372 // If the above cases didn't catch this character, it was
373 // illegal and this is therefore not a number.
374 return false;
375 }
376
377 return true;
378 }
379
380 // =============================================================================
381 //
382 bool string::ends_with (const string& other)
383 {
384 if (length() < other.length())
385 return false;
386
387 const int ofs = length() - other.length();
388 return strncmp (chars() + ofs, other.chars(), other.length()) == 0;
389 }
390
391 // =============================================================================
392 //
393 bool string::starts_with (const string& other)
394 {
395 if (length() < other.length())
396 return false;
397
398 return strncmp (chars(), other.chars(), other.length()) == 0;
399 }
400
401 // =============================================================================
402 //
403 void string::sprintf (const char* fmtstr, ...)
404 {
405 char* buf;
406 int bufsize = 256;
407 va_list va;
408 va_start (va, fmtstr);
409
410 do
411 buf = new char[bufsize];
412
413 while (vsnprintf (buf, bufsize, fmtstr, va) >= bufsize);
414
415 va_end (va);
416 m_string = buf;
417 delete[] buf;
418 }
419
420 // =============================================================================
421 //
422 void string::prepend (string a)
423 {
424 m_string = (a + m_string).std_string();
425 }
426
427 // =============================================================================
428 //
429 string string_list::join (const string& delim)
430 {
431 string result;
432
433 for (const string & it : std_deque())
434 {
435 if (!result.is_empty())
436 result += delim;
437
438 result += it;
439 }
440
441 return result;
442 }
443
444 // =============================================================================
445 //
446 bool string::mask (const string& pattern) const
447 {
448 // Elevate to uppercase for case-insensitive matching
449 string pattern_upper = pattern.to_uppercase();
450 string this_upper = to_uppercase();
451 const char* maskstring = pattern_upper.chars();
452 const char* mptr = &maskstring[0];
453
454 for (const char* sptr = this_upper.chars(); *sptr != '\0'; sptr++)
455 {
456 if (*mptr == '?')
457 {
458 if (* (sptr + 1) == '\0')
459 {
460 // ? demands that there's a character here and there wasn't.
461 // Therefore, mask matching fails
462 return false;
463 }
464 }
465
466 elif (*mptr == '*')
467 {
468 char end = * (++mptr);
469
470 // If '*' is the final character of the message, all of the remaining
471 // string matches against the '*'. We don't need to bother checking
472 // the string any further.
473 if (end == '\0')
474 return true;
475
476 // Skip to the end character
477 while (*sptr != end && *sptr != '\0')
478 sptr++;
479
480 // String ended while the mask still had stuff
481 if (*sptr == '\0')
482 return false;
483 }
484 elif (*sptr != *mptr)
485 return false;
486
487 mptr++;
488 }
489
490 return true;
491 }
492
493 // =============================================================================
494 //
495 string string::from_number (int a)
496 {
497 char buf[32];
498 ::sprintf (buf, "%d", a);
499 return string (buf);
500 }
501
502 // =============================================================================
503 //
504 string string::from_number (long a)
505 {
506 char buf[32];
507 ::sprintf (buf, "%ld", a);
508 return string (buf);
509 }

mercurial