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