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