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