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