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