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