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