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