root / arduino-1.0 / hardware / arduino / cores / arduino / WString.cpp @ 58d82c77
History | View | Annotate | Download (13.9 KB)
1 | 58d82c77 | Tom Mullins | /*
|
---|---|---|---|
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 || fromIndex < 0) 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 || fromIndex < 0) 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 |