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