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