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