Thu, 07 Jul 2016 12:23:34 +0200
added missing sanguino files
2 | 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 |