xref: /haiku/src/kits/support/String.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
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 <utf8_functions.h>
27 
28 
29 // define proper names for case-option of _DoReplace()
30 #define KEEP_CASE false
31 #define IGNORE_CASE true
32 
33 // define proper names for count-option of _DoReplace()
34 #define REPLACE_ALL 0x7FFFFFFF
35 
36 
37 const uint32 kPrivateDataOffset = 2 * sizeof(int32);
38 
39 const char* B_EMPTY_STRING = "";
40 
41 
42 // helper function, returns minimum of two given values (but clamps to 0):
43 static inline int32
44 min_clamp0(int32 num1, int32 num2)
45 {
46 	if (num1 < num2)
47 		return num1 > 0 ? num1 : 0;
48 
49 	return num2 > 0 ? num2 : 0;
50 }
51 
52 
53 //! Returns length of given string (but clamps to given maximum).
54 static inline int32
55 strlen_clamp(const char* str, int32 max)
56 {
57 	// this should yield 0 for max<0:
58 	int32 length = 0;
59 	while (length < max && *str++) {
60 		length++;
61 	}
62 	return length;
63 }
64 
65 
66 //! Helper function for strlen() that can handle NULL strings.
67 static inline size_t
68 string_length(const char* string)
69 {
70 	return string != NULL ? strlen(string) : 0;
71 }
72 
73 
74 //! helper function, massages given pointer into a legal c-string:
75 static inline const char*
76 safestr(const char* str)
77 {
78 	return str ? str : "";
79 }
80 
81 
82 static inline vint32&
83 data_reference_count(char* data)
84 {
85 	return *(((int32 *)data) - 2);
86 }
87 
88 
89 static inline int32&
90 data_length(char* data)
91 {
92 	return *(((int32*)data) - 1);
93 }
94 
95 
96 //	#pragma mark - PosVect
97 
98 
99 class BString::PosVect {
100 public:
101 	PosVect()
102 		:
103 		fSize(0),
104 		fBufferSize(20),
105 		fBuffer(NULL)
106 	{
107 	}
108 
109 	~PosVect()
110 	{
111 		free(fBuffer);
112 	}
113 
114 	bool Add(int32 pos)
115 	{
116 		if (fBuffer == NULL || fSize == fBufferSize) {
117 			if (fBuffer != NULL)
118 				fBufferSize *= 2;
119 
120 			int32* newBuffer = NULL;
121 			newBuffer = (int32*)realloc(fBuffer, fBufferSize * sizeof(int32));
122 			if (newBuffer == NULL)
123 				return false;
124 
125 			fBuffer = newBuffer;
126 		}
127 
128 		fBuffer[fSize++] = pos;
129 		return true;
130 	}
131 
132 	inline int32 ItemAt(int32 index) const
133 	{
134 		return fBuffer[index];
135 	}
136 
137 	inline int32 CountItems() const
138 	{
139 		return fSize;
140 	}
141 
142 private:
143 	int32	fSize;
144 	int32	fBufferSize;
145 	int32*	fBuffer;
146 };
147 
148 
149 //	#pragma mark - BStringRef
150 
151 
152 BStringRef::BStringRef(BString& string, int32 position)
153 	: fString(string), fPosition(position)
154 {
155 }
156 
157 
158 BStringRef::operator char() const
159 {
160 	return fPosition < fString.Length() ? fString.fPrivateData[fPosition] : 0;
161 }
162 
163 
164 BStringRef&
165 BStringRef::operator=(char c)
166 {
167 	fString._MakeWritable();
168 	fString.fPrivateData[fPosition] = c;
169 	return *this;
170 }
171 
172 
173 BStringRef&
174 BStringRef::operator=(const BStringRef &rc)
175 {
176 	return operator=(rc.fString.fPrivateData[rc.fPosition]);
177 }
178 
179 
180 const char*
181 BStringRef::operator&() const
182 {
183 	return &fString.fPrivateData[fPosition];
184 }
185 
186 
187 char*
188 BStringRef::operator&()
189 {
190 	if (fString._MakeWritable() != B_OK)
191 		return NULL;
192 
193 	fString._ReferenceCount() = -1;
194 		// mark as unsharable
195 	return &fString.fPrivateData[fPosition];
196 }
197 
198 
199 //	#pragma mark - BString
200 
201 
202 inline vint32&
203 BString::_ReferenceCount()
204 {
205 	return data_reference_count(fPrivateData);
206 }
207 
208 
209 inline const vint32&
210 BString::_ReferenceCount() const
211 {
212 	return data_reference_count(fPrivateData);
213 }
214 
215 
216 inline bool
217 BString::_IsShareable() const
218 {
219 	return fPrivateData != NULL && _ReferenceCount() >= 0;
220 }
221 
222 
223 BString::BString()
224 	:
225 	fPrivateData(NULL)
226 {
227 	_Init("", 0);
228 }
229 
230 
231 BString::BString(const char* string)
232 	:
233 	fPrivateData(NULL)
234 {
235 	_Init(string, strlen(safestr(string)));
236 }
237 
238 
239 BString::BString(const BString& string)
240 	:
241 	fPrivateData(NULL)
242 {
243 	// check if source is sharable - if so, share else clone
244 	if (string._IsShareable()) {
245 		fPrivateData = string.fPrivateData;
246 		atomic_add(&_ReferenceCount(), 1);
247 			// string cannot go away right now
248 	} else
249 		_Init(string.String(), string.Length());
250 }
251 
252 
253 BString::BString(const char* string, int32 maxLength)
254 	: fPrivateData(NULL)
255 {
256 	_Init(string, strlen_clamp(safestr(string), maxLength));
257 }
258 
259 
260 BString::~BString()
261 {
262 	if (!_IsShareable() || atomic_add(&_ReferenceCount(), -1) == 1)
263 		_FreePrivateData();
264 }
265 
266 
267 //	#pragma mark - Access
268 
269 
270 int32
271 BString::CountChars() const
272 {
273 	return UTF8CountChars(fPrivateData, Length());
274 }
275 
276 
277 int32
278 BString::CountBytes(int32 fromCharOffset, int32 charCount) const
279 {
280 	return UTF8CountBytes(
281 		fPrivateData + UTF8CountBytes(fPrivateData, fromCharOffset), charCount);
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 		fPrivateData[pos] = withThis;
1393 		for (pos = pos;;) {
1394 			pos = FindFirst(replaceThis, pos);
1395 			if (pos < 0)
1396 				break;
1397 			fPrivateData[pos] = withThis;
1398 		}
1399 	}
1400 	return *this;
1401 }
1402 
1403 
1404 BString&
1405 BString::Replace(char replaceThis, char withThis, int32 maxReplaceCount,
1406 	int32 fromOffset)
1407 {
1408 	fromOffset = min_clamp0(fromOffset, Length());
1409 	int32 pos = FindFirst(replaceThis, fromOffset);
1410 
1411 	if (maxReplaceCount > 0 && pos >= 0 && _MakeWritable() == B_OK) {
1412 		maxReplaceCount--;
1413 		fPrivateData[pos] = withThis;
1414 		for (pos = pos;  maxReplaceCount > 0; maxReplaceCount--) {
1415 			pos = FindFirst(replaceThis, pos);
1416 			if (pos < 0)
1417 				break;
1418 			fPrivateData[pos] = withThis;
1419 		}
1420 	}
1421 	return *this;
1422 }
1423 
1424 
1425 BString&
1426 BString::ReplaceFirst(const char* replaceThis, const char* withThis)
1427 {
1428 	if (!replaceThis || !withThis || FindFirst(replaceThis) < 0)
1429 		return *this;
1430 
1431 	if (_MakeWritable() != B_OK)
1432 		return *this;
1433 
1434 	return _DoReplace(replaceThis, withThis, 1, 0, KEEP_CASE);
1435 }
1436 
1437 
1438 BString&
1439 BString::ReplaceLast(const char* replaceThis, const char* withThis)
1440 {
1441 	if (!replaceThis || !withThis)
1442 		return *this;
1443 
1444 	int32 replaceThisLength = strlen(replaceThis);
1445 	int32 pos = _FindBefore(replaceThis, Length(), replaceThisLength);
1446 
1447 	if (pos >= 0) {
1448 		int32 withThisLength =  strlen(withThis);
1449 		int32 difference = withThisLength - replaceThisLength;
1450 
1451 		if (difference > 0) {
1452 			if (!_OpenAtBy(pos, difference))
1453 				return *this;
1454 		} else if (difference < 0) {
1455 			if (!_ShrinkAtBy(pos, -difference))
1456 				return *this;
1457 		} else {
1458 			if (_MakeWritable() != B_OK)
1459 				return *this;
1460 		}
1461 		memcpy(fPrivateData + pos, withThis, withThisLength);
1462 	}
1463 
1464 	return *this;
1465 }
1466 
1467 
1468 BString&
1469 BString::ReplaceAll(const char* replaceThis, const char* withThis,
1470 	int32 fromOffset)
1471 {
1472 	if (!replaceThis || !withThis || FindFirst(replaceThis) < 0)
1473 		return *this;
1474 
1475 	if (_MakeWritable() != B_OK)
1476 		return *this;
1477 
1478 	return _DoReplace(replaceThis, withThis, REPLACE_ALL,
1479 		min_clamp0(fromOffset, Length()), KEEP_CASE);
1480 }
1481 
1482 
1483 BString&
1484 BString::Replace(const char* replaceThis, const char* withThis,
1485 	int32 maxReplaceCount, int32 fromOffset)
1486 {
1487 	if (!replaceThis || !withThis || maxReplaceCount <= 0
1488 		|| FindFirst(replaceThis) < 0)
1489 		return *this;
1490 
1491 	if (_MakeWritable() != B_OK)
1492 		return *this;
1493 
1494 	return _DoReplace(replaceThis, withThis, maxReplaceCount,
1495 		min_clamp0(fromOffset, Length()), KEEP_CASE);
1496 }
1497 
1498 
1499 BString&
1500 BString::ReplaceAllChars(const char* replaceThis, const char* withThis,
1501 	int32 fromCharOffset)
1502 {
1503 	return ReplaceAll(replaceThis, withThis,
1504 		UTF8CountBytes(fPrivateData, fromCharOffset));
1505 }
1506 
1507 
1508 BString&
1509 BString::ReplaceChars(const char* replaceThis, const char* withThis,
1510 	int32 maxReplaceCount, int32 fromCharOffset)
1511 {
1512 	return Replace(replaceThis, withThis, maxReplaceCount,
1513 		UTF8CountBytes(fPrivateData, fromCharOffset));
1514 }
1515 
1516 
1517 BString&
1518 BString::IReplaceFirst(char replaceThis, char withThis)
1519 {
1520 	char tmp[2] = { replaceThis, '\0' };
1521 
1522 	int32 pos = _IFindAfter(tmp, 0, 1);
1523 	if (pos >= 0 && _MakeWritable() == B_OK)
1524 		fPrivateData[pos] = withThis;
1525 	return *this;
1526 }
1527 
1528 
1529 BString&
1530 BString::IReplaceLast(char replaceThis, char withThis)
1531 {
1532 	char tmp[2] = { replaceThis, '\0' };
1533 
1534 	int32 pos = _IFindBefore(tmp, Length(), 1);
1535 	if (pos >= 0 && _MakeWritable() == B_OK)
1536 		fPrivateData[pos] = withThis;
1537 	return *this;
1538 }
1539 
1540 
1541 BString&
1542 BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset)
1543 {
1544 	char tmp[2] = { replaceThis, '\0' };
1545 	fromOffset = min_clamp0(fromOffset, Length());
1546 	int32 pos = _IFindAfter(tmp, fromOffset, 1);
1547 
1548 	if (pos >= 0 && _MakeWritable() == B_OK) {
1549 		fPrivateData[pos] = withThis;
1550 		for (pos = pos;;) {
1551 			pos = _IFindAfter(tmp, pos, 1);
1552 			if (pos < 0)
1553 				break;
1554 			fPrivateData[pos] = withThis;
1555 		}
1556 	}
1557 	return *this;
1558 }
1559 
1560 
1561 BString&
1562 BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount,
1563 	int32 fromOffset)
1564 {
1565 	char tmp[2] = { replaceThis, '\0' };
1566 	fromOffset = min_clamp0(fromOffset, Length());
1567 	int32 pos = _IFindAfter(tmp, fromOffset, 1);
1568 
1569 	if (maxReplaceCount > 0 && pos >= 0 && _MakeWritable() == B_OK) {
1570 		fPrivateData[pos] = withThis;
1571 		maxReplaceCount--;
1572 		for (pos = pos;  maxReplaceCount > 0; maxReplaceCount--) {
1573 			pos = _IFindAfter(tmp, pos, 1);
1574 			if (pos < 0)
1575 				break;
1576 			fPrivateData[pos] = withThis;
1577 		}
1578 	}
1579 
1580 	return *this;
1581 }
1582 
1583 
1584 BString&
1585 BString::IReplaceFirst(const char* replaceThis, const char* withThis)
1586 {
1587 	if (!replaceThis || !withThis || IFindFirst(replaceThis) < 0)
1588 		return *this;
1589 
1590 	if (_MakeWritable() != B_OK)
1591 		return *this;
1592 	return _DoReplace(replaceThis, withThis, 1, 0, IGNORE_CASE);
1593 }
1594 
1595 
1596 BString&
1597 BString::IReplaceLast(const char* replaceThis, const char* withThis)
1598 {
1599 	if (!replaceThis || !withThis)
1600 		return *this;
1601 
1602 	int32 replaceThisLength = strlen(replaceThis);
1603 	int32 pos = _IFindBefore(replaceThis, Length(), replaceThisLength);
1604 
1605 	if (pos >= 0) {
1606 		int32 withThisLength = strlen(withThis);
1607 		int32 difference = withThisLength - replaceThisLength;
1608 
1609 		if (difference > 0) {
1610 			if (!_OpenAtBy(pos, difference))
1611 				return *this;
1612 		} else if (difference < 0) {
1613 			if (!_ShrinkAtBy(pos, -difference))
1614 				return *this;
1615 		} else {
1616 			if (_MakeWritable() != B_OK)
1617 				return *this;
1618 		}
1619 		memcpy(fPrivateData + pos, withThis, withThisLength);
1620 	}
1621 
1622 	return *this;
1623 }
1624 
1625 
1626 BString&
1627 BString::IReplaceAll(const char* replaceThis, const char* withThis,
1628 	int32 fromOffset)
1629 {
1630 	if (!replaceThis || !withThis || IFindFirst(replaceThis) < 0)
1631 		return *this;
1632 
1633 	if (_MakeWritable() != B_OK)
1634 		return *this;
1635 
1636 	return _DoReplace(replaceThis, withThis, REPLACE_ALL,
1637 		min_clamp0(fromOffset, Length()), IGNORE_CASE);
1638 }
1639 
1640 
1641 BString&
1642 BString::IReplace(const char* replaceThis, const char* withThis,
1643 	int32 maxReplaceCount, int32 fromOffset)
1644 {
1645 	if (!replaceThis || !withThis || maxReplaceCount <= 0
1646 		|| FindFirst(replaceThis) < 0)
1647 		return *this;
1648 
1649 	if (_MakeWritable() != B_OK)
1650 		return *this;
1651 
1652 	return _DoReplace(replaceThis, withThis, maxReplaceCount,
1653 		min_clamp0(fromOffset, Length()), IGNORE_CASE);
1654 }
1655 
1656 
1657 BString&
1658 BString::ReplaceSet(const char* setOfBytes, char with)
1659 {
1660 	if (!setOfBytes || strcspn(fPrivateData, setOfBytes) >= uint32(Length()))
1661 		return *this;
1662 
1663 	if (_MakeWritable() != B_OK)
1664 		return *this;
1665 
1666 	int32 offset = 0;
1667 	int32 length = Length();
1668 	for (int32 pos;;) {
1669 		pos = strcspn(fPrivateData + offset, setOfBytes);
1670 
1671 		offset += pos;
1672 		if (offset >= length)
1673 			break;
1674 
1675 		fPrivateData[offset] = with;
1676 		offset++;
1677 	}
1678 
1679 	return *this;
1680 }
1681 
1682 
1683 BString&
1684 BString::ReplaceSet(const char* setOfBytes, const char* with)
1685 {
1686 	if (!setOfBytes || !with
1687 		|| strcspn(fPrivateData, setOfBytes) >= uint32(Length()))
1688 		return *this;
1689 
1690 	// delegate simple case
1691 	int32 withLen = strlen(with);
1692 	if (withLen == 1)
1693 		return ReplaceSet(setOfBytes, *with);
1694 
1695 	if (_MakeWritable() != B_OK)
1696 		return *this;
1697 
1698 	int32 pos = 0;
1699 	int32 searchLen = 1;
1700 	int32 len = Length();
1701 
1702 	PosVect positions;
1703 	for (int32 offset = 0; offset < len; offset += (pos + searchLen)) {
1704 		pos = strcspn(fPrivateData + offset, setOfBytes);
1705 		if (pos + offset >= len)
1706 			break;
1707 		if (!positions.Add(offset + pos))
1708 			return *this;
1709 	}
1710 
1711 	_ReplaceAtPositions(&positions, searchLen, with, withLen);
1712 	return *this;
1713 }
1714 
1715 
1716 BString&
1717 BString::ReplaceCharsSet(const char* setOfChars, const char* with)
1718 {
1719 	if (!setOfChars || !with)
1720 		return *this;
1721 
1722 	int32 setCharCount = UTF8CountChars(setOfChars, -1);
1723 	if ((uint32)setCharCount == strlen(setOfChars)) {
1724 		// no multi-byte chars at all
1725 		return ReplaceSet(setOfChars, with);
1726 	}
1727 
1728 	BString setString(setOfChars);
1729 	BString result;
1730 
1731 	int32 withLength = strlen(with);
1732 	int32 charCount = CountChars();
1733 	for (int32 i = 0; i < charCount; i++) {
1734 		int32 charLength;
1735 		const char* sourceChar = CharAt(i, &charLength);
1736 		bool match = false;
1737 
1738 		for (int32 j = 0; j < setCharCount; j++) {
1739 			int32 setCharLength;
1740 			const char* setChar = setString.CharAt(j, &setCharLength);
1741 			if (charLength == setCharLength
1742 				&& memcmp(sourceChar, setChar, charLength) == 0) {
1743 				match = true;
1744 				break;
1745 			}
1746 		}
1747 
1748 		if (match)
1749 			result.Append(with, withLength);
1750 		else
1751 			result.Append(sourceChar, charLength);
1752 	}
1753 
1754 	*this = result;
1755 	return *this;
1756 }
1757 
1758 
1759 //	#pragma mark - Unchecked char access
1760 
1761 
1762 #if __GNUC__ > 3
1763 BStringRef
1764 BString::operator[](int32 index)
1765 {
1766 	return BStringRef(*this, index);
1767 }
1768 #else
1769 char&
1770 BString::operator[](int32 index)
1771 {
1772 	if (_MakeWritable() != B_OK) {
1773 		static char invalid;
1774 		return invalid;
1775 	}
1776 
1777 	_ReferenceCount() = -1;
1778 		// mark string as unshareable
1779 
1780 	return fPrivateData[index];
1781 }
1782 #endif
1783 
1784 
1785 const char*
1786 BString::CharAt(int32 charIndex, int32* bytes) const
1787 {
1788 	int32 offset = UTF8CountBytes(fPrivateData, charIndex);
1789 	if (bytes != NULL)
1790 		*bytes = UTF8NextCharLen(fPrivateData + offset);
1791 	return fPrivateData + offset;
1792 }
1793 
1794 
1795 bool
1796 BString::CharAt(int32 charIndex, char* buffer, int32* bytes) const
1797 {
1798 	int32 length;
1799 	const char* charAt = CharAt(charIndex, &length);
1800 	if (bytes != NULL) {
1801 		if (*bytes < length)
1802 			return false;
1803 		*bytes = length;
1804 	}
1805 
1806 	memcpy(buffer, charAt, length);
1807 	return true;
1808 }
1809 
1810 
1811 //	#pragma mark - Fast low-level manipulation
1812 
1813 
1814 char*
1815 BString::LockBuffer(int32 maxLength)
1816 {
1817 	int32 length = Length();
1818 	if (maxLength > length)
1819 		length = maxLength;
1820 
1821 	if (_MakeWritable(length, true) != B_OK)
1822 		return NULL;
1823 
1824 	_ReferenceCount() = -1;
1825 		// mark unshareable
1826 
1827 	return fPrivateData;
1828 }
1829 
1830 
1831 BString&
1832 BString::UnlockBuffer(int32 length)
1833 {
1834 	if (length > 0)
1835 		length = min_clamp0(length, Length());
1836 	else
1837 		length = fPrivateData == NULL ? 0 : strlen(fPrivateData);
1838 
1839 	if (_Resize(length) != NULL) {
1840 		fPrivateData[length] = '\0';
1841 		_ReferenceCount() = 1;
1842 			// mark shareable again
1843 	}
1844 
1845 	return *this;
1846 }
1847 
1848 
1849 //	#pragma mark - Uppercase <-> Lowercase
1850 
1851 
1852 BString&
1853 BString::ToLower()
1854 {
1855 	int32 length = Length();
1856 	if (length > 0 && _MakeWritable() == B_OK) {
1857 		for (int32 count = 0; count < length; count++)
1858 			fPrivateData[count] = tolower(fPrivateData[count]);
1859 	}
1860 	return *this;
1861 }
1862 
1863 
1864 BString&
1865 BString::ToUpper()
1866 {
1867 	int32 length = Length();
1868 	if (length > 0 && _MakeWritable() == B_OK) {
1869 		for (int32 count = 0; count < length; count++)
1870 			fPrivateData[count] = toupper(fPrivateData[count]);
1871 	}
1872 	return *this;
1873 }
1874 
1875 
1876 BString&
1877 BString::Capitalize()
1878 {
1879 	int32 length = Length();
1880 
1881 	if (length > 0 && _MakeWritable() == B_OK) {
1882 		fPrivateData[0] = toupper(fPrivateData[0]);
1883 		for (int32 count = 1; count < length; count++)
1884 			fPrivateData[count] = tolower(fPrivateData[count]);
1885 	}
1886 	return *this;
1887 }
1888 
1889 
1890 BString&
1891 BString::CapitalizeEachWord()
1892 {
1893 	int32 length = Length();
1894 
1895 	if (length > 0 && _MakeWritable() == B_OK) {
1896 		int32 count = 0;
1897 		do {
1898 			// Find the first alphabetical character...
1899 			for (; count < length; count++) {
1900 				if (isalpha(fPrivateData[count])) {
1901 					// ...found! Convert it to uppercase.
1902 					fPrivateData[count] = toupper(fPrivateData[count]);
1903 					count++;
1904 					break;
1905 				}
1906 			}
1907 
1908 			// Now find the first non-alphabetical character,
1909 			// and meanwhile, turn to lowercase all the alphabetical ones
1910 			for (; count < length; count++) {
1911 				if (isalpha(fPrivateData[count]))
1912 					fPrivateData[count] = tolower(fPrivateData[count]);
1913 				else
1914 					break;
1915 			}
1916 		} while (count < length);
1917 	}
1918 	return *this;
1919 }
1920 
1921 
1922 //	#pragma mark - Escaping and De-escaping
1923 
1924 
1925 BString&
1926 BString::CharacterEscape(const char* original,
1927 						 const char* setOfCharsToEscape, char escapeWith)
1928 {
1929 	if (setOfCharsToEscape)
1930 		_DoCharacterEscape(original, setOfCharsToEscape, escapeWith);
1931 	return *this;
1932 }
1933 
1934 
1935 BString&
1936 BString::CharacterEscape(const char* setOfCharsToEscape, char escapeWith)
1937 {
1938 	if (setOfCharsToEscape && Length() > 0)
1939 		_DoCharacterEscape(fPrivateData, setOfCharsToEscape, escapeWith);
1940 	return *this;
1941 }
1942 
1943 
1944 BString&
1945 BString::CharacterDeescape(const char* original, char escapeChar)
1946 {
1947 	return _DoCharacterDeescape(original, escapeChar);
1948 }
1949 
1950 
1951 BString&
1952 BString::CharacterDeescape(char escapeChar)
1953 {
1954 	if (Length() > 0)
1955 		_DoCharacterDeescape(fPrivateData, escapeChar);
1956 	return *this;
1957 }
1958 
1959 
1960 //	#pragma mark - Trimming
1961 
1962 
1963 BString&
1964 BString::Trim()
1965 {
1966 	if (Length() <= 0)
1967 		return *this;
1968 
1969 	const char* string = String();
1970 
1971 	// string is \0 terminated thus we don't need to check if we reached the end
1972 	int32 startCount = 0;
1973 	while (isspace(string[startCount]))
1974 		startCount++;
1975 
1976 	int32 endIndex = Length() - 1;
1977 	while (endIndex >= startCount && isspace(string[endIndex]))
1978 		endIndex--;
1979 
1980 	if (startCount == 0 && endIndex == Length() - 1)
1981 		return *this;
1982 
1983 	// We actually need to trim
1984 
1985 	ssize_t length = endIndex + 1 - startCount;
1986 	ASSERT(length >= 0);
1987 	if (startCount == 0 || length == 0) {
1988 		_MakeWritable(length, true);
1989 	} else if (_MakeWritable() == B_OK) {
1990 		memmove(fPrivateData, fPrivateData + startCount, length);
1991 		fPrivateData[length] = '\0';
1992 		_SetLength(length);
1993 	}
1994 
1995 	return *this;
1996 }
1997 
1998 
1999 //	#pragma mark - Insert
2000 
2001 
2002 BString&
2003 BString::operator<<(const char* string)
2004 {
2005 	if (string != NULL) {
2006 		int32 length = strlen(string);
2007 		if (length > 0)
2008 			_DoAppend(string, length);
2009 	}
2010 	return *this;
2011 }
2012 
2013 
2014 BString&
2015 BString::operator<<(const BString& string)
2016 {
2017 	if (string.Length() > 0)
2018 		_DoAppend(string.String(), string.Length());
2019 	return *this;
2020 }
2021 
2022 
2023 BString&
2024 BString::operator<<(char c)
2025 {
2026 	_DoAppend(&c, 1);
2027 	return *this;
2028 }
2029 
2030 
2031 BString&
2032 BString::operator<<(bool value)
2033 {
2034 	if (value)
2035 		_DoAppend("true", 4);
2036 	else
2037 		_DoAppend("false", 5);
2038 
2039 	return *this;
2040 }
2041 
2042 
2043 BString&
2044 BString::operator<<(int i)
2045 {
2046 	char num[32];
2047 	int32 length = snprintf(num, sizeof(num), "%d", i);
2048 
2049 	_DoAppend(num, length);
2050 	return *this;
2051 }
2052 
2053 
2054 BString&
2055 BString::operator<<(unsigned int i)
2056 {
2057 	char num[32];
2058 	int32 length = snprintf(num, sizeof(num), "%u", i);
2059 
2060 	_DoAppend(num, length);
2061 	return *this;
2062 }
2063 
2064 
2065 BString&
2066 BString::operator<<(unsigned long i)
2067 {
2068 	char num[32];
2069 	int32 length = snprintf(num, sizeof(num), "%lu", i);
2070 
2071 	_DoAppend(num, length);
2072 	return *this;
2073 }
2074 
2075 
2076 BString&
2077 BString::operator<<(long i)
2078 {
2079 	char num[32];
2080 	int32 length = snprintf(num, sizeof(num), "%ld", i);
2081 
2082 	_DoAppend(num, length);
2083 	return *this;
2084 }
2085 
2086 
2087 BString&
2088 BString::operator<<(unsigned long long i)
2089 {
2090 	char num[64];
2091 	int32 length = snprintf(num, sizeof(num), "%llu", i);
2092 
2093 	_DoAppend(num, length);
2094 	return *this;
2095 }
2096 
2097 
2098 BString&
2099 BString::operator<<(long long i)
2100 {
2101 	char num[64];
2102 	int32 length = snprintf(num, sizeof(num), "%lld", i);
2103 
2104 	_DoAppend(num, length);
2105 	return *this;
2106 }
2107 
2108 
2109 BString&
2110 BString::operator<<(float f)
2111 {
2112 	char num[64];
2113 	int32 length = snprintf(num, sizeof(num), "%.2f", f);
2114 
2115 	_DoAppend(num, length);
2116 	return *this;
2117 }
2118 
2119 
2120 BString&
2121 BString::operator<<(double value)
2122 {
2123 	char num[64];
2124 	int32 length = snprintf(num, sizeof(num), "%.2f", value);
2125 
2126 	_DoAppend(num, length);
2127 	return *this;
2128 }
2129 
2130 
2131 //	#pragma mark - Private or reserved
2132 
2133 
2134 /*!	Detaches this string from an eventually shared fPrivateData, ie. this makes
2135 	this string writable.
2136 */
2137 status_t
2138 BString::_MakeWritable()
2139 {
2140 	if (atomic_get(&_ReferenceCount()) > 1) {
2141 		// It might be shared, and this requires special treatment
2142 		char* newData = _Clone(fPrivateData, Length());
2143 		if (atomic_add(&_ReferenceCount(), -1) == 1) {
2144 			// someone else left, we were the last owner
2145 			_FreePrivateData();
2146 		}
2147 		if (newData == NULL)
2148 			return B_NO_MEMORY;
2149 
2150 		fPrivateData = newData;
2151 	}
2152 
2153 	return B_OK;
2154 }
2155 
2156 
2157 /*!	Makes this string writable, and resizes the buffer to \a length bytes (not
2158 	including the terminating null).
2159 
2160 	@param length The length of the new buffer in bytes.
2161 	@param copy If true, the current string will be copied into the new string.
2162 */
2163 status_t
2164 BString::_MakeWritable(int32 length, bool copy)
2165 {
2166 	char* newData = NULL;
2167 
2168 	if (atomic_get(&_ReferenceCount()) > 1) {
2169 		// we might share our data with someone else
2170 		if (copy)
2171 			newData = _Clone(fPrivateData, length);
2172 		else
2173 			newData = _Allocate(length);
2174 
2175 		if (newData == NULL)
2176 			return B_NO_MEMORY;
2177 
2178 		if (atomic_add(&_ReferenceCount(), -1) == 1) {
2179 			// someone else left, we were the last owner
2180 			_FreePrivateData();
2181 		}
2182 	} else {
2183 		// we don't share our data with someone else
2184 		newData = _Resize(length);
2185 
2186 		if (newData == NULL)
2187 			return B_NO_MEMORY;
2188 	}
2189 
2190 	fPrivateData = newData;
2191 	return B_OK;
2192 }
2193 
2194 
2195 /*!	Allocates a new private data buffer with the space to store \a length bytes
2196 	(not including the terminating null).
2197 */
2198 /*static*/ char*
2199 BString::_Allocate(int32 length)
2200 {
2201 	if (length < 0)
2202 		return NULL;
2203 
2204 	char* newData = (char*)malloc(length + kPrivateDataOffset + 1);
2205 	if (newData == NULL)
2206 		return NULL;
2207 
2208 	newData += kPrivateDataOffset;
2209 	newData[length] = '\0';
2210 
2211 	// initialize reference count & length
2212 	data_reference_count(newData) = 1;
2213 	data_length(newData) = length & 0x7fffffff;
2214 
2215 	return newData;
2216 }
2217 
2218 
2219 /*!	Resizes the private data buffer. You must already have a writable buffer
2220 	when you call this method.
2221 */
2222 char*
2223 BString::_Resize(int32 length)
2224 {
2225 	ASSERT(_ReferenceCount() == 1 || _ReferenceCount() == -1);
2226 
2227 	if (length == Length())
2228 		return fPrivateData;
2229 
2230 	char* data = fPrivateData ? fPrivateData - kPrivateDataOffset : NULL;
2231 	if (length < 0)
2232 		length = 0;
2233 
2234 	data = (char*)realloc(data, length + kPrivateDataOffset + 1);
2235 	if (data == NULL)
2236 		return NULL;
2237 
2238 	data += kPrivateDataOffset;
2239 
2240 	fPrivateData = data;
2241 	fPrivateData[length] = '\0';
2242 
2243 	_SetLength(length);
2244 	_ReferenceCount() = 1;
2245 
2246 	return data;
2247 }
2248 
2249 
2250 void
2251 BString::_Init(const char* src, int32 length)
2252 {
2253 	fPrivateData = _Clone(src, length);
2254 	if (fPrivateData == NULL)
2255 		fPrivateData = _Clone(NULL, 0);
2256 }
2257 
2258 
2259 char*
2260 BString::_Clone(const char* data, int32 length)
2261 {
2262 	char* newData = _Allocate(length);
2263 	if (newData == NULL)
2264 		return NULL;
2265 
2266 	if (data != NULL && length > 0) {
2267 		// "data" may not span over the whole length
2268 		strncpy(newData, data, length);
2269 	}
2270 
2271 	return newData;
2272 }
2273 
2274 
2275 char*
2276 BString::_OpenAtBy(int32 offset, int32 length)
2277 {
2278 	int32 oldLength = Length();
2279 
2280 	if (_MakeWritable() != B_OK)
2281 		return NULL;
2282 
2283 	memmove(fPrivateData + offset + length, fPrivateData + offset,
2284 		oldLength - offset);
2285 	return _Resize(oldLength + length);
2286 }
2287 
2288 
2289 char*
2290 BString::_ShrinkAtBy(int32 offset, int32 length)
2291 {
2292 	int32 oldLength = Length();
2293 	if (_MakeWritable() != B_OK)
2294 		return NULL;
2295 
2296 	memmove(fPrivateData + offset, fPrivateData + offset + length,
2297 		oldLength - offset - length);
2298 	return _Resize(oldLength - length);
2299 }
2300 
2301 
2302 void
2303 BString::_SetLength(int32 length)
2304 {
2305 	data_length(fPrivateData) = length & 0x7fffffff;
2306 }
2307 
2308 
2309 void
2310 BString::_FreePrivateData()
2311 {
2312 	if (fPrivateData != NULL) {
2313 		free(fPrivateData - kPrivateDataOffset);
2314 		fPrivateData = NULL;
2315 	}
2316 }
2317 
2318 
2319 bool
2320 BString::_DoAppend(const char* string, int32 length)
2321 {
2322 	int32 oldLength = Length();
2323 	if (_MakeWritable(oldLength + length, true) == B_OK) {
2324 		strncpy(fPrivateData + oldLength, string, length);
2325 		return true;
2326 	}
2327 	return false;
2328 }
2329 
2330 
2331 bool
2332 BString::_DoPrepend(const char* string, int32 length)
2333 {
2334 	// TODO: this could be optimized (allocate a new buffer, use memcpy())
2335 	int32 oldLength = Length();
2336 	if (_MakeWritable(oldLength + length, true) == B_OK) {
2337 		memmove(fPrivateData + length, fPrivateData, oldLength);
2338 		if (string && length)
2339 			strncpy(fPrivateData, string, length);
2340 		return true;
2341 	}
2342 	return false;
2343 }
2344 
2345 
2346 bool
2347 BString::_DoInsert(const char* string, int32 offset, int32 length)
2348 {
2349 	int32 oldLength = Length();
2350 	if (_MakeWritable(oldLength + length, true) == B_OK) {
2351 		memmove(fPrivateData + offset + length, fPrivateData + offset,
2352 			oldLength - offset);
2353 		if (string != NULL && length)
2354 			strncpy(fPrivateData + offset, string, length);
2355 		return true;
2356 	}
2357 	return false;
2358 }
2359 
2360 
2361 int32
2362 BString::_ShortFindAfter(const char* string, int32 len) const
2363 {
2364 	const char* ptr = strstr(String(), string);
2365 
2366 	if (ptr != NULL)
2367 		return ptr - String();
2368 
2369 	return B_ERROR;
2370 }
2371 
2372 
2373 int32
2374 BString::_FindAfter(const char* string, int32 offset, int32 length) const
2375 {
2376 	const char* ptr = strstr(String() + offset, string);
2377 
2378 	if (ptr != NULL)
2379 		return ptr - String();
2380 
2381 	return B_ERROR;
2382 }
2383 
2384 
2385 int32
2386 BString::_IFindAfter(const char* string, int32 offset, int32 length) const
2387 {
2388 	const char* ptr = strcasestr(String() + offset, string);
2389 
2390 	if (ptr != NULL)
2391 		return ptr - String();
2392 
2393 	return B_ERROR;
2394 }
2395 
2396 
2397 int32
2398 BString::_FindBefore(const char* string, int32 offset, int32 length) const
2399 {
2400 	if (fPrivateData != NULL) {
2401 		const char* ptr = fPrivateData + offset - length;
2402 
2403 		while (ptr >= fPrivateData) {
2404 			if (!memcmp(ptr, string, length))
2405 				return ptr - fPrivateData;
2406 			ptr--;
2407 		}
2408 	}
2409 	return B_ERROR;
2410 }
2411 
2412 
2413 int32
2414 BString::_IFindBefore(const char* string, int32 offset, int32 length) const
2415 {
2416 	if (fPrivateData != NULL) {
2417 		char* ptr1 = fPrivateData + offset - length;
2418 
2419 		while (ptr1 >= fPrivateData) {
2420 			if (!strncasecmp(ptr1, string, length))
2421 				return ptr1 - fPrivateData;
2422 			ptr1--;
2423 		}
2424 	}
2425 	return B_ERROR;
2426 }
2427 
2428 
2429 BString&
2430 BString::_DoCharacterEscape(const char* string, const char* setOfCharsToEscape,
2431 	char escapeChar)
2432 {
2433 	if (_MakeWritable(string_length(string), false) != B_OK)
2434 		return *this;
2435 
2436 	memcpy(fPrivateData, string, Length());
2437 
2438 	PosVect positions;
2439 	int32 length = Length();
2440 	int32 pos;
2441 	for (int32 offset = 0; offset < length; offset += pos + 1) {
2442 		pos = strcspn(fPrivateData + offset, setOfCharsToEscape);
2443 		if (pos < length - offset && !positions.Add(offset + pos))
2444 			return *this;
2445 	}
2446 
2447 	uint32 count = positions.CountItems();
2448 	int32 newLength = length + count;
2449 	if (!newLength) {
2450 		_Resize(0);
2451 		return *this;
2452 	}
2453 
2454 	char* newData = _Allocate(newLength);
2455 	if (newData) {
2456 		char* oldString = fPrivateData;
2457 		char* newString = newData;
2458 		int32 lastPos = 0;
2459 
2460 		for (uint32 i = 0; i < count; ++i) {
2461 			pos = positions.ItemAt(i);
2462 			length = pos - lastPos;
2463 			if (length > 0) {
2464 				memcpy(newString, oldString, length);
2465 				oldString += length;
2466 				newString += length;
2467 			}
2468 			*newString++ = escapeChar;
2469 			*newString++ = *oldString++;
2470 			lastPos = pos + 1;
2471 		}
2472 
2473 		length = Length() + 1 - lastPos;
2474 		if (length > 0)
2475 			memcpy(newString, oldString, length);
2476 
2477 		_FreePrivateData();
2478 		fPrivateData = newData;
2479 	}
2480 	return *this;
2481 }
2482 
2483 
2484 BString&
2485 BString::_DoCharacterDeescape(const char* string, char escapeChar)
2486 {
2487 	if (_MakeWritable(string_length(string), false) != B_OK)
2488 		return *this;
2489 
2490 	memcpy(fPrivateData, string, Length());
2491 	const char escape[2] = { escapeChar, '\0' };
2492 	return _DoReplace(escape, "", REPLACE_ALL, 0, KEEP_CASE);
2493 }
2494 
2495 
2496 BString&
2497 BString::_DoReplace(const char* findThis, const char* replaceWith,
2498 	int32 maxReplaceCount, int32 fromOffset, bool ignoreCase)
2499 {
2500 	if (findThis == NULL || maxReplaceCount <= 0
2501 		|| fromOffset < 0 || fromOffset >= Length())
2502 		return *this;
2503 
2504 	typedef int32 (BString::*TFindMethod)(const char*, int32, int32) const;
2505 	TFindMethod findMethod = ignoreCase
2506 		? &BString::_IFindAfter : &BString::_FindAfter;
2507 	int32 findLen = strlen(findThis);
2508 
2509 	if (!replaceWith)
2510 		replaceWith = "";
2511 
2512 	int32 replaceLen = strlen(replaceWith);
2513 	int32 lastSrcPos = fromOffset;
2514 	PosVect positions;
2515 	for (int32 srcPos = 0; maxReplaceCount > 0
2516 		&& (srcPos = (this->*findMethod)(findThis, lastSrcPos, findLen)) >= 0;
2517 			maxReplaceCount--) {
2518 		positions.Add(srcPos);
2519 		lastSrcPos = srcPos + findLen;
2520 	}
2521 	_ReplaceAtPositions(&positions, findLen, replaceWith, replaceLen);
2522 	return *this;
2523 }
2524 
2525 
2526 void
2527 BString::_ReplaceAtPositions(const PosVect* positions, int32 searchLength,
2528 	const char* with, int32 withLength)
2529 {
2530 	int32 length = Length();
2531 	uint32 count = positions->CountItems();
2532 	int32 newLength = length + count * (withLength - searchLength);
2533 	if (!newLength) {
2534 		_Resize(0);
2535 		return;
2536 	}
2537 
2538 	char* newData = _Allocate(newLength);
2539 	if (newData == NULL)
2540 		return;
2541 
2542 	char* oldString = fPrivateData;
2543 	char* newString = newData;
2544 	int32 lastPos = 0;
2545 
2546 	for (uint32 i = 0; i < count; ++i) {
2547 		int32 pos = positions->ItemAt(i);
2548 		length = pos - lastPos;
2549 		if (length > 0) {
2550 			memcpy(newString, oldString, length);
2551 			oldString += length;
2552 			newString += length;
2553 		}
2554 		memcpy(newString, with, withLength);
2555 		oldString += searchLength;
2556 		newString += withLength;
2557 		lastPos = pos + searchLength;
2558 	}
2559 
2560 	length = Length() + 1 - lastPos;
2561 	if (length > 0)
2562 		memcpy(newString, oldString, length);
2563 
2564 	_FreePrivateData();
2565 	fPrivateData = newData;
2566 }
2567 
2568 
2569 //	#pragma mark - backwards compatibility
2570 
2571 
2572 /*!	Translates to (missing const):
2573 	BString& BString::operator<<(BString& string)
2574 */
2575 extern "C" BString&
2576 __ls__7BStringR7BString(BString* self, BString& string)
2577 {
2578 	return self->operator<<(string);
2579 }
2580 
2581 
2582 //	#pragma mark - Non-member compare for sorting, etc.
2583 
2584 
2585 int
2586 Compare(const BString& string1, const BString& string2)
2587 {
2588 	return strcmp(string1.String(), string2.String());
2589 }
2590 
2591 
2592 int
2593 ICompare(const BString& string1, const BString& string2)
2594 {
2595 	return strcasecmp(string1.String(), string2.String());
2596 }
2597 
2598 
2599 int
2600 Compare(const BString* string1, const BString* string2)
2601 {
2602 	return strcmp(string1->String(), string2->String());
2603 }
2604 
2605 
2606 int
2607 ICompare(const BString* string1, const BString* string2)
2608 {
2609 	return strcasecmp(string1->String(), string2->String());
2610 }
2611