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