comparison deps/Platinum/ThirdParty/Neptune/Source/Core/NptStrings.cpp @ 0:3425707ddbf6

Initial import (hopefully this mercurial stuff works...)
author fraserofthenight
date Mon, 06 Jul 2009 08:06:28 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3425707ddbf6
1 /*****************************************************************
2 |
3 | Neptune - String Objects
4 |
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
6 | All rights reserved.
7 |
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are met:
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 | * Neither the name of Axiomatic Systems 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 AXIOMATIC SYSTEMS ''AS IS'' AND ANY
20 | 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 AXIOMATIC SYSTEMS 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
32 /*----------------------------------------------------------------------
33 | includes
34 +---------------------------------------------------------------------*/
35 #include "NptConfig.h"
36 #include "NptTypes.h"
37 #include "NptConstants.h"
38 #include "NptStrings.h"
39 #include "NptResults.h"
40 #include "NptUtils.h"
41 #include "NptDebug.h"
42
43 /*----------------------------------------------------------------------
44 | constants
45 +---------------------------------------------------------------------*/
46 #define NPT_STRINGS_WHITESPACE_CHARS "\r\n\t "
47
48 const unsigned int NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE = 256;
49 const unsigned int NPT_STRING_FORMAT_BUFFER_MAX_SIZE = 0x80000; // 512k
50
51 /*----------------------------------------------------------------------
52 | helpers
53 +---------------------------------------------------------------------*/
54 inline char NPT_Uppercase(char x) {
55 return (x >= 'a' && x <= 'z') ? x&0xdf : x;
56 }
57
58 inline char NPT_Lowercase(char x) {
59 return (x >= 'A' && x <= 'Z') ? x^32 : x;
60 }
61
62 /*----------------------------------------------------------------------
63 | NPT_String::EmptyString
64 +---------------------------------------------------------------------*/
65 char NPT_String::EmptyString = '\0';
66
67 /*----------------------------------------------------------------------
68 | NPT_String::FromInteger
69 +---------------------------------------------------------------------*/
70 NPT_String
71 NPT_String::FromInteger(NPT_Int64 value)
72 {
73 char str[32];
74 char* c = &str[31];
75 *c-- = '\0';
76
77 // handle the sign
78 bool negative = false;
79 if (value < 0) {
80 negative = true;
81 value = -value;
82 }
83
84 // process the digits
85 do {
86 int digit = (int)(value%10);
87 *c-- = '0'+digit;
88 value /= 10;
89 } while(value);
90
91 if (negative) {
92 *c = '-';
93 } else {
94 ++c;
95 }
96
97 return NPT_String(c);
98 }
99
100 /*----------------------------------------------------------------------
101 | NPT_String::FromIntegerU
102 +---------------------------------------------------------------------*/
103 NPT_String
104 NPT_String::FromIntegerU(NPT_UInt64 value)
105 {
106 char str[32];
107 char* c = &str[31];
108 *c = '\0';
109
110 // process the digits
111 do {
112 int digit = (int)(value%10);
113 *--c = '0'+digit;
114 value /= 10;
115 } while(value);
116
117 return NPT_String(c);
118 }
119
120 /*----------------------------------------------------------------------
121 | NPT_String::Format
122 +---------------------------------------------------------------------*/
123 NPT_String
124 NPT_String::Format(const char* format, ...)
125 {
126 NPT_String result;
127 NPT_Size buffer_size = NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE; // default value
128
129 va_list args;
130 va_start(args, format);
131
132 for(;;) {
133 /* try to format (it might not fit) */
134 result.Reserve(buffer_size);
135 char* buffer = result.UseChars();
136 int f_result = NPT_FormatStringVN(buffer, buffer_size, format, args);
137 if (f_result >= (int)(buffer_size)) f_result = -1;
138 if (f_result >= 0) {
139 result.SetLength(f_result);
140 break;
141 }
142
143 /* the buffer was too small, try something bigger */
144 /* (we don't trust the return value of NPT_FormatStringVN */
145 /* for the actual size needed) */
146 buffer_size *= 2;
147 if (buffer_size > NPT_STRING_FORMAT_BUFFER_MAX_SIZE) break;
148 }
149
150 va_end(args);
151
152 return result;
153 }
154
155 /*----------------------------------------------------------------------
156 | NPT_String::NPT_String
157 +---------------------------------------------------------------------*/
158 NPT_String::NPT_String(const char* str)
159 {
160 if (str == NULL) {
161 m_Chars = NULL;
162 } else {
163 m_Chars = Buffer::Create(str);
164 }
165 }
166
167 /*----------------------------------------------------------------------
168 | NPT_String::NPT_String
169 +---------------------------------------------------------------------*/
170 NPT_String::NPT_String(const char* str, NPT_Size length)
171 {
172 if (str == NULL || length == 0) {
173 m_Chars = NULL;
174 } else {
175 m_Chars = Buffer::Create(str, length);
176 }
177 }
178
179 /*----------------------------------------------------------------------
180 | NPT_String::NPT_String
181 +---------------------------------------------------------------------*/
182 NPT_String::NPT_String(const NPT_String& str)
183 {
184 if (str.GetLength() == 0) {
185 m_Chars = NULL;
186 } else {
187 m_Chars = Buffer::Create(str.GetChars(), str.GetLength());
188 }
189 }
190
191 /*----------------------------------------------------------------------
192 | NPT_String::NPT_String
193 +---------------------------------------------------------------------*/
194 NPT_String::NPT_String(const char* str,
195 NPT_Ordinal first,
196 NPT_Size length)
197 {
198 // shortcut
199 if (str != NULL && length != 0) {
200 // truncate length
201 NPT_Size str_length = StringLength(str);
202 if (first < str_length) {
203 if (first+length > str_length) {
204 length = str_length-first;
205 }
206 if (length != 0) {
207 m_Chars = Buffer::Create(str+first, length);
208 return;
209 }
210 }
211 }
212 m_Chars = NULL;
213 }
214
215 /*----------------------------------------------------------------------
216 | NPT_String::NPT_String
217 +---------------------------------------------------------------------*/
218 NPT_String::NPT_String(char c, NPT_Cardinal repeat)
219 {
220 if (repeat != 0) {
221 m_Chars = Buffer::Create(c, repeat);
222 } else {
223 m_Chars = NULL;
224 }
225 }
226
227 /*----------------------------------------------------------------------
228 | NPT_String::SetLength
229 +---------------------------------------------------------------------*/
230 NPT_Result
231 NPT_String::SetLength(NPT_Size length, bool pad)
232 {
233 // special case for 0
234 if (length == 0) {
235 Reset();
236 return NPT_SUCCESS;
237 }
238
239 // reserve the space
240 Reserve(length);
241
242 // pad with spaces if necessary
243 char* chars = UseChars();
244 if (pad) {
245 unsigned int current_length = GetLength();
246 if (length > current_length) {
247 unsigned int pad_length = length-current_length;
248 NPT_SetMemory(chars+current_length, ' ', pad_length);
249 }
250 }
251
252 // update the length and terminate the buffer
253 GetBuffer()->SetLength(length);
254 chars[length] = '\0';
255
256 return NPT_SUCCESS;
257 }
258
259 /*----------------------------------------------------------------------
260 | NPT_String::PrepareToWrite
261 +---------------------------------------------------------------------*/
262 inline char*
263 NPT_String::PrepareToWrite(NPT_Size length)
264 {
265 NPT_ASSERT(length != 0);
266 if (m_Chars == NULL || GetBuffer()->GetAllocated() < length) {
267 // the buffer is too small, we need to allocate a new one.
268 NPT_Size needed = length;
269 if (m_Chars != NULL) {
270 NPT_Size grow = GetBuffer()->GetAllocated()*2;
271 if (grow > length) needed = grow;
272 delete GetBuffer();
273 }
274 m_Chars = Buffer::Create(needed);
275 }
276 GetBuffer()->SetLength(length);
277 return m_Chars;
278 }
279
280 /*----------------------------------------------------------------------
281 | NPT_String::Reserve
282 +---------------------------------------------------------------------*/
283 void
284 NPT_String::Reserve(NPT_Size allocate)
285 {
286 if (m_Chars == NULL || GetBuffer()->GetAllocated() < allocate) {
287 // the buffer is too small, we need to allocate a new one.
288 NPT_Size needed = allocate;
289 if (m_Chars != NULL) {
290 NPT_Size grow = GetBuffer()->GetAllocated()*2;
291 if (grow > allocate) needed = grow;
292 }
293 NPT_Size length = GetLength();
294 char* copy = Buffer::Create(needed, length);
295 if (m_Chars != NULL) {
296 CopyString(copy, m_Chars);
297 delete GetBuffer();
298 } else {
299 copy[0] = '\0';
300 }
301 m_Chars = copy;
302 }
303 }
304
305 /*----------------------------------------------------------------------
306 | NPT_String::Assign
307 +---------------------------------------------------------------------*/
308 void
309 NPT_String::Assign(const char* str, NPT_Size length)
310 {
311 if (str == NULL || length == 0) {
312 Reset();
313 } else {
314 PrepareToWrite(length);
315 CopyBuffer(m_Chars, str, length);
316 m_Chars[length] = '\0';
317 }
318 }
319
320 /*----------------------------------------------------------------------
321 | NPT_String::operator=
322 +---------------------------------------------------------------------*/
323 NPT_String&
324 NPT_String::operator=(const char* str)
325 {
326 if (str == NULL) {
327 Reset();
328 } else {
329 NPT_Size length = StringLength(str);
330 if (length == 0) {
331 Reset();
332 } else {
333 CopyString(PrepareToWrite(length), str);
334 }
335 }
336
337 return *this;
338 }
339
340 /*----------------------------------------------------------------------
341 | NPT_String::operator=
342 +---------------------------------------------------------------------*/
343 NPT_String&
344 NPT_String::operator=(const NPT_String& str)
345 {
346 // do nothing if we're assigning to ourselves
347 if (this != &str) {
348 Assign(str.GetChars(), str.GetLength());
349 }
350 return *this;
351 }
352
353 /*----------------------------------------------------------------------
354 | NPT_String::Append
355 +---------------------------------------------------------------------*/
356 void
357 NPT_String::Append(const char* str, NPT_Size length)
358 {
359 // shortcut
360 if (str == NULL || length == 0) return;
361
362 // compute the new length
363 NPT_Size old_length = GetLength();
364 NPT_Size new_length = old_length + length;
365
366 // allocate enough space
367 Reserve(new_length);
368
369 // append the new string at the end of the current one
370 CopyBuffer(m_Chars+old_length, str, length);
371 m_Chars[new_length] = '\0';
372
373 // update the length
374 GetBuffer()->SetLength(new_length);
375 }
376
377 /*----------------------------------------------------------------------
378 | NPT_String::Compare
379 +---------------------------------------------------------------------*/
380 int
381 NPT_String::Compare(const char *s, bool ignore_case) const
382 {
383 return NPT_String::Compare(GetChars(), s, ignore_case);
384 }
385
386 /*----------------------------------------------------------------------
387 | NPT_String::Compare
388 +---------------------------------------------------------------------*/
389 int
390 NPT_String::Compare(const char *s1, const char *s2, bool ignore_case)
391 {
392 const char *r1 = s1;
393 const char *r2 = s2;
394
395 if (ignore_case) {
396 while (NPT_Uppercase(*r1) == NPT_Uppercase(*r2)) {
397 if (*r1++ == '\0') {
398 return 0;
399 }
400 r2++;
401 }
402 return NPT_Uppercase(*r1) - NPT_Uppercase(*r2);
403 } else {
404 while (*r1 == *r2) {
405 if (*r1++ == '\0') {
406 return 0;
407 }
408 r2++;
409 }
410 return (*r1 - *r2);
411 }
412 }
413
414 /*----------------------------------------------------------------------
415 | NPT_String::CompareN
416 +---------------------------------------------------------------------*/
417 int
418 NPT_String::CompareN(const char *s, NPT_Size count, bool ignore_case) const
419 {
420 return NPT_String::CompareN(GetChars(), s, count, ignore_case);
421 }
422
423 /*----------------------------------------------------------------------
424 | NPT_String::CompareN
425 +---------------------------------------------------------------------*/
426 int
427 NPT_String::CompareN(const char* s1, const char *s2, NPT_Size count, bool ignore_case)
428 {
429 const char* me = s1;
430
431 if (ignore_case) {
432 for (unsigned int i=0; i<count; i++) {
433 if (NPT_Uppercase(me[i]) != NPT_Uppercase(s2[i])) {
434 return NPT_Uppercase(me[i]) - NPT_Uppercase(s2[i]);
435 }
436 }
437 return 0;
438 } else {
439 for (unsigned int i=0; i<count; i++) {
440 if (me[i] != s2[i]) {
441 return (me[i] - s2[i]);
442 }
443 }
444 return 0;
445 }
446 }
447
448 /*----------------------------------------------------------------------
449 | NPT_String::Split
450 +---------------------------------------------------------------------*/
451 NPT_List<NPT_String>
452 NPT_String::Split(const char* separator) const
453 {
454 NPT_List<NPT_String> result;
455 NPT_Size separator_length = NPT_StringLength(separator);
456
457 // sepcial case for empty separators
458 if (separator_length == 0) {
459 result.Add(*this);
460 return result;
461 }
462
463 int current = 0;
464 int next;
465 do {
466 next = Find(separator, current);
467 unsigned int end = (next>=0?next:GetLength());
468 result.Add(SubString(current, end-current));
469 current = next+separator_length;
470 } while (next >= 0);
471
472 return result;
473 }
474
475 /*----------------------------------------------------------------------
476 | NPT_String::SubString
477 +---------------------------------------------------------------------*/
478 NPT_String
479 NPT_String::SubString(NPT_Ordinal first, NPT_Size length) const
480 {
481 if (first >= GetLength()) {
482 first = GetLength();
483 length = 0;
484 } else if (first+length >= GetLength()) {
485 length = GetLength()-first;
486 }
487 return NPT_String(GetChars()+first, length);
488 }
489
490 /*----------------------------------------------------------------------
491 | NPT_StringStartsWith
492 |
493 | returns:
494 | 1 if str starts with sub,
495 | 0 if str is large enough but does not start with sub
496 | -1 if str is too short to start with sub
497 +---------------------------------------------------------------------*/
498 static inline int
499 NPT_StringStartsWith(const char* str, const char* sub, bool ignore_case)
500 {
501 if (ignore_case) {
502 while (NPT_Uppercase(*str) == NPT_Uppercase(*sub)) {
503 if (*str++ == '\0') {
504 return 1;
505 }
506 sub++;
507 }
508 } else {
509 while (*str == *sub) {
510 if (*str++ == '\0') {
511 return 1;
512 }
513 sub++;
514 }
515 }
516 return (*sub == '\0') ? 1 : (*str == '\0' ? -1 : 0);
517 }
518
519 /*----------------------------------------------------------------------
520 | NPT_String::StartsWith
521 +---------------------------------------------------------------------*/
522 bool
523 NPT_String::StartsWith(const char *s, bool ignore_case) const
524 {
525 if (s == NULL) return false;
526 return NPT_StringStartsWith(GetChars(), s, ignore_case) == 1;
527 }
528
529 /*----------------------------------------------------------------------
530 | NPT_String::EndsWith
531 +---------------------------------------------------------------------*/
532 bool
533 NPT_String::EndsWith(const char *s, bool ignore_case) const
534 {
535 if (s == NULL) return false;
536 NPT_Size str_length = NPT_StringLength(s);
537 if (str_length > GetLength()) return false;
538 return NPT_StringStartsWith(GetChars()+GetLength()-str_length, s, ignore_case) == 1;
539 }
540
541 /*----------------------------------------------------------------------
542 | NPT_String::Find
543 +---------------------------------------------------------------------*/
544 int
545 NPT_String::Find(const char* str, NPT_Ordinal start, bool ignore_case) const
546 {
547 // check args
548 if (str == NULL || start >= GetLength()) return -1;
549
550 // skip to start position
551 const char* src = m_Chars + start;
552
553 // look for a substring
554 while (*src) {
555 int cmp = NPT_StringStartsWith(src, str, ignore_case);
556 switch (cmp) {
557 case -1:
558 // ref is too short, abort
559 return -1;
560 case 1:
561 // match
562 return (int)(src-m_Chars);
563 }
564 src++;
565 }
566
567 return -1;
568 }
569
570 /*----------------------------------------------------------------------
571 | NPT_String::Find
572 +---------------------------------------------------------------------*/
573 int
574 NPT_String::Find(char c, NPT_Ordinal start, bool ignore_case) const
575 {
576 // check args
577 if (start >= GetLength()) return -1;
578
579 // skip to start position
580 const char* src = m_Chars + start;
581
582 // look for the character
583 if (ignore_case) {
584 while (*src) {
585 if (NPT_Uppercase(*src) == NPT_Uppercase(c)) {
586 return (int)(src-m_Chars);
587 }
588 src++;
589 }
590 } else {
591 while (*src) {
592 if (*src == c) return (int)(src-m_Chars);
593 src++;
594 }
595 }
596
597 return -1;
598 }
599
600 /*----------------------------------------------------------------------
601 | NPT_String::ReverseFind
602 +---------------------------------------------------------------------*/
603 int
604 NPT_String::ReverseFind(const char* str, NPT_Ordinal start, bool ignore_case) const
605 {
606 // check args
607 if (str == NULL || *str == '\0') return -1;
608
609 // look for a substring
610 NPT_Size my_length = GetLength();
611 NPT_Size str_length = NPT_StringLength(str);
612 int i=my_length-start-str_length;
613 const char* src = GetChars();
614 if (i<0) return -1;
615 for (;i>=0; i--) {
616 int cmp = NPT_StringStartsWith(src+i, str, ignore_case);
617 if (cmp == 1) {
618 // match
619 return i;
620 }
621 }
622
623 return -1;
624 }
625
626 /*----------------------------------------------------------------------
627 | NPT_String::ReverseFind
628 +---------------------------------------------------------------------*/
629 int
630 NPT_String::ReverseFind(char c, NPT_Ordinal start, bool ignore_case) const
631 {
632 // check args
633 NPT_Size length = GetLength();
634 int i = length-start-1;
635 if (i < 0) return -1;
636
637 // look for the character
638 const char* src = GetChars();
639 if (ignore_case) {
640 for (;i>=0;i--) {
641 if (NPT_Uppercase(src[i]) == NPT_Uppercase(c)) {
642 return i;
643 }
644 }
645 } else {
646 for (;i>=0;i--) {
647 if (src[i] == c) return i;
648 }
649 }
650
651 return -1;
652 }
653
654 /*----------------------------------------------------------------------
655 | NPT_String::MakeLowercase
656 +---------------------------------------------------------------------*/
657 void
658 NPT_String::MakeLowercase()
659 {
660 // the source is the current buffer
661 const char* src = GetChars();
662
663 // convert all the characters of the existing buffer
664 char* dst = const_cast<char*>(src);
665 while (*dst != '\0') {
666 *dst = NPT_Lowercase(*dst);
667 dst++;
668 }
669 }
670
671 /*----------------------------------------------------------------------
672 | NPT_String::MakeUppercase
673 +---------------------------------------------------------------------*/
674 void
675 NPT_String::MakeUppercase()
676 {
677 // the source is the current buffer
678 const char* src = GetChars();
679
680 // convert all the characters of the existing buffer
681 char* dst = const_cast<char*>(src);
682 while (*dst != '\0') {
683 *dst = NPT_Uppercase(*dst);
684 dst++;
685 }
686 }
687
688 /*----------------------------------------------------------------------
689 | NPT_String::ToLowercase
690 +---------------------------------------------------------------------*/
691 NPT_String
692 NPT_String::ToLowercase() const
693 {
694 NPT_String result(*this);
695 result.MakeLowercase();
696 return result;
697 }
698
699 /*----------------------------------------------------------------------
700 | NPT_String::ToUppercase
701 +---------------------------------------------------------------------*/
702 NPT_String
703 NPT_String::ToUppercase() const
704 {
705 NPT_String result(*this);
706 result.MakeUppercase();
707 return result;
708 }
709
710 /*----------------------------------------------------------------------
711 | NPT_String::Replace
712 +---------------------------------------------------------------------*/
713 void
714 NPT_String::Replace(char a, char b)
715 {
716 // check args
717 if (m_Chars == NULL || a == '\0' || b == '\0') return;
718
719 // we are going to modify the characters
720 char* src = m_Chars;
721
722 // process the buffer in place
723 while (*src) {
724 if (*src == a) *src = b;
725 src++;
726 }
727 }
728
729 /*----------------------------------------------------------------------
730 | NPT_String::Replace
731 +---------------------------------------------------------------------*/
732 void
733 NPT_String::Replace(char a, const char* str)
734 {
735 // check args
736 if (m_Chars == NULL || a == '\0' || str == NULL || str[0] == '\0') return;
737
738 // optimization
739 if (NPT_StringLength(str) == 1) return Replace(a, str[0]);
740
741 // we are going to create a new string
742 NPT_String dst;
743 char* src = m_Chars;
744
745 // reserve at least as much as input
746 dst.Reserve(GetLength());
747
748 // process the buffer
749 while (*src) {
750 if (*src == a) {
751 dst += str;
752 } else {
753 dst += *src;
754 }
755 src++;
756 }
757
758 Assign(dst.GetChars(), dst.GetLength());
759 }
760
761 /*----------------------------------------------------------------------
762 | NPT_String::Insert
763 +---------------------------------------------------------------------*/
764 void
765 NPT_String::Insert(const char* str, NPT_Ordinal where)
766 {
767 // check args
768 if (str == NULL || where > GetLength()) return;
769
770 // measure the string to insert
771 NPT_Size str_length = StringLength(str);
772 if (str_length == 0) return;
773
774 // compute the size of the new string
775 NPT_Size old_length = GetLength();
776 NPT_Size new_length = str_length + GetLength();
777
778 // prepare to write the new string
779 char* src = m_Chars;
780 char* nst = Buffer::Create(new_length, new_length);
781 char* dst = nst;
782
783 // copy the beginning of the old string
784 if (where > 0) {
785 CopyBuffer(dst, src, where);
786 src += where;
787 dst += where;
788 }
789
790 // copy the inserted string
791 CopyString(dst, str);
792 dst += str_length;
793
794 // copy the end of the old string
795 if (old_length > where) {
796 CopyString(dst, src);
797 }
798
799 // use the new string
800 if (m_Chars) delete GetBuffer();
801 m_Chars = nst;
802 }
803
804 /*----------------------------------------------------------------------
805 | NPT_String::Erase
806 +---------------------------------------------------------------------*/
807 void
808 NPT_String::Erase(NPT_Ordinal start, NPT_Cardinal count /* = 1 */)
809 {
810 // check bounds
811 NPT_Size length = GetLength();
812 if (start+count > length) {
813 if (start >= length) return;
814 count = length-start;
815 }
816 if (count == 0) return;
817
818 CopyString(m_Chars+start, m_Chars+start+count);
819 GetBuffer()->SetLength(length-count);
820 }
821
822 /*----------------------------------------------------------------------
823 | NPT_String::ToInteger
824 +---------------------------------------------------------------------*/
825 NPT_Result
826 NPT_String::ToInteger(NPT_Int32& value, bool relaxed) const
827 {
828 return NPT_ParseInteger32(GetChars(), value, relaxed);
829 }
830
831 /*----------------------------------------------------------------------
832 | NPT_String::ToInteger
833 +---------------------------------------------------------------------*/
834 NPT_Result
835 NPT_String::ToInteger(NPT_UInt32& value, bool relaxed) const
836 {
837 return NPT_ParseInteger32U(GetChars(), value, relaxed);
838 }
839
840 /*----------------------------------------------------------------------
841 | NPT_String::ToInteger
842 +---------------------------------------------------------------------*/
843 NPT_Result
844 NPT_String::ToInteger(NPT_Int64& value, bool relaxed) const
845 {
846 return NPT_ParseInteger64(GetChars(), value, relaxed);
847 }
848
849 /*----------------------------------------------------------------------
850 | NPT_String::ToInteger
851 +---------------------------------------------------------------------*/
852 NPT_Result
853 NPT_String::ToInteger(NPT_UInt64& value, bool relaxed) const
854 {
855 return NPT_ParseInteger64U(GetChars(), value, relaxed);
856 }
857
858 /*----------------------------------------------------------------------
859 | NPT_String::ToFloat
860 +---------------------------------------------------------------------*/
861 NPT_Result
862 NPT_String::ToFloat(float& value, bool relaxed) const
863 {
864 return NPT_ParseFloat(GetChars(), value, relaxed);
865 }
866
867 /*----------------------------------------------------------------------
868 | NPT_String::TrimLeft
869 +---------------------------------------------------------------------*/
870 void
871 NPT_String::TrimLeft()
872 {
873 TrimLeft(NPT_STRINGS_WHITESPACE_CHARS);
874 }
875
876 /*----------------------------------------------------------------------
877 | NPT_String::TrimLeft
878 +---------------------------------------------------------------------*/
879 void
880 NPT_String::TrimLeft(char c)
881 {
882 char s[2] = {c, 0};
883 TrimLeft((const char*)s);
884 }
885
886 /*----------------------------------------------------------------------
887 | NPT_String::TrimLeft
888 +---------------------------------------------------------------------*/
889 void
890 NPT_String::TrimLeft(const char* chars)
891 {
892 if (m_Chars == NULL) return;
893 const char* s = m_Chars;
894 while (char c = *s) {
895 const char* x = chars;
896 while (*x) {
897 if (*x == c) break;
898 x++;
899 }
900 if (*x == 0) break; // not found
901 s++;
902 }
903 if (s == m_Chars) {
904 // nothing was trimmed
905 return;
906 }
907
908 // shift chars to the left
909 char* d = m_Chars;
910 GetBuffer()->SetLength(GetLength()-(s-d));
911 while ((*d++ = *s++)) {};
912 }
913
914 /*----------------------------------------------------------------------
915 | NPT_String::TrimRight
916 +---------------------------------------------------------------------*/
917 void
918 NPT_String::TrimRight()
919 {
920 TrimRight(NPT_STRINGS_WHITESPACE_CHARS);
921 }
922
923 /*----------------------------------------------------------------------
924 | NPT_String::TrimRight
925 +---------------------------------------------------------------------*/
926 void
927 NPT_String::TrimRight(char c)
928 {
929 char s[2] = {c, 0};
930 TrimRight((const char*)s);
931 }
932
933 /*----------------------------------------------------------------------
934 | NPT_String::TrimRight
935 +---------------------------------------------------------------------*/
936 void
937 NPT_String::TrimRight(const char* chars)
938 {
939 if (m_Chars == NULL || m_Chars[0] == '\0') return;
940 char* tail = m_Chars+GetLength()-1;
941 char* s = tail;
942 while (s != m_Chars-1) {
943 const char* x = chars;
944 while (*x) {
945 if (*x == *s) {
946 *s = '\0';
947 break;
948 }
949 x++;
950 }
951 if (*x == 0) break; // not found
952 s--;
953 }
954 if (s == tail) {
955 // nothing was trimmed
956 return;
957 }
958 GetBuffer()->SetLength(1+(int)(s-m_Chars));
959 }
960
961 /*----------------------------------------------------------------------
962 | NPT_String::Trim
963 +---------------------------------------------------------------------*/
964 void
965 NPT_String::Trim()
966 {
967 TrimLeft();
968 TrimRight();
969 }
970
971 /*----------------------------------------------------------------------
972 | NPT_String::Trim
973 +---------------------------------------------------------------------*/
974 void
975 NPT_String::Trim(char c)
976 {
977 char s[2] = {c, 0};
978 TrimLeft((const char*)s);
979 TrimRight((const char*)s);
980 }
981
982 /*----------------------------------------------------------------------
983 | NPT_String::Trim
984 +---------------------------------------------------------------------*/
985 void
986 NPT_String::Trim(const char* chars)
987 {
988 TrimLeft(chars);
989 TrimRight(chars);
990 }
991
992 /*----------------------------------------------------------------------
993 | NPT_String::operator+(const NPT_String&, const char*)
994 +---------------------------------------------------------------------*/
995 NPT_String
996 operator+(const NPT_String& s1, const char* s2)
997 {
998 // shortcut
999 if (s2 == NULL) return NPT_String(s1);
1000
1001 // measure strings
1002 NPT_Size s1_length = s1.GetLength();
1003 NPT_Size s2_length = NPT_String::StringLength(s2);
1004
1005 // allocate space for the new string
1006 NPT_String result;
1007 char* start = result.PrepareToWrite(s1_length+s2_length);
1008
1009 // concatenate the two strings into the result
1010 NPT_String::CopyBuffer(start, s1, s1_length);
1011 NPT_String::CopyString(start+s1_length, s2);
1012
1013 return result;
1014 }
1015
1016 /*----------------------------------------------------------------------
1017 | NPT_String::operator+(const NPT_String& , const char*)
1018 +---------------------------------------------------------------------*/
1019 NPT_String
1020 operator+(const char* s1, const NPT_String& s2)
1021 {
1022 // shortcut
1023 if (s1 == NULL) return NPT_String(s2);
1024
1025 // measure strings
1026 NPT_Size s1_length = NPT_String::StringLength(s1);
1027 NPT_Size s2_length = s2.GetLength();
1028
1029 // allocate space for the new string
1030 NPT_String result;
1031 char* start = result.PrepareToWrite(s1_length+s2_length);
1032
1033 // concatenate the two strings into the result
1034 NPT_String::CopyBuffer(start, s1, s1_length);
1035 NPT_String::CopyString(start+s1_length, s2.GetChars());
1036
1037 return result;
1038 }
1039
1040 /*----------------------------------------------------------------------
1041 | NPT_String::operator+(const NPT_String& , char)
1042 +---------------------------------------------------------------------*/
1043 NPT_String
1044 operator+(const NPT_String& s1, char c)
1045 {
1046 // allocate space for the new string
1047 NPT_String result;
1048 result.Reserve(s1.GetLength()+1);
1049
1050 // append
1051 result = s1;
1052 result += c;
1053
1054 return result;
1055 }
1056