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