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