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