src/str.cc

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

mercurial