|
1 /* |
|
2 WString.cpp - String library for Wiring & Arduino |
|
3 ...mostly rewritten by Paul Stoffregen... |
|
4 Copyright (c) 2009-10 Hernando Barragan. All rights reserved. |
|
5 Copyright 2011, Paul Stoffregen, paul@pjrc.com |
|
6 |
|
7 This library is free software; you can redistribute it and/or |
|
8 modify it under the terms of the GNU Lesser General Public |
|
9 License as published by the Free Software Foundation; either |
|
10 version 2.1 of the License, or (at your option) any later version. |
|
11 |
|
12 This library is distributed in the hope that it will be useful, |
|
13 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
15 Lesser General Public License for more details. |
|
16 |
|
17 You should have received a copy of the GNU Lesser General Public |
|
18 License along with this library; if not, write to the Free Software |
|
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|
20 */ |
|
21 |
|
22 #include "WString.h" |
|
23 |
|
24 |
|
25 /*********************************************/ |
|
26 /* Constructors */ |
|
27 /*********************************************/ |
|
28 |
|
29 String::String(const char *cstr) |
|
30 { |
|
31 init(); |
|
32 if (cstr) copy(cstr, strlen(cstr)); |
|
33 } |
|
34 |
|
35 String::String(const String &value) |
|
36 { |
|
37 init(); |
|
38 *this = value; |
|
39 } |
|
40 |
|
41 #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
|
42 String::String(String &&rval) |
|
43 { |
|
44 init(); |
|
45 move(rval); |
|
46 } |
|
47 String::String(StringSumHelper &&rval) |
|
48 { |
|
49 init(); |
|
50 move(rval); |
|
51 } |
|
52 #endif |
|
53 |
|
54 String::String(char c) |
|
55 { |
|
56 init(); |
|
57 char buf[2]; |
|
58 buf[0] = c; |
|
59 buf[1] = 0; |
|
60 *this = buf; |
|
61 } |
|
62 |
|
63 String::String(unsigned char value, unsigned char base) |
|
64 { |
|
65 init(); |
|
66 char buf[9]; |
|
67 utoa(value, buf, base); |
|
68 *this = buf; |
|
69 } |
|
70 |
|
71 String::String(int value, unsigned char base) |
|
72 { |
|
73 init(); |
|
74 char buf[18]; |
|
75 itoa(value, buf, base); |
|
76 *this = buf; |
|
77 } |
|
78 |
|
79 String::String(unsigned int value, unsigned char base) |
|
80 { |
|
81 init(); |
|
82 char buf[17]; |
|
83 utoa(value, buf, base); |
|
84 *this = buf; |
|
85 } |
|
86 |
|
87 String::String(long value, unsigned char base) |
|
88 { |
|
89 init(); |
|
90 char buf[34]; |
|
91 ltoa(value, buf, base); |
|
92 *this = buf; |
|
93 } |
|
94 |
|
95 String::String(unsigned long value, unsigned char base) |
|
96 { |
|
97 init(); |
|
98 char buf[33]; |
|
99 ultoa(value, buf, base); |
|
100 *this = buf; |
|
101 } |
|
102 |
|
103 String::~String() |
|
104 { |
|
105 free(buffer); |
|
106 } |
|
107 |
|
108 /*********************************************/ |
|
109 /* Memory Management */ |
|
110 /*********************************************/ |
|
111 |
|
112 inline void String::init(void) |
|
113 { |
|
114 buffer = NULL; |
|
115 capacity = 0; |
|
116 len = 0; |
|
117 flags = 0; |
|
118 } |
|
119 |
|
120 void String::invalidate(void) |
|
121 { |
|
122 if (buffer) free(buffer); |
|
123 buffer = NULL; |
|
124 capacity = len = 0; |
|
125 } |
|
126 |
|
127 unsigned char String::reserve(unsigned int size) |
|
128 { |
|
129 if (buffer && capacity >= size) return 1; |
|
130 if (changeBuffer(size)) { |
|
131 if (len == 0) buffer[0] = 0; |
|
132 return 1; |
|
133 } |
|
134 return 0; |
|
135 } |
|
136 |
|
137 unsigned char String::changeBuffer(unsigned int maxStrLen) |
|
138 { |
|
139 char *newbuffer = (char *)realloc(buffer, maxStrLen + 1); |
|
140 if (newbuffer) { |
|
141 buffer = newbuffer; |
|
142 capacity = maxStrLen; |
|
143 return 1; |
|
144 } |
|
145 return 0; |
|
146 } |
|
147 |
|
148 /*********************************************/ |
|
149 /* Copy and Move */ |
|
150 /*********************************************/ |
|
151 |
|
152 String & String::copy(const char *cstr, unsigned int length) |
|
153 { |
|
154 if (!reserve(length)) { |
|
155 invalidate(); |
|
156 return *this; |
|
157 } |
|
158 len = length; |
|
159 strcpy(buffer, cstr); |
|
160 return *this; |
|
161 } |
|
162 |
|
163 #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
|
164 void String::move(String &rhs) |
|
165 { |
|
166 if (buffer) { |
|
167 if (capacity >= rhs.len) { |
|
168 strcpy(buffer, rhs.buffer); |
|
169 len = rhs.len; |
|
170 rhs.len = 0; |
|
171 return; |
|
172 } else { |
|
173 free(buffer); |
|
174 } |
|
175 } |
|
176 buffer = rhs.buffer; |
|
177 capacity = rhs.capacity; |
|
178 len = rhs.len; |
|
179 rhs.buffer = NULL; |
|
180 rhs.capacity = 0; |
|
181 rhs.len = 0; |
|
182 } |
|
183 #endif |
|
184 |
|
185 String & String::operator = (const String &rhs) |
|
186 { |
|
187 if (this == &rhs) return *this; |
|
188 |
|
189 if (rhs.buffer) copy(rhs.buffer, rhs.len); |
|
190 else invalidate(); |
|
191 |
|
192 return *this; |
|
193 } |
|
194 |
|
195 #ifdef __GXX_EXPERIMENTAL_CXX0X__ |
|
196 String & String::operator = (String &&rval) |
|
197 { |
|
198 if (this != &rval) move(rval); |
|
199 return *this; |
|
200 } |
|
201 |
|
202 String & String::operator = (StringSumHelper &&rval) |
|
203 { |
|
204 if (this != &rval) move(rval); |
|
205 return *this; |
|
206 } |
|
207 #endif |
|
208 |
|
209 String & String::operator = (const char *cstr) |
|
210 { |
|
211 if (cstr) copy(cstr, strlen(cstr)); |
|
212 else invalidate(); |
|
213 |
|
214 return *this; |
|
215 } |
|
216 |
|
217 /*********************************************/ |
|
218 /* concat */ |
|
219 /*********************************************/ |
|
220 |
|
221 unsigned char String::concat(const String &s) |
|
222 { |
|
223 return concat(s.buffer, s.len); |
|
224 } |
|
225 |
|
226 unsigned char String::concat(const char *cstr, unsigned int length) |
|
227 { |
|
228 unsigned int newlen = len + length; |
|
229 if (!cstr) return 0; |
|
230 if (length == 0) return 1; |
|
231 if (!reserve(newlen)) return 0; |
|
232 strcpy(buffer + len, cstr); |
|
233 len = newlen; |
|
234 return 1; |
|
235 } |
|
236 |
|
237 unsigned char String::concat(const char *cstr) |
|
238 { |
|
239 if (!cstr) return 0; |
|
240 return concat(cstr, strlen(cstr)); |
|
241 } |
|
242 |
|
243 unsigned char String::concat(char c) |
|
244 { |
|
245 char buf[2]; |
|
246 buf[0] = c; |
|
247 buf[1] = 0; |
|
248 return concat(buf, 1); |
|
249 } |
|
250 |
|
251 unsigned char String::concat(unsigned char num) |
|
252 { |
|
253 char buf[4]; |
|
254 itoa(num, buf, 10); |
|
255 return concat(buf, strlen(buf)); |
|
256 } |
|
257 |
|
258 unsigned char String::concat(int num) |
|
259 { |
|
260 char buf[7]; |
|
261 itoa(num, buf, 10); |
|
262 return concat(buf, strlen(buf)); |
|
263 } |
|
264 |
|
265 unsigned char String::concat(unsigned int num) |
|
266 { |
|
267 char buf[6]; |
|
268 utoa(num, buf, 10); |
|
269 return concat(buf, strlen(buf)); |
|
270 } |
|
271 |
|
272 unsigned char String::concat(long num) |
|
273 { |
|
274 char buf[12]; |
|
275 ltoa(num, buf, 10); |
|
276 return concat(buf, strlen(buf)); |
|
277 } |
|
278 |
|
279 unsigned char String::concat(unsigned long num) |
|
280 { |
|
281 char buf[11]; |
|
282 ultoa(num, buf, 10); |
|
283 return concat(buf, strlen(buf)); |
|
284 } |
|
285 |
|
286 /*********************************************/ |
|
287 /* Concatenate */ |
|
288 /*********************************************/ |
|
289 |
|
290 StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs) |
|
291 { |
|
292 StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
|
293 if (!a.concat(rhs.buffer, rhs.len)) a.invalidate(); |
|
294 return a; |
|
295 } |
|
296 |
|
297 StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) |
|
298 { |
|
299 StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
|
300 if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate(); |
|
301 return a; |
|
302 } |
|
303 |
|
304 StringSumHelper & operator + (const StringSumHelper &lhs, char c) |
|
305 { |
|
306 StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
|
307 if (!a.concat(c)) a.invalidate(); |
|
308 return a; |
|
309 } |
|
310 |
|
311 StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num) |
|
312 { |
|
313 StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
|
314 if (!a.concat(num)) a.invalidate(); |
|
315 return a; |
|
316 } |
|
317 |
|
318 StringSumHelper & operator + (const StringSumHelper &lhs, int num) |
|
319 { |
|
320 StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
|
321 if (!a.concat(num)) a.invalidate(); |
|
322 return a; |
|
323 } |
|
324 |
|
325 StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num) |
|
326 { |
|
327 StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
|
328 if (!a.concat(num)) a.invalidate(); |
|
329 return a; |
|
330 } |
|
331 |
|
332 StringSumHelper & operator + (const StringSumHelper &lhs, long num) |
|
333 { |
|
334 StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
|
335 if (!a.concat(num)) a.invalidate(); |
|
336 return a; |
|
337 } |
|
338 |
|
339 StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) |
|
340 { |
|
341 StringSumHelper &a = const_cast<StringSumHelper&>(lhs); |
|
342 if (!a.concat(num)) a.invalidate(); |
|
343 return a; |
|
344 } |
|
345 |
|
346 /*********************************************/ |
|
347 /* Comparison */ |
|
348 /*********************************************/ |
|
349 |
|
350 int String::compareTo(const String &s) const |
|
351 { |
|
352 if (!buffer || !s.buffer) { |
|
353 if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer; |
|
354 if (buffer && len > 0) return *(unsigned char *)buffer; |
|
355 return 0; |
|
356 } |
|
357 return strcmp(buffer, s.buffer); |
|
358 } |
|
359 |
|
360 unsigned char String::equals(const String &s2) const |
|
361 { |
|
362 return (len == s2.len && compareTo(s2) == 0); |
|
363 } |
|
364 |
|
365 unsigned char String::equals(const char *cstr) const |
|
366 { |
|
367 if (len == 0) return (cstr == NULL || *cstr == 0); |
|
368 if (cstr == NULL) return buffer[0] == 0; |
|
369 return strcmp(buffer, cstr) == 0; |
|
370 } |
|
371 |
|
372 unsigned char String::operator<(const String &rhs) const |
|
373 { |
|
374 return compareTo(rhs) < 0; |
|
375 } |
|
376 |
|
377 unsigned char String::operator>(const String &rhs) const |
|
378 { |
|
379 return compareTo(rhs) > 0; |
|
380 } |
|
381 |
|
382 unsigned char String::operator<=(const String &rhs) const |
|
383 { |
|
384 return compareTo(rhs) <= 0; |
|
385 } |
|
386 |
|
387 unsigned char String::operator>=(const String &rhs) const |
|
388 { |
|
389 return compareTo(rhs) >= 0; |
|
390 } |
|
391 |
|
392 unsigned char String::equalsIgnoreCase( const String &s2 ) const |
|
393 { |
|
394 if (this == &s2) return 1; |
|
395 if (len != s2.len) return 0; |
|
396 if (len == 0) return 1; |
|
397 const char *p1 = buffer; |
|
398 const char *p2 = s2.buffer; |
|
399 while (*p1) { |
|
400 if (tolower(*p1++) != tolower(*p2++)) return 0; |
|
401 } |
|
402 return 1; |
|
403 } |
|
404 |
|
405 unsigned char String::startsWith( const String &s2 ) const |
|
406 { |
|
407 if (len < s2.len) return 0; |
|
408 return startsWith(s2, 0); |
|
409 } |
|
410 |
|
411 unsigned char String::startsWith( const String &s2, unsigned int offset ) const |
|
412 { |
|
413 if (offset > len - s2.len || !buffer || !s2.buffer) return 0; |
|
414 return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0; |
|
415 } |
|
416 |
|
417 unsigned char String::endsWith( const String &s2 ) const |
|
418 { |
|
419 if ( len < s2.len || !buffer || !s2.buffer) return 0; |
|
420 return strcmp(&buffer[len - s2.len], s2.buffer) == 0; |
|
421 } |
|
422 |
|
423 /*********************************************/ |
|
424 /* Character Access */ |
|
425 /*********************************************/ |
|
426 |
|
427 char String::charAt(unsigned int loc) const |
|
428 { |
|
429 return operator[](loc); |
|
430 } |
|
431 |
|
432 void String::setCharAt(unsigned int loc, char c) |
|
433 { |
|
434 if (loc < len) buffer[loc] = c; |
|
435 } |
|
436 |
|
437 char & String::operator[](unsigned int index) |
|
438 { |
|
439 static char dummy_writable_char; |
|
440 if (index >= len || !buffer) { |
|
441 dummy_writable_char = 0; |
|
442 return dummy_writable_char; |
|
443 } |
|
444 return buffer[index]; |
|
445 } |
|
446 |
|
447 char String::operator[]( unsigned int index ) const |
|
448 { |
|
449 if (index >= len || !buffer) return 0; |
|
450 return buffer[index]; |
|
451 } |
|
452 |
|
453 void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const |
|
454 { |
|
455 if (!bufsize || !buf) return; |
|
456 if (index >= len) { |
|
457 buf[0] = 0; |
|
458 return; |
|
459 } |
|
460 unsigned int n = bufsize - 1; |
|
461 if (n > len - index) n = len - index; |
|
462 strncpy((char *)buf, buffer + index, n); |
|
463 buf[n] = 0; |
|
464 } |
|
465 |
|
466 /*********************************************/ |
|
467 /* Search */ |
|
468 /*********************************************/ |
|
469 |
|
470 int String::indexOf(char c) const |
|
471 { |
|
472 return indexOf(c, 0); |
|
473 } |
|
474 |
|
475 int String::indexOf( char ch, unsigned int fromIndex ) const |
|
476 { |
|
477 if (fromIndex >= len) return -1; |
|
478 const char* temp = strchr(buffer + fromIndex, ch); |
|
479 if (temp == NULL) return -1; |
|
480 return temp - buffer; |
|
481 } |
|
482 |
|
483 int String::indexOf(const String &s2) const |
|
484 { |
|
485 return indexOf(s2, 0); |
|
486 } |
|
487 |
|
488 int String::indexOf(const String &s2, unsigned int fromIndex) const |
|
489 { |
|
490 if (fromIndex >= len) return -1; |
|
491 const char *found = strstr(buffer + fromIndex, s2.buffer); |
|
492 if (found == NULL) return -1; |
|
493 return found - buffer; |
|
494 } |
|
495 |
|
496 int String::lastIndexOf( char theChar ) const |
|
497 { |
|
498 return lastIndexOf(theChar, len - 1); |
|
499 } |
|
500 |
|
501 int String::lastIndexOf(char ch, unsigned int fromIndex) const |
|
502 { |
|
503 if (fromIndex >= len) return -1; |
|
504 char tempchar = buffer[fromIndex + 1]; |
|
505 buffer[fromIndex + 1] = '\0'; |
|
506 char* temp = strrchr( buffer, ch ); |
|
507 buffer[fromIndex + 1] = tempchar; |
|
508 if (temp == NULL) return -1; |
|
509 return temp - buffer; |
|
510 } |
|
511 |
|
512 int String::lastIndexOf(const String &s2) const |
|
513 { |
|
514 return lastIndexOf(s2, len - s2.len); |
|
515 } |
|
516 |
|
517 int String::lastIndexOf(const String &s2, unsigned int fromIndex) const |
|
518 { |
|
519 if (s2.len == 0 || len == 0 || s2.len > len) return -1; |
|
520 if (fromIndex >= len) fromIndex = len - 1; |
|
521 int found = -1; |
|
522 for (char *p = buffer; p <= buffer + fromIndex; p++) { |
|
523 p = strstr(p, s2.buffer); |
|
524 if (!p) break; |
|
525 if ((unsigned int)(p - buffer) <= fromIndex) found = p - buffer; |
|
526 } |
|
527 return found; |
|
528 } |
|
529 |
|
530 String String::substring( unsigned int left ) const |
|
531 { |
|
532 return substring(left, len); |
|
533 } |
|
534 |
|
535 String String::substring(unsigned int left, unsigned int right) const |
|
536 { |
|
537 if (left > right) { |
|
538 unsigned int temp = right; |
|
539 right = left; |
|
540 left = temp; |
|
541 } |
|
542 String out; |
|
543 if (left > len) return out; |
|
544 if (right > len) right = len; |
|
545 char temp = buffer[right]; // save the replaced character |
|
546 buffer[right] = '\0'; |
|
547 out = buffer + left; // pointer arithmetic |
|
548 buffer[right] = temp; //restore character |
|
549 return out; |
|
550 } |
|
551 |
|
552 /*********************************************/ |
|
553 /* Modification */ |
|
554 /*********************************************/ |
|
555 |
|
556 void String::replace(char find, char replace) |
|
557 { |
|
558 if (!buffer) return; |
|
559 for (char *p = buffer; *p; p++) { |
|
560 if (*p == find) *p = replace; |
|
561 } |
|
562 } |
|
563 |
|
564 void String::replace(const String& find, const String& replace) |
|
565 { |
|
566 if (len == 0 || find.len == 0) return; |
|
567 int diff = replace.len - find.len; |
|
568 char *readFrom = buffer; |
|
569 char *foundAt; |
|
570 if (diff == 0) { |
|
571 while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { |
|
572 memcpy(foundAt, replace.buffer, replace.len); |
|
573 readFrom = foundAt + replace.len; |
|
574 } |
|
575 } else if (diff < 0) { |
|
576 char *writeTo = buffer; |
|
577 while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { |
|
578 unsigned int n = foundAt - readFrom; |
|
579 memcpy(writeTo, readFrom, n); |
|
580 writeTo += n; |
|
581 memcpy(writeTo, replace.buffer, replace.len); |
|
582 writeTo += replace.len; |
|
583 readFrom = foundAt + find.len; |
|
584 len += diff; |
|
585 } |
|
586 strcpy(writeTo, readFrom); |
|
587 } else { |
|
588 unsigned int size = len; // compute size needed for result |
|
589 while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { |
|
590 readFrom = foundAt + find.len; |
|
591 size += diff; |
|
592 } |
|
593 if (size == len) return; |
|
594 if (size > capacity && !changeBuffer(size)) return; // XXX: tell user! |
|
595 int index = len - 1; |
|
596 while (index >= 0 && (index = lastIndexOf(find, index)) >= 0) { |
|
597 readFrom = buffer + index + find.len; |
|
598 memmove(readFrom + diff, readFrom, len - (readFrom - buffer)); |
|
599 len += diff; |
|
600 buffer[len] = 0; |
|
601 memcpy(buffer + index, replace.buffer, replace.len); |
|
602 index--; |
|
603 } |
|
604 } |
|
605 } |
|
606 |
|
607 void String::toLowerCase(void) |
|
608 { |
|
609 if (!buffer) return; |
|
610 for (char *p = buffer; *p; p++) { |
|
611 *p = tolower(*p); |
|
612 } |
|
613 } |
|
614 |
|
615 void String::toUpperCase(void) |
|
616 { |
|
617 if (!buffer) return; |
|
618 for (char *p = buffer; *p; p++) { |
|
619 *p = toupper(*p); |
|
620 } |
|
621 } |
|
622 |
|
623 void String::trim(void) |
|
624 { |
|
625 if (!buffer || len == 0) return; |
|
626 char *begin = buffer; |
|
627 while (isspace(*begin)) begin++; |
|
628 char *end = buffer + len - 1; |
|
629 while (isspace(*end) && end >= begin) end--; |
|
630 len = end + 1 - begin; |
|
631 if (begin > buffer) memcpy(buffer, begin, len); |
|
632 buffer[len] = 0; |
|
633 } |
|
634 |
|
635 /*********************************************/ |
|
636 /* Parsing / Conversion */ |
|
637 /*********************************************/ |
|
638 |
|
639 long String::toInt(void) const |
|
640 { |
|
641 if (buffer) return atol(buffer); |
|
642 return 0; |
|
643 } |
|
644 |
|
645 |