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