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