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