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