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