vfs: check userland buffers before reading them.
[haiku.git] / src / kits / support / String.cpp
blob3145c63321fef72aaf53b9a2a82ddce299def87a
1 /*
2 * Copyright 2001-2014 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
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. */
17 #include <String.h>
19 #include <ctype.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <strings.h>
25 #include <Debug.h>
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):
46 static inline int32
47 min_clamp0(int32 num1, int32 num2)
49 if (num1 < num2)
50 return num1 > 0 ? num1 : 0;
52 return num2 > 0 ? num2 : 0;
56 //! Returns length of given string (but clamps to given maximum).
57 static inline int32
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.
66 static inline size_t
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 {
85 public:
86 PosVect()
88 fSize(0),
89 fBufferSize(20),
90 fBuffer(NULL)
94 ~PosVect()
96 free(fBuffer);
99 bool Add(int32 pos)
101 if (fBuffer == NULL || fSize == fBufferSize) {
102 if (fBuffer != NULL)
103 fBufferSize *= 2;
105 int32* newBuffer = NULL;
106 newBuffer = (int32*)realloc(fBuffer, fBufferSize * sizeof(int32));
107 if (newBuffer == NULL)
108 return false;
110 fBuffer = newBuffer;
113 fBuffer[fSize++] = pos;
115 return true;
118 inline int32 ItemAt(int32 index) const
120 return fBuffer[index];
123 inline int32 CountItems() const
125 return fSize;
128 private:
129 int32 fSize;
130 int32 fBufferSize;
131 int32* fBuffer;
135 // #pragma mark - BString
138 inline int32&
139 BString::_ReferenceCount()
141 return Private::DataRefCount(fPrivateData);
145 inline const int32&
146 BString::_ReferenceCount() const
148 return Private::DataRefCount(fPrivateData);
152 inline bool
153 BString::_IsShareable() const
155 return fPrivateData != NULL && _ReferenceCount() >= 0;
159 BString::BString()
161 fPrivateData(NULL)
163 _Init("", 0);
167 BString::BString(const char* string)
169 fPrivateData(NULL)
171 _Init(string, strlen(safestr(string)));
175 BString::BString(const BString& string)
177 fPrivateData(NULL)
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
184 } else
185 _Init(string.String(), string.Length());
189 BString::BString(const char* string, int32 maxLength)
190 : fPrivateData(NULL)
192 _Init(string, strlen_clamp(safestr(string), maxLength));
196 BString::~BString()
198 if (!_IsShareable() || atomic_add(&_ReferenceCount(), -1) == 1)
199 _FreePrivateData();
203 // #pragma mark - Access
206 int32
207 BString::CountChars() const
209 return UTF8CountChars(fPrivateData, Length());
213 int32
214 BString::CountBytes(int32 fromCharOffset, int32 charCount) const
216 return UTF8CountBytes(
217 fPrivateData + UTF8CountBytes(fPrivateData, fromCharOffset), charCount);
221 /*static*/ uint32
222 BString::HashValue(const char* string)
224 // from the Dragon Book: a slightly modified hashpjw()
225 uint32 h = 0;
226 if (string != NULL) {
227 for (; *string; string++) {
228 uint32 g = h & 0xf0000000;
229 if (g)
230 h ^= g >> 24;
231 h = (h << 4) + *string;
234 return h;
238 // #pragma mark - Assignment
241 BString&
242 BString::operator=(const BString& string)
244 return SetTo(string);
248 BString&
249 BString::operator=(const char* string)
251 if (!string)
252 string = "";
253 if (string != String())
254 SetTo(string, strlen(string));
255 return *this;
259 BString&
260 BString::operator=(char c)
262 return SetTo(c, 1);
266 BString&
267 BString::SetTo(const char* string, int32 maxLength)
269 if (maxLength < 0)
270 maxLength = INT32_MAX;
272 maxLength = strlen_clamp(safestr(string), maxLength);
274 if (_MakeWritable(maxLength, false) == B_OK)
275 memcpy(fPrivateData, string, maxLength);
277 return *this;
281 BString&
282 BString::SetTo(const BString& string)
284 // we share the information already
285 if (fPrivateData == string.fPrivateData)
286 return *this;
288 bool freeData = true;
290 if (_IsShareable() && atomic_add(&_ReferenceCount(), -1) > 1) {
291 // there is still someone who shares our data
292 freeData = false;
295 if (freeData)
296 _FreePrivateData();
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
303 } else
304 _Init(string.String(), string.Length());
306 return *this;
310 BString&
311 BString::Adopt(BString& from)
313 SetTo(from);
314 from.SetTo("");
316 return *this;
320 BString&
321 BString::SetTo(const BString& string, int32 maxLength)
323 if (maxLength < 0)
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);
332 return *this;
336 BString&
337 BString::Adopt(BString& from, int32 maxLength)
339 SetTo(from, maxLength);
340 from.SetTo("");
342 return *this;
346 BString&
347 BString::SetTo(char c, int32 count)
349 if (count < 0)
350 count = 0;
352 if (_MakeWritable(count, false) == B_OK)
353 memset(fPrivateData, c, count);
355 return *this;
359 BString&
360 BString::SetToChars(const char* string, int32 charCount)
362 return SetTo(string, UTF8CountBytes(string, charCount));
366 BString&
367 BString::SetToChars(const BString& string, int32 charCount)
369 return SetTo(string, UTF8CountBytes(string.String(), charCount));
373 BString&
374 BString::AdoptChars(BString& string, int32 charCount)
376 return Adopt(string, UTF8CountBytes(string.String(), charCount));
380 BString&
381 BString::SetToFormat(const char* format, ...)
383 va_list args;
384 va_start(args, format);
385 SetToFormatVarArgs(format, args);
386 va_end(args);
388 return *this;
392 BString&
393 BString::SetToFormatVarArgs(const char* format, va_list args)
395 // Use a small on-stack buffer to save a second vsnprintf() call for most
396 // use cases.
397 int32 bufferSize = 1024;
398 char buffer[bufferSize];
400 va_list clonedArgs;
401 #if __GNUC__ == 2
402 __va_copy(clonedArgs, args);
403 #else
404 va_copy(clonedArgs, args);
405 #endif
406 int32 bytes = vsnprintf(buffer, bufferSize, format, clonedArgs);
407 va_end(clonedArgs);
409 if (bytes < 0)
410 return Truncate(0);
412 if (bytes < bufferSize) {
413 SetTo(buffer);
414 return *this;
417 bytes = vsnprintf(LockBuffer(bytes), bytes + 1, format, args);
418 if (bytes < 0)
419 bytes = 0;
421 UnlockBuffer(bytes);
422 return *this;
427 BString::ScanWithFormat(const char* format, ...)
429 va_list args;
430 va_start(args, format);
431 int result = ScanWithFormatVarArgs(format, args);
432 va_end(args);
434 return result;
439 BString::ScanWithFormatVarArgs(const char* format, va_list args)
441 return vsscanf(fPrivateData, format, args);
445 // #pragma mark - Substring copying
448 BString&
449 BString::CopyInto(BString& into, int32 fromOffset, int32 length) const
451 if (this != &into)
452 into.SetTo(fPrivateData + fromOffset, length);
453 return into;
457 void
458 BString::CopyInto(char* into, int32 fromOffset, int32 length) const
460 if (into) {
461 length = min_clamp0(length, Length() - fromOffset);
462 memcpy(into, fPrivateData + fromOffset, length);
467 BString&
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);
477 bool
478 BString::CopyCharsInto(char* into, int32* intoLength, int32 fromCharOffset,
479 int32 charCount) const
481 if (into == NULL)
482 return false;
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)
490 return false;
491 *intoLength = length;
494 memcpy(into, fPrivateData + fromOffset, length);
495 return true;
499 bool
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)
507 return true;
508 return _list.Add(*this);
511 int32 index = 0;
512 for (;;) {
513 int32 endIndex = index < length ? FindFirst(separator, index) : length;
514 if (endIndex < 0)
515 endIndex = length;
517 if (endIndex > index || !noEmptyStrings) {
518 BString toAppend(String() + index, endIndex - index);
519 if (toAppend.Length() != endIndex - index
520 || !_list.Add(toAppend)) {
521 return false;
525 if (endIndex == length)
526 break;
528 index = endIndex + 1;
531 return true;
535 // #pragma mark - Appending
538 BString&
539 BString::operator+=(const char* string)
541 if (string) {
542 int32 length = strlen(string);
543 if (length > 0)
544 _DoAppend(string, length);
546 return *this;
550 BString&
551 BString::operator+=(char c)
553 _DoAppend(&c, 1);
554 return *this;
558 BString&
559 BString::Append(const BString& string, int32 length)
561 if (&string != this) {
562 length = min_clamp0(length, string.Length());
563 if (length > 0)
564 _DoAppend(string.fPrivateData, length);
566 return *this;
570 BString&
571 BString::Append(const char* string, int32 length)
573 if (string) {
574 length = strlen_clamp(string, length);
575 if (length > 0)
576 _DoAppend(string, length);
578 return *this;
582 BString&
583 BString::Append(char c, int32 count)
585 int32 oldLength = Length();
586 if (count > 0 && _DoAppend("", count))
587 memset(fPrivateData + oldLength, c, count);
588 return *this;
592 BString&
593 BString::AppendChars(const BString& string, int32 charCount)
595 return Append(string, UTF8CountBytes(string.String(), charCount));
599 BString&
600 BString::AppendChars(const char* string, int32 charCount)
602 return Append(string, UTF8CountBytes(string, charCount));
606 // #pragma mark - Prepending
609 BString&
610 BString::Prepend(const char* string)
612 if (string)
613 _DoPrepend(string, strlen(string));
614 return *this;
618 BString&
619 BString::Prepend(const BString& string)
621 if (&string != this)
622 _DoPrepend(string.String(), string.Length());
623 return *this;
627 BString&
628 BString::Prepend(const char* string, int32 length)
630 if (string)
631 _DoPrepend(string, strlen_clamp(string, length));
632 return *this;
636 BString&
637 BString::Prepend(const BString& string, int32 length)
639 if (&string != this)
640 _DoPrepend(string.fPrivateData, min_clamp0(length, string.Length()));
641 return *this;
645 BString&
646 BString::Prepend(char c, int32 count)
648 if (count > 0 && _DoPrepend("", count))
649 memset(fPrivateData, c, count);
650 return *this;
654 BString&
655 BString::PrependChars(const char* string, int32 charCount)
657 return Prepend(string, UTF8CountBytes(string, charCount));
661 BString&
662 BString::PrependChars(const BString& string, int32 charCount)
664 return Prepend(string, UTF8CountBytes(string.String(), charCount));
668 // #pragma mark - Inserting
671 BString&
672 BString::Insert(const char* string, int32 position)
674 if (string != NULL && position <= Length()) {
675 int32 len = int32(strlen(string));
676 if (position < 0) {
677 int32 skipLen = min_clamp0(-1 * position, len);
678 string += skipLen;
679 len -= skipLen;
680 position = 0;
681 } else {
682 position = min_clamp0(position, Length());
684 _DoInsert(string, position, len);
686 return *this;
690 BString&
691 BString::Insert(const char* string, int32 length, int32 position)
693 if (string != NULL && position <= Length()) {
694 int32 len = strlen_clamp(string, length);
695 if (position < 0) {
696 int32 skipLen = min_clamp0(-1 * position, len);
697 string += skipLen;
698 len -= skipLen;
699 position = 0;
700 } else {
701 position = min_clamp0(position, Length());
703 _DoInsert(string, position, len);
705 return *this;
709 BString&
710 BString::Insert(const char* string, int32 fromOffset, int32 length,
711 int32 position)
713 if (string)
714 Insert(string + fromOffset, length, position);
715 return *this;
719 BString&
720 BString::Insert(const BString& string, int32 position)
722 if (&string != this && string.Length() > 0)
723 Insert(string.fPrivateData, position);
724 return *this;
728 BString&
729 BString::Insert(const BString& string, int32 length, int32 position)
731 if (&string != this && string.Length() > 0)
732 Insert(string.String(), length, position);
733 return *this;
737 BString&
738 BString::Insert(const BString& string, int32 fromOffset, int32 length,
739 int32 position)
741 if (&string != this && string.Length() > 0)
742 Insert(string.String() + fromOffset, length, position);
743 return *this;
747 BString&
748 BString::Insert(char c, int32 count, int32 position)
750 if (position < 0) {
751 count = MAX(count + position, 0);
752 position = 0;
753 } else
754 position = min_clamp0(position, Length());
756 if (count > 0 && _DoInsert("", position, count))
757 memset(fPrivateData + position, c, count);
759 return *this;
763 BString&
764 BString::InsertChars(const char* string, int32 charPosition)
766 return Insert(string, UTF8CountBytes(fPrivateData, charPosition));
770 BString&
771 BString::InsertChars(const char* string, int32 charCount, int32 charPosition)
773 return Insert(string, UTF8CountBytes(string, charCount),
774 UTF8CountBytes(fPrivateData, charPosition));
778 BString&
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));
789 BString&
790 BString::InsertChars(const BString& string, int32 charPosition)
792 return Insert(string, UTF8CountBytes(fPrivateData, charPosition));
796 BString&
797 BString::InsertChars(const BString& string, int32 charCount, int32 charPosition)
799 return Insert(string, UTF8CountBytes(string.String(), charCount),
800 UTF8CountBytes(fPrivateData, charPosition));
804 BString&
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
818 BString&
819 BString::Truncate(int32 newLength, bool lazy)
821 if (newLength < 0)
822 newLength = 0;
824 if (newLength < Length()) {
825 // ignore lazy, since we might detach
826 _MakeWritable(newLength, true);
829 return *this;
833 BString&
834 BString::TruncateChars(int32 newCharCount, bool lazy)
836 return Truncate(UTF8CountBytes(fPrivateData, newCharCount));
840 BString&
841 BString::Remove(int32 from, int32 length)
843 if (length > 0 && from < Length())
844 _ShrinkAtBy(from, min_clamp0(length, (Length() - from)));
845 return *this;
849 BString&
850 BString::RemoveChars(int32 fromCharOffset, int32 charCount)
852 int32 fromOffset = UTF8CountBytes(fPrivateData, fromCharOffset);
853 return Remove(fromOffset,
854 UTF8CountBytes(fPrivateData + fromOffset, charCount));
858 BString&
859 BString::RemoveFirst(const BString& string)
861 if (string.Length() > 0) {
862 int32 pos = _ShortFindAfter(string.String(), string.Length());
863 if (pos >= 0)
864 _ShrinkAtBy(pos, string.Length());
866 return *this;
870 BString&
871 BString::RemoveLast(const BString& string)
873 int32 pos = _FindBefore(string.String(), Length(), string.Length());
874 if (pos >= 0)
875 _ShrinkAtBy(pos, string.Length());
877 return *this;
881 BString&
882 BString::RemoveAll(const BString& string)
884 if (string.Length() == 0 || Length() == 0 || FindFirst(string) < 0)
885 return *this;
887 if (_MakeWritable() != B_OK)
888 return *this;
890 return _DoReplace(string.String(), "", REPLACE_ALL, 0, KEEP_CASE);
894 BString&
895 BString::RemoveFirst(const char* string)
897 int32 length = string ? strlen(string) : 0;
898 if (length > 0) {
899 int32 pos = _ShortFindAfter(string, length);
900 if (pos >= 0)
901 _ShrinkAtBy(pos, length);
903 return *this;
907 BString&
908 BString::RemoveLast(const char* string)
910 int32 length = string ? strlen(string) : 0;
911 if (length > 0) {
912 int32 pos = _FindBefore(string, Length(), length);
913 if (pos >= 0)
914 _ShrinkAtBy(pos, length);
916 return *this;
920 BString&
921 BString::RemoveAll(const char* string)
923 if (!string || Length() == 0 || FindFirst(string) < 0)
924 return *this;
926 if (_MakeWritable() != B_OK)
927 return *this;
929 return _DoReplace(string, "", REPLACE_ALL, 0, KEEP_CASE);
933 BString&
934 BString::RemoveSet(const char* setOfBytesToRemove)
936 return ReplaceSet(setOfBytesToRemove, "");
940 BString&
941 BString::RemoveCharsSet(const char* setOfCharsToRemove)
943 return ReplaceCharsSet(setOfCharsToRemove, "");
947 BString&
948 BString::MoveInto(BString& into, int32 from, int32 length)
950 if (length) {
951 CopyInto(into, from, length);
952 Remove(from, length);
954 return into;
958 void
959 BString::MoveInto(char* into, int32 from, int32 length)
961 if (into) {
962 CopyInto(into, from, length);
963 Remove(from, length);
968 BString&
969 BString::MoveCharsInto(BString& into, int32 fromCharOffset, int32 charCount)
971 if (charCount > 0) {
972 CopyCharsInto(into, fromCharOffset, charCount);
973 RemoveChars(fromCharOffset, charCount);
976 return into;
980 bool
981 BString::MoveCharsInto(char* into, int32* intoLength, int32 fromCharOffset,
982 int32 charCount)
984 if (!CopyCharsInto(into, intoLength, fromCharOffset, charCount))
985 return false;
987 RemoveChars(fromCharOffset, charCount);
988 return true;
992 // #pragma mark - Compare functions
995 bool
996 BString::operator<(const char* string) const
998 return strcmp(String(), safestr(string)) < 0;
1002 bool
1003 BString::operator<=(const char* string) const
1005 return strcmp(String(), safestr(string)) <= 0;
1009 bool
1010 BString::operator==(const char* string) const
1012 return strcmp(String(), safestr(string)) == 0;
1016 bool
1017 BString::operator>=(const char* string) const
1019 return strcmp(String(), safestr(string)) >= 0;
1023 bool
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
1113 int32
1114 BString::FindFirst(const BString& string) const
1116 return _ShortFindAfter(string.String(), string.Length());
1120 int32
1121 BString::FindFirst(const char* string) const
1123 if (string == NULL)
1124 return B_BAD_VALUE;
1126 return _ShortFindAfter(string, strlen(string));
1130 int32
1131 BString::FindFirst(const BString& string, int32 fromOffset) const
1133 if (fromOffset < 0)
1134 return B_ERROR;
1136 return _FindAfter(string.String(), min_clamp0(fromOffset, Length()),
1137 string.Length());
1141 int32
1142 BString::FindFirst(const char* string, int32 fromOffset) const
1144 if (string == NULL)
1145 return B_BAD_VALUE;
1147 if (fromOffset < 0)
1148 return B_ERROR;
1150 return _FindAfter(string, min_clamp0(fromOffset, Length()),
1151 strlen(safestr(string)));
1155 int32
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) {
1164 start++;
1167 if (start == end)
1168 return B_ERROR;
1170 return start - String();
1174 int32
1175 BString::FindFirst(char c, int32 fromOffset) const
1177 if (fromOffset < 0)
1178 return B_ERROR;
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) {
1186 start++;
1189 if (start >= end)
1190 return B_ERROR;
1192 return start - String();
1196 int32
1197 BString::FindFirstChars(const BString& string, int32 fromCharOffset) const
1199 return FindFirst(string, UTF8CountBytes(fPrivateData, fromCharOffset));
1203 int32
1204 BString::FindFirstChars(const char* string, int32 fromCharOffset) const
1206 return FindFirst(string, UTF8CountBytes(fPrivateData, fromCharOffset));
1210 int32
1211 BString::FindLast(const BString& string) const
1213 return _FindBefore(string.String(), Length(), string.Length());
1217 int32
1218 BString::FindLast(const char* string) const
1220 if (string == NULL)
1221 return B_BAD_VALUE;
1223 return _FindBefore(string, Length(), strlen(safestr(string)));
1227 int32
1228 BString::FindLast(const BString& string, int32 beforeOffset) const
1230 if (beforeOffset < 0)
1231 return B_ERROR;
1233 return _FindBefore(string.String(), min_clamp0(beforeOffset, Length()),
1234 string.Length());
1238 int32
1239 BString::FindLast(const char* string, int32 beforeOffset) const
1241 if (string == NULL)
1242 return B_BAD_VALUE;
1244 if (beforeOffset < 0)
1245 return B_ERROR;
1247 return _FindBefore(string, min_clamp0(beforeOffset, Length()),
1248 strlen(safestr(string)));
1252 int32
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) {
1261 end--;
1264 if (end < start)
1265 return B_ERROR;
1267 return end - start;
1271 int32
1272 BString::FindLast(char c, int32 beforeOffset) const
1274 if (beforeOffset < 0)
1275 return B_ERROR;
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) {
1283 end--;
1286 if (end < start)
1287 return B_ERROR;
1289 return end - start;
1293 int32
1294 BString::FindLastChars(const BString& string, int32 beforeCharOffset) const
1296 return FindLast(string, UTF8CountBytes(fPrivateData, beforeCharOffset));
1300 int32
1301 BString::FindLastChars(const char* string, int32 beforeCharOffset) const
1303 return FindLast(string, UTF8CountBytes(fPrivateData, beforeCharOffset));
1307 int32
1308 BString::IFindFirst(const BString& string) const
1310 return _IFindAfter(string.String(), 0, string.Length());
1314 int32
1315 BString::IFindFirst(const char* string) const
1317 if (string == NULL)
1318 return B_BAD_VALUE;
1320 return _IFindAfter(string, 0, strlen(safestr(string)));
1324 int32
1325 BString::IFindFirst(const BString& string, int32 fromOffset) const
1327 if (fromOffset < 0)
1328 return B_ERROR;
1330 return _IFindAfter(string.String(), min_clamp0(fromOffset, Length()),
1331 string.Length());
1335 int32
1336 BString::IFindFirst(const char* string, int32 fromOffset) const
1338 if (string == NULL)
1339 return B_BAD_VALUE;
1341 if (fromOffset < 0)
1342 return B_ERROR;
1344 return _IFindAfter(string, min_clamp0(fromOffset,Length()),
1345 strlen(safestr(string)));
1349 int32
1350 BString::IFindLast(const BString& string) const
1352 return _IFindBefore(string.String(), Length(), string.Length());
1356 int32
1357 BString::IFindLast(const char* string) const
1359 if (string == NULL)
1360 return B_BAD_VALUE;
1362 return _IFindBefore(string, Length(), strlen(safestr(string)));
1366 int32
1367 BString::IFindLast(const BString& string, int32 beforeOffset) const
1369 if (beforeOffset < 0)
1370 return B_ERROR;
1372 return _IFindBefore(string.String(), min_clamp0(beforeOffset, Length()),
1373 string.Length());
1377 int32
1378 BString::IFindLast(const char* string, int32 beforeOffset) const
1380 if (string == NULL)
1381 return B_BAD_VALUE;
1383 if (beforeOffset < 0)
1384 return B_ERROR;
1386 return _IFindBefore(string, min_clamp0(beforeOffset, Length()),
1387 strlen(safestr(string)));
1391 bool
1392 BString::StartsWith(const BString& string) const
1394 return StartsWith(string.String(), string.Length());
1398 bool
1399 BString::StartsWith(const char* string) const
1401 return StartsWith(string, strlen(safestr(string)));
1405 bool
1406 BString::StartsWith(const char* string, int32 length) const
1408 if (length > Length())
1409 return false;
1411 return memcmp(String(), string, length) == 0;
1415 bool
1416 BString::IStartsWith(const BString& string) const
1418 return IStartsWith(string.String(), string.Length());
1422 bool
1423 BString::IStartsWith(const char* string) const
1425 return IStartsWith(string, strlen(safestr(string)));
1429 bool
1430 BString::IStartsWith(const char* string, int32 length) const
1432 if (length > Length() || length > (int32)strlen(safestr(string)))
1433 return false;
1435 return _IFindAfter(string, 0, length) == 0;
1439 bool
1440 BString::EndsWith(const BString& string) const
1442 return EndsWith(string.String(), string.Length());
1446 bool
1447 BString::EndsWith(const char* string) const
1449 return EndsWith(string, strlen(safestr(string)));
1453 bool
1454 BString::EndsWith(const char* string, int32 length) const
1456 int32 offset = Length() - length;
1457 if (offset < 0)
1458 return false;
1460 return memcmp(String() + offset, string, length) == 0;
1464 bool
1465 BString::IEndsWith(const BString& string) const
1467 return IEndsWith(string.String(), string.Length());
1471 bool
1472 BString::IEndsWith(const char* string) const
1474 return IEndsWith(string, strlen(safestr(string)));
1478 bool
1479 BString::IEndsWith(const char* string, int32 length) const
1481 int32 offset = Length() - length;
1482 if (offset < 0)
1483 return false;
1485 return _IFindBefore(string, Length(), length) == offset;
1489 // #pragma mark - Replacing
1492 BString&
1493 BString::ReplaceFirst(char replaceThis, char withThis)
1495 int32 pos = FindFirst(replaceThis);
1496 if (pos >= 0 && _MakeWritable() == B_OK)
1497 fPrivateData[pos] = withThis;
1498 return *this;
1502 BString&
1503 BString::ReplaceLast(char replaceThis, char withThis)
1505 int32 pos = FindLast(replaceThis);
1506 if (pos >= 0 && _MakeWritable() == B_OK)
1507 fPrivateData[pos] = withThis;
1508 return *this;
1512 BString&
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;
1523 return *this;
1527 BString&
1528 BString::Replace(char replaceThis, char withThis, int32 maxReplaceCount,
1529 int32 fromOffset)
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;
1538 maxReplaceCount--;
1541 return *this;
1545 BString&
1546 BString::ReplaceFirst(const char* replaceThis, const char* withThis)
1548 if (!replaceThis || !withThis || FindFirst(replaceThis) < 0)
1549 return *this;
1551 if (_MakeWritable() != B_OK)
1552 return *this;
1554 return _DoReplace(replaceThis, withThis, 1, 0, KEEP_CASE);
1558 BString&
1559 BString::ReplaceLast(const char* replaceThis, const char* withThis)
1561 if (!replaceThis || !withThis)
1562 return *this;
1564 int32 replaceThisLength = strlen(replaceThis);
1565 int32 pos = _FindBefore(replaceThis, Length(), replaceThisLength);
1567 if (pos >= 0) {
1568 int32 withThisLength = strlen(withThis);
1569 int32 difference = withThisLength - replaceThisLength;
1571 if (difference > 0) {
1572 if (!_OpenAtBy(pos, difference))
1573 return *this;
1574 } else if (difference < 0) {
1575 if (!_ShrinkAtBy(pos, -difference))
1576 return *this;
1577 } else {
1578 if (_MakeWritable() != B_OK)
1579 return *this;
1581 memcpy(fPrivateData + pos, withThis, withThisLength);
1584 return *this;
1588 BString&
1589 BString::ReplaceAll(const char* replaceThis, const char* withThis,
1590 int32 fromOffset)
1592 if (!replaceThis || !withThis || FindFirst(replaceThis) < 0)
1593 return *this;
1595 if (_MakeWritable() != B_OK)
1596 return *this;
1598 return _DoReplace(replaceThis, withThis, REPLACE_ALL,
1599 min_clamp0(fromOffset, Length()), KEEP_CASE);
1603 BString&
1604 BString::Replace(const char* replaceThis, const char* withThis,
1605 int32 maxReplaceCount, int32 fromOffset)
1607 if (!replaceThis || !withThis || maxReplaceCount <= 0
1608 || FindFirst(replaceThis) < 0)
1609 return *this;
1611 if (_MakeWritable() != B_OK)
1612 return *this;
1614 return _DoReplace(replaceThis, withThis, maxReplaceCount,
1615 min_clamp0(fromOffset, Length()), KEEP_CASE);
1619 BString&
1620 BString::ReplaceAllChars(const char* replaceThis, const char* withThis,
1621 int32 fromCharOffset)
1623 return ReplaceAll(replaceThis, withThis,
1624 UTF8CountBytes(fPrivateData, fromCharOffset));
1628 BString&
1629 BString::ReplaceChars(const char* replaceThis, const char* withThis,
1630 int32 maxReplaceCount, int32 fromCharOffset)
1632 return Replace(replaceThis, withThis, maxReplaceCount,
1633 UTF8CountBytes(fPrivateData, fromCharOffset));
1637 BString&
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;
1645 return *this;
1649 BString&
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;
1657 return *this;
1661 BString&
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;
1672 return *this;
1676 BString&
1677 BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount,
1678 int32 fromOffset)
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;
1688 maxReplaceCount--;
1692 return *this;
1696 BString&
1697 BString::IReplaceFirst(const char* replaceThis, const char* withThis)
1699 if (!replaceThis || !withThis || IFindFirst(replaceThis) < 0)
1700 return *this;
1702 if (_MakeWritable() != B_OK)
1703 return *this;
1704 return _DoReplace(replaceThis, withThis, 1, 0, IGNORE_CASE);
1708 BString&
1709 BString::IReplaceLast(const char* replaceThis, const char* withThis)
1711 if (!replaceThis || !withThis)
1712 return *this;
1714 int32 replaceThisLength = strlen(replaceThis);
1715 int32 pos = _IFindBefore(replaceThis, Length(), replaceThisLength);
1717 if (pos >= 0) {
1718 int32 withThisLength = strlen(withThis);
1719 int32 difference = withThisLength - replaceThisLength;
1721 if (difference > 0) {
1722 if (!_OpenAtBy(pos, difference))
1723 return *this;
1724 } else if (difference < 0) {
1725 if (!_ShrinkAtBy(pos, -difference))
1726 return *this;
1727 } else {
1728 if (_MakeWritable() != B_OK)
1729 return *this;
1731 memcpy(fPrivateData + pos, withThis, withThisLength);
1734 return *this;
1738 BString&
1739 BString::IReplaceAll(const char* replaceThis, const char* withThis,
1740 int32 fromOffset)
1742 if (!replaceThis || !withThis || IFindFirst(replaceThis) < 0)
1743 return *this;
1745 if (_MakeWritable() != B_OK)
1746 return *this;
1748 return _DoReplace(replaceThis, withThis, REPLACE_ALL,
1749 min_clamp0(fromOffset, Length()), IGNORE_CASE);
1753 BString&
1754 BString::IReplace(const char* replaceThis, const char* withThis,
1755 int32 maxReplaceCount, int32 fromOffset)
1757 if (!replaceThis || !withThis || maxReplaceCount <= 0
1758 || FindFirst(replaceThis) < 0)
1759 return *this;
1761 if (_MakeWritable() != B_OK)
1762 return *this;
1764 return _DoReplace(replaceThis, withThis, maxReplaceCount,
1765 min_clamp0(fromOffset, Length()), IGNORE_CASE);
1769 BString&
1770 BString::ReplaceSet(const char* setOfBytes, char with)
1772 if (!setOfBytes || strcspn(fPrivateData, setOfBytes) >= uint32(Length()))
1773 return *this;
1775 if (_MakeWritable() != B_OK)
1776 return *this;
1778 int32 offset = 0;
1779 int32 length = Length();
1780 for (int32 pos;;) {
1781 pos = strcspn(fPrivateData + offset, setOfBytes);
1783 offset += pos;
1784 if (offset >= length)
1785 break;
1787 fPrivateData[offset] = with;
1788 offset++;
1791 return *this;
1795 BString&
1796 BString::ReplaceSet(const char* setOfBytes, const char* with)
1798 if (!setOfBytes || !with
1799 || strcspn(fPrivateData, setOfBytes) >= uint32(Length()))
1800 return *this;
1802 // delegate simple case
1803 int32 withLen = strlen(with);
1804 if (withLen == 1)
1805 return ReplaceSet(setOfBytes, *with);
1807 if (_MakeWritable() != B_OK)
1808 return *this;
1810 int32 pos = 0;
1811 int32 searchLen = 1;
1812 int32 len = Length();
1814 PosVect positions;
1815 for (int32 offset = 0; offset < len; offset += (pos + searchLen)) {
1816 pos = strcspn(fPrivateData + offset, setOfBytes);
1817 if (pos + offset >= len)
1818 break;
1819 if (!positions.Add(offset + pos))
1820 return *this;
1823 _ReplaceAtPositions(&positions, searchLen, with, withLen);
1824 return *this;
1828 BString&
1829 BString::ReplaceCharsSet(const char* setOfChars, const char* with)
1831 if (!setOfChars || !with)
1832 return *this;
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);
1841 BString result;
1843 int32 withLength = strlen(with);
1844 int32 charCount = CountChars();
1845 for (int32 i = 0; i < charCount; i++) {
1846 int32 charLength;
1847 const char* sourceChar = CharAt(i, &charLength);
1848 bool match = false;
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) {
1855 match = true;
1856 break;
1860 if (match)
1861 result.Append(with, withLength);
1862 else
1863 result.Append(sourceChar, charLength);
1866 *this = result;
1867 return *this;
1871 // #pragma mark - Unchecked char access
1874 #if __GNUC__ == 2
1875 char&
1876 BString::operator[](int32 index)
1878 if (_MakeWritable() != B_OK) {
1879 static char invalid;
1880 return invalid;
1883 _ReferenceCount() = -1;
1884 // mark string as unshareable
1886 return fPrivateData[index];
1888 #endif
1891 const char*
1892 BString::CharAt(int32 charIndex, int32* bytes) const
1894 int32 offset = UTF8CountBytes(fPrivateData, charIndex);
1895 if (bytes != NULL)
1896 *bytes = UTF8NextCharLen(fPrivateData + offset);
1897 return fPrivateData + offset;
1901 bool
1902 BString::CharAt(int32 charIndex, char* buffer, int32* bytes) const
1904 int32 length;
1905 const char* charAt = CharAt(charIndex, &length);
1906 if (bytes != NULL) {
1907 if (*bytes < length)
1908 return false;
1909 *bytes = length;
1912 memcpy(buffer, charAt, length);
1913 return true;
1917 // #pragma mark - Fast low-level manipulation
1920 char*
1921 BString::LockBuffer(int32 maxLength)
1923 int32 length = Length();
1924 if (maxLength > length)
1925 length = maxLength;
1927 if (_MakeWritable(length, true) != B_OK)
1928 return NULL;
1930 _ReferenceCount() = -1;
1931 // mark unshareable
1933 return fPrivateData;
1937 BString&
1938 BString::UnlockBuffer(int32 length)
1940 if (length > 0)
1941 length = min_clamp0(length, Length());
1942 else
1943 length = fPrivateData == NULL ? 0 : strlen(fPrivateData);
1945 if (_Resize(length) != NULL) {
1946 fPrivateData[length] = '\0';
1947 _ReferenceCount() = 1;
1948 // mark shareable again
1951 return *this;
1955 BString&
1956 BString::SetByteAt(int32 pos, char to)
1958 if (pos < Length() && _MakeWritable() == B_OK)
1959 fPrivateData[pos] = to;
1961 return *this;
1965 // #pragma mark - Uppercase <-> Lowercase
1968 BString&
1969 BString::ToLower()
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]);
1976 return *this;
1980 BString&
1981 BString::ToUpper()
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]);
1988 return *this;
1992 BString&
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]);
2002 return *this;
2006 BString&
2007 BString::CapitalizeEachWord()
2009 int32 length = Length();
2011 if (length > 0 && _MakeWritable() == B_OK) {
2012 int32 count = 0;
2013 do {
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]);
2019 count++;
2020 break;
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]);
2029 else
2030 break;
2032 } while (count < length);
2034 return *this;
2038 // #pragma mark - Escaping and De-escaping
2041 BString&
2042 BString::CharacterEscape(const char* original,
2043 const char* setOfCharsToEscape, char escapeWith)
2045 if (setOfCharsToEscape)
2046 _DoCharacterEscape(original, setOfCharsToEscape, escapeWith);
2047 return *this;
2051 BString&
2052 BString::CharacterEscape(const char* setOfCharsToEscape, char escapeWith)
2054 if (setOfCharsToEscape && Length() > 0)
2055 _DoCharacterEscape(fPrivateData, setOfCharsToEscape, escapeWith);
2056 return *this;
2060 BString&
2061 BString::CharacterDeescape(const char* original, char escapeChar)
2063 return _DoCharacterDeescape(original, escapeChar);
2067 BString&
2068 BString::CharacterDeescape(char escapeChar)
2070 if (Length() > 0)
2071 _DoCharacterDeescape(fPrivateData, escapeChar);
2072 return *this;
2076 // #pragma mark - Trimming
2079 BString&
2080 BString::Trim()
2082 if (Length() <= 0)
2083 return *this;
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]))
2090 startCount++;
2092 int32 endIndex = Length() - 1;
2093 while (endIndex >= startCount && isspace(string[endIndex]))
2094 endIndex--;
2096 if (startCount == 0 && endIndex == Length() - 1)
2097 return *this;
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';
2108 _SetLength(length);
2111 return *this;
2115 // #pragma mark - Insert
2118 BString&
2119 BString::operator<<(const char* string)
2121 if (string != NULL) {
2122 int32 length = strlen(string);
2123 if (length > 0)
2124 _DoAppend(string, length);
2126 return *this;
2130 BString&
2131 BString::operator<<(const BString& string)
2133 if (string.Length() > 0)
2134 _DoAppend(string.String(), string.Length());
2135 return *this;
2139 BString&
2140 BString::operator<<(char c)
2142 _DoAppend(&c, 1);
2143 return *this;
2147 BString&
2148 BString::operator<<(bool value)
2150 if (value)
2151 _DoAppend("true", 4);
2152 else
2153 _DoAppend("false", 5);
2155 return *this;
2159 BString&
2160 BString::operator<<(int i)
2162 char num[32];
2163 int32 length = snprintf(num, sizeof(num), "%d", i);
2165 _DoAppend(num, length);
2166 return *this;
2170 BString&
2171 BString::operator<<(unsigned int i)
2173 char num[32];
2174 int32 length = snprintf(num, sizeof(num), "%u", i);
2176 _DoAppend(num, length);
2177 return *this;
2181 BString&
2182 BString::operator<<(unsigned long i)
2184 char num[32];
2185 int32 length = snprintf(num, sizeof(num), "%lu", i);
2187 _DoAppend(num, length);
2188 return *this;
2192 BString&
2193 BString::operator<<(long i)
2195 char num[32];
2196 int32 length = snprintf(num, sizeof(num), "%ld", i);
2198 _DoAppend(num, length);
2199 return *this;
2203 BString&
2204 BString::operator<<(unsigned long long i)
2206 char num[64];
2207 int32 length = snprintf(num, sizeof(num), "%llu", i);
2209 _DoAppend(num, length);
2210 return *this;
2214 BString&
2215 BString::operator<<(long long i)
2217 char num[64];
2218 int32 length = snprintf(num, sizeof(num), "%lld", i);
2220 _DoAppend(num, length);
2221 return *this;
2225 BString&
2226 BString::operator<<(float f)
2228 char num[64];
2229 int32 length = snprintf(num, sizeof(num), "%.2f", f);
2231 _DoAppend(num, length);
2232 return *this;
2236 BString&
2237 BString::operator<<(double value)
2239 char num[64];
2240 int32 length = snprintf(num, sizeof(num), "%.2f", value);
2242 _DoAppend(num, length);
2243 return *this;
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.
2262 status_t
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
2270 _FreePrivateData();
2272 if (newData == NULL)
2273 return B_NO_MEMORY;
2275 fPrivateData = newData;
2278 return B_OK;
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.
2288 status_t
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
2295 if (copy)
2296 newData = _Clone(fPrivateData, length);
2297 else
2298 newData = _Allocate(length);
2300 if (newData == NULL)
2301 return B_NO_MEMORY;
2303 if (atomic_add(&_ReferenceCount(), -1) == 1) {
2304 // someone else left, we were the last owner
2305 _FreePrivateData();
2307 } else {
2308 // we don't share our data with someone else
2309 newData = _Resize(length);
2311 if (newData == NULL)
2312 return B_NO_MEMORY;
2315 fPrivateData = newData;
2316 return B_OK;
2320 /*! Allocates a new private data buffer with the space to store \a length bytes
2321 (not including the terminating null).
2323 /*static*/ char*
2324 BString::_Allocate(int32 length)
2326 if (length < 0)
2327 return NULL;
2329 char* newData = (char*)malloc(length + kPrivateDataOffset + 1);
2330 if (newData == NULL)
2331 return NULL;
2333 newData += kPrivateDataOffset;
2334 newData[length] = '\0';
2336 // initialize reference count & length
2337 Private::DataRefCount(newData) = 1;
2338 Private::DataLength(newData) = length & 0x7fffffff;
2340 return newData;
2344 /*! Resizes the private data buffer. You must already have a writable buffer
2345 when you call this method.
2347 char*
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;
2356 if (length < 0)
2357 length = 0;
2359 data = (char*)realloc(data, length + kPrivateDataOffset + 1);
2360 if (data == NULL)
2361 return NULL;
2363 data += kPrivateDataOffset;
2365 fPrivateData = data;
2366 fPrivateData[length] = '\0';
2368 _SetLength(length);
2369 _ReferenceCount() = 1;
2371 return data;
2375 void
2376 BString::_Init(const char* src, int32 length)
2378 fPrivateData = _Clone(src, length);
2379 if (fPrivateData == NULL)
2380 fPrivateData = _Clone(NULL, 0);
2384 char*
2385 BString::_Clone(const char* data, int32 length)
2387 char* newData = _Allocate(length);
2388 if (newData == NULL)
2389 return NULL;
2391 if (data != NULL && length > 0) {
2392 // "data" may not span over the whole length
2393 strncpy(newData, data, length);
2396 return newData;
2400 char*
2401 BString::_OpenAtBy(int32 offset, int32 length)
2403 int32 oldLength = Length();
2405 if (_MakeWritable() != B_OK)
2406 return NULL;
2408 memmove(fPrivateData + offset + length, fPrivateData + offset,
2409 oldLength - offset);
2410 return _Resize(oldLength + length);
2414 char*
2415 BString::_ShrinkAtBy(int32 offset, int32 length)
2417 int32 oldLength = Length();
2418 if (_MakeWritable() != B_OK)
2419 return NULL;
2421 memmove(fPrivateData + offset, fPrivateData + offset + length,
2422 oldLength - offset - length);
2423 return _Resize(oldLength - length);
2427 void
2428 BString::_SetLength(int32 length)
2430 Private::DataLength(fPrivateData) = length & 0x7fffffff;
2434 void
2435 BString::_FreePrivateData()
2437 if (fPrivateData != NULL) {
2438 free(fPrivateData - kPrivateDataOffset);
2439 fPrivateData = NULL;
2444 bool
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);
2450 return true;
2452 return false;
2456 bool
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);
2465 return true;
2467 return false;
2471 bool
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);
2480 return true;
2482 return false;
2486 int32
2487 BString::_ShortFindAfter(const char* string, int32 len) const
2489 const char* ptr = strstr(String(), string);
2491 if (ptr != NULL)
2492 return ptr - String();
2494 return B_ERROR;
2498 int32
2499 BString::_FindAfter(const char* string, int32 offset, int32 length) const
2501 const char* ptr = strstr(String() + offset, string);
2503 if (ptr != NULL)
2504 return ptr - String();
2506 return B_ERROR;
2510 int32
2511 BString::_IFindAfter(const char* string, int32 offset, int32 length) const
2513 const char* ptr = strcasestr(String() + offset, string);
2515 if (ptr != NULL)
2516 return ptr - String();
2518 return B_ERROR;
2522 int32
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;
2531 ptr--;
2534 return B_ERROR;
2538 int32
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;
2547 ptr1--;
2550 return B_ERROR;
2554 BString&
2555 BString::_DoCharacterEscape(const char* string, const char* setOfCharsToEscape,
2556 char escapeChar)
2558 if (_MakeWritable(string_length(string), false) != B_OK)
2559 return *this;
2561 memcpy(fPrivateData, string, Length());
2563 PosVect positions;
2564 int32 length = Length();
2565 int32 pos;
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))
2569 return *this;
2572 uint32 count = positions.CountItems();
2573 int32 newLength = length + count;
2574 if (!newLength) {
2575 _Resize(0);
2576 return *this;
2579 char* newData = _Allocate(newLength);
2580 if (newData) {
2581 char* oldString = fPrivateData;
2582 char* newString = newData;
2583 int32 lastPos = 0;
2585 for (uint32 i = 0; i < count; ++i) {
2586 pos = positions.ItemAt(i);
2587 length = pos - lastPos;
2588 if (length > 0) {
2589 memcpy(newString, oldString, length);
2590 oldString += length;
2591 newString += length;
2593 *newString++ = escapeChar;
2594 *newString++ = *oldString++;
2595 lastPos = pos + 1;
2598 length = Length() + 1 - lastPos;
2599 if (length > 0)
2600 memcpy(newString, oldString, length);
2602 _FreePrivateData();
2603 fPrivateData = newData;
2605 return *this;
2609 BString&
2610 BString::_DoCharacterDeescape(const char* string, char escapeChar)
2612 if (_MakeWritable(string_length(string), false) != B_OK)
2613 return *this;
2615 memcpy(fPrivateData, string, Length());
2616 const char escape[2] = { escapeChar, '\0' };
2617 return _DoReplace(escape, "", REPLACE_ALL, 0, KEEP_CASE);
2621 BString&
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())
2627 return *this;
2629 int32 findLen = strlen(findThis);
2630 if (findLen == 0)
2631 return *this;
2633 typedef int32 (BString::*TFindMethod)(const char*, int32, int32) const;
2634 TFindMethod findMethod = ignoreCase
2635 ? &BString::_IFindAfter : &BString::_FindAfter;
2637 if (!replaceWith)
2638 replaceWith = "";
2640 int32 replaceLen = strlen(replaceWith);
2641 int32 lastSrcPos = fromOffset;
2642 PosVect positions;
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);
2650 return *this;
2654 void
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);
2661 if (!newLength) {
2662 _Resize(0);
2663 return;
2666 char* newData = _Allocate(newLength);
2667 if (newData == NULL)
2668 return;
2670 char* oldString = fPrivateData;
2671 char* newString = newData;
2672 int32 lastPos = 0;
2674 for (uint32 i = 0; i < count; ++i) {
2675 int32 pos = positions->ItemAt(i);
2676 length = pos - lastPos;
2677 if (length > 0) {
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;
2689 if (length > 0)
2690 memcpy(newString, oldString, length);
2692 _FreePrivateData();
2693 fPrivateData = newData;
2697 // #pragma mark - backwards compatibility
2700 /*! Translates to (missing const):
2701 BString& BString::operator<<(BString& string)
2703 extern "C" BString&
2704 __ls__7BStringR7BString(BString* self, BString& string)
2706 return self->operator<<(string);
2710 #if __GNUC__ > 3
2712 // #pragma mark - BStringRef backwards compatibility
2715 class BStringRef {
2716 public:
2717 BStringRef(BString& string, int32 position);
2718 ~BStringRef() {}
2720 operator char() const;
2722 char* operator&();
2723 const char* operator&() const;
2725 BStringRef& operator=(char c);
2726 BStringRef& operator=(const BStringRef& rc);
2728 private:
2729 BString& fString;
2730 int32 fPosition;
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;
2747 BStringRef&
2748 BStringRef::operator=(char c)
2750 fString._MakeWritable();
2751 fString.fPrivateData[fPosition] = c;
2752 return *this;
2756 BStringRef&
2757 BStringRef::operator=(const BStringRef &rc)
2759 return operator=(rc.fString.fPrivateData[rc.fPosition]);
2763 const char*
2764 BStringRef::operator&() const
2766 return &fString.fPrivateData[fPosition];
2770 char*
2771 BStringRef::operator&()
2773 if (fString._MakeWritable() != B_OK)
2774 return NULL;
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);
2789 #endif
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());