xref: /haiku/src/kits/support/String.cpp (revision b55a57da7173b9af0432bd3e148d03f06161d036)
1 /*
2  * Copyright 2001-2009, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  *		Stefano Ceccherini (burton666@libero.it)
8  *		Oliver Tappe (openbeos@hirschkaefer.de)
9  *		Axel Dörfler, axeld@pinc-software.de
10  *		Julun <host.haiku@gmx.de>
11  */
12 
13 
14 /*! String class supporting common string operations. */
15 
16 
17 #include <String.h>
18 
19 #include <ctype.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #include <Debug.h>
25 
26 
27 // define proper names for case-option of _DoReplace()
28 #define KEEP_CASE false
29 #define IGNORE_CASE true
30 
31 // define proper names for count-option of _DoReplace()
32 #define REPLACE_ALL 0x7FFFFFFF
33 
34 
35 const uint32 kPrivateDataOffset = 2 * sizeof(int32);
36 
37 const char* B_EMPTY_STRING = "";
38 
39 
40 // helper function, returns minimum of two given values (but clamps to 0):
41 static inline int32
42 min_clamp0(int32 num1, int32 num2)
43 {
44 	if (num1 < num2)
45 		return num1 > 0 ? num1 : 0;
46 
47 	return num2 > 0 ? num2 : 0;
48 }
49 
50 
51 //! Returns length of given string (but clamps to given maximum).
52 static inline int32
53 strlen_clamp(const char* str, int32 max)
54 {
55 	// this should yield 0 for max<0:
56 	int32 length = 0;
57 	while (length < max && *str++) {
58 		length++;
59 	}
60 	return length;
61 }
62 
63 
64 //! Helper function for strlen() that can handle NULL strings.
65 static inline size_t
66 string_length(const char* string)
67 {
68 	return string != NULL ? strlen(string) : 0;
69 }
70 
71 
72 //! helper function, massages given pointer into a legal c-string:
73 static inline const char*
74 safestr(const char* str)
75 {
76 	return str ? str : "";
77 }
78 
79 
80 static inline vint32&
81 data_reference_count(char* data)
82 {
83 	return *(((int32 *)data) - 2);
84 }
85 
86 
87 static inline int32&
88 data_length(char* data)
89 {
90 	return *(((int32*)data) - 1);
91 }
92 
93 
94 //	#pragma mark - PosVect
95 
96 
97 class BString::PosVect {
98 public:
99 	PosVect()
100 		:
101 		fSize(0),
102 		fBufferSize(20),
103 		fBuffer(NULL)
104 	{
105 	}
106 
107 	~PosVect()
108 	{
109 		free(fBuffer);
110 	}
111 
112 	bool Add(int32 pos)
113 	{
114 		if (fBuffer == NULL || fSize == fBufferSize) {
115 			if (fBuffer != NULL)
116 				fBufferSize *= 2;
117 
118 			int32* newBuffer = NULL;
119 			newBuffer = (int32*)realloc(fBuffer, fBufferSize * sizeof(int32));
120 			if (newBuffer == NULL)
121 				return false;
122 
123 			fBuffer = newBuffer;
124 		}
125 
126 		fBuffer[fSize++] = pos;
127 		return true;
128 	}
129 
130 	inline int32 ItemAt(int32 index) const
131 	{
132 		return fBuffer[index];
133 	}
134 
135 	inline int32 CountItems() const
136 	{
137 		return fSize;
138 	}
139 
140 private:
141 	int32	fSize;
142 	int32	fBufferSize;
143 	int32*	fBuffer;
144 };
145 
146 
147 //	#pragma mark - BStringRef
148 
149 
150 BStringRef::BStringRef(BString& string, int32 position)
151 	: fString(string), fPosition(position)
152 {
153 }
154 
155 
156 BStringRef::operator char() const
157 {
158 	return fPosition < fString.Length() ? fString.fPrivateData[fPosition] : 0;
159 }
160 
161 
162 BStringRef&
163 BStringRef::operator=(char c)
164 {
165 	fString._MakeWritable();
166 	fString.fPrivateData[fPosition] = c;
167 	return *this;
168 }
169 
170 
171 BStringRef&
172 BStringRef::operator=(const BStringRef &rc)
173 {
174 	return operator=(rc.fString.fPrivateData[rc.fPosition]);
175 }
176 
177 
178 const char*
179 BStringRef::operator&() const
180 {
181 	return &fString.fPrivateData[fPosition];
182 }
183 
184 
185 char*
186 BStringRef::operator&()
187 {
188 	if (fString._MakeWritable() != B_OK)
189 		return NULL;
190 
191 	fString._ReferenceCount() = -1;
192 		// mark as unsharable
193 	return &fString.fPrivateData[fPosition];
194 }
195 
196 
197 //	#pragma mark - BString
198 
199 
200 inline vint32&
201 BString::_ReferenceCount()
202 {
203 	return data_reference_count(fPrivateData);
204 }
205 
206 
207 inline const vint32&
208 BString::_ReferenceCount() const
209 {
210 	return data_reference_count(fPrivateData);
211 }
212 
213 
214 inline bool
215 BString::_IsShareable() const
216 {
217 	return fPrivateData != NULL && _ReferenceCount() >= 0;
218 }
219 
220 
221 BString::BString()
222 	:
223 	fPrivateData(NULL)
224 {
225 	_Init("", 0);
226 }
227 
228 
229 BString::BString(const char* string)
230 	:
231 	fPrivateData(NULL)
232 {
233 	_Init(string, strlen(safestr(string)));
234 }
235 
236 
237 BString::BString(const BString& string)
238 	:
239 	fPrivateData(NULL)
240 {
241 	// check if source is sharable - if so, share else clone
242 	if (string._IsShareable()) {
243 		fPrivateData = string.fPrivateData;
244 		atomic_add(&_ReferenceCount(), 1);
245 			// string cannot go away right now
246 	} else
247 		_Init(string.String(), string.Length());
248 }
249 
250 
251 BString::BString(const char* string, int32 maxLength)
252 	: fPrivateData(NULL)
253 {
254 	_Init(string, strlen_clamp(safestr(string), maxLength));
255 }
256 
257 
258 BString::~BString()
259 {
260 	if (!_IsShareable() || atomic_add(&_ReferenceCount(), -1) == 1)
261 		_FreePrivateData();
262 }
263 
264 
265 //	#pragma mark - Access
266 
267 
268 int32
269 BString::CountChars() const
270 {
271 	int32 count = 0;
272 
273 	const char* start = fPrivateData;
274 	const char* end = fPrivateData + Length();
275 
276 	while (start++ != end) {
277 		count++;
278 
279 		// Jump to next UTF8 character
280 		for (; (*start & 0xc0) == 0x80; start++);
281 	}
282 
283 	return count;
284 }
285 
286 
287 //	#pragma mark - Assignment
288 
289 
290 BString&
291 BString::operator=(const BString& string)
292 {
293 	return SetTo(string);
294 }
295 
296 
297 BString&
298 BString::operator=(const char* string)
299 {
300 	if (!string)
301 		string = "";
302 	if (string != String())
303 		SetTo(string, strlen(string));
304 	return *this;
305 }
306 
307 
308 BString&
309 BString::operator=(char c)
310 {
311 	return SetTo(c, 1);
312 }
313 
314 
315 BString&
316 BString::SetTo(const char* string, int32 maxLength)
317 {
318 	if (maxLength < 0)
319 		maxLength = INT32_MAX;
320 
321 	maxLength = strlen_clamp(safestr(string), maxLength);
322 
323 	if (_MakeWritable(maxLength, false) == B_OK)
324 		memcpy(fPrivateData, string, maxLength);
325 
326 	return *this;
327 }
328 
329 
330 BString&
331 BString::SetTo(const BString& string)
332 {
333 	// we share the information already
334 	if (fPrivateData == string.fPrivateData)
335 		return *this;
336 
337 	bool freeData = true;
338 
339 	if (_IsShareable() && atomic_add(&_ReferenceCount(), -1) > 1) {
340 		// there is still someone who shares our data
341 		freeData = false;
342 	}
343 
344 	if (freeData)
345 		_FreePrivateData();
346 
347 	// if source is sharable share, otherwise clone
348 	if (string._IsShareable()) {
349 		fPrivateData = string.fPrivateData;
350 		atomic_add(&_ReferenceCount(), 1);
351 			// the string cannot go away right now
352 	} else
353 		_Init(string.String(), string.Length());
354 
355 	return *this;
356 }
357 
358 
359 BString&
360 BString::Adopt(BString& from)
361 {
362 	SetTo(from);
363 	from.SetTo("");
364 
365 	return *this;
366 }
367 
368 
369 BString&
370 BString::SetTo(const BString& string, int32 maxLength)
371 {
372 	if (maxLength < 0)
373 		maxLength = INT32_MAX;
374 	if (fPrivateData != string.fPrivateData
375 		// make sure we reassing in case length is different
376 		|| (fPrivateData == string.fPrivateData && Length() > maxLength)) {
377 		maxLength = min_clamp0(maxLength, string.Length());
378 		if (_MakeWritable(maxLength, false) == B_OK)
379 			memcpy(fPrivateData, string.String(), maxLength);
380 	}
381 	return *this;
382 }
383 
384 
385 BString&
386 BString::Adopt(BString& from, int32 maxLength)
387 {
388 	SetTo(from, maxLength);
389 	from.SetTo("");
390 
391 	return *this;
392 }
393 
394 
395 BString&
396 BString::SetTo(char c, int32 count)
397 {
398 	if (count < 0)
399 		count = 0;
400 
401 	if (_MakeWritable(count, false) == B_OK)
402 		memset(fPrivateData, c, count);
403 	return *this;
404 }
405 
406 
407 //	#pragma mark - Substring copying
408 
409 
410 BString&
411 BString::CopyInto(BString& into, int32 fromOffset, int32 length) const
412 {
413 	if (this != &into)
414 		into.SetTo(fPrivateData + fromOffset, length);
415 	return into;
416 }
417 
418 
419 void
420 BString::CopyInto(char* into, int32 fromOffset, int32 length) const
421 {
422 	if (into) {
423 		length = min_clamp0(length, Length() - fromOffset);
424 		memcpy(into, fPrivateData + fromOffset, length);
425 	}
426 }
427 
428 
429 //	#pragma mark - Appending
430 
431 
432 BString&
433 BString::operator+=(const char* string)
434 {
435 	if (string) {
436 		int32 length = strlen(string);
437 		if (length > 0)
438 			_DoAppend(string, length);
439 	}
440 	return *this;
441 }
442 
443 
444 BString&
445 BString::operator+=(char c)
446 {
447 	_DoAppend(&c, 1);
448 	return *this;
449 }
450 
451 
452 BString&
453 BString::Append(const BString& string, int32 length)
454 {
455 	if (&string != this) {
456 		length = min_clamp0(length, string.Length());
457 		if (length > 0)
458 			_DoAppend(string.fPrivateData, length);
459 	}
460 	return *this;
461 }
462 
463 
464 BString&
465 BString::Append(const char* string, int32 length)
466 {
467 	if (string) {
468 		length = strlen_clamp(string, length);
469 		if (length > 0)
470 			_DoAppend(string, length);
471 	}
472 	return *this;
473 }
474 
475 
476 BString&
477 BString::Append(char c, int32 count)
478 {
479 	int32 oldLength = Length();
480 	if (count > 0 && _DoAppend("", count))
481 		memset(fPrivateData + oldLength, c, count);
482 	return *this;
483 }
484 
485 
486 //	#pragma mark - Prepending
487 
488 
489 BString&
490 BString::Prepend(const char* string)
491 {
492 	if (string)
493 		_DoPrepend(string, strlen(string));
494 	return *this;
495 }
496 
497 
498 BString&
499 BString::Prepend(const BString& string)
500 {
501 	if (&string != this)
502 		_DoPrepend(string.String(), string.Length());
503 	return *this;
504 }
505 
506 
507 BString&
508 BString::Prepend(const char* string, int32 length)
509 {
510 	if (string)
511 		_DoPrepend(string, strlen_clamp(string, length));
512 	return *this;
513 }
514 
515 
516 BString&
517 BString::Prepend(const BString& string, int32 length)
518 {
519 	if (&string != this)
520 		_DoPrepend(string.fPrivateData, min_clamp0(length, string.Length()));
521 	return *this;
522 }
523 
524 
525 BString&
526 BString::Prepend(char c, int32 count)
527 {
528 	if (count > 0 && _DoPrepend("", count))
529 		memset(fPrivateData, c, count);
530 	return *this;
531 }
532 
533 
534 //	#pragma mark - Inserting
535 
536 
537 BString&
538 BString::Insert(const char* string, int32 position)
539 {
540 	if (string != NULL && position <= Length()) {
541 		int32 len = int32(strlen(string));
542 		if (position < 0) {
543 			int32 skipLen = min_clamp0(-1 * position, len);
544 			string += skipLen;
545 			len -= skipLen;
546 			position = 0;
547 		} else {
548 			position = min_clamp0(position, Length());
549 		}
550 		_DoInsert(string, position, len);
551 	}
552 	return *this;
553 }
554 
555 
556 BString&
557 BString::Insert(const char* string, int32 length, int32 position)
558 {
559 	if (string != NULL && position <= Length()) {
560 		int32 len = strlen_clamp(string, length);
561 		if (position < 0) {
562 			int32 skipLen = min_clamp0(-1 * position, len);
563 			string += skipLen;
564 			len -= skipLen;
565 			position = 0;
566 		} else {
567 			position = min_clamp0(position, Length());
568 		}
569 		_DoInsert(string, position, len);
570 	}
571 	return *this;
572 }
573 
574 
575 BString&
576 BString::Insert(const char* string, int32 fromOffset, int32 length,
577 	int32 position)
578 {
579 	if (string)
580 		Insert(string + fromOffset, length, position);
581 	return *this;
582 }
583 
584 
585 BString&
586 BString::Insert(const BString& string, int32 position)
587 {
588 	if (&string != this && string.Length() > 0)
589 		Insert(string.fPrivateData, position);
590 	return *this;
591 }
592 
593 
594 BString&
595 BString::Insert(const BString& string, int32 length, int32 position)
596 {
597 	if (&string != this && string.Length() > 0)
598 		Insert(string.String(), length, position);
599 	return *this;
600 }
601 
602 
603 BString&
604 BString::Insert(const BString& string, int32 fromOffset, int32 length,
605 	int32 position)
606 {
607 	if (&string != this && string.Length() > 0)
608 		Insert(string.String() + fromOffset, length, position);
609 	return *this;
610 }
611 
612 
613 BString&
614 BString::Insert(char c, int32 count, int32 position)
615 {
616 	if (position < 0) {
617 		count = MAX(count + position, 0);
618 		position = 0;
619 	} else
620 		position = min_clamp0(position, Length());
621 
622 	if (count > 0 && _DoInsert("", position, count))
623 		memset(fPrivateData + position, c, count);
624 
625 	return *this;
626 }
627 
628 
629 //	#pragma mark - Removing
630 
631 
632 BString&
633 BString::Truncate(int32 newLength, bool lazy)
634 {
635 	if (newLength < 0)
636 		newLength = 0;
637 
638 	if (newLength < Length()) {
639 		// ignore lazy, since we might detach
640 		_MakeWritable(newLength, true);
641 	}
642 
643 	return *this;
644 }
645 
646 
647 BString&
648 BString::Remove(int32 from, int32 length)
649 {
650 	if (length > 0 && from < Length())
651 		_ShrinkAtBy(from, min_clamp0(length, (Length() - from)));
652 	return *this;
653 }
654 
655 
656 BString&
657 BString::RemoveFirst(const BString& string)
658 {
659 	if (string.Length() > 0) {
660 		int32 pos = _ShortFindAfter(string.String(), string.Length());
661 		if (pos >= 0)
662 			_ShrinkAtBy(pos, string.Length());
663 	}
664 	return *this;
665 }
666 
667 
668 BString&
669 BString::RemoveLast(const BString& string)
670 {
671 	int32 pos = _FindBefore(string.String(), Length(), string.Length());
672 	if (pos >= 0)
673 		_ShrinkAtBy(pos, string.Length());
674 
675 	return *this;
676 }
677 
678 
679 BString&
680 BString::RemoveAll(const BString& string)
681 {
682 	if (string.Length() == 0 || Length() == 0 || FindFirst(string) < 0)
683 		return *this;
684 
685 	if (_MakeWritable() != B_OK)
686 		return *this;
687 
688 	return _DoReplace(string.String(), "", REPLACE_ALL, 0, KEEP_CASE);
689 }
690 
691 
692 BString&
693 BString::RemoveFirst(const char* string)
694 {
695 	int32 length = string ? strlen(string) : 0;
696 	if (length > 0) {
697 		int32 pos = _ShortFindAfter(string, length);
698 		if (pos >= 0)
699 			_ShrinkAtBy(pos, length);
700 	}
701 	return *this;
702 }
703 
704 
705 BString&
706 BString::RemoveLast(const char* string)
707 {
708 	int32 length = string ? strlen(string) : 0;
709 	if (length > 0) {
710 		int32 pos = _FindBefore(string, Length(), length);
711 		if (pos >= 0)
712 			_ShrinkAtBy(pos, length);
713 	}
714 	return *this;
715 }
716 
717 
718 BString&
719 BString::RemoveAll(const char* string)
720 {
721 	if (!string || Length() == 0 || FindFirst(string) < 0)
722 		return *this;
723 
724 	if (_MakeWritable() != B_OK)
725 		return *this;
726 
727 	return _DoReplace(string, "", REPLACE_ALL, 0, KEEP_CASE);
728 }
729 
730 
731 BString&
732 BString::RemoveSet(const char* setOfCharsToRemove)
733 {
734 	return ReplaceSet(setOfCharsToRemove, "");
735 }
736 
737 
738 BString&
739 BString::MoveInto(BString& into, int32 from, int32 length)
740 {
741 	if (length) {
742 		CopyInto(into, from, length);
743 		Remove(from, length);
744 	}
745 	return into;
746 }
747 
748 
749 void
750 BString::MoveInto(char* into, int32 from, int32 length)
751 {
752 	if (into) {
753 		CopyInto(into, from, length);
754 		Remove(from, length);
755 	}
756 }
757 
758 
759 //	#pragma mark - Compare functions
760 
761 
762 bool
763 BString::operator<(const char* string) const
764 {
765 	return strcmp(String(), safestr(string)) < 0;
766 }
767 
768 
769 bool
770 BString::operator<=(const char* string) const
771 {
772 	return strcmp(String(), safestr(string)) <= 0;
773 }
774 
775 
776 bool
777 BString::operator==(const char* string) const
778 {
779 	return strcmp(String(), safestr(string)) == 0;
780 }
781 
782 
783 bool
784 BString::operator>=(const char* string) const
785 {
786 	return strcmp(String(), safestr(string)) >= 0;
787 }
788 
789 
790 bool
791 BString::operator>(const char* string) const
792 {
793 	return strcmp(String(), safestr(string)) > 0;
794 }
795 
796 
797 //	#pragma mark - strcmp()-style compare functions
798 
799 
800 int
801 BString::Compare(const BString& string) const
802 {
803 	return strcmp(String(), string.String());
804 }
805 
806 
807 int
808 BString::Compare(const char* string) const
809 {
810 	return strcmp(String(), safestr(string));
811 }
812 
813 
814 int
815 BString::Compare(const BString& string, int32 length) const
816 {
817 	return strncmp(String(), string.String(), length);
818 }
819 
820 
821 int
822 BString::Compare(const char* string, int32 length) const
823 {
824 	return strncmp(String(), safestr(string), length);
825 }
826 
827 
828 int
829 BString::ICompare(const BString& string) const
830 {
831 	return strcasecmp(String(), string.String());
832 }
833 
834 
835 int
836 BString::ICompare(const char* string) const
837 {
838 	return strcasecmp(String(), safestr(string));
839 }
840 
841 
842 int
843 BString::ICompare(const BString& string, int32 length) const
844 {
845 	return strncasecmp(String(), string.String(), length);
846 }
847 
848 
849 int
850 BString::ICompare(const char* string, int32 length) const
851 {
852 	return strncasecmp(String(), safestr(string), length);
853 }
854 
855 
856 //	#pragma mark - Searching
857 
858 
859 int32
860 BString::FindFirst(const BString& string) const
861 {
862 	return _ShortFindAfter(string.String(), string.Length());
863 }
864 
865 
866 int32
867 BString::FindFirst(const char* string) const
868 {
869 	if (string == NULL)
870 		return B_BAD_VALUE;
871 
872 	return _ShortFindAfter(string, strlen(string));
873 }
874 
875 
876 int32
877 BString::FindFirst(const BString& string, int32 fromOffset) const
878 {
879 	if (fromOffset < 0)
880 		return B_ERROR;
881 
882 	return _FindAfter(string.String(), min_clamp0(fromOffset, Length()),
883 		string.Length());
884 }
885 
886 
887 int32
888 BString::FindFirst(const char* string, int32 fromOffset) const
889 {
890 	if (string == NULL)
891 		return B_BAD_VALUE;
892 
893 	if (fromOffset < 0)
894 		return B_ERROR;
895 
896 	return _FindAfter(string, min_clamp0(fromOffset, Length()),
897 		strlen(safestr(string)));
898 }
899 
900 
901 int32
902 BString::FindFirst(char c) const
903 {
904 	const char* start = String();
905 	const char* end = String() + Length();
906 
907 	// Scans the string until we found the
908 	// character, or we reach the string's start
909 	while (start != end && *start != c) {
910 		start++;
911 	}
912 
913 	if (start == end)
914 		return B_ERROR;
915 
916 	return start - String();
917 }
918 
919 
920 int32
921 BString::FindFirst(char c, int32 fromOffset) const
922 {
923 	if (fromOffset < 0)
924 		return B_ERROR;
925 
926 	const char* start = String() + min_clamp0(fromOffset, Length());
927 	const char* end = String() + Length();
928 
929 	// Scans the string until we found the
930 	// character, or we reach the string's start
931 	while (start < end && *start != c) {
932 		start++;
933 	}
934 
935 	if (start >= end)
936 		return B_ERROR;
937 
938 	return start - String();
939 }
940 
941 
942 int32
943 BString::FindLast(const BString& string) const
944 {
945 	return _FindBefore(string.String(), Length(), string.Length());
946 }
947 
948 
949 int32
950 BString::FindLast(const char* string) const
951 {
952 	if (string == NULL)
953 		return B_BAD_VALUE;
954 
955 	return _FindBefore(string, Length(), strlen(safestr(string)));
956 }
957 
958 
959 int32
960 BString::FindLast(const BString& string, int32 beforeOffset) const
961 {
962 	if (beforeOffset < 0)
963 		return B_ERROR;
964 
965 	return _FindBefore(string.String(), min_clamp0(beforeOffset, Length()),
966 		string.Length());
967 }
968 
969 
970 int32
971 BString::FindLast(const char* string, int32 beforeOffset) const
972 {
973 	if (string == NULL)
974 		return B_BAD_VALUE;
975 
976 	if (beforeOffset < 0)
977 		return B_ERROR;
978 
979 	return _FindBefore(string, min_clamp0(beforeOffset, Length()),
980 		strlen(safestr(string)));
981 }
982 
983 
984 int32
985 BString::FindLast(char c) const
986 {
987 	const char* start = String();
988 	const char* end = String() + Length();
989 
990 	// Scans the string backwards until we found
991 	// the character, or we reach the string's start
992 	while (end != start && *end != c) {
993 		end--;
994 	}
995 
996 	if (end == start)
997 		return B_ERROR;
998 
999 	return end - String();
1000 }
1001 
1002 
1003 int32
1004 BString::FindLast(char c, int32 beforeOffset) const
1005 {
1006 	if (beforeOffset < 0)
1007 		return B_ERROR;
1008 
1009 	const char* start = String();
1010 	const char* end = String() + min_clamp0(beforeOffset, Length());
1011 
1012 	// Scans the string backwards until we found
1013 	// the character, or we reach the string's start
1014 	while (end > start && *end != c) {
1015 		end--;
1016 	}
1017 
1018 	if (end <= start)
1019 		return B_ERROR;
1020 
1021 	return end - String();
1022 }
1023 
1024 
1025 int32
1026 BString::IFindFirst(const BString& string) const
1027 {
1028 	return _IFindAfter(string.String(), 0, string.Length());
1029 }
1030 
1031 
1032 int32
1033 BString::IFindFirst(const char* string) const
1034 {
1035 	if (string == NULL)
1036 		return B_BAD_VALUE;
1037 
1038 	return _IFindAfter(string, 0, strlen(safestr(string)));
1039 }
1040 
1041 
1042 int32
1043 BString::IFindFirst(const BString& string, int32 fromOffset) const
1044 {
1045 	if (fromOffset < 0)
1046 		return B_ERROR;
1047 
1048 	return _IFindAfter(string.String(), min_clamp0(fromOffset, Length()),
1049 		string.Length());
1050 }
1051 
1052 
1053 int32
1054 BString::IFindFirst(const char* string, int32 fromOffset) const
1055 {
1056 	if (string == NULL)
1057 		return B_BAD_VALUE;
1058 
1059 	if (fromOffset < 0)
1060 		return B_ERROR;
1061 
1062 	return _IFindAfter(string, min_clamp0(fromOffset,Length()),
1063 		strlen(safestr(string)));
1064 }
1065 
1066 
1067 int32
1068 BString::IFindLast(const BString& string) const
1069 {
1070 	return _IFindBefore(string.String(), Length(), string.Length());
1071 }
1072 
1073 
1074 int32
1075 BString::IFindLast(const char* string) const
1076 {
1077 	if (string == NULL)
1078 		return B_BAD_VALUE;
1079 
1080 	return _IFindBefore(string, Length(), strlen(safestr(string)));
1081 }
1082 
1083 
1084 int32
1085 BString::IFindLast(const BString& string, int32 beforeOffset) const
1086 {
1087 	if (beforeOffset < 0)
1088 		return B_ERROR;
1089 
1090 	return _IFindBefore(string.String(), min_clamp0(beforeOffset, Length()),
1091 		string.Length());
1092 }
1093 
1094 
1095 int32
1096 BString::IFindLast(const char* string, int32 beforeOffset) const
1097 {
1098 	if (string == NULL)
1099 		return B_BAD_VALUE;
1100 
1101 	if (beforeOffset < 0)
1102 		return B_ERROR;
1103 
1104 	return _IFindBefore(string, min_clamp0(beforeOffset, Length()),
1105 		strlen(safestr(string)));
1106 }
1107 
1108 
1109 //	#pragma mark - Replacing
1110 
1111 
1112 BString&
1113 BString::ReplaceFirst(char replaceThis, char withThis)
1114 {
1115 	int32 pos = FindFirst(replaceThis);
1116 	if (pos >= 0 && _MakeWritable() == B_OK)
1117 		fPrivateData[pos] = withThis;
1118 	return *this;
1119 }
1120 
1121 
1122 BString&
1123 BString::ReplaceLast(char replaceThis, char withThis)
1124 {
1125 	int32 pos = FindLast(replaceThis);
1126 	if (pos >= 0 && _MakeWritable() == B_OK)
1127 		fPrivateData[pos] = withThis;
1128 	return *this;
1129 }
1130 
1131 
1132 BString&
1133 BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset)
1134 {
1135 	fromOffset = min_clamp0(fromOffset, Length());
1136 	int32 pos = FindFirst(replaceThis, fromOffset);
1137 
1138 	// detach and set first match
1139 	if (pos >= 0 && _MakeWritable() == B_OK) {
1140 		fPrivateData[pos] = withThis;
1141 		for (pos = pos;;) {
1142 			pos = FindFirst(replaceThis, pos);
1143 			if (pos < 0)
1144 				break;
1145 			fPrivateData[pos] = withThis;
1146 		}
1147 	}
1148 	return *this;
1149 }
1150 
1151 
1152 BString&
1153 BString::Replace(char replaceThis, char withThis, int32 maxReplaceCount,
1154 	int32 fromOffset)
1155 {
1156 	fromOffset = min_clamp0(fromOffset, Length());
1157 	int32 pos = FindFirst(replaceThis, fromOffset);
1158 
1159 	if (maxReplaceCount > 0 && pos >= 0 && _MakeWritable() == B_OK) {
1160 		maxReplaceCount--;
1161 		fPrivateData[pos] = withThis;
1162 		for (pos = pos;  maxReplaceCount > 0; maxReplaceCount--) {
1163 			pos = FindFirst(replaceThis, pos);
1164 			if (pos < 0)
1165 				break;
1166 			fPrivateData[pos] = withThis;
1167 		}
1168 	}
1169 	return *this;
1170 }
1171 
1172 
1173 BString&
1174 BString::ReplaceFirst(const char* replaceThis, const char* withThis)
1175 {
1176 	if (!replaceThis || !withThis || FindFirst(replaceThis) < 0)
1177 		return *this;
1178 
1179 	if (_MakeWritable() != B_OK)
1180 		return *this;
1181 
1182 	return _DoReplace(replaceThis, withThis, 1, 0, KEEP_CASE);
1183 }
1184 
1185 
1186 BString&
1187 BString::ReplaceLast(const char* replaceThis, const char* withThis)
1188 {
1189 	if (!replaceThis || !withThis)
1190 		return *this;
1191 
1192 	int32 replaceThisLength = strlen(replaceThis);
1193 	int32 pos = _FindBefore(replaceThis, Length(), replaceThisLength);
1194 
1195 	if (pos >= 0) {
1196 		int32 withThisLength =  strlen(withThis);
1197 		int32 difference = withThisLength - replaceThisLength;
1198 
1199 		if (difference > 0) {
1200 			if (!_OpenAtBy(pos, difference))
1201 				return *this;
1202 		} else if (difference < 0) {
1203 			if (!_ShrinkAtBy(pos, -difference))
1204 				return *this;
1205 		} else {
1206 			if (_MakeWritable() != B_OK)
1207 				return *this;
1208 		}
1209 		memcpy(fPrivateData + pos, withThis, withThisLength);
1210 	}
1211 
1212 	return *this;
1213 }
1214 
1215 
1216 BString&
1217 BString::ReplaceAll(const char* replaceThis, const char* withThis,
1218 	int32 fromOffset)
1219 {
1220 	if (!replaceThis || !withThis || FindFirst(replaceThis) < 0)
1221 		return *this;
1222 
1223 	if (_MakeWritable() != B_OK)
1224 		return *this;
1225 
1226 	return _DoReplace(replaceThis, withThis, REPLACE_ALL,
1227 		min_clamp0(fromOffset, Length()), KEEP_CASE);
1228 }
1229 
1230 
1231 BString&
1232 BString::Replace(const char* replaceThis, const char* withThis,
1233 	int32 maxReplaceCount, int32 fromOffset)
1234 {
1235 	if (!replaceThis || !withThis || maxReplaceCount <= 0
1236 		|| FindFirst(replaceThis) < 0)
1237 		return *this;
1238 
1239 	if (_MakeWritable() != B_OK)
1240 		return *this;
1241 
1242 	return _DoReplace(replaceThis, withThis, maxReplaceCount,
1243 		min_clamp0(fromOffset, Length()), KEEP_CASE);
1244 }
1245 
1246 
1247 BString&
1248 BString::IReplaceFirst(char replaceThis, char withThis)
1249 {
1250 	char tmp[2] = { replaceThis, '\0' };
1251 
1252 	int32 pos = _IFindAfter(tmp, 0, 1);
1253 	if (pos >= 0 && _MakeWritable() == B_OK)
1254 		fPrivateData[pos] = withThis;
1255 	return *this;
1256 }
1257 
1258 
1259 BString&
1260 BString::IReplaceLast(char replaceThis, char withThis)
1261 {
1262 	char tmp[2] = { replaceThis, '\0' };
1263 
1264 	int32 pos = _IFindBefore(tmp, Length(), 1);
1265 	if (pos >= 0 && _MakeWritable() == B_OK)
1266 		fPrivateData[pos] = withThis;
1267 	return *this;
1268 }
1269 
1270 
1271 BString&
1272 BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset)
1273 {
1274 	char tmp[2] = { replaceThis, '\0' };
1275 	fromOffset = min_clamp0(fromOffset, Length());
1276 	int32 pos = _IFindAfter(tmp, fromOffset, 1);
1277 
1278 	if (pos >= 0 && _MakeWritable() == B_OK) {
1279 		fPrivateData[pos] = withThis;
1280 		for (pos = pos;;) {
1281 			pos = _IFindAfter(tmp, pos, 1);
1282 			if (pos < 0)
1283 				break;
1284 			fPrivateData[pos] = withThis;
1285 		}
1286 	}
1287 	return *this;
1288 }
1289 
1290 
1291 BString&
1292 BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount,
1293 	int32 fromOffset)
1294 {
1295 	char tmp[2] = { replaceThis, '\0' };
1296 	fromOffset = min_clamp0(fromOffset, Length());
1297 	int32 pos = _IFindAfter(tmp, fromOffset, 1);
1298 
1299 	if (maxReplaceCount > 0 && pos >= 0 && _MakeWritable() == B_OK) {
1300 		fPrivateData[pos] = withThis;
1301 		maxReplaceCount--;
1302 		for (pos = pos;  maxReplaceCount > 0; maxReplaceCount--) {
1303 			pos = _IFindAfter(tmp, pos, 1);
1304 			if (pos < 0)
1305 				break;
1306 			fPrivateData[pos] = withThis;
1307 		}
1308 	}
1309 
1310 	return *this;
1311 }
1312 
1313 
1314 BString&
1315 BString::IReplaceFirst(const char* replaceThis, const char* withThis)
1316 {
1317 	if (!replaceThis || !withThis || IFindFirst(replaceThis) < 0)
1318 		return *this;
1319 
1320 	if (_MakeWritable() != B_OK)
1321 		return *this;
1322 	return _DoReplace(replaceThis, withThis, 1, 0, IGNORE_CASE);
1323 }
1324 
1325 
1326 BString&
1327 BString::IReplaceLast(const char* replaceThis, const char* withThis)
1328 {
1329 	if (!replaceThis || !withThis)
1330 		return *this;
1331 
1332 	int32 replaceThisLength = strlen(replaceThis);
1333 	int32 pos = _IFindBefore(replaceThis, Length(), replaceThisLength);
1334 
1335 	if (pos >= 0) {
1336 		int32 withThisLength = strlen(withThis);
1337 		int32 difference = withThisLength - replaceThisLength;
1338 
1339 		if (difference > 0) {
1340 			if (!_OpenAtBy(pos, difference))
1341 				return *this;
1342 		} else if (difference < 0) {
1343 			if (!_ShrinkAtBy(pos, -difference))
1344 				return *this;
1345 		} else {
1346 			if (_MakeWritable() != B_OK)
1347 				return *this;
1348 		}
1349 		memcpy(fPrivateData + pos, withThis, withThisLength);
1350 	}
1351 
1352 	return *this;
1353 }
1354 
1355 
1356 BString&
1357 BString::IReplaceAll(const char* replaceThis, const char* withThis,
1358 	int32 fromOffset)
1359 {
1360 	if (!replaceThis || !withThis || IFindFirst(replaceThis) < 0)
1361 		return *this;
1362 
1363 	if (_MakeWritable() != B_OK)
1364 		return *this;
1365 
1366 	return _DoReplace(replaceThis, withThis, REPLACE_ALL,
1367 		min_clamp0(fromOffset, Length()), IGNORE_CASE);
1368 }
1369 
1370 
1371 BString&
1372 BString::IReplace(const char* replaceThis, const char* withThis,
1373 	int32 maxReplaceCount, int32 fromOffset)
1374 {
1375 	if (!replaceThis || !withThis || maxReplaceCount <= 0
1376 		|| FindFirst(replaceThis) < 0)
1377 		return *this;
1378 
1379 	if (_MakeWritable() != B_OK)
1380 		return *this;
1381 
1382 	return _DoReplace(replaceThis, withThis, maxReplaceCount,
1383 		min_clamp0(fromOffset, Length()), IGNORE_CASE);
1384 }
1385 
1386 
1387 BString&
1388 BString::ReplaceSet(const char* setOfChars, char with)
1389 {
1390 	if (!setOfChars || strcspn(fPrivateData, setOfChars) >= uint32(Length()))
1391 		return *this;
1392 
1393 	if (_MakeWritable() != B_OK)
1394 		return *this;
1395 
1396 	int32 offset = 0;
1397 	int32 length = Length();
1398 	for (int32 pos;;) {
1399 		pos = strcspn(fPrivateData + offset, setOfChars);
1400 
1401 		offset += pos;
1402 		if (offset >= length)
1403 			break;
1404 
1405 		fPrivateData[offset] = with;
1406 		offset++;
1407 	}
1408 
1409 	return *this;
1410 }
1411 
1412 
1413 BString&
1414 BString::ReplaceSet(const char* setOfChars, const char* with)
1415 {
1416 	if (!setOfChars || !with
1417 		|| strcspn(fPrivateData, setOfChars) >= uint32(Length()))
1418 		return *this;
1419 
1420 	// delegate simple case
1421 	int32 withLen = strlen(with);
1422 	if (withLen == 1)
1423 		return ReplaceSet(setOfChars, *with);
1424 
1425 	if (_MakeWritable() != B_OK)
1426 		return *this;
1427 
1428 	int32 pos = 0;
1429 	int32 searchLen = 1;
1430 	int32 len = Length();
1431 
1432 	PosVect positions;
1433 	for (int32 offset = 0; offset < len; offset += (pos + searchLen)) {
1434 		pos = strcspn(fPrivateData + offset, setOfChars);
1435 		if (pos + offset >= len)
1436 			break;
1437 		if (!positions.Add(offset + pos))
1438 			return *this;
1439 	}
1440 
1441 	_ReplaceAtPositions(&positions, searchLen, with, withLen);
1442 	return *this;
1443 }
1444 
1445 
1446 //	#pragma mark - Unchecked char access
1447 
1448 
1449 #if __GNUC__ > 3
1450 BStringRef
1451 BString::operator[](int32 index)
1452 {
1453 	return BStringRef(*this, index);
1454 }
1455 #else
1456 char&
1457 BString::operator[](int32 index)
1458 {
1459 	if (_MakeWritable() != B_OK) {
1460 		static char invalid;
1461 		return invalid;
1462 	}
1463 
1464 	_ReferenceCount() = -1;
1465 		// mark string as unshareable
1466 
1467 	return fPrivateData[index];
1468 }
1469 #endif
1470 
1471 
1472 //	#pragma mark - Fast low-level manipulation
1473 
1474 
1475 char*
1476 BString::LockBuffer(int32 maxLength)
1477 {
1478 	int32 length = Length();
1479 	if (maxLength > length)
1480 		length = maxLength;
1481 
1482 	if (_MakeWritable(length, true) == B_OK) {
1483 		_ReferenceCount() = -1;
1484 			// mark unshareable
1485 	}
1486 	return fPrivateData;
1487 }
1488 
1489 
1490 BString&
1491 BString::UnlockBuffer(int32 length)
1492 {
1493 	if (length > 0)
1494 		length = min_clamp0(length, Length());
1495 	else
1496 		length = fPrivateData == NULL ? 0 : strlen(fPrivateData);
1497 
1498 	if (_Resize(length) != NULL) {
1499 		fPrivateData[length] = '\0';
1500 		_ReferenceCount() = 1;
1501 			// mark shareable again
1502 	}
1503 
1504 	return *this;
1505 }
1506 
1507 
1508 //	#pragma mark - Uppercase <-> Lowercase
1509 
1510 
1511 BString&
1512 BString::ToLower()
1513 {
1514 	int32 length = Length();
1515 	if (length > 0 && _MakeWritable() == B_OK) {
1516 		for (int32 count = 0; count < length; count++)
1517 			fPrivateData[count] = tolower(fPrivateData[count]);
1518 	}
1519 	return *this;
1520 }
1521 
1522 
1523 BString&
1524 BString::ToUpper()
1525 {
1526 	int32 length = Length();
1527 	if (length > 0 && _MakeWritable() == B_OK) {
1528 		for (int32 count = 0; count < length; count++)
1529 			fPrivateData[count] = toupper(fPrivateData[count]);
1530 	}
1531 	return *this;
1532 }
1533 
1534 
1535 BString&
1536 BString::Capitalize()
1537 {
1538 	int32 length = Length();
1539 
1540 	if (length > 0 && _MakeWritable() == B_OK) {
1541 		fPrivateData[0] = toupper(fPrivateData[0]);
1542 		for (int32 count = 1; count < length; count++)
1543 			fPrivateData[count] = tolower(fPrivateData[count]);
1544 	}
1545 	return *this;
1546 }
1547 
1548 
1549 BString&
1550 BString::CapitalizeEachWord()
1551 {
1552 	int32 length = Length();
1553 
1554 	if (length > 0 && _MakeWritable() == B_OK) {
1555 		int32 count = 0;
1556 		do {
1557 			// Find the first alphabetical character...
1558 			for (; count < length; count++) {
1559 				if (isalpha(fPrivateData[count])) {
1560 					// ...found! Convert it to uppercase.
1561 					fPrivateData[count] = toupper(fPrivateData[count]);
1562 					count++;
1563 					break;
1564 				}
1565 			}
1566 
1567 			// Now find the first non-alphabetical character,
1568 			// and meanwhile, turn to lowercase all the alphabetical ones
1569 			for (; count < length; count++) {
1570 				if (isalpha(fPrivateData[count]))
1571 					fPrivateData[count] = tolower(fPrivateData[count]);
1572 				else
1573 					break;
1574 			}
1575 		} while (count < length);
1576 	}
1577 	return *this;
1578 }
1579 
1580 
1581 //	#pragma mark - Escaping and De-escaping
1582 
1583 
1584 BString&
1585 BString::CharacterEscape(const char* original,
1586 						 const char* setOfCharsToEscape, char escapeWith)
1587 {
1588 	if (setOfCharsToEscape)
1589 		_DoCharacterEscape(original, setOfCharsToEscape, escapeWith);
1590 	return *this;
1591 }
1592 
1593 
1594 BString&
1595 BString::CharacterEscape(const char* setOfCharsToEscape, char escapeWith)
1596 {
1597 	if (setOfCharsToEscape && Length() > 0)
1598 		_DoCharacterEscape(fPrivateData, setOfCharsToEscape, escapeWith);
1599 	return *this;
1600 }
1601 
1602 
1603 BString&
1604 BString::CharacterDeescape(const char* original, char escapeChar)
1605 {
1606 	return _DoCharacterDeescape(original, escapeChar);
1607 }
1608 
1609 
1610 BString&
1611 BString::CharacterDeescape(char escapeChar)
1612 {
1613 	if (Length() > 0)
1614 		_DoCharacterDeescape(fPrivateData, escapeChar);
1615 	return *this;
1616 }
1617 
1618 
1619 //	#pragma mark - Trimming
1620 
1621 
1622 BString&
1623 BString::Trim()
1624 {
1625 	const char* string = String();
1626 
1627 	int32 startCount = 0;
1628 	while (isspace(string[startCount])) {
1629 		startCount++;
1630 	}
1631 
1632 	int32 endCount = 0;
1633 	while (isspace(string[Length() - endCount - 1])) {
1634 		endCount++;
1635 	}
1636 
1637 	if (startCount == 0 && endCount == 0)
1638 		return *this;
1639 
1640 	// We actually need to trim
1641 
1642 	size_t length = Length() - startCount - endCount;
1643 	if (startCount == 0) {
1644 		_MakeWritable(length, true);
1645 	} else if (_MakeWritable() == B_OK) {
1646 		memmove(fPrivateData, fPrivateData + startCount, length);
1647 		fPrivateData[length] = '\0';
1648 		_SetLength(length);
1649 	}
1650 
1651 	return *this;
1652 }
1653 
1654 
1655 //	#pragma mark - Insert
1656 
1657 
1658 BString&
1659 BString::operator<<(const char* string)
1660 {
1661 	if (string != NULL) {
1662 		int32 length = strlen(string);
1663 		if (length > 0)
1664 			_DoAppend(string, length);
1665 	}
1666 	return *this;
1667 }
1668 
1669 
1670 BString&
1671 BString::operator<<(const BString& string)
1672 {
1673 	if (string.Length() > 0)
1674 		_DoAppend(string.String(), string.Length());
1675 	return *this;
1676 }
1677 
1678 
1679 BString&
1680 BString::operator<<(char c)
1681 {
1682 	_DoAppend(&c, 1);
1683 	return *this;
1684 }
1685 
1686 
1687 BString&
1688 BString::operator<<(int i)
1689 {
1690 	char num[32];
1691 	int32 length = snprintf(num, sizeof(num), "%d", i);
1692 
1693 	_DoAppend(num, length);
1694 	return *this;
1695 }
1696 
1697 
1698 BString&
1699 BString::operator<<(unsigned int i)
1700 {
1701 	char num[32];
1702 	int32 length = snprintf(num, sizeof(num), "%u", i);
1703 
1704 	_DoAppend(num, length);
1705 	return *this;
1706 }
1707 
1708 
1709 BString&
1710 BString::operator<<(uint32 i)
1711 {
1712 	char num[32];
1713 	int32 length = snprintf(num, sizeof(num), "%lu", i);
1714 
1715 	_DoAppend(num, length);
1716 	return *this;
1717 }
1718 
1719 
1720 BString&
1721 BString::operator<<(int32 i)
1722 {
1723 	char num[32];
1724 	int32 length = snprintf(num, sizeof(num), "%ld", i);
1725 
1726 	_DoAppend(num, length);
1727 	return *this;
1728 }
1729 
1730 
1731 BString&
1732 BString::operator<<(uint64 i)
1733 {
1734 	char num[64];
1735 	int32 length = snprintf(num, sizeof(num), "%llu", i);
1736 
1737 	_DoAppend(num, length);
1738 	return *this;
1739 }
1740 
1741 
1742 BString&
1743 BString::operator<<(int64 i)
1744 {
1745 	char num[64];
1746 	int32 length = snprintf(num, sizeof(num), "%lld", i);
1747 
1748 	_DoAppend(num, length);
1749 	return *this;
1750 }
1751 
1752 
1753 BString&
1754 BString::operator<<(float f)
1755 {
1756 	char num[64];
1757 	int32 length = snprintf(num, sizeof(num), "%.2f", f);
1758 
1759 	_DoAppend(num, length);
1760 	return *this;
1761 }
1762 
1763 
1764 //	#pragma mark - Private or reserved
1765 
1766 
1767 /*!	Detaches this string from an eventually shared fPrivateData, ie. this makes
1768 	this string writable.
1769 */
1770 status_t
1771 BString::_MakeWritable()
1772 {
1773 	if (atomic_get(&_ReferenceCount()) > 1) {
1774 		// It might be shared, and this requires special treatment
1775 		char* newData = _Clone(fPrivateData, Length());
1776 		if (atomic_add(&_ReferenceCount(), -1) == 1) {
1777 			// someone else left, we were the last owner
1778 			_FreePrivateData();
1779 		}
1780 		if (newData == NULL)
1781 			return B_NO_MEMORY;
1782 
1783 		fPrivateData = newData;
1784 	}
1785 
1786 	return B_OK;
1787 }
1788 
1789 
1790 /*!	Makes this string writable, and resizes the buffer to \a length bytes (not
1791 	including the terminating null).
1792 
1793 	@param length The length of the new buffer in bytes.
1794 	@param copy If true, the current string will be copied into the new string.
1795 */
1796 status_t
1797 BString::_MakeWritable(int32 length, bool copy)
1798 {
1799 	char* newData = NULL;
1800 
1801 	if (atomic_get(&_ReferenceCount()) > 1) {
1802 		// we might share our data with someone else
1803 		if (copy)
1804 			newData = _Clone(fPrivateData, length);
1805 		else
1806 			newData = _Allocate(length);
1807 
1808 		if (newData == NULL)
1809 			return B_NO_MEMORY;
1810 
1811 		if (atomic_add(&_ReferenceCount(), -1) == 1) {
1812 			// someone else left, we were the last owner
1813 			_FreePrivateData();
1814 		}
1815 	} else {
1816 		// we don't share our data with someone else
1817 		newData = _Resize(length);
1818 
1819 		if (newData == NULL)
1820 			return B_NO_MEMORY;
1821 	}
1822 
1823 	fPrivateData = newData;
1824 	return B_OK;
1825 }
1826 
1827 
1828 /*!	Allocates a new private data buffer with the space to store \a length bytes
1829 	(not including the terminating null).
1830 */
1831 /*static*/ char*
1832 BString::_Allocate(int32 length)
1833 {
1834 	if (length < 0)
1835 		return NULL;
1836 
1837 	char* newData = (char*)malloc(length + kPrivateDataOffset + 1);
1838 	if (newData == NULL)
1839 		return NULL;
1840 
1841 	newData += kPrivateDataOffset;
1842 	newData[length] = '\0';
1843 
1844 	// initialize reference count & length
1845 	data_reference_count(newData) = 1;
1846 	data_length(newData) = length & 0x7fffffff;
1847 
1848 	return newData;
1849 }
1850 
1851 
1852 /*!	Resizes the private data buffer. You must already have a writable buffer
1853 	when you call this method.
1854 */
1855 char*
1856 BString::_Resize(int32 length)
1857 {
1858 	ASSERT(_ReferenceCount() == 1 || _ReferenceCount() == -1);
1859 
1860 	if (length == Length())
1861 		return fPrivateData;
1862 
1863 	char* data = fPrivateData ? fPrivateData - kPrivateDataOffset : NULL;
1864 	if (length < 0)
1865 		length = 0;
1866 
1867 	data = (char*)realloc(data, length + kPrivateDataOffset + 1);
1868 	if (data == NULL)
1869 		return NULL;
1870 
1871 	data += kPrivateDataOffset;
1872 
1873 	fPrivateData = data;
1874 	fPrivateData[length] = '\0';
1875 
1876 	_SetLength(length);
1877 	_ReferenceCount() = 1;
1878 
1879 	return data;
1880 }
1881 
1882 
1883 void
1884 BString::_Init(const char* src, int32 length)
1885 {
1886 	fPrivateData = _Clone(src, length);
1887 	if (fPrivateData == NULL)
1888 		fPrivateData = _Clone(NULL, 0);
1889 }
1890 
1891 
1892 char*
1893 BString::_Clone(const char* data, int32 length)
1894 {
1895 	char* newData = _Allocate(length);
1896 	if (newData == NULL)
1897 		return NULL;
1898 
1899 	if (data != NULL && length > 0) {
1900 		// "data" may not span over the whole length
1901 		strncpy(newData, data, length);
1902 	}
1903 
1904 	return newData;
1905 }
1906 
1907 
1908 char*
1909 BString::_OpenAtBy(int32 offset, int32 length)
1910 {
1911 	int32 oldLength = Length();
1912 
1913 	if (_MakeWritable() != B_OK)
1914 		return NULL;
1915 
1916 	memmove(fPrivateData + offset + length, fPrivateData + offset,
1917 		oldLength - offset);
1918 	return _Resize(oldLength + length);
1919 }
1920 
1921 
1922 char*
1923 BString::_ShrinkAtBy(int32 offset, int32 length)
1924 {
1925 	int32 oldLength = Length();
1926 	if (_MakeWritable() != B_OK)
1927 		return NULL;
1928 
1929 	memmove(fPrivateData + offset, fPrivateData + offset + length,
1930 		oldLength - offset - length);
1931 	return _Resize(oldLength - length);
1932 }
1933 
1934 
1935 void
1936 BString::_SetLength(int32 length)
1937 {
1938 	data_length(fPrivateData) = length & 0x7fffffff;
1939 }
1940 
1941 
1942 void
1943 BString::_FreePrivateData()
1944 {
1945 	if (fPrivateData != NULL) {
1946 		free(fPrivateData - kPrivateDataOffset);
1947 		fPrivateData = NULL;
1948 	}
1949 }
1950 
1951 
1952 bool
1953 BString::_DoAppend(const char* string, int32 length)
1954 {
1955 	int32 oldLength = Length();
1956 	if (_MakeWritable(oldLength + length, true) == B_OK) {
1957 		strncpy(fPrivateData + oldLength, string, length);
1958 		return true;
1959 	}
1960 	return false;
1961 }
1962 
1963 
1964 bool
1965 BString::_DoPrepend(const char* string, int32 length)
1966 {
1967 	// TODO: this could be optimized (allocate a new buffer, use memcpy())
1968 	int32 oldLength = Length();
1969 	if (_MakeWritable(oldLength + length, true) == B_OK) {
1970 		memmove(fPrivateData + length, fPrivateData, oldLength);
1971 		if (string && length)
1972 			strncpy(fPrivateData, string, length);
1973 		return true;
1974 	}
1975 	return false;
1976 }
1977 
1978 
1979 bool
1980 BString::_DoInsert(const char* string, int32 offset, int32 length)
1981 {
1982 	int32 oldLength = Length();
1983 	if (_MakeWritable(oldLength + length, true) == B_OK) {
1984 		memmove(fPrivateData + offset + length, fPrivateData + offset,
1985 			oldLength - offset);
1986 		if (string != NULL && length)
1987 			strncpy(fPrivateData + offset, string, length);
1988 		return true;
1989 	}
1990 	return false;
1991 }
1992 
1993 
1994 int32
1995 BString::_ShortFindAfter(const char* string, int32 len) const
1996 {
1997 	const char* ptr = strstr(String(), string);
1998 
1999 	if (ptr != NULL)
2000 		return ptr - String();
2001 
2002 	return B_ERROR;
2003 }
2004 
2005 
2006 int32
2007 BString::_FindAfter(const char* string, int32 offset, int32 length) const
2008 {
2009 	const char* ptr = strstr(String() + offset, string);
2010 
2011 	if (ptr != NULL)
2012 		return ptr - String();
2013 
2014 	return B_ERROR;
2015 }
2016 
2017 
2018 int32
2019 BString::_IFindAfter(const char* string, int32 offset, int32 length) const
2020 {
2021 	const char* ptr = strcasestr(String() + offset, string);
2022 
2023 	if (ptr != NULL)
2024 		return ptr - String();
2025 
2026 	return B_ERROR;
2027 }
2028 
2029 
2030 int32
2031 BString::_FindBefore(const char* string, int32 offset, int32 length) const
2032 {
2033 	if (fPrivateData != NULL) {
2034 		const char* ptr = fPrivateData + offset - length;
2035 
2036 		while (ptr >= fPrivateData) {
2037 			if (!memcmp(ptr, string, length))
2038 				return ptr - fPrivateData;
2039 			ptr--;
2040 		}
2041 	}
2042 	return B_ERROR;
2043 }
2044 
2045 
2046 int32
2047 BString::_IFindBefore(const char* string, int32 offset, int32 length) const
2048 {
2049 	if (fPrivateData != NULL) {
2050 		char* ptr1 = fPrivateData + offset - length;
2051 
2052 		while (ptr1 >= fPrivateData) {
2053 			if (!strncasecmp(ptr1, string, length))
2054 				return ptr1 - fPrivateData;
2055 			ptr1--;
2056 		}
2057 	}
2058 	return B_ERROR;
2059 }
2060 
2061 
2062 BString&
2063 BString::_DoCharacterEscape(const char* string, const char* setOfCharsToEscape,
2064 	char escapeChar)
2065 {
2066 	if (_MakeWritable(string_length(string), false) != B_OK)
2067 		return *this;
2068 
2069 	memcpy(fPrivateData, string, Length());
2070 
2071 	PosVect positions;
2072 	int32 length = Length();
2073 	int32 pos;
2074 	for (int32 offset = 0; offset < length; offset += pos + 1) {
2075 		pos = strcspn(fPrivateData + offset, setOfCharsToEscape);
2076 		if (pos < length - offset && !positions.Add(offset + pos))
2077 			return *this;
2078 	}
2079 
2080 	uint32 count = positions.CountItems();
2081 	int32 newLength = length + count;
2082 	if (!newLength) {
2083 		_Resize(0);
2084 		return *this;
2085 	}
2086 
2087 	char* newData = _Allocate(newLength);
2088 	if (newData) {
2089 		char* oldString = fPrivateData;
2090 		char* newString = newData;
2091 		int32 lastPos = 0;
2092 
2093 		for (uint32 i = 0; i < count; ++i) {
2094 			pos = positions.ItemAt(i);
2095 			length = pos - lastPos;
2096 			if (length > 0) {
2097 				memcpy(newString, oldString, length);
2098 				oldString += length;
2099 				newString += length;
2100 			}
2101 			*newString++ = escapeChar;
2102 			*newString++ = *oldString++;
2103 			lastPos = pos + 1;
2104 		}
2105 
2106 		length = Length() + 1 - lastPos;
2107 		if (length > 0)
2108 			memcpy(newString, oldString, length);
2109 
2110 		_FreePrivateData();
2111 		fPrivateData = newData;
2112 	}
2113 	return *this;
2114 }
2115 
2116 
2117 BString&
2118 BString::_DoCharacterDeescape(const char* string, char escapeChar)
2119 {
2120 	if (_MakeWritable(string_length(string), false) != B_OK)
2121 		return *this;
2122 
2123 	memcpy(fPrivateData, string, Length());
2124 	const char escape[2] = { escapeChar, '\0' };
2125 	return _DoReplace(escape, "", REPLACE_ALL, 0, KEEP_CASE);
2126 }
2127 
2128 
2129 BString&
2130 BString::_DoReplace(const char* findThis, const char* replaceWith,
2131 	int32 maxReplaceCount, int32 fromOffset, bool ignoreCase)
2132 {
2133 	if (findThis == NULL || maxReplaceCount <= 0
2134 		|| fromOffset < 0 || fromOffset >= Length())
2135 		return *this;
2136 
2137 	typedef int32 (BString::*TFindMethod)(const char*, int32, int32) const;
2138 	TFindMethod findMethod = ignoreCase
2139 		? &BString::_IFindAfter : &BString::_FindAfter;
2140 	int32 findLen = strlen(findThis);
2141 
2142 	if (!replaceWith)
2143 		replaceWith = "";
2144 
2145 	int32 replaceLen = strlen(replaceWith);
2146 	int32 lastSrcPos = fromOffset;
2147 	PosVect positions;
2148 	for (int32 srcPos = 0; maxReplaceCount > 0
2149 		&& (srcPos = (this->*findMethod)(findThis, lastSrcPos, findLen)) >= 0;
2150 			maxReplaceCount--) {
2151 		positions.Add(srcPos);
2152 		lastSrcPos = srcPos + findLen;
2153 	}
2154 	_ReplaceAtPositions(&positions, findLen, replaceWith, replaceLen);
2155 	return *this;
2156 }
2157 
2158 
2159 void
2160 BString::_ReplaceAtPositions(const PosVect* positions, int32 searchLength,
2161 	const char* with, int32 withLength)
2162 {
2163 	int32 length = Length();
2164 	uint32 count = positions->CountItems();
2165 	int32 newLength = length + count * (withLength - searchLength);
2166 	if (!newLength) {
2167 		_Resize(0);
2168 		return;
2169 	}
2170 
2171 	char* newData = _Allocate(newLength);
2172 	if (newData == NULL)
2173 		return;
2174 
2175 	char* oldString = fPrivateData;
2176 	char* newString = newData;
2177 	int32 lastPos = 0;
2178 
2179 	for (uint32 i = 0; i < count; ++i) {
2180 		int32 pos = positions->ItemAt(i);
2181 		length = pos - lastPos;
2182 		if (length > 0) {
2183 			memcpy(newString, oldString, length);
2184 			oldString += length;
2185 			newString += length;
2186 		}
2187 		memcpy(newString, with, withLength);
2188 		oldString += searchLength;
2189 		newString += withLength;
2190 		lastPos = pos + searchLength;
2191 	}
2192 
2193 	length = Length() + 1 - lastPos;
2194 	if (length > 0)
2195 		memcpy(newString, oldString, length);
2196 
2197 	_FreePrivateData();
2198 	fPrivateData = newData;
2199 }
2200 
2201 
2202 //	#pragma mark - backwards compatibility
2203 
2204 
2205 /*!	Translates to (missing const):
2206 	BString& BString::operator<<(BString& string)
2207 */
2208 extern "C" BString&
2209 __ls__7BStringR7BString(BString* self, BString& string)
2210 {
2211 	return self->operator<<(string);
2212 }
2213 
2214 
2215 //	#pragma mark - Non-member compare for sorting, etc.
2216 
2217 
2218 int
2219 Compare(const BString& string1, const BString& string2)
2220 {
2221 	return strcmp(string1.String(), string2.String());
2222 }
2223 
2224 
2225 int
2226 ICompare(const BString& string1, const BString& string2)
2227 {
2228 	return strcasecmp(string1.String(), string2.String());
2229 }
2230 
2231 
2232 int
2233 Compare(const BString* string1, const BString* string2)
2234 {
2235 	return strcmp(string1->String(), string2->String());
2236 }
2237 
2238 
2239 int
2240 ICompare(const BString* string1, const BString* string2)
2241 {
2242 	return strcasecmp(string1->String(), string2->String());
2243 }
2244