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