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