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