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