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