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