1 /*****************************************************************
3 | Neptune - String Objects
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
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.
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.
30 ****************************************************************/
32 /*----------------------------------------------------------------------
34 +---------------------------------------------------------------------*/
35 #include "NptConfig.h"
37 #include "NptConstants.h"
38 #include "NptStrings.h"
39 #include "NptResults.h"
43 /*----------------------------------------------------------------------
45 +---------------------------------------------------------------------*/
46 #define NPT_STRINGS_WHITESPACE_CHARS "\r\n\t "
48 const unsigned int NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE
= 256;
49 const unsigned int NPT_STRING_FORMAT_BUFFER_MAX_SIZE
= 0x80000; // 512k
51 /*----------------------------------------------------------------------
53 +---------------------------------------------------------------------*/
54 inline char NPT_Uppercase(char x
) {
55 return (x
>= 'a' && x
<= 'z') ? x
&0xdf : x
;
58 inline char NPT_Lowercase(char x
) {
59 return (x
>= 'A' && x
<= 'Z') ? x
^32 : x
;
62 /*----------------------------------------------------------------------
63 | NPT_String::EmptyString
64 +---------------------------------------------------------------------*/
65 char NPT_String::EmptyString
= '\0';
67 /*----------------------------------------------------------------------
68 | NPT_String::FromInteger
69 +---------------------------------------------------------------------*/
71 NPT_String::FromInteger(NPT_Int64 value
)
78 bool negative
= false;
86 int digit
= (int)(value
%10);
100 /*----------------------------------------------------------------------
101 | NPT_String::FromIntegerU
102 +---------------------------------------------------------------------*/
104 NPT_String::FromIntegerU(NPT_UInt64 value
)
110 // process the digits
112 int digit
= (int)(value
%10);
117 return NPT_String(c
);
120 /*----------------------------------------------------------------------
122 +---------------------------------------------------------------------*/
124 NPT_String::Format(const char* format
, ...)
127 NPT_Size buffer_size
= NPT_STRING_FORMAT_BUFFER_DEFAULT_SIZE
; // default value
132 /* try to format (it might not fit) */
133 result
.Reserve(buffer_size
);
134 char* buffer
= result
.UseChars();
135 va_start(args
, format
);
136 int f_result
= NPT_FormatStringVN(buffer
, buffer_size
, format
, args
);
138 if (f_result
>= (int)(buffer_size
)) f_result
= -1;
140 result
.SetLength(f_result
);
144 /* the buffer was too small, try something bigger */
145 /* (we don't trust the return value of NPT_FormatStringVN */
146 /* for the actual size needed) */
148 if (buffer_size
> NPT_STRING_FORMAT_BUFFER_MAX_SIZE
) break;
154 /*----------------------------------------------------------------------
155 | NPT_String::NPT_String
156 +---------------------------------------------------------------------*/
157 NPT_String::NPT_String(const char* str
)
162 m_Chars
= Buffer::Create(str
);
166 /*----------------------------------------------------------------------
167 | NPT_String::NPT_String
168 +---------------------------------------------------------------------*/
169 NPT_String::NPT_String(const char* str
, NPT_Size length
)
171 if (str
== NULL
|| length
== 0) {
174 for (unsigned int i
=0; i
<length
-1; i
++) {
175 if (str
[i
] == '\0') {
184 m_Chars
= Buffer::Create(str
, length
);
188 /*----------------------------------------------------------------------
189 | NPT_String::NPT_String
190 +---------------------------------------------------------------------*/
191 NPT_String::NPT_String(const NPT_String
& str
)
193 if (str
.GetLength() == 0) {
196 m_Chars
= Buffer::Create(str
.GetChars(), str
.GetLength());
200 /*----------------------------------------------------------------------
201 | NPT_String::NPT_String
202 +---------------------------------------------------------------------*/
203 NPT_String::NPT_String(char c
, NPT_Cardinal repeat
)
206 m_Chars
= Buffer::Create(c
, repeat
);
212 /*----------------------------------------------------------------------
213 | NPT_String::SetLength
214 +---------------------------------------------------------------------*/
216 NPT_String::SetLength(NPT_Size length
, bool pad
)
218 // special case for 0
227 // pad with spaces if necessary
228 char* chars
= UseChars();
230 unsigned int current_length
= GetLength();
231 if (length
> current_length
) {
232 unsigned int pad_length
= length
-current_length
;
233 NPT_SetMemory(chars
+current_length
, ' ', pad_length
);
237 // update the length and terminate the buffer
238 GetBuffer()->SetLength(length
);
239 chars
[length
] = '\0';
244 /*----------------------------------------------------------------------
245 | NPT_String::PrepareToWrite
246 +---------------------------------------------------------------------*/
248 NPT_String::PrepareToWrite(NPT_Size length
)
250 NPT_ASSERT(length
!= 0);
251 if (m_Chars
== NULL
|| GetBuffer()->GetAllocated() < length
) {
252 // the buffer is too small, we need to allocate a new one.
253 NPT_Size needed
= length
;
254 if (m_Chars
!= NULL
) {
255 NPT_Size grow
= GetBuffer()->GetAllocated()*2;
256 if (grow
> length
) needed
= grow
;
259 m_Chars
= Buffer::Create(needed
);
261 GetBuffer()->SetLength(length
);
265 /*----------------------------------------------------------------------
266 | NPT_String::Reserve
267 +---------------------------------------------------------------------*/
269 NPT_String::Reserve(NPT_Size allocate
)
271 if (m_Chars
== NULL
|| GetBuffer()->GetAllocated() < allocate
) {
272 // the buffer is too small, we need to allocate a new one.
273 NPT_Size needed
= allocate
;
274 if (m_Chars
!= NULL
) {
275 NPT_Size grow
= GetBuffer()->GetAllocated()*2;
276 if (grow
> allocate
) needed
= grow
;
278 NPT_Size length
= GetLength();
279 char* copy
= Buffer::Create(needed
, length
);
280 if (m_Chars
!= NULL
) {
281 CopyString(copy
, m_Chars
);
290 /*----------------------------------------------------------------------
292 +---------------------------------------------------------------------*/
294 NPT_String::Assign(const char* str
, NPT_Size length
)
296 if (str
== NULL
|| length
== 0) {
299 for (unsigned int i
=0; i
<length
-1; i
++) {
300 if (str
[i
] == '\0') {
310 PrepareToWrite(length
);
311 CopyBuffer(m_Chars
, str
, length
);
312 m_Chars
[length
] = '\0';
316 /*----------------------------------------------------------------------
317 | NPT_String::operator=
318 +---------------------------------------------------------------------*/
320 NPT_String::operator=(const char* str
)
325 NPT_Size length
= StringLength(str
);
329 CopyString(PrepareToWrite(length
), str
);
336 /*----------------------------------------------------------------------
337 | NPT_String::operator=
338 +---------------------------------------------------------------------*/
340 NPT_String::operator=(const NPT_String
& str
)
342 // do nothing if we're assigning to ourselves
344 Assign(str
.GetChars(), str
.GetLength());
349 /*----------------------------------------------------------------------
350 | NPT_String::GetHash32
351 +---------------------------------------------------------------------*/
353 NPT_String::GetHash32() const
355 return NPT_Fnv1aHashStr32(GetChars());
358 /*----------------------------------------------------------------------
359 | NPT_String::GetHash64
360 +---------------------------------------------------------------------*/
362 NPT_String::GetHash64() const
364 return NPT_Fnv1aHashStr64(GetChars());
367 /*----------------------------------------------------------------------
369 +---------------------------------------------------------------------*/
371 NPT_String::Append(const char* str
, NPT_Size length
)
374 if (str
== NULL
|| length
== 0) return;
376 // compute the new length
377 NPT_Size old_length
= GetLength();
378 NPT_Size new_length
= old_length
+ length
;
380 // allocate enough space
383 // append the new string at the end of the current one
384 CopyBuffer(m_Chars
+old_length
, str
, length
);
385 m_Chars
[new_length
] = '\0';
388 GetBuffer()->SetLength(new_length
);
391 /*----------------------------------------------------------------------
392 | NPT_String::Compare
393 +---------------------------------------------------------------------*/
395 NPT_String::Compare(const char *s
, bool ignore_case
) const
397 return NPT_String::Compare(GetChars(), s
, ignore_case
);
400 /*----------------------------------------------------------------------
401 | NPT_String::Compare
402 +---------------------------------------------------------------------*/
404 NPT_String::Compare(const char *s1
, const char *s2
, bool ignore_case
)
410 while (NPT_Uppercase(*r1
) == NPT_Uppercase(*r2
)) {
416 return NPT_Uppercase(*r1
) - NPT_Uppercase(*r2
);
428 /*----------------------------------------------------------------------
429 | NPT_String::CompareN
430 +---------------------------------------------------------------------*/
432 NPT_String::CompareN(const char *s
, NPT_Size count
, bool ignore_case
) const
434 return NPT_String::CompareN(GetChars(), s
, count
, ignore_case
);
437 /*----------------------------------------------------------------------
438 | NPT_String::CompareN
439 +---------------------------------------------------------------------*/
441 NPT_String::CompareN(const char* s1
, const char *s2
, NPT_Size count
, bool ignore_case
)
446 for (unsigned int i
=0; i
<count
; i
++) {
447 if (NPT_Uppercase(me
[i
]) != NPT_Uppercase(s2
[i
])) {
448 return NPT_Uppercase(me
[i
]) - NPT_Uppercase(s2
[i
]);
453 for (unsigned int i
=0; i
<count
; i
++) {
454 if (me
[i
] != s2
[i
]) {
455 return (me
[i
] - s2
[i
]);
462 /*----------------------------------------------------------------------
464 +---------------------------------------------------------------------*/
466 NPT_String::Split(const char* separator
) const
468 NPT_List
<NPT_String
> result
;
469 NPT_Size separator_length
= NPT_StringLength(separator
);
471 // sepcial case for empty separators
472 if (separator_length
== 0) {
480 next
= Find(separator
, current
);
481 unsigned int end
= (next
>=0?(unsigned int)next
:GetLength());
482 result
.Add(SubString(current
, end
-current
));
483 current
= next
+separator_length
;
489 /*----------------------------------------------------------------------
490 | NPT_String::SplitAny
491 +---------------------------------------------------------------------*/
492 NPT_Array
<NPT_String
>
493 NPT_String::SplitAny(const char* separator
) const
495 NPT_Array
<NPT_String
> result((GetLength()>>1)+1);
497 // sepcial case for empty separators
498 if (NPT_StringLength(separator
) == 0) {
506 next
= FindAny(separator
, current
);
507 unsigned int end
= (next
>=0?(unsigned int)next
:GetLength());
508 result
.Add(SubString(current
, end
-current
));
515 /*----------------------------------------------------------------------
517 +---------------------------------------------------------------------*/
519 NPT_String::Join(NPT_List
<NPT_String
>& args
, const char* separator
)
522 NPT_List
<NPT_String
>::Iterator arg
= args
.GetFirstItem();
525 if (++arg
) output
+= separator
;
531 /*----------------------------------------------------------------------
532 | NPT_String::SubString
533 +---------------------------------------------------------------------*/
535 NPT_String::SubString(NPT_Ordinal first
, NPT_Size length
) const
537 if (first
>= GetLength()) {
540 } else if (first
+length
>= GetLength()) {
541 length
= GetLength()-first
;
543 return NPT_String(GetChars()+first
, length
);
546 /*----------------------------------------------------------------------
547 | NPT_StringStartsWith
550 | 1 if str starts with sub,
551 | 0 if str is large enough but does not start with sub
552 | -1 if str is too short to start with sub
553 +---------------------------------------------------------------------*/
555 NPT_StringStartsWith(const char* str
, const char* sub
, bool ignore_case
)
558 while (NPT_Uppercase(*str
) == NPT_Uppercase(*sub
)) {
559 if (*str
++ == '\0') {
565 while (*str
== *sub
) {
566 if (*str
++ == '\0') {
572 return (*sub
== '\0') ? 1 : (*str
== '\0' ? -1 : 0);
575 /*----------------------------------------------------------------------
576 | NPT_String::StartsWith
577 +---------------------------------------------------------------------*/
579 NPT_String::StartsWith(const char *s
, bool ignore_case
) const
581 if (s
== NULL
) return false;
582 return NPT_StringStartsWith(GetChars(), s
, ignore_case
) == 1;
585 /*----------------------------------------------------------------------
586 | NPT_String::EndsWith
587 +---------------------------------------------------------------------*/
589 NPT_String::EndsWith(const char *s
, bool ignore_case
) const
591 if (s
== NULL
) return false;
592 NPT_Size str_length
= NPT_StringLength(s
);
593 if (str_length
> GetLength()) return false;
594 return NPT_StringStartsWith(GetChars()+GetLength()-str_length
, s
, ignore_case
) == 1;
597 /*----------------------------------------------------------------------
599 +---------------------------------------------------------------------*/
601 NPT_String::Find(const char* str
, NPT_Ordinal start
, bool ignore_case
) const
604 if (str
== NULL
|| start
>= GetLength()) return -1;
606 // skip to start position
607 const char* src
= m_Chars
+ start
;
609 // look for a substring
611 int cmp
= NPT_StringStartsWith(src
, str
, ignore_case
);
614 // ref is too short, abort
618 return (int)(src
-m_Chars
);
626 /*----------------------------------------------------------------------
628 +---------------------------------------------------------------------*/
630 NPT_String::Find(char c
, NPT_Ordinal start
, bool ignore_case
) const
633 if (start
>= GetLength()) return -1;
635 // skip to start position
636 const char* src
= m_Chars
+ start
;
638 // look for the character
641 if (NPT_Uppercase(*src
) == NPT_Uppercase(c
)) {
642 return (int)(src
-m_Chars
);
648 if (*src
== c
) return (int)(src
-m_Chars
);
656 /*----------------------------------------------------------------------
657 | NPT_String::FindAny
658 +---------------------------------------------------------------------*/
660 NPT_String::FindAny(const char* s
, NPT_Ordinal start
, bool ignore_case
) const
663 if (start
>= GetLength()) return -1;
665 // skip to start position
666 const char* src
= m_Chars
+ start
;
668 // look for the character
671 for (NPT_Size i
=0; i
<NPT_StringLength(s
); i
++) {
672 if (NPT_Uppercase(*src
) == NPT_Uppercase(s
[i
])) {
673 return (int)(src
-m_Chars
);
680 for (NPT_Size i
=0; i
<NPT_StringLength(s
); i
++) {
681 if (*src
== s
[i
]) return (int)(src
-m_Chars
);
690 /*----------------------------------------------------------------------
691 | NPT_String::ReverseFind
692 +---------------------------------------------------------------------*/
694 NPT_String::ReverseFind(const char* str
, NPT_Ordinal start
, bool ignore_case
) const
697 if (str
== NULL
|| *str
== '\0') return -1;
699 // look for a substring
700 NPT_Size my_length
= GetLength();
701 NPT_Size str_length
= NPT_StringLength(str
);
702 int i
=my_length
-start
-str_length
;
703 const char* src
= GetChars();
706 int cmp
= NPT_StringStartsWith(src
+i
, str
, ignore_case
);
716 /*----------------------------------------------------------------------
717 | NPT_String::ReverseFind
718 +---------------------------------------------------------------------*/
720 NPT_String::ReverseFind(char c
, NPT_Ordinal start
, bool ignore_case
) const
723 NPT_Size length
= GetLength();
724 int i
= length
-start
-1;
725 if (i
< 0) return -1;
727 // look for the character
728 const char* src
= GetChars();
731 if (NPT_Uppercase(src
[i
]) == NPT_Uppercase(c
)) {
737 if (src
[i
] == c
) return i
;
744 /*----------------------------------------------------------------------
745 | NPT_String::MakeLowercase
746 +---------------------------------------------------------------------*/
748 NPT_String::MakeLowercase()
750 // the source is the current buffer
751 const char* src
= GetChars();
753 // convert all the characters of the existing buffer
754 char* dst
= const_cast<char*>(src
);
755 while (*dst
!= '\0') {
756 *dst
= NPT_Lowercase(*dst
);
761 /*----------------------------------------------------------------------
762 | NPT_String::MakeUppercase
763 +---------------------------------------------------------------------*/
765 NPT_String::MakeUppercase()
767 // the source is the current buffer
768 const char* src
= GetChars();
770 // convert all the characters of the existing buffer
771 char* dst
= const_cast<char*>(src
);
772 while (*dst
!= '\0') {
773 *dst
= NPT_Uppercase(*dst
);
778 /*----------------------------------------------------------------------
779 | NPT_String::ToLowercase
780 +---------------------------------------------------------------------*/
782 NPT_String::ToLowercase() const
784 NPT_String
result(*this);
785 result
.MakeLowercase();
789 /*----------------------------------------------------------------------
790 | NPT_String::ToUppercase
791 +---------------------------------------------------------------------*/
793 NPT_String::ToUppercase() const
795 NPT_String
result(*this);
796 result
.MakeUppercase();
800 /*----------------------------------------------------------------------
801 | NPT_String::Replace
802 +---------------------------------------------------------------------*/
804 NPT_String::Replace(char a
, char b
)
807 if (m_Chars
== NULL
|| a
== '\0' || b
== '\0') return *this;
809 // we are going to modify the characters
812 // process the buffer in place
814 if (*src
== a
) *src
= b
;
820 /*----------------------------------------------------------------------
821 | NPT_String::Replace
822 +---------------------------------------------------------------------*/
824 NPT_String::Replace(char a
, const char* str
)
827 if (m_Chars
== NULL
|| a
== '\0' || str
== NULL
|| str
[0] == '\0') return *this;
830 if (NPT_StringLength(str
) == 1) return Replace(a
, str
[0]);
832 // we are going to create a new string
836 // reserve at least as much as input
837 dst
.Reserve(GetLength());
839 // process the buffer
849 Assign(dst
.GetChars(), dst
.GetLength());
853 /*----------------------------------------------------------------------
854 | NPT_String::Replace
855 +---------------------------------------------------------------------*/
857 NPT_String::Replace(const char* before
, const char* after
)
859 NPT_Size size_before
= NPT_StringLength(before
);
860 NPT_Size size_after
= NPT_StringLength(after
);
861 int index
= Find(before
);
862 while (index
!= NPT_STRING_SEARCH_FAILED
) {
863 Erase(index
, size_before
);
864 Insert(after
, index
);
865 index
= Find(before
, index
+size_after
);
870 /*----------------------------------------------------------------------
872 +---------------------------------------------------------------------*/
874 NPT_String::Insert(const char* str
, NPT_Ordinal where
)
877 if (str
== NULL
|| where
> GetLength()) return *this;
879 // measure the string to insert
880 NPT_Size str_length
= StringLength(str
);
881 if (str_length
== 0) return *this;
883 // compute the size of the new string
884 NPT_Size old_length
= GetLength();
885 NPT_Size new_length
= str_length
+ GetLength();
887 // prepare to write the new string
889 char* nst
= Buffer::Create(new_length
, new_length
);
892 // copy the beginning of the old string
894 CopyBuffer(dst
, src
, where
);
899 // copy the inserted string
900 CopyString(dst
, str
);
903 // copy the end of the old string
904 if (old_length
> where
) {
905 CopyString(dst
, src
);
908 // use the new string
909 if (m_Chars
) delete GetBuffer();
914 /*----------------------------------------------------------------------
916 +---------------------------------------------------------------------*/
918 NPT_String::Erase(NPT_Ordinal start
, NPT_Cardinal count
/* = 1 */)
921 NPT_Size length
= GetLength();
922 if (start
+count
> length
) {
923 if (start
>= length
) return *this;
924 count
= length
-start
;
926 if (count
== 0) return *this;
928 CopyString(m_Chars
+start
, m_Chars
+start
+count
);
929 GetBuffer()->SetLength(length
-count
);
933 /*----------------------------------------------------------------------
934 | NPT_String::ToInteger
935 +---------------------------------------------------------------------*/
937 NPT_String::ToInteger(int& value
, bool relaxed
) const
939 return NPT_ParseInteger(GetChars(), value
, relaxed
);
942 /*----------------------------------------------------------------------
943 | NPT_String::ToInteger
944 +---------------------------------------------------------------------*/
946 NPT_String::ToInteger(unsigned int& value
, bool relaxed
) const
948 return NPT_ParseInteger(GetChars(), value
, relaxed
);
951 /*----------------------------------------------------------------------
952 | NPT_String::ToInteger
953 +---------------------------------------------------------------------*/
955 NPT_String::ToInteger(long& value
, bool relaxed
) const
957 return NPT_ParseInteger(GetChars(), value
, relaxed
);
960 /*----------------------------------------------------------------------
961 | NPT_String::ToInteger
962 +---------------------------------------------------------------------*/
964 NPT_String::ToInteger(unsigned long& value
, bool relaxed
) const
966 return NPT_ParseInteger(GetChars(), value
, relaxed
);
969 /*----------------------------------------------------------------------
970 | NPT_String::ToInteger32
971 +---------------------------------------------------------------------*/
973 NPT_String::ToInteger32(NPT_Int32
& value
, bool relaxed
) const
975 return NPT_ParseInteger32(GetChars(), value
, relaxed
);
978 /*----------------------------------------------------------------------
979 | NPT_String::ToInteger32
980 +---------------------------------------------------------------------*/
982 NPT_String::ToInteger32(NPT_UInt32
& value
, bool relaxed
) const
984 return NPT_ParseInteger32(GetChars(), value
, relaxed
);
987 /*----------------------------------------------------------------------
988 | NPT_String::ToInteger64
989 +---------------------------------------------------------------------*/
991 NPT_String::ToInteger64(NPT_Int64
& value
, bool relaxed
) const
993 return NPT_ParseInteger64(GetChars(), value
, relaxed
);
996 /*----------------------------------------------------------------------
997 | NPT_String::ToInteger64
998 +---------------------------------------------------------------------*/
1000 NPT_String::ToInteger64(NPT_UInt64
& value
, bool relaxed
) const
1002 return NPT_ParseInteger64(GetChars(), value
, relaxed
);
1005 /*----------------------------------------------------------------------
1006 | NPT_String::ToFloat
1007 +---------------------------------------------------------------------*/
1009 NPT_String::ToFloat(float& value
, bool relaxed
) const
1011 return NPT_ParseFloat(GetChars(), value
, relaxed
);
1014 /*----------------------------------------------------------------------
1015 | NPT_String::TrimLeft
1016 +---------------------------------------------------------------------*/
1018 NPT_String::TrimLeft()
1020 return TrimLeft(NPT_STRINGS_WHITESPACE_CHARS
);
1023 /*----------------------------------------------------------------------
1024 | NPT_String::TrimLeft
1025 +---------------------------------------------------------------------*/
1027 NPT_String::TrimLeft(char c
)
1030 return TrimLeft((const char*)s
);
1033 /*----------------------------------------------------------------------
1034 | NPT_String::TrimLeft
1035 +---------------------------------------------------------------------*/
1037 NPT_String::TrimLeft(const char* chars
)
1039 if (m_Chars
== NULL
) return *this;
1040 const char* s
= m_Chars
;
1041 while (char c
= *s
) {
1042 const char* x
= chars
;
1047 if (*x
== 0) break; // not found
1051 // nothing was trimmed
1055 // shift chars to the left
1057 GetBuffer()->SetLength(GetLength()-(NPT_Size
)(s
-d
));
1058 while ((*d
++ = *s
++)) {};
1062 /*----------------------------------------------------------------------
1063 | NPT_String::TrimRight
1064 +---------------------------------------------------------------------*/
1066 NPT_String::TrimRight()
1068 return TrimRight(NPT_STRINGS_WHITESPACE_CHARS
);
1071 /*----------------------------------------------------------------------
1072 | NPT_String::TrimRight
1073 +---------------------------------------------------------------------*/
1075 NPT_String::TrimRight(char c
)
1078 return TrimRight((const char*)s
);
1081 /*----------------------------------------------------------------------
1082 | NPT_String::TrimRight
1083 +---------------------------------------------------------------------*/
1085 NPT_String::TrimRight(const char* chars
)
1087 if (m_Chars
== NULL
|| m_Chars
[0] == '\0') return *this;
1088 char* tail
= m_Chars
+GetLength()-1;
1090 while (s
!= m_Chars
-1) {
1091 const char* x
= chars
;
1099 if (*x
== 0) break; // not found
1103 // nothing was trimmed
1106 GetBuffer()->SetLength(1+(int)(s
-m_Chars
));
1110 /*----------------------------------------------------------------------
1112 +---------------------------------------------------------------------*/
1120 /*----------------------------------------------------------------------
1122 +---------------------------------------------------------------------*/
1124 NPT_String::Trim(char c
)
1127 TrimLeft((const char*)s
);
1128 return TrimRight((const char*)s
);
1131 /*----------------------------------------------------------------------
1133 +---------------------------------------------------------------------*/
1135 NPT_String::Trim(const char* chars
)
1138 return TrimRight(chars
);
1141 /*----------------------------------------------------------------------
1142 | NPT_String::operator+(const NPT_String&, const char*)
1143 +---------------------------------------------------------------------*/
1145 operator+(const NPT_String
& s1
, const char* s2
)
1148 if (s2
== NULL
) return NPT_String(s1
);
1151 NPT_Size s1_length
= s1
.GetLength();
1152 NPT_Size s2_length
= NPT_String::StringLength(s2
);
1154 // allocate space for the new string
1156 char* start
= result
.PrepareToWrite(s1_length
+s2_length
);
1158 // concatenate the two strings into the result
1159 NPT_String::CopyBuffer(start
, s1
, s1_length
);
1160 NPT_String::CopyString(start
+s1_length
, s2
);
1165 /*----------------------------------------------------------------------
1166 | NPT_String::operator+(const NPT_String& , const char*)
1167 +---------------------------------------------------------------------*/
1169 operator+(const char* s1
, const NPT_String
& s2
)
1172 if (s1
== NULL
) return NPT_String(s2
);
1175 NPT_Size s1_length
= NPT_String::StringLength(s1
);
1176 NPT_Size s2_length
= s2
.GetLength();
1178 // allocate space for the new string
1180 char* start
= result
.PrepareToWrite(s1_length
+s2_length
);
1182 // concatenate the two strings into the result
1183 NPT_String::CopyBuffer(start
, s1
, s1_length
);
1184 NPT_String::CopyString(start
+s1_length
, s2
.GetChars());
1189 /*----------------------------------------------------------------------
1190 | NPT_String::operator+(const NPT_String& , char)
1191 +---------------------------------------------------------------------*/
1193 operator+(const NPT_String
& s1
, char c
)
1195 // allocate space for the new string
1197 result
.Reserve(s1
.GetLength()+1);