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