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