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