xref: /haiku/src/kits/support/String.cpp (revision 495060760727dd782c9f8a90db71e5d727f19748)
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 =
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 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 + separatorLength;
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 == NULL || 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 == NULL)
1562 		return *this;
1563 	if (withThis == NULL)
1564 		withThis = "";
1565 
1566 	int32 replaceThisLength = strlen(replaceThis);
1567 	int32 pos = _FindBefore(replaceThis, Length(), replaceThisLength);
1568 
1569 	if (pos >= 0) {
1570 		int32 withThisLength = strlen(withThis);
1571 		int32 difference = withThisLength - replaceThisLength;
1572 
1573 		if (difference > 0) {
1574 			if (!_OpenAtBy(pos, difference))
1575 				return *this;
1576 		} else if (difference < 0) {
1577 			if (!_ShrinkAtBy(pos, -difference))
1578 				return *this;
1579 		} else {
1580 			if (_MakeWritable() != B_OK)
1581 				return *this;
1582 		}
1583 		memcpy(fPrivateData + pos, withThis, withThisLength);
1584 	}
1585 
1586 	return *this;
1587 }
1588 
1589 
1590 BString&
1591 BString::ReplaceAll(const char* replaceThis, const char* withThis,
1592 	int32 fromOffset)
1593 {
1594 	if (replaceThis == NULL || FindFirst(replaceThis) < 0)
1595 		return *this;
1596 
1597 	if (_MakeWritable() != B_OK)
1598 		return *this;
1599 
1600 	return _DoReplace(replaceThis, withThis, REPLACE_ALL,
1601 		min_clamp0(fromOffset, Length()), KEEP_CASE);
1602 }
1603 
1604 
1605 BString&
1606 BString::Replace(const char* replaceThis, const char* withThis,
1607 	int32 maxReplaceCount, int32 fromOffset)
1608 {
1609 	if (replaceThis == NULL || maxReplaceCount <= 0
1610 		|| FindFirst(replaceThis) < 0)
1611 		return *this;
1612 
1613 	if (_MakeWritable() != B_OK)
1614 		return *this;
1615 
1616 	return _DoReplace(replaceThis, withThis, maxReplaceCount,
1617 		min_clamp0(fromOffset, Length()), KEEP_CASE);
1618 }
1619 
1620 
1621 BString&
1622 BString::ReplaceAllChars(const char* replaceThis, const char* withThis,
1623 	int32 fromCharOffset)
1624 {
1625 	return ReplaceAll(replaceThis, withThis,
1626 		UTF8CountBytes(fPrivateData, fromCharOffset));
1627 }
1628 
1629 
1630 BString&
1631 BString::ReplaceChars(const char* replaceThis, const char* withThis,
1632 	int32 maxReplaceCount, int32 fromCharOffset)
1633 {
1634 	return Replace(replaceThis, withThis, maxReplaceCount,
1635 		UTF8CountBytes(fPrivateData, fromCharOffset));
1636 }
1637 
1638 
1639 BString&
1640 BString::IReplaceFirst(char replaceThis, char withThis)
1641 {
1642 	char tmp[2] = { replaceThis, '\0' };
1643 
1644 	int32 pos = _IFindAfter(tmp, 0, 1);
1645 	if (pos >= 0 && _MakeWritable() == B_OK)
1646 		fPrivateData[pos] = withThis;
1647 	return *this;
1648 }
1649 
1650 
1651 BString&
1652 BString::IReplaceLast(char replaceThis, char withThis)
1653 {
1654 	char tmp[2] = { replaceThis, '\0' };
1655 
1656 	int32 pos = _IFindBefore(tmp, Length(), 1);
1657 	if (pos >= 0 && _MakeWritable() == B_OK)
1658 		fPrivateData[pos] = withThis;
1659 	return *this;
1660 }
1661 
1662 
1663 BString&
1664 BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset)
1665 {
1666 	char tmp[2] = { replaceThis, '\0' };
1667 	fromOffset = min_clamp0(fromOffset, Length());
1668 	int32 pos = _IFindAfter(tmp, fromOffset, 1);
1669 
1670 	if (pos >= 0 && _MakeWritable() == B_OK) {
1671 		for( ; pos >= 0; pos = _IFindAfter(tmp, pos + 1, 1))
1672 			fPrivateData[pos] = withThis;
1673 	}
1674 	return *this;
1675 }
1676 
1677 
1678 BString&
1679 BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount,
1680 	int32 fromOffset)
1681 {
1682 	char tmp[2] = { replaceThis, '\0' };
1683 	fromOffset = min_clamp0(fromOffset, Length());
1684 	int32 pos = _IFindAfter(tmp, fromOffset, 1);
1685 
1686 	if (maxReplaceCount > 0 && pos >= 0 && _MakeWritable() == B_OK) {
1687 		for( ; maxReplaceCount > 0 && pos >= 0;
1688 			pos = _IFindAfter(tmp, pos + 1, 1)) {
1689 			fPrivateData[pos] = withThis;
1690 			maxReplaceCount--;
1691 		}
1692 	}
1693 
1694 	return *this;
1695 }
1696 
1697 
1698 BString&
1699 BString::IReplaceFirst(const char* replaceThis, const char* withThis)
1700 {
1701 	if (replaceThis == NULL || IFindFirst(replaceThis) < 0)
1702 		return *this;
1703 
1704 	if (_MakeWritable() != B_OK)
1705 		return *this;
1706 	return _DoReplace(replaceThis, withThis, 1, 0, IGNORE_CASE);
1707 }
1708 
1709 
1710 BString&
1711 BString::IReplaceLast(const char* replaceThis, const char* withThis)
1712 {
1713 	if (replaceThis == NULL)
1714 		return *this;
1715 	if (withThis == NULL)
1716 		withThis = "";
1717 
1718 	int32 replaceThisLength = strlen(replaceThis);
1719 	int32 pos = _IFindBefore(replaceThis, Length(), replaceThisLength);
1720 
1721 	if (pos >= 0) {
1722 		int32 withThisLength = strlen(withThis);
1723 		int32 difference = withThisLength - replaceThisLength;
1724 
1725 		if (difference > 0) {
1726 			if (!_OpenAtBy(pos, difference))
1727 				return *this;
1728 		} else if (difference < 0) {
1729 			if (!_ShrinkAtBy(pos, -difference))
1730 				return *this;
1731 		} else {
1732 			if (_MakeWritable() != B_OK)
1733 				return *this;
1734 		}
1735 		memcpy(fPrivateData + pos, withThis, withThisLength);
1736 	}
1737 
1738 	return *this;
1739 }
1740 
1741 
1742 BString&
1743 BString::IReplaceAll(const char* replaceThis, const char* withThis,
1744 	int32 fromOffset)
1745 {
1746 	if (replaceThis == NULL || IFindFirst(replaceThis) < 0)
1747 		return *this;
1748 
1749 	if (_MakeWritable() != B_OK)
1750 		return *this;
1751 
1752 	return _DoReplace(replaceThis, withThis, REPLACE_ALL,
1753 		min_clamp0(fromOffset, Length()), IGNORE_CASE);
1754 }
1755 
1756 
1757 BString&
1758 BString::IReplace(const char* replaceThis, const char* withThis,
1759 	int32 maxReplaceCount, int32 fromOffset)
1760 {
1761 	if (replaceThis == NULL || maxReplaceCount <= 0
1762 		|| FindFirst(replaceThis) < 0)
1763 		return *this;
1764 
1765 	if (_MakeWritable() != B_OK)
1766 		return *this;
1767 
1768 	return _DoReplace(replaceThis, withThis, maxReplaceCount,
1769 		min_clamp0(fromOffset, Length()), IGNORE_CASE);
1770 }
1771 
1772 
1773 BString&
1774 BString::ReplaceSet(const char* setOfBytes, char with)
1775 {
1776 	if (!setOfBytes || strcspn(fPrivateData, setOfBytes) >= uint32(Length()))
1777 		return *this;
1778 
1779 	if (_MakeWritable() != B_OK)
1780 		return *this;
1781 
1782 	int32 offset = 0;
1783 	int32 length = Length();
1784 	for (int32 pos;;) {
1785 		pos = strcspn(fPrivateData + offset, setOfBytes);
1786 
1787 		offset += pos;
1788 		if (offset >= length)
1789 			break;
1790 
1791 		fPrivateData[offset] = with;
1792 		offset++;
1793 	}
1794 
1795 	return *this;
1796 }
1797 
1798 
1799 BString&
1800 BString::ReplaceSet(const char* setOfBytes, const char* with)
1801 {
1802 	if (!setOfBytes || !with
1803 		|| strcspn(fPrivateData, setOfBytes) >= uint32(Length()))
1804 		return *this;
1805 
1806 	// delegate simple case
1807 	int32 withLen = strlen(with);
1808 	if (withLen == 1)
1809 		return ReplaceSet(setOfBytes, *with);
1810 
1811 	if (_MakeWritable() != B_OK)
1812 		return *this;
1813 
1814 	int32 pos = 0;
1815 	int32 searchLen = 1;
1816 	int32 len = Length();
1817 
1818 	PosVect positions;
1819 	for (int32 offset = 0; offset < len; offset += (pos + searchLen)) {
1820 		pos = strcspn(fPrivateData + offset, setOfBytes);
1821 		if (pos + offset >= len)
1822 			break;
1823 		if (!positions.Add(offset + pos))
1824 			return *this;
1825 	}
1826 
1827 	_ReplaceAtPositions(&positions, searchLen, with, withLen);
1828 	return *this;
1829 }
1830 
1831 
1832 BString&
1833 BString::ReplaceCharsSet(const char* setOfChars, const char* with)
1834 {
1835 	if (!setOfChars || !with)
1836 		return *this;
1837 
1838 	int32 setCharCount = UTF8CountChars(setOfChars, -1);
1839 	if ((uint32)setCharCount == strlen(setOfChars)) {
1840 		// no multi-byte chars at all
1841 		return ReplaceSet(setOfChars, with);
1842 	}
1843 
1844 	BString setString(setOfChars);
1845 	BString result;
1846 
1847 	int32 withLength = strlen(with);
1848 	int32 charCount = CountChars();
1849 	for (int32 i = 0; i < charCount; i++) {
1850 		int32 charLength;
1851 		const char* sourceChar = CharAt(i, &charLength);
1852 		bool match = false;
1853 
1854 		for (int32 j = 0; j < setCharCount; j++) {
1855 			int32 setCharLength;
1856 			const char* setChar = setString.CharAt(j, &setCharLength);
1857 			if (charLength == setCharLength
1858 				&& memcmp(sourceChar, setChar, charLength) == 0) {
1859 				match = true;
1860 				break;
1861 			}
1862 		}
1863 
1864 		if (match)
1865 			result.Append(with, withLength);
1866 		else
1867 			result.Append(sourceChar, charLength);
1868 	}
1869 
1870 	*this = result;
1871 	return *this;
1872 }
1873 
1874 
1875 //	#pragma mark - Unchecked char access
1876 
1877 
1878 #if __GNUC__ == 2
1879 char&
1880 BString::operator[](int32 index)
1881 {
1882 	if (_MakeWritable() != B_OK) {
1883 		static char invalid;
1884 		return invalid;
1885 	}
1886 
1887 	_ReferenceCount() = -1;
1888 		// mark string as unshareable
1889 
1890 	return fPrivateData[index];
1891 }
1892 #endif
1893 
1894 
1895 const char*
1896 BString::CharAt(int32 charIndex, int32* bytes) const
1897 {
1898 	int32 offset = UTF8CountBytes(fPrivateData, charIndex);
1899 	if (bytes != NULL)
1900 		*bytes = UTF8NextCharLen(fPrivateData + offset);
1901 	return fPrivateData + offset;
1902 }
1903 
1904 
1905 bool
1906 BString::CharAt(int32 charIndex, char* buffer, int32* bytes) const
1907 {
1908 	int32 length;
1909 	const char* charAt = CharAt(charIndex, &length);
1910 	if (bytes != NULL) {
1911 		if (*bytes < length)
1912 			return false;
1913 		*bytes = length;
1914 	}
1915 
1916 	memcpy(buffer, charAt, length);
1917 	return true;
1918 }
1919 
1920 
1921 //	#pragma mark - Fast low-level manipulation
1922 
1923 
1924 char*
1925 BString::LockBuffer(int32 maxLength)
1926 {
1927 	int32 length = Length();
1928 	if (maxLength > length)
1929 		length = maxLength;
1930 
1931 	if (_MakeWritable(length, true) != B_OK)
1932 		return NULL;
1933 
1934 	_ReferenceCount() = -1;
1935 		// mark unshareable
1936 
1937 	return fPrivateData;
1938 }
1939 
1940 
1941 BString&
1942 BString::UnlockBuffer(int32 length)
1943 {
1944 	if (length > 0)
1945 		length = min_clamp0(length, Length());
1946 	else
1947 		length = fPrivateData == NULL ? 0 : strlen(fPrivateData);
1948 
1949 	if (_Resize(length) != NULL) {
1950 		fPrivateData[length] = '\0';
1951 		_ReferenceCount() = 1;
1952 			// mark shareable again
1953 	}
1954 
1955 	return *this;
1956 }
1957 
1958 
1959 BString&
1960 BString::SetByteAt(int32 pos, char to)
1961 {
1962 	if (pos < Length() && _MakeWritable() == B_OK)
1963 		fPrivateData[pos] = to;
1964 
1965 	return *this;
1966 }
1967 
1968 
1969 //	#pragma mark - Uppercase <-> Lowercase
1970 
1971 
1972 BString&
1973 BString::ToLower()
1974 {
1975 	int32 length = Length();
1976 	if (length > 0 && _MakeWritable() == B_OK) {
1977 		for (int32 count = 0; count < length; count++)
1978 			fPrivateData[count] = tolower(fPrivateData[count]);
1979 	}
1980 	return *this;
1981 }
1982 
1983 
1984 BString&
1985 BString::ToUpper()
1986 {
1987 	int32 length = Length();
1988 	if (length > 0 && _MakeWritable() == B_OK) {
1989 		for (int32 count = 0; count < length; count++)
1990 			fPrivateData[count] = toupper(fPrivateData[count]);
1991 	}
1992 	return *this;
1993 }
1994 
1995 
1996 BString&
1997 BString::Capitalize()
1998 {
1999 	int32 length = Length();
2000 
2001 	if (length > 0 && _MakeWritable() == B_OK) {
2002 		fPrivateData[0] = toupper(fPrivateData[0]);
2003 		for (int32 count = 1; count < length; count++)
2004 			fPrivateData[count] = tolower(fPrivateData[count]);
2005 	}
2006 	return *this;
2007 }
2008 
2009 
2010 BString&
2011 BString::CapitalizeEachWord()
2012 {
2013 	int32 length = Length();
2014 
2015 	if (length > 0 && _MakeWritable() == B_OK) {
2016 		int32 count = 0;
2017 		do {
2018 			// Find the first alphabetical character...
2019 			for (; count < length; count++) {
2020 				if (isalpha(fPrivateData[count])) {
2021 					// ...found! Convert it to uppercase.
2022 					fPrivateData[count] = toupper(fPrivateData[count]);
2023 					count++;
2024 					break;
2025 				}
2026 			}
2027 
2028 			// Now find the first non-alphabetical character,
2029 			// and meanwhile, turn to lowercase all the alphabetical ones
2030 			for (; count < length; count++) {
2031 				if (isalpha(fPrivateData[count]))
2032 					fPrivateData[count] = tolower(fPrivateData[count]);
2033 				else
2034 					break;
2035 			}
2036 		} while (count < length);
2037 	}
2038 	return *this;
2039 }
2040 
2041 
2042 //	#pragma mark - Escaping and De-escaping
2043 
2044 
2045 BString&
2046 BString::CharacterEscape(const char* original,
2047 						 const char* setOfCharsToEscape, char escapeWith)
2048 {
2049 	if (setOfCharsToEscape)
2050 		_DoCharacterEscape(original, setOfCharsToEscape, escapeWith);
2051 	return *this;
2052 }
2053 
2054 
2055 BString&
2056 BString::CharacterEscape(const char* setOfCharsToEscape, char escapeWith)
2057 {
2058 	if (setOfCharsToEscape && Length() > 0)
2059 		_DoCharacterEscape(fPrivateData, setOfCharsToEscape, escapeWith);
2060 	return *this;
2061 }
2062 
2063 
2064 BString&
2065 BString::CharacterDeescape(const char* original, char escapeChar)
2066 {
2067 	return _DoCharacterDeescape(original, escapeChar);
2068 }
2069 
2070 
2071 BString&
2072 BString::CharacterDeescape(char escapeChar)
2073 {
2074 	if (Length() > 0)
2075 		_DoCharacterDeescape(fPrivateData, escapeChar);
2076 	return *this;
2077 }
2078 
2079 
2080 //	#pragma mark - Trimming
2081 
2082 
2083 BString&
2084 BString::Trim()
2085 {
2086 	if (Length() <= 0)
2087 		return *this;
2088 
2089 	const char* string = String();
2090 
2091 	// string is \0 terminated thus we don't need to check if we reached the end
2092 	int32 startCount = 0;
2093 	while (isspace(string[startCount]))
2094 		startCount++;
2095 
2096 	int32 endIndex = Length() - 1;
2097 	while (endIndex >= startCount && isspace(string[endIndex]))
2098 		endIndex--;
2099 
2100 	if (startCount == 0 && endIndex == Length() - 1)
2101 		return *this;
2102 
2103 	// We actually need to trim
2104 
2105 	ssize_t length = endIndex + 1 - startCount;
2106 	ASSERT(length >= 0);
2107 	if (startCount == 0 || length == 0) {
2108 		_MakeWritable(length, true);
2109 	} else if (_MakeWritable() == B_OK) {
2110 		memmove(fPrivateData, fPrivateData + startCount, length);
2111 		fPrivateData[length] = '\0';
2112 		_SetLength(length);
2113 	}
2114 
2115 	return *this;
2116 }
2117 
2118 
2119 //	#pragma mark - Insert
2120 
2121 
2122 BString&
2123 BString::operator<<(const char* string)
2124 {
2125 	if (string != NULL) {
2126 		int32 length = strlen(string);
2127 		if (length > 0)
2128 			_DoAppend(string, length);
2129 	}
2130 	return *this;
2131 }
2132 
2133 
2134 BString&
2135 BString::operator<<(const BString& string)
2136 {
2137 	if (string.Length() > 0)
2138 		_DoAppend(string.String(), string.Length());
2139 	return *this;
2140 }
2141 
2142 
2143 BString&
2144 BString::operator<<(char c)
2145 {
2146 	_DoAppend(&c, 1);
2147 	return *this;
2148 }
2149 
2150 
2151 BString&
2152 BString::operator<<(bool value)
2153 {
2154 	if (value)
2155 		_DoAppend("true", 4);
2156 	else
2157 		_DoAppend("false", 5);
2158 
2159 	return *this;
2160 }
2161 
2162 
2163 BString&
2164 BString::operator<<(int i)
2165 {
2166 	char num[32];
2167 	int32 length = snprintf(num, sizeof(num), "%d", i);
2168 
2169 	_DoAppend(num, length);
2170 	return *this;
2171 }
2172 
2173 
2174 BString&
2175 BString::operator<<(unsigned int i)
2176 {
2177 	char num[32];
2178 	int32 length = snprintf(num, sizeof(num), "%u", i);
2179 
2180 	_DoAppend(num, length);
2181 	return *this;
2182 }
2183 
2184 
2185 BString&
2186 BString::operator<<(unsigned long i)
2187 {
2188 	char num[32];
2189 	int32 length = snprintf(num, sizeof(num), "%lu", i);
2190 
2191 	_DoAppend(num, length);
2192 	return *this;
2193 }
2194 
2195 
2196 BString&
2197 BString::operator<<(long i)
2198 {
2199 	char num[32];
2200 	int32 length = snprintf(num, sizeof(num), "%ld", i);
2201 
2202 	_DoAppend(num, length);
2203 	return *this;
2204 }
2205 
2206 
2207 BString&
2208 BString::operator<<(unsigned long long i)
2209 {
2210 	char num[64];
2211 	int32 length = snprintf(num, sizeof(num), "%llu", i);
2212 
2213 	_DoAppend(num, length);
2214 	return *this;
2215 }
2216 
2217 
2218 BString&
2219 BString::operator<<(long long i)
2220 {
2221 	char num[64];
2222 	int32 length = snprintf(num, sizeof(num), "%lld", i);
2223 
2224 	_DoAppend(num, length);
2225 	return *this;
2226 }
2227 
2228 
2229 BString&
2230 BString::operator<<(float f)
2231 {
2232 	char num[64];
2233 	int32 length = snprintf(num, sizeof(num), "%.2f", f);
2234 
2235 	_DoAppend(num, length);
2236 	return *this;
2237 }
2238 
2239 
2240 BString&
2241 BString::operator<<(double value)
2242 {
2243 	char num[64];
2244 	int32 length = snprintf(num, sizeof(num), "%.2f", value);
2245 
2246 	_DoAppend(num, length);
2247 	return *this;
2248 }
2249 
2250 
2251 //	#pragma mark - Private or reserved
2252 
2253 
2254 BString::BString(char* privateData, PrivateDataTag tag)
2255 	:
2256 	fPrivateData(privateData)
2257 {
2258 	if (fPrivateData != NULL)
2259 		atomic_add(&_ReferenceCount(), 1);
2260 }
2261 
2262 
2263 /*!	Detaches this string from an eventually shared fPrivateData, ie. this makes
2264 	this string writable.
2265 */
2266 status_t
2267 BString::_MakeWritable()
2268 {
2269 	if (atomic_get(&_ReferenceCount()) > 1) {
2270 		// It might be shared, and this requires special treatment
2271 		char* newData = _Clone(fPrivateData, Length());
2272 		if (atomic_add(&_ReferenceCount(), -1) == 1) {
2273 			// someone else left, we were the last owner
2274 			_FreePrivateData();
2275 		}
2276 		if (newData == NULL)
2277 			return B_NO_MEMORY;
2278 
2279 		fPrivateData = newData;
2280 	}
2281 
2282 	return B_OK;
2283 }
2284 
2285 
2286 /*!	Makes this string writable, and resizes the buffer to \a length bytes (not
2287 	including the terminating null).
2288 
2289 	@param length The length of the new buffer in bytes.
2290 	@param copy If true, the current string will be copied into the new string.
2291 */
2292 status_t
2293 BString::_MakeWritable(int32 length, bool copy)
2294 {
2295 	char* newData = NULL;
2296 
2297 	if (atomic_get(&_ReferenceCount()) > 1) {
2298 		// we might share our data with someone else
2299 		if (copy)
2300 			newData = _Clone(fPrivateData, length);
2301 		else
2302 			newData = _Allocate(length);
2303 
2304 		if (newData == NULL)
2305 			return B_NO_MEMORY;
2306 
2307 		if (atomic_add(&_ReferenceCount(), -1) == 1) {
2308 			// someone else left, we were the last owner
2309 			_FreePrivateData();
2310 		}
2311 	} else {
2312 		// we don't share our data with someone else
2313 		newData = _Resize(length);
2314 
2315 		if (newData == NULL)
2316 			return B_NO_MEMORY;
2317 	}
2318 
2319 	fPrivateData = newData;
2320 	return B_OK;
2321 }
2322 
2323 
2324 /*!	Allocates a new private data buffer with the space to store \a length bytes
2325 	(not including the terminating null).
2326 */
2327 /*static*/ char*
2328 BString::_Allocate(int32 length)
2329 {
2330 	if (length < 0)
2331 		return NULL;
2332 
2333 	char* newData = (char*)malloc(length + kPrivateDataOffset + 1);
2334 	if (newData == NULL)
2335 		return NULL;
2336 
2337 	newData += kPrivateDataOffset;
2338 	newData[length] = '\0';
2339 
2340 	// initialize reference count & length
2341 	Private::DataRefCount(newData) = 1;
2342 	Private::DataLength(newData) = length & 0x7fffffff;
2343 
2344 	return newData;
2345 }
2346 
2347 
2348 /*!	Resizes the private data buffer. You must already have a writable buffer
2349 	when you call this method.
2350 */
2351 char*
2352 BString::_Resize(int32 length)
2353 {
2354 	ASSERT(_ReferenceCount() == 1 || _ReferenceCount() == -1);
2355 
2356 	if (length == Length())
2357 		return fPrivateData;
2358 
2359 	char* data = fPrivateData ? fPrivateData - kPrivateDataOffset : NULL;
2360 	if (length < 0)
2361 		length = 0;
2362 
2363 	char* newData = (char*)realloc(data, length + kPrivateDataOffset + 1);
2364 	if (newData == NULL) {
2365 		free(data);
2366 		data = NULL;
2367 		return NULL;
2368 	} else {
2369 		data = newData;
2370 	}
2371 
2372 	data += kPrivateDataOffset;
2373 
2374 	fPrivateData = data;
2375 	fPrivateData[length] = '\0';
2376 
2377 	_SetLength(length);
2378 	_ReferenceCount() = 1;
2379 
2380 	return data;
2381 }
2382 
2383 
2384 void
2385 BString::_Init(const char* src, int32 length)
2386 {
2387 	fPrivateData = _Clone(src, length);
2388 	if (fPrivateData == NULL)
2389 		fPrivateData = _Clone(NULL, 0);
2390 }
2391 
2392 
2393 char*
2394 BString::_Clone(const char* data, int32 length)
2395 {
2396 	char* newData = _Allocate(length);
2397 	if (newData == NULL)
2398 		return NULL;
2399 
2400 	if (data != NULL && length > 0) {
2401 		// "data" may not span over the whole length
2402 		strncpy(newData, data, length);
2403 	}
2404 
2405 	return newData;
2406 }
2407 
2408 
2409 char*
2410 BString::_OpenAtBy(int32 offset, int32 length)
2411 {
2412 	int32 oldLength = Length();
2413 
2414 	if (_MakeWritable() != B_OK)
2415 		return NULL;
2416 
2417 	memmove(fPrivateData + offset + length, fPrivateData + offset,
2418 		oldLength - offset);
2419 	return _Resize(oldLength + length);
2420 }
2421 
2422 
2423 char*
2424 BString::_ShrinkAtBy(int32 offset, int32 length)
2425 {
2426 	int32 oldLength = Length();
2427 	if (_MakeWritable() != B_OK)
2428 		return NULL;
2429 
2430 	memmove(fPrivateData + offset, fPrivateData + offset + length,
2431 		oldLength - offset - length);
2432 	return _Resize(oldLength - length);
2433 }
2434 
2435 
2436 void
2437 BString::_SetLength(int32 length)
2438 {
2439 	Private::DataLength(fPrivateData) = length & 0x7fffffff;
2440 }
2441 
2442 
2443 void
2444 BString::_FreePrivateData()
2445 {
2446 	if (fPrivateData != NULL) {
2447 		free(fPrivateData - kPrivateDataOffset);
2448 		fPrivateData = NULL;
2449 	}
2450 }
2451 
2452 
2453 bool
2454 BString::_DoAppend(const char* string, int32 length)
2455 {
2456 	int32 oldLength = Length();
2457 	if (_MakeWritable(oldLength + length, true) == B_OK) {
2458 		strncpy(fPrivateData + oldLength, string, length);
2459 		return true;
2460 	}
2461 	return false;
2462 }
2463 
2464 
2465 bool
2466 BString::_DoPrepend(const char* string, int32 length)
2467 {
2468 	// TODO: this could be optimized (allocate a new buffer, use memcpy())
2469 	int32 oldLength = Length();
2470 	if (_MakeWritable(oldLength + length, true) == B_OK) {
2471 		memmove(fPrivateData + length, fPrivateData, oldLength);
2472 		if (string && length)
2473 			strncpy(fPrivateData, string, length);
2474 		return true;
2475 	}
2476 	return false;
2477 }
2478 
2479 
2480 bool
2481 BString::_DoInsert(const char* string, int32 offset, int32 length)
2482 {
2483 	int32 oldLength = Length();
2484 	if (_MakeWritable(oldLength + length, true) == B_OK) {
2485 		memmove(fPrivateData + offset + length, fPrivateData + offset,
2486 			oldLength - offset);
2487 		if (string != NULL && length)
2488 			strncpy(fPrivateData + offset, string, length);
2489 		return true;
2490 	}
2491 	return false;
2492 }
2493 
2494 
2495 int32
2496 BString::_ShortFindAfter(const char* string, int32 len) const
2497 {
2498 	const char* ptr = strstr(String(), string);
2499 
2500 	if (ptr != NULL)
2501 		return ptr - String();
2502 
2503 	return B_ERROR;
2504 }
2505 
2506 
2507 int32
2508 BString::_FindAfter(const char* string, int32 offset, int32 length) const
2509 {
2510 	const char* ptr = strstr(String() + offset, string);
2511 
2512 	if (ptr != NULL)
2513 		return ptr - String();
2514 
2515 	return B_ERROR;
2516 }
2517 
2518 
2519 int32
2520 BString::_IFindAfter(const char* string, int32 offset, int32 length) const
2521 {
2522 	const char* ptr = strcasestr(String() + offset, string);
2523 
2524 	if (ptr != NULL)
2525 		return ptr - String();
2526 
2527 	return B_ERROR;
2528 }
2529 
2530 
2531 int32
2532 BString::_FindBefore(const char* string, int32 offset, int32 length) const
2533 {
2534 	if (fPrivateData != NULL) {
2535 		const char* ptr = fPrivateData + offset - length;
2536 
2537 		while (ptr >= fPrivateData) {
2538 			if (!memcmp(ptr, string, length))
2539 				return ptr - fPrivateData;
2540 			ptr--;
2541 		}
2542 	}
2543 	return B_ERROR;
2544 }
2545 
2546 
2547 int32
2548 BString::_IFindBefore(const char* string, int32 offset, int32 length) const
2549 {
2550 	if (fPrivateData != NULL) {
2551 		char* ptr1 = fPrivateData + offset - length;
2552 
2553 		while (ptr1 >= fPrivateData) {
2554 			if (!strncasecmp(ptr1, string, length))
2555 				return ptr1 - fPrivateData;
2556 			ptr1--;
2557 		}
2558 	}
2559 	return B_ERROR;
2560 }
2561 
2562 
2563 BString&
2564 BString::_DoCharacterEscape(const char* string, const char* setOfCharsToEscape,
2565 	char escapeChar)
2566 {
2567 	if (_MakeWritable(string_length(string), false) != B_OK)
2568 		return *this;
2569 
2570 	memcpy(fPrivateData, string, Length());
2571 
2572 	PosVect positions;
2573 	int32 length = Length();
2574 	int32 pos;
2575 	for (int32 offset = 0; offset < length; offset += pos + 1) {
2576 		pos = strcspn(fPrivateData + offset, setOfCharsToEscape);
2577 		if (pos < length - offset && !positions.Add(offset + pos))
2578 			return *this;
2579 	}
2580 
2581 	uint32 count = positions.CountItems();
2582 	int32 newLength = length + count;
2583 	if (!newLength) {
2584 		_Resize(0);
2585 		return *this;
2586 	}
2587 
2588 	char* newData = _Allocate(newLength);
2589 	if (newData) {
2590 		char* oldString = fPrivateData;
2591 		char* newString = newData;
2592 		int32 lastPos = 0;
2593 
2594 		for (uint32 i = 0; i < count; ++i) {
2595 			pos = positions.ItemAt(i);
2596 			length = pos - lastPos;
2597 			if (length > 0) {
2598 				memcpy(newString, oldString, length);
2599 				oldString += length;
2600 				newString += length;
2601 			}
2602 			*newString++ = escapeChar;
2603 			*newString++ = *oldString++;
2604 			lastPos = pos + 1;
2605 		}
2606 
2607 		length = Length() + 1 - lastPos;
2608 		if (length > 0)
2609 			memcpy(newString, oldString, length);
2610 
2611 		_FreePrivateData();
2612 		fPrivateData = newData;
2613 	}
2614 	return *this;
2615 }
2616 
2617 
2618 BString&
2619 BString::_DoCharacterDeescape(const char* string, char escapeChar)
2620 {
2621 	if (_MakeWritable(string_length(string), false) != B_OK)
2622 		return *this;
2623 
2624 	memcpy(fPrivateData, string, Length());
2625 	const char escape[2] = { escapeChar, '\0' };
2626 	return _DoReplace(escape, "", REPLACE_ALL, 0, KEEP_CASE);
2627 }
2628 
2629 
2630 BString&
2631 BString::_DoReplace(const char* findThis, const char* replaceWith,
2632 	int32 maxReplaceCount, int32 fromOffset, bool ignoreCase)
2633 {
2634 	if (findThis == NULL || maxReplaceCount <= 0
2635 		|| fromOffset < 0 || fromOffset >= Length())
2636 		return *this;
2637 
2638 	int32 findLen = strlen(findThis);
2639 	if (findLen == 0)
2640 		return *this;
2641 
2642 	typedef int32 (BString::*TFindMethod)(const char*, int32, int32) const;
2643 	TFindMethod findMethod = ignoreCase
2644 		? &BString::_IFindAfter : &BString::_FindAfter;
2645 
2646 	if (replaceWith == NULL)
2647 		replaceWith = "";
2648 
2649 	int32 replaceLen = strlen(replaceWith);
2650 	int32 lastSrcPos = fromOffset;
2651 	PosVect positions;
2652 	for (int32 srcPos = 0; maxReplaceCount > 0
2653 		&& (srcPos = (this->*findMethod)(findThis, lastSrcPos, findLen)) >= 0;
2654 			maxReplaceCount--) {
2655 		positions.Add(srcPos);
2656 		lastSrcPos = srcPos + findLen;
2657 	}
2658 	_ReplaceAtPositions(&positions, findLen, replaceWith, replaceLen);
2659 	return *this;
2660 }
2661 
2662 
2663 void
2664 BString::_ReplaceAtPositions(const PosVect* positions, int32 searchLength,
2665 	const char* with, int32 withLength)
2666 {
2667 	int32 length = Length();
2668 	uint32 count = positions->CountItems();
2669 	int32 newLength = length + count * (withLength - searchLength);
2670 	if (!newLength) {
2671 		_Resize(0);
2672 		return;
2673 	}
2674 
2675 	char* newData = _Allocate(newLength);
2676 	if (newData == NULL)
2677 		return;
2678 
2679 	char* oldString = fPrivateData;
2680 	char* newString = newData;
2681 	int32 lastPos = 0;
2682 
2683 	for (uint32 i = 0; i < count; ++i) {
2684 		int32 pos = positions->ItemAt(i);
2685 		length = pos - lastPos;
2686 		if (length > 0) {
2687 			memcpy(newString, oldString, length);
2688 			oldString += length;
2689 			newString += length;
2690 		}
2691 		memcpy(newString, with, withLength);
2692 		oldString += searchLength;
2693 		newString += withLength;
2694 		lastPos = pos + searchLength;
2695 	}
2696 
2697 	length = Length() + 1 - lastPos;
2698 	if (length > 0)
2699 		memcpy(newString, oldString, length);
2700 
2701 	_FreePrivateData();
2702 	fPrivateData = newData;
2703 }
2704 
2705 
2706 //	#pragma mark - backwards compatibility
2707 
2708 
2709 /*!	Translates to (missing const):
2710 	BString& BString::operator<<(BString& string)
2711 */
2712 extern "C" BString&
2713 __ls__7BStringR7BString(BString* self, BString& string)
2714 {
2715 	return self->operator<<(string);
2716 }
2717 
2718 
2719 #if __GNUC__ > 3
2720 
2721 //	#pragma mark - BStringRef backwards compatibility
2722 
2723 
2724 class BStringRef {
2725 public:
2726 	BStringRef(BString& string, int32 position);
2727 	~BStringRef() {}
2728 
2729 	operator char() const;
2730 
2731 	char* operator&();
2732 	const char* operator&() const;
2733 
2734 	BStringRef& operator=(char c);
2735 	BStringRef& operator=(const BStringRef& rc);
2736 
2737 private:
2738 	BString&	fString;
2739 	int32		fPosition;
2740 };
2741 
2742 
2743 BStringRef::BStringRef(BString& string, int32 position)
2744 	:
2745 	fString(string), fPosition(position)
2746 {
2747 }
2748 
2749 
2750 BStringRef::operator char() const
2751 {
2752 	return fPosition < fString.Length() ? fString.fPrivateData[fPosition] : 0;
2753 }
2754 
2755 
2756 BStringRef&
2757 BStringRef::operator=(char c)
2758 {
2759 	fString._MakeWritable();
2760 	fString.fPrivateData[fPosition] = c;
2761 	return *this;
2762 }
2763 
2764 
2765 BStringRef&
2766 BStringRef::operator=(const BStringRef &rc)
2767 {
2768 	return operator=(rc.fString.fPrivateData[rc.fPosition]);
2769 }
2770 
2771 
2772 const char*
2773 BStringRef::operator&() const
2774 {
2775 	return &fString.fPrivateData[fPosition];
2776 }
2777 
2778 
2779 char*
2780 BStringRef::operator&()
2781 {
2782 	if (fString._MakeWritable() != B_OK)
2783 		return NULL;
2784 
2785 	fString._ReferenceCount() = -1;
2786 		// mark as unsharable
2787 	return &fString.fPrivateData[fPosition];
2788 }
2789 
2790 
2791 
2792 extern "C" BStringRef
2793 _ZN7BStringixEi(BString* self, int32 index)
2794 
2795 {
2796 	return BStringRef(*self, index);
2797 }
2798 #endif
2799 
2800 
2801 //	#pragma mark - Non-member compare for sorting, etc.
2802 
2803 
2804 int
2805 Compare(const BString& string1, const BString& string2)
2806 {
2807 	return strcmp(string1.String(), string2.String());
2808 }
2809 
2810 
2811 int
2812 ICompare(const BString& string1, const BString& string2)
2813 {
2814 	return strcasecmp(string1.String(), string2.String());
2815 }
2816 
2817 
2818 int
2819 Compare(const BString* string1, const BString* string2)
2820 {
2821 	return strcmp(string1->String(), string2->String());
2822 }
2823 
2824 
2825 int
2826 ICompare(const BString* string1, const BString* string2)
2827 {
2828 	return strcasecmp(string1->String(), string2->String());
2829 }
2830