2 * Copyright 2001-2014 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Stefano Ceccherini, burton666@libero.it
7 * Axel Dörfler, axeld@pinc-software.de
8 * Marc Flerackers, mflerackers@androme.be
9 * Julun, host.haiku@gmx.de
10 * Michael Lotz, mmlr@mlotz.ch
11 * Oliver Tappe, openbeos@hirschkaefer.de
15 /*! String class supporting common string operations. */
26 #include <StringList.h>
28 #include <StringPrivate.h>
29 #include <utf8_functions.h>
32 // define proper names for case-option of _DoReplace()
33 #define KEEP_CASE false
34 #define IGNORE_CASE true
36 // define proper names for count-option of _DoReplace()
37 #define REPLACE_ALL 0x7FFFFFFF
40 static const uint32 kPrivateDataOffset
= BString::Private::kPrivateDataOffset
;
42 const char* B_EMPTY_STRING
= "";
45 // helper function, returns minimum of two given values (but clamps to 0):
47 min_clamp0(int32 num1
, int32 num2
)
50 return num1
> 0 ? num1
: 0;
52 return num2
> 0 ? num2
: 0;
56 //! Returns length of given string (but clamps to given maximum).
58 strlen_clamp(const char* string
, int32 max
)
60 // this should yield 0 for max<0:
61 return max
<= 0 ? 0 : strnlen(string
, max
);
65 //! Helper function for strlen() that can handle NULL strings.
67 string_length(const char* string
)
69 return string
!= NULL
? strlen(string
) : 0;
73 //! helper function, massages given pointer into a legal c-string:
74 static inline const char*
75 safestr(const char* string
)
77 return string
!= NULL
? string
: "";
81 // #pragma mark - PosVect
84 class BString::PosVect
{
101 if (fBuffer
== NULL
|| fSize
== fBufferSize
) {
105 int32
* newBuffer
= NULL
;
106 newBuffer
= (int32
*)realloc(fBuffer
, fBufferSize
* sizeof(int32
));
107 if (newBuffer
== NULL
)
113 fBuffer
[fSize
++] = pos
;
118 inline int32
ItemAt(int32 index
) const
120 return fBuffer
[index
];
123 inline int32
CountItems() const
135 // #pragma mark - BString
139 BString::_ReferenceCount()
141 return Private::DataRefCount(fPrivateData
);
146 BString::_ReferenceCount() const
148 return Private::DataRefCount(fPrivateData
);
153 BString::_IsShareable() const
155 return fPrivateData
!= NULL
&& _ReferenceCount() >= 0;
167 BString::BString(const char* string
)
171 _Init(string
, strlen(safestr(string
)));
175 BString::BString(const BString
& string
)
179 // check if source is sharable - if so, share else clone
180 if (string
._IsShareable()) {
181 fPrivateData
= string
.fPrivateData
;
182 atomic_add(&_ReferenceCount(), 1);
183 // string cannot go away right now
185 _Init(string
.String(), string
.Length());
189 BString::BString(const char* string
, int32 maxLength
)
192 _Init(string
, strlen_clamp(safestr(string
), maxLength
));
198 if (!_IsShareable() || atomic_add(&_ReferenceCount(), -1) == 1)
203 // #pragma mark - Access
207 BString::CountChars() const
209 return UTF8CountChars(fPrivateData
, Length());
214 BString::CountBytes(int32 fromCharOffset
, int32 charCount
) const
216 return UTF8CountBytes(
217 fPrivateData
+ UTF8CountBytes(fPrivateData
, fromCharOffset
), charCount
);
222 BString::HashValue(const char* string
)
224 // from the Dragon Book: a slightly modified hashpjw()
226 if (string
!= NULL
) {
227 for (; *string
; string
++) {
228 uint32 g
= h
& 0xf0000000;
231 h
= (h
<< 4) + *string
;
238 // #pragma mark - Assignment
242 BString::operator=(const BString
& string
)
244 return SetTo(string
);
249 BString::operator=(const char* string
)
253 if (string
!= String())
254 SetTo(string
, strlen(string
));
260 BString::operator=(char c
)
267 BString::SetTo(const char* string
, int32 maxLength
)
270 maxLength
= INT32_MAX
;
272 maxLength
= strlen_clamp(safestr(string
), maxLength
);
274 if (_MakeWritable(maxLength
, false) == B_OK
)
275 memcpy(fPrivateData
, string
, maxLength
);
282 BString::SetTo(const BString
& string
)
284 // we share the information already
285 if (fPrivateData
== string
.fPrivateData
)
288 bool freeData
= true;
290 if (_IsShareable() && atomic_add(&_ReferenceCount(), -1) > 1) {
291 // there is still someone who shares our data
298 // if source is sharable share, otherwise clone
299 if (string
._IsShareable()) {
300 fPrivateData
= string
.fPrivateData
;
301 atomic_add(&_ReferenceCount(), 1);
302 // the string cannot go away right now
304 _Init(string
.String(), string
.Length());
311 BString::Adopt(BString
& from
)
321 BString::SetTo(const BString
& string
, int32 maxLength
)
324 maxLength
= INT32_MAX
;
325 if (fPrivateData
!= string
.fPrivateData
326 // make sure we reassing in case length is different
327 || (fPrivateData
== string
.fPrivateData
&& Length() > maxLength
)) {
328 maxLength
= min_clamp0(maxLength
, string
.Length());
329 if (_MakeWritable(maxLength
, false) == B_OK
)
330 memcpy(fPrivateData
, string
.String(), maxLength
);
337 BString::Adopt(BString
& from
, int32 maxLength
)
339 SetTo(from
, maxLength
);
347 BString::SetTo(char c
, int32 count
)
352 if (_MakeWritable(count
, false) == B_OK
)
353 memset(fPrivateData
, c
, count
);
360 BString::SetToChars(const char* string
, int32 charCount
)
362 return SetTo(string
, UTF8CountBytes(string
, charCount
));
367 BString::SetToChars(const BString
& string
, int32 charCount
)
369 return SetTo(string
, UTF8CountBytes(string
.String(), charCount
));
374 BString::AdoptChars(BString
& string
, int32 charCount
)
376 return Adopt(string
, UTF8CountBytes(string
.String(), charCount
));
381 BString::SetToFormat(const char* format
, ...)
384 va_start(args
, format
);
385 SetToFormatVarArgs(format
, args
);
393 BString::SetToFormatVarArgs(const char* format
, va_list args
)
395 // Use a small on-stack buffer to save a second vsnprintf() call for most
397 int32 bufferSize
= 1024;
398 char buffer
[bufferSize
];
402 __va_copy(clonedArgs
, args
);
404 va_copy(clonedArgs
, args
);
406 int32 bytes
= vsnprintf(buffer
, bufferSize
, format
, clonedArgs
);
412 if (bytes
< bufferSize
) {
417 bytes
= vsnprintf(LockBuffer(bytes
), bytes
+ 1, format
, args
);
427 BString::ScanWithFormat(const char* format
, ...)
430 va_start(args
, format
);
431 int result
= ScanWithFormatVarArgs(format
, args
);
439 BString::ScanWithFormatVarArgs(const char* format
, va_list args
)
441 return vsscanf(fPrivateData
, format
, args
);
445 // #pragma mark - Substring copying
449 BString::CopyInto(BString
& into
, int32 fromOffset
, int32 length
) const
452 into
.SetTo(fPrivateData
+ fromOffset
, length
);
458 BString::CopyInto(char* into
, int32 fromOffset
, int32 length
) const
461 length
= min_clamp0(length
, Length() - fromOffset
);
462 memcpy(into
, fPrivateData
+ fromOffset
, length
);
468 BString::CopyCharsInto(BString
& into
, int32 fromCharOffset
,
469 int32 charCount
) const
471 int32 fromOffset
= UTF8CountBytes(fPrivateData
, fromCharOffset
);
472 int32 length
= UTF8CountBytes(fPrivateData
+ fromOffset
, charCount
);
473 return CopyInto(into
, fromOffset
, length
);
478 BString::CopyCharsInto(char* into
, int32
* intoLength
, int32 fromCharOffset
,
479 int32 charCount
) const
484 int32 fromOffset
= UTF8CountBytes(fPrivateData
, fromCharOffset
);
485 int32 length
= UTF8CountBytes(fPrivateData
+ fromOffset
, charCount
);
486 length
= min_clamp0(length
, Length() - fromOffset
);
488 if (intoLength
!= NULL
) {
489 if (*intoLength
< length
)
491 *intoLength
= length
;
494 memcpy(into
, fPrivateData
+ fromOffset
, length
);
500 BString::Split(const char* separator
, bool noEmptyStrings
,
501 BStringList
& _list
) const
503 int32 separatorLength
= strlen(separator
);
504 int32 length
= Length();
505 if (separatorLength
== 0 || length
== 0 || separatorLength
> length
) {
506 if (length
== 0 && noEmptyStrings
)
508 return _list
.Add(*this);
513 int32 endIndex
= index
< length
? FindFirst(separator
, index
) : length
;
517 if (endIndex
> index
|| !noEmptyStrings
) {
518 BString
toAppend(String() + index
, endIndex
- index
);
519 if (toAppend
.Length() != endIndex
- index
520 || !_list
.Add(toAppend
)) {
525 if (endIndex
== length
)
528 index
= endIndex
+ 1;
535 // #pragma mark - Appending
539 BString::operator+=(const char* string
)
542 int32 length
= strlen(string
);
544 _DoAppend(string
, length
);
551 BString::operator+=(char c
)
559 BString::Append(const BString
& string
, int32 length
)
561 if (&string
!= this) {
562 length
= min_clamp0(length
, string
.Length());
564 _DoAppend(string
.fPrivateData
, length
);
571 BString::Append(const char* string
, int32 length
)
574 length
= strlen_clamp(string
, length
);
576 _DoAppend(string
, length
);
583 BString::Append(char c
, int32 count
)
585 int32 oldLength
= Length();
586 if (count
> 0 && _DoAppend("", count
))
587 memset(fPrivateData
+ oldLength
, c
, count
);
593 BString::AppendChars(const BString
& string
, int32 charCount
)
595 return Append(string
, UTF8CountBytes(string
.String(), charCount
));
600 BString::AppendChars(const char* string
, int32 charCount
)
602 return Append(string
, UTF8CountBytes(string
, charCount
));
606 // #pragma mark - Prepending
610 BString::Prepend(const char* string
)
613 _DoPrepend(string
, strlen(string
));
619 BString::Prepend(const BString
& string
)
622 _DoPrepend(string
.String(), string
.Length());
628 BString::Prepend(const char* string
, int32 length
)
631 _DoPrepend(string
, strlen_clamp(string
, length
));
637 BString::Prepend(const BString
& string
, int32 length
)
640 _DoPrepend(string
.fPrivateData
, min_clamp0(length
, string
.Length()));
646 BString::Prepend(char c
, int32 count
)
648 if (count
> 0 && _DoPrepend("", count
))
649 memset(fPrivateData
, c
, count
);
655 BString::PrependChars(const char* string
, int32 charCount
)
657 return Prepend(string
, UTF8CountBytes(string
, charCount
));
662 BString::PrependChars(const BString
& string
, int32 charCount
)
664 return Prepend(string
, UTF8CountBytes(string
.String(), charCount
));
668 // #pragma mark - Inserting
672 BString::Insert(const char* string
, int32 position
)
674 if (string
!= NULL
&& position
<= Length()) {
675 int32 len
= int32(strlen(string
));
677 int32 skipLen
= min_clamp0(-1 * position
, len
);
682 position
= min_clamp0(position
, Length());
684 _DoInsert(string
, position
, len
);
691 BString::Insert(const char* string
, int32 length
, int32 position
)
693 if (string
!= NULL
&& position
<= Length()) {
694 int32 len
= strlen_clamp(string
, length
);
696 int32 skipLen
= min_clamp0(-1 * position
, len
);
701 position
= min_clamp0(position
, Length());
703 _DoInsert(string
, position
, len
);
710 BString::Insert(const char* string
, int32 fromOffset
, int32 length
,
714 Insert(string
+ fromOffset
, length
, position
);
720 BString::Insert(const BString
& string
, int32 position
)
722 if (&string
!= this && string
.Length() > 0)
723 Insert(string
.fPrivateData
, position
);
729 BString::Insert(const BString
& string
, int32 length
, int32 position
)
731 if (&string
!= this && string
.Length() > 0)
732 Insert(string
.String(), length
, position
);
738 BString::Insert(const BString
& string
, int32 fromOffset
, int32 length
,
741 if (&string
!= this && string
.Length() > 0)
742 Insert(string
.String() + fromOffset
, length
, position
);
748 BString::Insert(char c
, int32 count
, int32 position
)
751 count
= MAX(count
+ position
, 0);
754 position
= min_clamp0(position
, Length());
756 if (count
> 0 && _DoInsert("", position
, count
))
757 memset(fPrivateData
+ position
, c
, count
);
764 BString::InsertChars(const char* string
, int32 charPosition
)
766 return Insert(string
, UTF8CountBytes(fPrivateData
, charPosition
));
771 BString::InsertChars(const char* string
, int32 charCount
, int32 charPosition
)
773 return Insert(string
, UTF8CountBytes(string
, charCount
),
774 UTF8CountBytes(fPrivateData
, charPosition
));
779 BString::InsertChars(const char* string
, int32 fromCharOffset
,
780 int32 charCount
, int32 charPosition
)
782 int32 fromOffset
= UTF8CountBytes(string
, fromCharOffset
);
783 return Insert(string
, fromOffset
,
784 UTF8CountBytes(string
+ fromOffset
, charCount
),
785 UTF8CountBytes(fPrivateData
, charPosition
));
790 BString::InsertChars(const BString
& string
, int32 charPosition
)
792 return Insert(string
, UTF8CountBytes(fPrivateData
, charPosition
));
797 BString::InsertChars(const BString
& string
, int32 charCount
, int32 charPosition
)
799 return Insert(string
, UTF8CountBytes(string
.String(), charCount
),
800 UTF8CountBytes(fPrivateData
, charPosition
));
805 BString::InsertChars(const BString
& string
, int32 fromCharOffset
,
806 int32 charCount
, int32 charPosition
)
808 int32 fromOffset
= UTF8CountBytes(string
.String(), fromCharOffset
);
809 return Insert(string
, fromOffset
,
810 UTF8CountBytes(string
.String() + fromOffset
, charCount
),
811 UTF8CountBytes(fPrivateData
, charPosition
));
815 // #pragma mark - Removing
819 BString::Truncate(int32 newLength
, bool lazy
)
824 if (newLength
< Length()) {
825 // ignore lazy, since we might detach
826 _MakeWritable(newLength
, true);
834 BString::TruncateChars(int32 newCharCount
, bool lazy
)
836 return Truncate(UTF8CountBytes(fPrivateData
, newCharCount
));
841 BString::Remove(int32 from
, int32 length
)
843 if (length
> 0 && from
< Length())
844 _ShrinkAtBy(from
, min_clamp0(length
, (Length() - from
)));
850 BString::RemoveChars(int32 fromCharOffset
, int32 charCount
)
852 int32 fromOffset
= UTF8CountBytes(fPrivateData
, fromCharOffset
);
853 return Remove(fromOffset
,
854 UTF8CountBytes(fPrivateData
+ fromOffset
, charCount
));
859 BString::RemoveFirst(const BString
& string
)
861 if (string
.Length() > 0) {
862 int32 pos
= _ShortFindAfter(string
.String(), string
.Length());
864 _ShrinkAtBy(pos
, string
.Length());
871 BString::RemoveLast(const BString
& string
)
873 int32 pos
= _FindBefore(string
.String(), Length(), string
.Length());
875 _ShrinkAtBy(pos
, string
.Length());
882 BString::RemoveAll(const BString
& string
)
884 if (string
.Length() == 0 || Length() == 0 || FindFirst(string
) < 0)
887 if (_MakeWritable() != B_OK
)
890 return _DoReplace(string
.String(), "", REPLACE_ALL
, 0, KEEP_CASE
);
895 BString::RemoveFirst(const char* string
)
897 int32 length
= string
? strlen(string
) : 0;
899 int32 pos
= _ShortFindAfter(string
, length
);
901 _ShrinkAtBy(pos
, length
);
908 BString::RemoveLast(const char* string
)
910 int32 length
= string
? strlen(string
) : 0;
912 int32 pos
= _FindBefore(string
, Length(), length
);
914 _ShrinkAtBy(pos
, length
);
921 BString::RemoveAll(const char* string
)
923 if (!string
|| Length() == 0 || FindFirst(string
) < 0)
926 if (_MakeWritable() != B_OK
)
929 return _DoReplace(string
, "", REPLACE_ALL
, 0, KEEP_CASE
);
934 BString::RemoveSet(const char* setOfBytesToRemove
)
936 return ReplaceSet(setOfBytesToRemove
, "");
941 BString::RemoveCharsSet(const char* setOfCharsToRemove
)
943 return ReplaceCharsSet(setOfCharsToRemove
, "");
948 BString::MoveInto(BString
& into
, int32 from
, int32 length
)
951 CopyInto(into
, from
, length
);
952 Remove(from
, length
);
959 BString::MoveInto(char* into
, int32 from
, int32 length
)
962 CopyInto(into
, from
, length
);
963 Remove(from
, length
);
969 BString::MoveCharsInto(BString
& into
, int32 fromCharOffset
, int32 charCount
)
972 CopyCharsInto(into
, fromCharOffset
, charCount
);
973 RemoveChars(fromCharOffset
, charCount
);
981 BString::MoveCharsInto(char* into
, int32
* intoLength
, int32 fromCharOffset
,
984 if (!CopyCharsInto(into
, intoLength
, fromCharOffset
, charCount
))
987 RemoveChars(fromCharOffset
, charCount
);
992 // #pragma mark - Compare functions
996 BString::operator<(const char* string
) const
998 return strcmp(String(), safestr(string
)) < 0;
1003 BString::operator<=(const char* string
) const
1005 return strcmp(String(), safestr(string
)) <= 0;
1010 BString::operator==(const char* string
) const
1012 return strcmp(String(), safestr(string
)) == 0;
1017 BString::operator>=(const char* string
) const
1019 return strcmp(String(), safestr(string
)) >= 0;
1024 BString::operator>(const char* string
) const
1026 return strcmp(String(), safestr(string
)) > 0;
1030 // #pragma mark - strcmp()-style compare functions
1034 BString::Compare(const BString
& string
) const
1036 return strcmp(String(), string
.String());
1041 BString::Compare(const char* string
) const
1043 return strcmp(String(), safestr(string
));
1048 BString::Compare(const BString
& string
, int32 length
) const
1050 return strncmp(String(), string
.String(), length
);
1055 BString::Compare(const char* string
, int32 length
) const
1057 return strncmp(String(), safestr(string
), length
);
1062 BString::CompareAt(size_t offset
, const BString
& string
, int32 length
) const
1064 return strncmp(String() + offset
, string
.String(), length
);
1069 BString::CompareChars(const BString
& string
, int32 charCount
) const
1071 return Compare(string
, UTF8CountBytes(fPrivateData
, charCount
));
1076 BString::CompareChars(const char* string
, int32 charCount
) const
1078 return Compare(string
, UTF8CountBytes(fPrivateData
, charCount
));
1083 BString::ICompare(const BString
& string
) const
1085 return strcasecmp(String(), string
.String());
1090 BString::ICompare(const char* string
) const
1092 return strcasecmp(String(), safestr(string
));
1097 BString::ICompare(const BString
& string
, int32 length
) const
1099 return strncasecmp(String(), string
.String(), length
);
1104 BString::ICompare(const char* string
, int32 length
) const
1106 return strncasecmp(String(), safestr(string
), length
);
1110 // #pragma mark - Searching
1114 BString::FindFirst(const BString
& string
) const
1116 return _ShortFindAfter(string
.String(), string
.Length());
1121 BString::FindFirst(const char* string
) const
1126 return _ShortFindAfter(string
, strlen(string
));
1131 BString::FindFirst(const BString
& string
, int32 fromOffset
) const
1136 return _FindAfter(string
.String(), min_clamp0(fromOffset
, Length()),
1142 BString::FindFirst(const char* string
, int32 fromOffset
) const
1150 return _FindAfter(string
, min_clamp0(fromOffset
, Length()),
1151 strlen(safestr(string
)));
1156 BString::FindFirst(char c
) const
1158 const char* start
= String();
1159 const char* end
= String() + Length();
1161 // Scans the string until we found the
1162 // character, or we reach the string's start
1163 while (start
!= end
&& *start
!= c
) {
1170 return start
- String();
1175 BString::FindFirst(char c
, int32 fromOffset
) const
1180 const char* start
= String() + min_clamp0(fromOffset
, Length());
1181 const char* end
= String() + Length();
1183 // Scans the string until we found the
1184 // character, or we reach the string's start
1185 while (start
< end
&& *start
!= c
) {
1192 return start
- String();
1197 BString::FindFirstChars(const BString
& string
, int32 fromCharOffset
) const
1199 return FindFirst(string
, UTF8CountBytes(fPrivateData
, fromCharOffset
));
1204 BString::FindFirstChars(const char* string
, int32 fromCharOffset
) const
1206 return FindFirst(string
, UTF8CountBytes(fPrivateData
, fromCharOffset
));
1211 BString::FindLast(const BString
& string
) const
1213 return _FindBefore(string
.String(), Length(), string
.Length());
1218 BString::FindLast(const char* string
) const
1223 return _FindBefore(string
, Length(), strlen(safestr(string
)));
1228 BString::FindLast(const BString
& string
, int32 beforeOffset
) const
1230 if (beforeOffset
< 0)
1233 return _FindBefore(string
.String(), min_clamp0(beforeOffset
, Length()),
1239 BString::FindLast(const char* string
, int32 beforeOffset
) const
1244 if (beforeOffset
< 0)
1247 return _FindBefore(string
, min_clamp0(beforeOffset
, Length()),
1248 strlen(safestr(string
)));
1253 BString::FindLast(char c
) const
1255 const char* const start
= String();
1256 const char* end
= String() + Length() - 1;
1258 // Scans the string backwards until we found
1259 // the character, or we reach the string's start
1260 while (end
>= start
&& *end
!= c
) {
1272 BString::FindLast(char c
, int32 beforeOffset
) const
1274 if (beforeOffset
< 0)
1277 const char* const start
= String();
1278 const char* end
= String() + min_clamp0(beforeOffset
+ 1, Length()) - 1;
1280 // Scans the string backwards until we found
1281 // the character, or we reach the string's start
1282 while (end
>= start
&& *end
!= c
) {
1294 BString::FindLastChars(const BString
& string
, int32 beforeCharOffset
) const
1296 return FindLast(string
, UTF8CountBytes(fPrivateData
, beforeCharOffset
));
1301 BString::FindLastChars(const char* string
, int32 beforeCharOffset
) const
1303 return FindLast(string
, UTF8CountBytes(fPrivateData
, beforeCharOffset
));
1308 BString::IFindFirst(const BString
& string
) const
1310 return _IFindAfter(string
.String(), 0, string
.Length());
1315 BString::IFindFirst(const char* string
) const
1320 return _IFindAfter(string
, 0, strlen(safestr(string
)));
1325 BString::IFindFirst(const BString
& string
, int32 fromOffset
) const
1330 return _IFindAfter(string
.String(), min_clamp0(fromOffset
, Length()),
1336 BString::IFindFirst(const char* string
, int32 fromOffset
) const
1344 return _IFindAfter(string
, min_clamp0(fromOffset
,Length()),
1345 strlen(safestr(string
)));
1350 BString::IFindLast(const BString
& string
) const
1352 return _IFindBefore(string
.String(), Length(), string
.Length());
1357 BString::IFindLast(const char* string
) const
1362 return _IFindBefore(string
, Length(), strlen(safestr(string
)));
1367 BString::IFindLast(const BString
& string
, int32 beforeOffset
) const
1369 if (beforeOffset
< 0)
1372 return _IFindBefore(string
.String(), min_clamp0(beforeOffset
, Length()),
1378 BString::IFindLast(const char* string
, int32 beforeOffset
) const
1383 if (beforeOffset
< 0)
1386 return _IFindBefore(string
, min_clamp0(beforeOffset
, Length()),
1387 strlen(safestr(string
)));
1392 BString::StartsWith(const BString
& string
) const
1394 return StartsWith(string
.String(), string
.Length());
1399 BString::StartsWith(const char* string
) const
1401 return StartsWith(string
, strlen(safestr(string
)));
1406 BString::StartsWith(const char* string
, int32 length
) const
1408 if (length
> Length())
1411 return memcmp(String(), string
, length
) == 0;
1416 BString::IStartsWith(const BString
& string
) const
1418 return IStartsWith(string
.String(), string
.Length());
1423 BString::IStartsWith(const char* string
) const
1425 return IStartsWith(string
, strlen(safestr(string
)));
1430 BString::IStartsWith(const char* string
, int32 length
) const
1432 if (length
> Length() || length
> (int32
)strlen(safestr(string
)))
1435 return _IFindAfter(string
, 0, length
) == 0;
1440 BString::EndsWith(const BString
& string
) const
1442 return EndsWith(string
.String(), string
.Length());
1447 BString::EndsWith(const char* string
) const
1449 return EndsWith(string
, strlen(safestr(string
)));
1454 BString::EndsWith(const char* string
, int32 length
) const
1456 int32 offset
= Length() - length
;
1460 return memcmp(String() + offset
, string
, length
) == 0;
1465 BString::IEndsWith(const BString
& string
) const
1467 return IEndsWith(string
.String(), string
.Length());
1472 BString::IEndsWith(const char* string
) const
1474 return IEndsWith(string
, strlen(safestr(string
)));
1479 BString::IEndsWith(const char* string
, int32 length
) const
1481 int32 offset
= Length() - length
;
1485 return _IFindBefore(string
, Length(), length
) == offset
;
1489 // #pragma mark - Replacing
1493 BString::ReplaceFirst(char replaceThis
, char withThis
)
1495 int32 pos
= FindFirst(replaceThis
);
1496 if (pos
>= 0 && _MakeWritable() == B_OK
)
1497 fPrivateData
[pos
] = withThis
;
1503 BString::ReplaceLast(char replaceThis
, char withThis
)
1505 int32 pos
= FindLast(replaceThis
);
1506 if (pos
>= 0 && _MakeWritable() == B_OK
)
1507 fPrivateData
[pos
] = withThis
;
1513 BString::ReplaceAll(char replaceThis
, char withThis
, int32 fromOffset
)
1515 fromOffset
= min_clamp0(fromOffset
, Length());
1516 int32 pos
= FindFirst(replaceThis
, fromOffset
);
1518 // detach and set first match
1519 if (pos
>= 0 && _MakeWritable() == B_OK
) {
1520 for( ; pos
>= 0; pos
= FindFirst(replaceThis
, pos
+ 1))
1521 fPrivateData
[pos
] = withThis
;
1528 BString::Replace(char replaceThis
, char withThis
, int32 maxReplaceCount
,
1531 fromOffset
= min_clamp0(fromOffset
, Length());
1532 int32 pos
= FindFirst(replaceThis
, fromOffset
);
1534 if (maxReplaceCount
> 0 && pos
>= 0 && _MakeWritable() == B_OK
) {
1535 for( ; maxReplaceCount
> 0 && pos
>= 0;
1536 pos
= FindFirst(replaceThis
, pos
+ 1)) {
1537 fPrivateData
[pos
] = withThis
;
1546 BString::ReplaceFirst(const char* replaceThis
, const char* withThis
)
1548 if (!replaceThis
|| !withThis
|| FindFirst(replaceThis
) < 0)
1551 if (_MakeWritable() != B_OK
)
1554 return _DoReplace(replaceThis
, withThis
, 1, 0, KEEP_CASE
);
1559 BString::ReplaceLast(const char* replaceThis
, const char* withThis
)
1561 if (!replaceThis
|| !withThis
)
1564 int32 replaceThisLength
= strlen(replaceThis
);
1565 int32 pos
= _FindBefore(replaceThis
, Length(), replaceThisLength
);
1568 int32 withThisLength
= strlen(withThis
);
1569 int32 difference
= withThisLength
- replaceThisLength
;
1571 if (difference
> 0) {
1572 if (!_OpenAtBy(pos
, difference
))
1574 } else if (difference
< 0) {
1575 if (!_ShrinkAtBy(pos
, -difference
))
1578 if (_MakeWritable() != B_OK
)
1581 memcpy(fPrivateData
+ pos
, withThis
, withThisLength
);
1589 BString::ReplaceAll(const char* replaceThis
, const char* withThis
,
1592 if (!replaceThis
|| !withThis
|| FindFirst(replaceThis
) < 0)
1595 if (_MakeWritable() != B_OK
)
1598 return _DoReplace(replaceThis
, withThis
, REPLACE_ALL
,
1599 min_clamp0(fromOffset
, Length()), KEEP_CASE
);
1604 BString::Replace(const char* replaceThis
, const char* withThis
,
1605 int32 maxReplaceCount
, int32 fromOffset
)
1607 if (!replaceThis
|| !withThis
|| maxReplaceCount
<= 0
1608 || FindFirst(replaceThis
) < 0)
1611 if (_MakeWritable() != B_OK
)
1614 return _DoReplace(replaceThis
, withThis
, maxReplaceCount
,
1615 min_clamp0(fromOffset
, Length()), KEEP_CASE
);
1620 BString::ReplaceAllChars(const char* replaceThis
, const char* withThis
,
1621 int32 fromCharOffset
)
1623 return ReplaceAll(replaceThis
, withThis
,
1624 UTF8CountBytes(fPrivateData
, fromCharOffset
));
1629 BString::ReplaceChars(const char* replaceThis
, const char* withThis
,
1630 int32 maxReplaceCount
, int32 fromCharOffset
)
1632 return Replace(replaceThis
, withThis
, maxReplaceCount
,
1633 UTF8CountBytes(fPrivateData
, fromCharOffset
));
1638 BString::IReplaceFirst(char replaceThis
, char withThis
)
1640 char tmp
[2] = { replaceThis
, '\0' };
1642 int32 pos
= _IFindAfter(tmp
, 0, 1);
1643 if (pos
>= 0 && _MakeWritable() == B_OK
)
1644 fPrivateData
[pos
] = withThis
;
1650 BString::IReplaceLast(char replaceThis
, char withThis
)
1652 char tmp
[2] = { replaceThis
, '\0' };
1654 int32 pos
= _IFindBefore(tmp
, Length(), 1);
1655 if (pos
>= 0 && _MakeWritable() == B_OK
)
1656 fPrivateData
[pos
] = withThis
;
1662 BString::IReplaceAll(char replaceThis
, char withThis
, int32 fromOffset
)
1664 char tmp
[2] = { replaceThis
, '\0' };
1665 fromOffset
= min_clamp0(fromOffset
, Length());
1666 int32 pos
= _IFindAfter(tmp
, fromOffset
, 1);
1668 if (pos
>= 0 && _MakeWritable() == B_OK
) {
1669 for( ; pos
>= 0; pos
= _IFindAfter(tmp
, pos
+ 1, 1))
1670 fPrivateData
[pos
] = withThis
;
1677 BString::IReplace(char replaceThis
, char withThis
, int32 maxReplaceCount
,
1680 char tmp
[2] = { replaceThis
, '\0' };
1681 fromOffset
= min_clamp0(fromOffset
, Length());
1682 int32 pos
= _IFindAfter(tmp
, fromOffset
, 1);
1684 if (maxReplaceCount
> 0 && pos
>= 0 && _MakeWritable() == B_OK
) {
1685 for( ; maxReplaceCount
> 0 && pos
>= 0;
1686 pos
= _IFindAfter(tmp
, pos
+ 1, 1)) {
1687 fPrivateData
[pos
] = withThis
;
1697 BString::IReplaceFirst(const char* replaceThis
, const char* withThis
)
1699 if (!replaceThis
|| !withThis
|| IFindFirst(replaceThis
) < 0)
1702 if (_MakeWritable() != B_OK
)
1704 return _DoReplace(replaceThis
, withThis
, 1, 0, IGNORE_CASE
);
1709 BString::IReplaceLast(const char* replaceThis
, const char* withThis
)
1711 if (!replaceThis
|| !withThis
)
1714 int32 replaceThisLength
= strlen(replaceThis
);
1715 int32 pos
= _IFindBefore(replaceThis
, Length(), replaceThisLength
);
1718 int32 withThisLength
= strlen(withThis
);
1719 int32 difference
= withThisLength
- replaceThisLength
;
1721 if (difference
> 0) {
1722 if (!_OpenAtBy(pos
, difference
))
1724 } else if (difference
< 0) {
1725 if (!_ShrinkAtBy(pos
, -difference
))
1728 if (_MakeWritable() != B_OK
)
1731 memcpy(fPrivateData
+ pos
, withThis
, withThisLength
);
1739 BString::IReplaceAll(const char* replaceThis
, const char* withThis
,
1742 if (!replaceThis
|| !withThis
|| IFindFirst(replaceThis
) < 0)
1745 if (_MakeWritable() != B_OK
)
1748 return _DoReplace(replaceThis
, withThis
, REPLACE_ALL
,
1749 min_clamp0(fromOffset
, Length()), IGNORE_CASE
);
1754 BString::IReplace(const char* replaceThis
, const char* withThis
,
1755 int32 maxReplaceCount
, int32 fromOffset
)
1757 if (!replaceThis
|| !withThis
|| maxReplaceCount
<= 0
1758 || FindFirst(replaceThis
) < 0)
1761 if (_MakeWritable() != B_OK
)
1764 return _DoReplace(replaceThis
, withThis
, maxReplaceCount
,
1765 min_clamp0(fromOffset
, Length()), IGNORE_CASE
);
1770 BString::ReplaceSet(const char* setOfBytes
, char with
)
1772 if (!setOfBytes
|| strcspn(fPrivateData
, setOfBytes
) >= uint32(Length()))
1775 if (_MakeWritable() != B_OK
)
1779 int32 length
= Length();
1781 pos
= strcspn(fPrivateData
+ offset
, setOfBytes
);
1784 if (offset
>= length
)
1787 fPrivateData
[offset
] = with
;
1796 BString::ReplaceSet(const char* setOfBytes
, const char* with
)
1798 if (!setOfBytes
|| !with
1799 || strcspn(fPrivateData
, setOfBytes
) >= uint32(Length()))
1802 // delegate simple case
1803 int32 withLen
= strlen(with
);
1805 return ReplaceSet(setOfBytes
, *with
);
1807 if (_MakeWritable() != B_OK
)
1811 int32 searchLen
= 1;
1812 int32 len
= Length();
1815 for (int32 offset
= 0; offset
< len
; offset
+= (pos
+ searchLen
)) {
1816 pos
= strcspn(fPrivateData
+ offset
, setOfBytes
);
1817 if (pos
+ offset
>= len
)
1819 if (!positions
.Add(offset
+ pos
))
1823 _ReplaceAtPositions(&positions
, searchLen
, with
, withLen
);
1829 BString::ReplaceCharsSet(const char* setOfChars
, const char* with
)
1831 if (!setOfChars
|| !with
)
1834 int32 setCharCount
= UTF8CountChars(setOfChars
, -1);
1835 if ((uint32
)setCharCount
== strlen(setOfChars
)) {
1836 // no multi-byte chars at all
1837 return ReplaceSet(setOfChars
, with
);
1840 BString
setString(setOfChars
);
1843 int32 withLength
= strlen(with
);
1844 int32 charCount
= CountChars();
1845 for (int32 i
= 0; i
< charCount
; i
++) {
1847 const char* sourceChar
= CharAt(i
, &charLength
);
1850 for (int32 j
= 0; j
< setCharCount
; j
++) {
1851 int32 setCharLength
;
1852 const char* setChar
= setString
.CharAt(j
, &setCharLength
);
1853 if (charLength
== setCharLength
1854 && memcmp(sourceChar
, setChar
, charLength
) == 0) {
1861 result
.Append(with
, withLength
);
1863 result
.Append(sourceChar
, charLength
);
1871 // #pragma mark - Unchecked char access
1876 BString::operator[](int32 index
)
1878 if (_MakeWritable() != B_OK
) {
1879 static char invalid
;
1883 _ReferenceCount() = -1;
1884 // mark string as unshareable
1886 return fPrivateData
[index
];
1892 BString::CharAt(int32 charIndex
, int32
* bytes
) const
1894 int32 offset
= UTF8CountBytes(fPrivateData
, charIndex
);
1896 *bytes
= UTF8NextCharLen(fPrivateData
+ offset
);
1897 return fPrivateData
+ offset
;
1902 BString::CharAt(int32 charIndex
, char* buffer
, int32
* bytes
) const
1905 const char* charAt
= CharAt(charIndex
, &length
);
1906 if (bytes
!= NULL
) {
1907 if (*bytes
< length
)
1912 memcpy(buffer
, charAt
, length
);
1917 // #pragma mark - Fast low-level manipulation
1921 BString::LockBuffer(int32 maxLength
)
1923 int32 length
= Length();
1924 if (maxLength
> length
)
1927 if (_MakeWritable(length
, true) != B_OK
)
1930 _ReferenceCount() = -1;
1933 return fPrivateData
;
1938 BString::UnlockBuffer(int32 length
)
1941 length
= min_clamp0(length
, Length());
1943 length
= fPrivateData
== NULL
? 0 : strlen(fPrivateData
);
1945 if (_Resize(length
) != NULL
) {
1946 fPrivateData
[length
] = '\0';
1947 _ReferenceCount() = 1;
1948 // mark shareable again
1956 BString::SetByteAt(int32 pos
, char to
)
1958 if (pos
< Length() && _MakeWritable() == B_OK
)
1959 fPrivateData
[pos
] = to
;
1965 // #pragma mark - Uppercase <-> Lowercase
1971 int32 length
= Length();
1972 if (length
> 0 && _MakeWritable() == B_OK
) {
1973 for (int32 count
= 0; count
< length
; count
++)
1974 fPrivateData
[count
] = tolower(fPrivateData
[count
]);
1983 int32 length
= Length();
1984 if (length
> 0 && _MakeWritable() == B_OK
) {
1985 for (int32 count
= 0; count
< length
; count
++)
1986 fPrivateData
[count
] = toupper(fPrivateData
[count
]);
1993 BString::Capitalize()
1995 int32 length
= Length();
1997 if (length
> 0 && _MakeWritable() == B_OK
) {
1998 fPrivateData
[0] = toupper(fPrivateData
[0]);
1999 for (int32 count
= 1; count
< length
; count
++)
2000 fPrivateData
[count
] = tolower(fPrivateData
[count
]);
2007 BString::CapitalizeEachWord()
2009 int32 length
= Length();
2011 if (length
> 0 && _MakeWritable() == B_OK
) {
2014 // Find the first alphabetical character...
2015 for (; count
< length
; count
++) {
2016 if (isalpha(fPrivateData
[count
])) {
2017 // ...found! Convert it to uppercase.
2018 fPrivateData
[count
] = toupper(fPrivateData
[count
]);
2024 // Now find the first non-alphabetical character,
2025 // and meanwhile, turn to lowercase all the alphabetical ones
2026 for (; count
< length
; count
++) {
2027 if (isalpha(fPrivateData
[count
]))
2028 fPrivateData
[count
] = tolower(fPrivateData
[count
]);
2032 } while (count
< length
);
2038 // #pragma mark - Escaping and De-escaping
2042 BString::CharacterEscape(const char* original
,
2043 const char* setOfCharsToEscape
, char escapeWith
)
2045 if (setOfCharsToEscape
)
2046 _DoCharacterEscape(original
, setOfCharsToEscape
, escapeWith
);
2052 BString::CharacterEscape(const char* setOfCharsToEscape
, char escapeWith
)
2054 if (setOfCharsToEscape
&& Length() > 0)
2055 _DoCharacterEscape(fPrivateData
, setOfCharsToEscape
, escapeWith
);
2061 BString::CharacterDeescape(const char* original
, char escapeChar
)
2063 return _DoCharacterDeescape(original
, escapeChar
);
2068 BString::CharacterDeescape(char escapeChar
)
2071 _DoCharacterDeescape(fPrivateData
, escapeChar
);
2076 // #pragma mark - Trimming
2085 const char* string
= String();
2087 // string is \0 terminated thus we don't need to check if we reached the end
2088 int32 startCount
= 0;
2089 while (isspace(string
[startCount
]))
2092 int32 endIndex
= Length() - 1;
2093 while (endIndex
>= startCount
&& isspace(string
[endIndex
]))
2096 if (startCount
== 0 && endIndex
== Length() - 1)
2099 // We actually need to trim
2101 ssize_t length
= endIndex
+ 1 - startCount
;
2102 ASSERT(length
>= 0);
2103 if (startCount
== 0 || length
== 0) {
2104 _MakeWritable(length
, true);
2105 } else if (_MakeWritable() == B_OK
) {
2106 memmove(fPrivateData
, fPrivateData
+ startCount
, length
);
2107 fPrivateData
[length
] = '\0';
2115 // #pragma mark - Insert
2119 BString::operator<<(const char* string
)
2121 if (string
!= NULL
) {
2122 int32 length
= strlen(string
);
2124 _DoAppend(string
, length
);
2131 BString::operator<<(const BString
& string
)
2133 if (string
.Length() > 0)
2134 _DoAppend(string
.String(), string
.Length());
2140 BString::operator<<(char c
)
2148 BString::operator<<(bool value
)
2151 _DoAppend("true", 4);
2153 _DoAppend("false", 5);
2160 BString::operator<<(int i
)
2163 int32 length
= snprintf(num
, sizeof(num
), "%d", i
);
2165 _DoAppend(num
, length
);
2171 BString::operator<<(unsigned int i
)
2174 int32 length
= snprintf(num
, sizeof(num
), "%u", i
);
2176 _DoAppend(num
, length
);
2182 BString::operator<<(unsigned long i
)
2185 int32 length
= snprintf(num
, sizeof(num
), "%lu", i
);
2187 _DoAppend(num
, length
);
2193 BString::operator<<(long i
)
2196 int32 length
= snprintf(num
, sizeof(num
), "%ld", i
);
2198 _DoAppend(num
, length
);
2204 BString::operator<<(unsigned long long i
)
2207 int32 length
= snprintf(num
, sizeof(num
), "%llu", i
);
2209 _DoAppend(num
, length
);
2215 BString::operator<<(long long i
)
2218 int32 length
= snprintf(num
, sizeof(num
), "%lld", i
);
2220 _DoAppend(num
, length
);
2226 BString::operator<<(float f
)
2229 int32 length
= snprintf(num
, sizeof(num
), "%.2f", f
);
2231 _DoAppend(num
, length
);
2237 BString::operator<<(double value
)
2240 int32 length
= snprintf(num
, sizeof(num
), "%.2f", value
);
2242 _DoAppend(num
, length
);
2247 // #pragma mark - Private or reserved
2250 BString::BString(char* privateData
, PrivateDataTag tag
)
2252 fPrivateData(privateData
)
2254 if (fPrivateData
!= NULL
)
2255 atomic_add(&_ReferenceCount(), 1);
2259 /*! Detaches this string from an eventually shared fPrivateData, ie. this makes
2260 this string writable.
2263 BString::_MakeWritable()
2265 if (atomic_get(&_ReferenceCount()) > 1) {
2266 // It might be shared, and this requires special treatment
2267 char* newData
= _Clone(fPrivateData
, Length());
2268 if (atomic_add(&_ReferenceCount(), -1) == 1) {
2269 // someone else left, we were the last owner
2272 if (newData
== NULL
)
2275 fPrivateData
= newData
;
2282 /*! Makes this string writable, and resizes the buffer to \a length bytes (not
2283 including the terminating null).
2285 @param length The length of the new buffer in bytes.
2286 @param copy If true, the current string will be copied into the new string.
2289 BString::_MakeWritable(int32 length
, bool copy
)
2291 char* newData
= NULL
;
2293 if (atomic_get(&_ReferenceCount()) > 1) {
2294 // we might share our data with someone else
2296 newData
= _Clone(fPrivateData
, length
);
2298 newData
= _Allocate(length
);
2300 if (newData
== NULL
)
2303 if (atomic_add(&_ReferenceCount(), -1) == 1) {
2304 // someone else left, we were the last owner
2308 // we don't share our data with someone else
2309 newData
= _Resize(length
);
2311 if (newData
== NULL
)
2315 fPrivateData
= newData
;
2320 /*! Allocates a new private data buffer with the space to store \a length bytes
2321 (not including the terminating null).
2324 BString::_Allocate(int32 length
)
2329 char* newData
= (char*)malloc(length
+ kPrivateDataOffset
+ 1);
2330 if (newData
== NULL
)
2333 newData
+= kPrivateDataOffset
;
2334 newData
[length
] = '\0';
2336 // initialize reference count & length
2337 Private::DataRefCount(newData
) = 1;
2338 Private::DataLength(newData
) = length
& 0x7fffffff;
2344 /*! Resizes the private data buffer. You must already have a writable buffer
2345 when you call this method.
2348 BString::_Resize(int32 length
)
2350 ASSERT(_ReferenceCount() == 1 || _ReferenceCount() == -1);
2352 if (length
== Length())
2353 return fPrivateData
;
2355 char* data
= fPrivateData
? fPrivateData
- kPrivateDataOffset
: NULL
;
2359 data
= (char*)realloc(data
, length
+ kPrivateDataOffset
+ 1);
2363 data
+= kPrivateDataOffset
;
2365 fPrivateData
= data
;
2366 fPrivateData
[length
] = '\0';
2369 _ReferenceCount() = 1;
2376 BString::_Init(const char* src
, int32 length
)
2378 fPrivateData
= _Clone(src
, length
);
2379 if (fPrivateData
== NULL
)
2380 fPrivateData
= _Clone(NULL
, 0);
2385 BString::_Clone(const char* data
, int32 length
)
2387 char* newData
= _Allocate(length
);
2388 if (newData
== NULL
)
2391 if (data
!= NULL
&& length
> 0) {
2392 // "data" may not span over the whole length
2393 strncpy(newData
, data
, length
);
2401 BString::_OpenAtBy(int32 offset
, int32 length
)
2403 int32 oldLength
= Length();
2405 if (_MakeWritable() != B_OK
)
2408 memmove(fPrivateData
+ offset
+ length
, fPrivateData
+ offset
,
2409 oldLength
- offset
);
2410 return _Resize(oldLength
+ length
);
2415 BString::_ShrinkAtBy(int32 offset
, int32 length
)
2417 int32 oldLength
= Length();
2418 if (_MakeWritable() != B_OK
)
2421 memmove(fPrivateData
+ offset
, fPrivateData
+ offset
+ length
,
2422 oldLength
- offset
- length
);
2423 return _Resize(oldLength
- length
);
2428 BString::_SetLength(int32 length
)
2430 Private::DataLength(fPrivateData
) = length
& 0x7fffffff;
2435 BString::_FreePrivateData()
2437 if (fPrivateData
!= NULL
) {
2438 free(fPrivateData
- kPrivateDataOffset
);
2439 fPrivateData
= NULL
;
2445 BString::_DoAppend(const char* string
, int32 length
)
2447 int32 oldLength
= Length();
2448 if (_MakeWritable(oldLength
+ length
, true) == B_OK
) {
2449 strncpy(fPrivateData
+ oldLength
, string
, length
);
2457 BString::_DoPrepend(const char* string
, int32 length
)
2459 // TODO: this could be optimized (allocate a new buffer, use memcpy())
2460 int32 oldLength
= Length();
2461 if (_MakeWritable(oldLength
+ length
, true) == B_OK
) {
2462 memmove(fPrivateData
+ length
, fPrivateData
, oldLength
);
2463 if (string
&& length
)
2464 strncpy(fPrivateData
, string
, length
);
2472 BString::_DoInsert(const char* string
, int32 offset
, int32 length
)
2474 int32 oldLength
= Length();
2475 if (_MakeWritable(oldLength
+ length
, true) == B_OK
) {
2476 memmove(fPrivateData
+ offset
+ length
, fPrivateData
+ offset
,
2477 oldLength
- offset
);
2478 if (string
!= NULL
&& length
)
2479 strncpy(fPrivateData
+ offset
, string
, length
);
2487 BString::_ShortFindAfter(const char* string
, int32 len
) const
2489 const char* ptr
= strstr(String(), string
);
2492 return ptr
- String();
2499 BString::_FindAfter(const char* string
, int32 offset
, int32 length
) const
2501 const char* ptr
= strstr(String() + offset
, string
);
2504 return ptr
- String();
2511 BString::_IFindAfter(const char* string
, int32 offset
, int32 length
) const
2513 const char* ptr
= strcasestr(String() + offset
, string
);
2516 return ptr
- String();
2523 BString::_FindBefore(const char* string
, int32 offset
, int32 length
) const
2525 if (fPrivateData
!= NULL
) {
2526 const char* ptr
= fPrivateData
+ offset
- length
;
2528 while (ptr
>= fPrivateData
) {
2529 if (!memcmp(ptr
, string
, length
))
2530 return ptr
- fPrivateData
;
2539 BString::_IFindBefore(const char* string
, int32 offset
, int32 length
) const
2541 if (fPrivateData
!= NULL
) {
2542 char* ptr1
= fPrivateData
+ offset
- length
;
2544 while (ptr1
>= fPrivateData
) {
2545 if (!strncasecmp(ptr1
, string
, length
))
2546 return ptr1
- fPrivateData
;
2555 BString::_DoCharacterEscape(const char* string
, const char* setOfCharsToEscape
,
2558 if (_MakeWritable(string_length(string
), false) != B_OK
)
2561 memcpy(fPrivateData
, string
, Length());
2564 int32 length
= Length();
2566 for (int32 offset
= 0; offset
< length
; offset
+= pos
+ 1) {
2567 pos
= strcspn(fPrivateData
+ offset
, setOfCharsToEscape
);
2568 if (pos
< length
- offset
&& !positions
.Add(offset
+ pos
))
2572 uint32 count
= positions
.CountItems();
2573 int32 newLength
= length
+ count
;
2579 char* newData
= _Allocate(newLength
);
2581 char* oldString
= fPrivateData
;
2582 char* newString
= newData
;
2585 for (uint32 i
= 0; i
< count
; ++i
) {
2586 pos
= positions
.ItemAt(i
);
2587 length
= pos
- lastPos
;
2589 memcpy(newString
, oldString
, length
);
2590 oldString
+= length
;
2591 newString
+= length
;
2593 *newString
++ = escapeChar
;
2594 *newString
++ = *oldString
++;
2598 length
= Length() + 1 - lastPos
;
2600 memcpy(newString
, oldString
, length
);
2603 fPrivateData
= newData
;
2610 BString::_DoCharacterDeescape(const char* string
, char escapeChar
)
2612 if (_MakeWritable(string_length(string
), false) != B_OK
)
2615 memcpy(fPrivateData
, string
, Length());
2616 const char escape
[2] = { escapeChar
, '\0' };
2617 return _DoReplace(escape
, "", REPLACE_ALL
, 0, KEEP_CASE
);
2622 BString::_DoReplace(const char* findThis
, const char* replaceWith
,
2623 int32 maxReplaceCount
, int32 fromOffset
, bool ignoreCase
)
2625 if (findThis
== NULL
|| maxReplaceCount
<= 0
2626 || fromOffset
< 0 || fromOffset
>= Length())
2629 int32 findLen
= strlen(findThis
);
2633 typedef int32 (BString::*TFindMethod
)(const char*, int32
, int32
) const;
2634 TFindMethod findMethod
= ignoreCase
2635 ? &BString::_IFindAfter
: &BString::_FindAfter
;
2640 int32 replaceLen
= strlen(replaceWith
);
2641 int32 lastSrcPos
= fromOffset
;
2643 for (int32 srcPos
= 0; maxReplaceCount
> 0
2644 && (srcPos
= (this->*findMethod
)(findThis
, lastSrcPos
, findLen
)) >= 0;
2645 maxReplaceCount
--) {
2646 positions
.Add(srcPos
);
2647 lastSrcPos
= srcPos
+ findLen
;
2649 _ReplaceAtPositions(&positions
, findLen
, replaceWith
, replaceLen
);
2655 BString::_ReplaceAtPositions(const PosVect
* positions
, int32 searchLength
,
2656 const char* with
, int32 withLength
)
2658 int32 length
= Length();
2659 uint32 count
= positions
->CountItems();
2660 int32 newLength
= length
+ count
* (withLength
- searchLength
);
2666 char* newData
= _Allocate(newLength
);
2667 if (newData
== NULL
)
2670 char* oldString
= fPrivateData
;
2671 char* newString
= newData
;
2674 for (uint32 i
= 0; i
< count
; ++i
) {
2675 int32 pos
= positions
->ItemAt(i
);
2676 length
= pos
- lastPos
;
2678 memcpy(newString
, oldString
, length
);
2679 oldString
+= length
;
2680 newString
+= length
;
2682 memcpy(newString
, with
, withLength
);
2683 oldString
+= searchLength
;
2684 newString
+= withLength
;
2685 lastPos
= pos
+ searchLength
;
2688 length
= Length() + 1 - lastPos
;
2690 memcpy(newString
, oldString
, length
);
2693 fPrivateData
= newData
;
2697 // #pragma mark - backwards compatibility
2700 /*! Translates to (missing const):
2701 BString& BString::operator<<(BString& string)
2704 __ls__7BStringR7BString(BString
* self
, BString
& string
)
2706 return self
->operator<<(string
);
2712 // #pragma mark - BStringRef backwards compatibility
2717 BStringRef(BString
& string
, int32 position
);
2720 operator char() const;
2723 const char* operator&() const;
2725 BStringRef
& operator=(char c
);
2726 BStringRef
& operator=(const BStringRef
& rc
);
2734 BStringRef::BStringRef(BString
& string
, int32 position
)
2736 fString(string
), fPosition(position
)
2741 BStringRef::operator char() const
2743 return fPosition
< fString
.Length() ? fString
.fPrivateData
[fPosition
] : 0;
2748 BStringRef::operator=(char c
)
2750 fString
._MakeWritable();
2751 fString
.fPrivateData
[fPosition
] = c
;
2757 BStringRef::operator=(const BStringRef
&rc
)
2759 return operator=(rc
.fString
.fPrivateData
[rc
.fPosition
]);
2764 BStringRef::operator&() const
2766 return &fString
.fPrivateData
[fPosition
];
2771 BStringRef::operator&()
2773 if (fString
._MakeWritable() != B_OK
)
2776 fString
._ReferenceCount() = -1;
2777 // mark as unsharable
2778 return &fString
.fPrivateData
[fPosition
];
2783 extern "C" BStringRef
2784 _ZN7BStringixEi(BString
* self
, int32 index
)
2787 return BStringRef(*self
, index
);
2792 // #pragma mark - Non-member compare for sorting, etc.
2796 Compare(const BString
& string1
, const BString
& string2
)
2798 return strcmp(string1
.String(), string2
.String());
2803 ICompare(const BString
& string1
, const BString
& string2
)
2805 return strcasecmp(string1
.String(), string2
.String());
2810 Compare(const BString
* string1
, const BString
* string2
)
2812 return strcmp(string1
->String(), string2
->String());
2817 ICompare(const BString
* string1
, const BString
* string2
)
2819 return strcasecmp(string1
->String(), string2
->String());