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