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