1 /* 2 * Copyright 2001-2007, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marc Flerackers (mflerackers@androme.be) 7 * Stefano Ceccherini (burton666@libero.it) 8 * Oliver Tappe (openbeos@hirschkaefer.de) 9 * Axel Dörfler, axeld@pinc-software.de 10 */ 11 12 /* String class supporting common string operations. */ 13 14 15 #include <Debug.h> 16 #include <String.h> 17 18 #include <ctype.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 22 23 // Set this to 1 to make some private methods inline 24 #define ENABLE_INLINES 0 25 26 // define proper names for case-option of _DoReplace() 27 #define KEEP_CASE false 28 #define IGNORE_CASE true 29 30 // define proper names for count-option of _DoReplace() 31 #define REPLACE_ALL 0x7FFFFFFF 32 33 34 // helper macro that is used to fall into debugger if a given param check fails: 35 #ifdef DEBUG 36 #define CHECK_PARAM( expr, msg) \ 37 if (!(expr)) \ 38 debugger( msg) 39 40 #define CHECK_PARAM_RET( expr, msg, retval) \ 41 if (!(expr)) \ 42 debugger( msg) 43 44 #define CHECK_PARAM_VOID( expr, msg) \ 45 if (!(expr)) \ 46 debugger( msg) 47 #else 48 #define CHECK_PARAM( expr, msg) \ 49 if (!(expr)) \ 50 return *this 51 52 #define CHECK_PARAM_RET( expr, msg, retval) \ 53 if (!(expr)) \ 54 return (retval); 55 56 #define CHECK_PARAM_VOID( expr, msg) 57 #endif 58 59 60 //! helper class for BString::_ReplaceAtPositions(): 61 class BString::PosVect { 62 public: 63 PosVect(); 64 ~PosVect(); 65 66 bool Add(int32 pos); 67 68 inline int32 ItemAt(int32 index) const 69 { return fBuffer[index]; } 70 inline int32 CountItems() const 71 { return fSize; } 72 73 private: 74 int32 fSize; 75 int32 fBufferSize; 76 int32* fBuffer; 77 }; 78 79 80 const char *B_EMPTY_STRING = ""; 81 82 83 // helper function, returns minimum of two given values (but clamps to 0): 84 static inline int32 85 min_clamp0(int32 num1, int32 num2) 86 { 87 if (num1 < num2) 88 return num1 > 0 ? num1 : 0; 89 90 return num2 > 0 ? num2 : 0; 91 } 92 93 94 //! helper function, returns length of given string (but clamps to given maximum): 95 static inline int32 96 strlen_clamp(const char* str, int32 max) 97 { 98 // this should yield 0 for max<0: 99 int32 length = 0; 100 while (length < max && *str++) { 101 length++; 102 } 103 return length; 104 } 105 106 107 //! helper function, massages given pointer into a legal c-string: 108 static inline const char * 109 safestr(const char* str) 110 { 111 return str ? str : ""; 112 } 113 114 115 // #pragma mark - 116 117 118 BString::PosVect::PosVect() 119 : 120 fSize(0), 121 fBufferSize(20), 122 fBuffer(NULL) 123 { 124 } 125 126 127 BString::PosVect::~PosVect() 128 { 129 free(fBuffer); 130 } 131 132 133 bool 134 BString::PosVect::Add(int32 pos) 135 { 136 if (fBuffer == NULL || fSize == fBufferSize) { 137 if (fBuffer != NULL) 138 fBufferSize *= 2; 139 140 int32* newBuffer = (int32 *)realloc(fBuffer, fBufferSize * sizeof(int32)); 141 if (newBuffer == NULL) 142 return false; 143 144 fBuffer = newBuffer; 145 } 146 147 fBuffer[fSize++] = pos; 148 return true; 149 } 150 151 152 // #pragma mark - BString 153 154 155 BString::BString() 156 : fPrivateData(NULL) 157 { 158 } 159 160 161 BString::BString(const char* string) 162 : fPrivateData(NULL) 163 { 164 if (string != NULL) 165 _Init(string, strlen(string)); 166 } 167 168 169 BString::BString(const BString &string) 170 : fPrivateData(NULL) 171 { 172 _Init(string.String(), string.Length()); 173 } 174 175 176 BString::BString(const char *string, int32 maxLength) 177 : fPrivateData(NULL) 178 { 179 if (string != NULL) 180 _Init(string, strlen_clamp(string, maxLength)); 181 } 182 183 184 BString::~BString() 185 { 186 if (fPrivateData) 187 free(fPrivateData - sizeof(int32)); 188 } 189 190 191 // #pragma mark - Access 192 193 194 int32 195 BString::CountChars() const 196 { 197 int32 count = 0; 198 199 const char *start = fPrivateData; 200 const char *end = fPrivateData + Length(); 201 202 while (start++ != end) { 203 count++; 204 205 // Jump to next UTF8 character 206 for (; (*start & 0xc0) == 0x80; start++); 207 } 208 209 return count; 210 } 211 212 213 // #pragma mark - Assignment 214 215 216 BString& 217 BString::operator=(const BString &string) 218 { 219 if (&string != this) // Avoid auto-assignment 220 _DoAssign(string.String(), string.Length()); 221 return *this; 222 } 223 224 225 BString& 226 BString::operator=(const char *str) 227 { 228 if (str != NULL) 229 _DoAssign(str, strlen(str)); 230 else 231 _Alloc(0); 232 233 return *this; 234 } 235 236 237 BString& 238 BString::operator=(char c) 239 { 240 _DoAssign(&c, 1); 241 return *this; 242 } 243 244 245 BString& 246 BString::SetTo(const char *str, int32 maxLength) 247 { 248 if (str != NULL) 249 _DoAssign(str, strlen_clamp(str, maxLength)); 250 else 251 _Alloc(0); 252 253 return *this; 254 } 255 256 257 BString& 258 BString::SetTo(const BString &from) 259 { 260 if (&from != this) { 261 // Avoid auto-assignment 262 _DoAssign(from.String(), from.Length()); 263 } 264 return *this; 265 } 266 267 268 BString& 269 BString::Adopt(BString &from) 270 { 271 if (&from == this) { 272 // Avoid auto-adoption 273 return *this; 274 } 275 276 if (fPrivateData) 277 free(fPrivateData - sizeof(int32)); 278 279 /* "steal" the data from the given BString */ 280 fPrivateData = from.fPrivateData; 281 from.fPrivateData = NULL; 282 283 return *this; 284 } 285 286 287 BString& 288 BString::SetTo(const BString &string, int32 length) 289 { 290 if (&string != this) // Avoid auto-assignment 291 _DoAssign(string.String(), min_clamp0(length, string.Length())); 292 return *this; 293 } 294 295 296 BString& 297 BString::Adopt(BString &from, int32 length) 298 { 299 if (&from == this) // Avoid auto-adoption 300 return *this; 301 302 int32 len = min_clamp0(length, from.Length()); 303 304 if (fPrivateData) 305 free(fPrivateData - sizeof(int32)); 306 307 /* "steal" the data from the given BString */ 308 fPrivateData = from.fPrivateData; 309 from.fPrivateData = NULL; 310 311 if (len < Length()) 312 _Alloc(len); 313 314 return *this; 315 } 316 317 318 BString& 319 BString::SetTo(char c, int32 count) 320 { 321 if (count < 0) 322 count = 0; 323 int32 curLen = Length(); 324 325 if (curLen == count || _GrowBy(count - curLen)) 326 memset(fPrivateData, c, count); 327 return *this; 328 } 329 330 331 // #pragma mark - Substring copying 332 333 334 BString & 335 BString::CopyInto(BString &into, int32 fromOffset, int32 length) const 336 { 337 if (&into != this) { 338 CHECK_PARAM_RET(fromOffset >= 0, "'fromOffset' must not be negative!", 339 into); 340 CHECK_PARAM_RET(fromOffset <= Length(), "'fromOffset' exceeds length!", 341 into); 342 into.SetTo(String() + fromOffset, length); 343 } 344 return into; 345 } 346 347 348 void 349 BString::CopyInto(char *into, int32 fromOffset, int32 length) const 350 { 351 if (into != NULL) { 352 CHECK_PARAM_VOID(fromOffset >= 0, "'fromOffset' must not be negative!"); 353 CHECK_PARAM_VOID(fromOffset <= Length(), "'fromOffset' exceeds length!"); 354 int32 len = min_clamp0(length, Length() - fromOffset); 355 memcpy(into, fPrivateData + fromOffset, len); 356 } 357 } 358 359 360 // #pragma mark - Appending 361 362 363 BString& 364 BString::operator+=(const char *str) 365 { 366 if (str != NULL) 367 _DoAppend(str, strlen(str)); 368 return *this; 369 } 370 371 372 BString& 373 BString::operator+=(char c) 374 { 375 _DoAppend(&c, 1); 376 return *this; 377 } 378 379 380 BString& 381 BString::Append(const BString &string, int32 length) 382 { 383 _DoAppend(string.String(), min_clamp0(length, string.Length())); 384 return *this; 385 } 386 387 388 BString& 389 BString::Append(const char *str, int32 length) 390 { 391 if (str != NULL) { 392 int32 len = strlen_clamp(str, length); 393 _DoAppend(str, len); 394 } 395 return *this; 396 } 397 398 399 BString& 400 BString::Append(char c, int32 count) 401 { 402 int32 len = Length(); 403 if (count > 0 && _GrowBy(count)) 404 memset(fPrivateData + len, c, count); 405 406 return *this; 407 } 408 409 410 // #pragma mark - Prepending 411 412 413 BString& 414 BString::Prepend(const char *str) 415 { 416 if (str != NULL) 417 _DoPrepend(str, strlen(str)); 418 return *this; 419 } 420 421 422 // Prepend 423 BString& 424 BString::Prepend(const BString &string) 425 { 426 if (&string != this) 427 _DoPrepend(string.String(), string.Length()); 428 return *this; 429 } 430 431 432 // Prepend 433 BString& 434 BString::Prepend(const char *str, int32 length) 435 { 436 if (str != NULL) { 437 int32 len = strlen_clamp(str, length); 438 _DoPrepend(str, len); 439 } 440 return *this; 441 } 442 443 444 // Prepend 445 BString& 446 BString::Prepend(const BString &string, int32 len) 447 { 448 if (&string != this) 449 _DoPrepend(string.String(), min_clamp0(len, string.Length())); 450 return *this; 451 } 452 453 454 // Prepend 455 BString& 456 BString::Prepend(char c, int32 count) 457 { 458 if (count > 0 && _OpenAtBy(0, count)) 459 memset(fPrivateData, c, count); 460 461 return *this; 462 } 463 464 465 // #pragma mark - Inserting 466 467 468 BString& 469 BString::Insert(const char *str, int32 pos) 470 { 471 if (str != NULL) { 472 CHECK_PARAM(pos <= Length(), "'pos' exceeds length!"); 473 int32 len = (int32)strlen(str); 474 if (pos < 0) { 475 int32 skipLen = min_clamp0(-1 * pos, len); 476 str += skipLen; 477 len -= skipLen; 478 pos = 0; 479 } else 480 pos = min_clamp0(pos, Length()); 481 if (_OpenAtBy(pos, len)) 482 memcpy(fPrivateData + pos, str, len); 483 } 484 return *this; 485 } 486 487 488 // Insert 489 BString& 490 BString::Insert(const char *str, int32 length, int32 pos) 491 { 492 if (str != NULL) { 493 CHECK_PARAM(pos <= Length(), "'pos' exceeds length!"); 494 int32 len = strlen_clamp(str, length); 495 if (pos < 0) { 496 int32 skipLen = min_clamp0(-1 * pos, len); 497 str += skipLen; 498 len -= skipLen; 499 pos = 0; 500 } else 501 pos = min_clamp0(pos, Length()); 502 if (_OpenAtBy(pos, len)) 503 memcpy(fPrivateData + pos, str, len); 504 } 505 return *this; 506 } 507 508 509 // Insert 510 BString& 511 BString::Insert(const char *str, int32 fromOffset, int32 length, int32 pos) 512 { 513 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 514 return Insert(str + fromOffset, length, pos); 515 } 516 517 518 // Insert 519 BString& 520 BString::Insert(const BString &string, int32 pos) 521 { 522 if (&string != this) 523 Insert(string.String(), pos); //TODO: Optimize 524 return *this; 525 } 526 527 528 // Insert 529 BString& 530 BString::Insert(const BString &string, int32 length, int32 pos) 531 { 532 if (&string != this) 533 Insert(string.String(), length, pos); //TODO: Optimize 534 return *this; 535 } 536 537 538 // Insert 539 BString& 540 BString::Insert(const BString &string, int32 fromOffset, int32 length, int32 pos) 541 { 542 if (&string != this) { 543 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 544 Insert(string.String() + fromOffset, length, pos); 545 } 546 return *this; 547 } 548 549 550 // Insert 551 BString& 552 BString::Insert(char c, int32 count, int32 pos) 553 { 554 CHECK_PARAM(pos <= Length(), "'pos' exceeds length!"); 555 if (pos < 0) { 556 count = max_c(count + pos, 0); 557 pos = 0; 558 } else 559 pos = min_clamp0(pos, Length()); 560 561 if (count > 0 && _OpenAtBy(pos, count)) 562 memset(fPrivateData + pos, c, count); 563 564 return *this; 565 } 566 567 568 // #pragma mark - Removing 569 570 571 BString& 572 BString::Truncate(int32 newLength, bool lazy) 573 { 574 if (newLength < 0) 575 newLength = 0; 576 577 int32 curLen = Length(); 578 579 if (newLength < curLen) { 580 if (lazy) { 581 // don't free memory yet, just set new length 582 _SetLength(newLength); 583 fPrivateData[newLength] = '\0'; 584 } else 585 _Alloc(newLength); 586 } 587 588 return *this; 589 } 590 591 592 // Remove 593 BString& 594 BString::Remove(int32 from, int32 length) 595 { 596 int32 len = Length(); 597 if (from < 0) { 598 int32 skipLen = min_clamp0(from, len); 599 len -= skipLen; 600 from = 0; 601 } else 602 from = min_clamp0(from, len); 603 _ShrinkAtBy(from, min_clamp0(length, len - from)); 604 return *this; 605 } 606 607 608 // Remove 609 BString& 610 BString::RemoveFirst(const BString &string) 611 { 612 if (string.Length() > 0) { 613 int32 pos = _ShortFindAfter(string.String(), string.Length()); 614 if (pos >= 0) 615 _ShrinkAtBy(pos, string.Length()); 616 } 617 return *this; 618 } 619 620 621 // Remove 622 BString& 623 BString::RemoveLast(const BString &string) 624 { 625 int32 pos = _FindBefore(string.String(), Length(), string.Length()); 626 if (pos >= 0) 627 _ShrinkAtBy(pos, string.Length()); 628 629 return *this; 630 } 631 632 633 // Remove 634 BString& 635 BString::RemoveAll(const BString &string) 636 { 637 return _DoReplace(string.String(), "", REPLACE_ALL, 0, KEEP_CASE); 638 } 639 640 641 // Remove 642 BString& 643 BString::RemoveFirst(const char *string) 644 { 645 int32 length = string ? strlen(string) : 0; 646 if (length > 0) { 647 int32 pos = _ShortFindAfter(string, length); 648 if (pos >= 0) 649 _ShrinkAtBy(pos, length); 650 } 651 return *this; 652 } 653 654 655 // Remove 656 BString& 657 BString::RemoveLast(const char *string) 658 { 659 int32 length = string ? strlen(string) : 0; 660 if (length > 0) { 661 int32 pos = _FindBefore(string, Length(), length); 662 if (pos >= 0) 663 _ShrinkAtBy(pos, length); 664 } 665 return *this; 666 } 667 668 669 // Remove 670 BString& 671 BString::RemoveAll(const char *str) 672 { 673 return _DoReplace(str, "", REPLACE_ALL, 0, KEEP_CASE); 674 } 675 676 677 // Remove 678 BString& 679 BString::RemoveSet(const char *setOfCharsToRemove) 680 { 681 return ReplaceSet(setOfCharsToRemove, ""); 682 } 683 684 685 // MoveInto 686 BString& 687 BString::MoveInto(BString &into, int32 from, int32 length) 688 { 689 CHECK_PARAM_RET(from >= 0, "'from' must not be negative!", into); 690 CHECK_PARAM_RET(from <= Length(), "'from' exceeds length!", into); 691 int32 len = min_clamp0(length, Length() - from); 692 if (&into == this) { 693 /* TODO: [zooey]: to be activated later (>R1): 694 // strings are identical, just move the data: 695 if (from>0 && fPrivateData) 696 memmove( fPrivateData, fPrivateData+from, len); 697 Truncate( len); 698 */ 699 return *this; 700 } 701 into.SetTo(String() + from, len); 702 _ShrinkAtBy(from, len); 703 704 return into; 705 } 706 707 708 // MoveInto 709 void 710 BString::MoveInto(char *into, int32 from, int32 length) 711 { 712 if (into != NULL) { 713 CHECK_PARAM_VOID(from >= 0, "'from' must not be negative!"); 714 CHECK_PARAM_VOID(from <= Length(), "'from' exceeds length!"); 715 int32 len = min_clamp0(length, Length() - from); 716 memcpy(into, String() + from, len); 717 into[len] = '\0'; 718 _ShrinkAtBy(from, len); 719 } 720 } 721 722 723 /*---- Compare functions ---------------------------------------------------*/ 724 bool 725 BString::operator<(const char *string) const 726 { 727 return strcmp(String(), safestr(string)) < 0; 728 } 729 730 731 bool 732 BString::operator<=(const char *string) const 733 { 734 return strcmp(String(), safestr(string)) <= 0; 735 } 736 737 738 bool 739 BString::operator==(const char *string) const 740 { 741 return strcmp(String(), safestr(string)) == 0; 742 } 743 744 745 bool 746 BString::operator>=(const char *string) const 747 { 748 return strcmp(String(), safestr(string)) >= 0; 749 } 750 751 752 bool 753 BString::operator>(const char *string) const 754 { 755 return strcmp(String(), safestr(string)) > 0; 756 } 757 758 759 // #pragma mark - Comparison 760 761 762 int 763 BString::Compare(const BString &string) const 764 { 765 return strcmp(String(), string.String()); 766 } 767 768 769 int 770 BString::Compare(const char *string) const 771 { 772 return strcmp(String(), safestr(string)); 773 } 774 775 776 int 777 BString::Compare(const BString &string, int32 n) const 778 { 779 return strncmp(String(), string.String(), n); 780 } 781 782 783 int 784 BString::Compare(const char *string, int32 n) const 785 { 786 return strncmp(String(), safestr(string), n); 787 } 788 789 790 int 791 BString::ICompare(const BString &string) const 792 { 793 return strcasecmp(String(), string.String()); 794 } 795 796 797 int 798 BString::ICompare(const char *str) const 799 { 800 return strcasecmp(String(), safestr(str)); 801 } 802 803 804 int 805 BString::ICompare(const BString &string, int32 n) const 806 { 807 return strncasecmp(String(), string.String(), n); 808 } 809 810 811 int 812 BString::ICompare(const char *str, int32 n) const 813 { 814 return strncasecmp(String(), safestr(str), n); 815 } 816 817 818 // #pragma mark - Searching 819 820 821 int32 822 BString::FindFirst(const BString &string) const 823 { 824 return _ShortFindAfter(string.String(), string.Length()); 825 } 826 827 828 // FindFirst 829 int32 830 BString::FindFirst(const char *string) const 831 { 832 if (string == NULL) 833 return B_BAD_VALUE; 834 835 return _ShortFindAfter(string, strlen(string)); 836 } 837 838 839 // FindFirst 840 int32 841 BString::FindFirst(const BString &string, int32 fromOffset) const 842 { 843 if (fromOffset < 0) 844 return B_ERROR; 845 846 return _FindAfter(string.String(), min_clamp0(fromOffset, Length()), 847 string.Length()); 848 } 849 850 851 // FindFirst 852 int32 853 BString::FindFirst(const char *string, int32 fromOffset) const 854 { 855 if (string == NULL) 856 return B_BAD_VALUE; 857 if (fromOffset < 0) 858 return B_ERROR; 859 860 return _FindAfter(string, min_clamp0(fromOffset, Length()), 861 strlen(string)); 862 } 863 864 865 // FindFirst 866 int32 867 BString::FindFirst(char c) const 868 { 869 const char *start = String(); 870 const char *end = String() + Length(); 871 872 /* Scans the string until we find the character, */ 873 /* or we hit the string's end */ 874 while (start != end && *start != c) { 875 start++; 876 } 877 878 if (start == end) 879 return B_ERROR; 880 881 return start - String(); 882 } 883 884 885 // FindFirst 886 int32 887 BString::FindFirst(char c, int32 fromOffset) const 888 { 889 if (fromOffset < 0) 890 return B_ERROR; 891 892 const char *start = String() + min_clamp0(fromOffset, Length()); 893 const char *end = String() + Length(); 894 895 /* Scans the string until we found the character, */ 896 /* or we hit the string's end */ 897 while (start < end && *start != c) { 898 start++; 899 } 900 901 if (start >= end) 902 return B_ERROR; 903 904 return start - String(); 905 } 906 907 908 // FindLast 909 int32 910 BString::FindLast(const BString &string) const 911 { 912 return _FindBefore(string.String(), Length(), string.Length()); 913 } 914 915 916 // FindLast 917 int32 918 BString::FindLast(const char *string) const 919 { 920 if (string == NULL) 921 return B_BAD_VALUE; 922 923 return _FindBefore(string, Length(), strlen(string)); 924 } 925 926 927 // FindLast 928 int32 929 BString::FindLast(const BString &string, int32 beforeOffset) const 930 { 931 if (beforeOffset < 0) 932 return B_ERROR; 933 934 return _FindBefore(string.String(), min_clamp0(beforeOffset, Length()), 935 string.Length()); 936 } 937 938 939 // FindLast 940 int32 941 BString::FindLast(const char *string, int32 beforeOffset) const 942 { 943 if (string == NULL) 944 return B_BAD_VALUE; 945 if (beforeOffset < 0) 946 return B_ERROR; 947 948 return _FindBefore(string, min_clamp0(beforeOffset, Length()), strlen(string)); 949 } 950 951 952 // FindLast 953 int32 954 BString::FindLast(char c) const 955 { 956 const char *start = String(); 957 const char *end = String() + Length(); 958 959 /* Scans the string backwards until we found the character, */ 960 /* or we reach the string's start */ 961 while (end != start && *end != c) { 962 end--; 963 } 964 965 if (end == start) 966 return B_ERROR; 967 968 return end - String(); 969 } 970 971 972 // FindLast 973 int32 974 BString::FindLast(char c, int32 beforeOffset) const 975 { 976 if (beforeOffset < 0) 977 return B_ERROR; 978 979 const char *start = String(); 980 const char *end = String() + min_clamp0(beforeOffset, Length()); 981 982 /* Scans the string backwards until we found the character, */ 983 /* or we reach the string's start */ 984 while (end > start && *end != c) { 985 end--; 986 } 987 988 if (end <= start) 989 return B_ERROR; 990 991 return end - String(); 992 } 993 994 995 int32 996 BString::IFindFirst(const BString &string) const 997 { 998 return _IFindAfter(string.String(), 0, string.Length()); 999 } 1000 1001 1002 int32 1003 BString::IFindFirst(const char *string) const 1004 { 1005 if (string == NULL) 1006 return B_BAD_VALUE; 1007 1008 return _IFindAfter(string, 0, strlen(string)); 1009 } 1010 1011 1012 int32 1013 BString::IFindFirst(const BString &string, int32 fromOffset) const 1014 { 1015 if (fromOffset < 0) 1016 return B_ERROR; 1017 1018 return _IFindAfter(string.String(), min_clamp0(fromOffset, Length()), 1019 string.Length()); 1020 } 1021 1022 1023 int32 1024 BString::IFindFirst(const char *string, int32 fromOffset) const 1025 { 1026 if (string == NULL) 1027 return B_BAD_VALUE; 1028 if (fromOffset < 0) 1029 return B_ERROR; 1030 1031 return _IFindAfter(string, min_clamp0(fromOffset,Length()), strlen(string)); 1032 } 1033 1034 1035 int32 1036 BString::IFindLast(const BString &string) const 1037 { 1038 return _IFindBefore(string.String(), Length(), string.Length()); 1039 } 1040 1041 1042 int32 1043 BString::IFindLast(const char *string) const 1044 { 1045 if (string == NULL) 1046 return B_BAD_VALUE; 1047 1048 return _IFindBefore(string, Length(), strlen(string)); 1049 } 1050 1051 1052 int32 1053 BString::IFindLast(const BString &string, int32 beforeOffset) const 1054 { 1055 if (beforeOffset < 0) 1056 return B_ERROR; 1057 1058 return _IFindBefore(string.String(), min_clamp0(beforeOffset, Length()), 1059 string.Length()); 1060 } 1061 1062 1063 int32 1064 BString::IFindLast(const char *string, int32 beforeOffset) const 1065 { 1066 if (string == NULL) 1067 return B_BAD_VALUE; 1068 if (beforeOffset < 0) 1069 return B_ERROR; 1070 1071 return _IFindBefore(string, min_clamp0(beforeOffset, Length()), 1072 strlen(string)); 1073 } 1074 1075 1076 // #pragma mark - Replacing 1077 1078 1079 BString& 1080 BString::ReplaceFirst(char replaceThis, char withThis) 1081 { 1082 int32 pos = FindFirst(replaceThis); 1083 if (pos >= 0) 1084 fPrivateData[pos] = withThis; 1085 1086 return *this; 1087 } 1088 1089 1090 BString& 1091 BString::ReplaceLast(char replaceThis, char withThis) 1092 { 1093 int32 pos = FindLast(replaceThis); 1094 if (pos >= 0) 1095 fPrivateData[pos] = withThis; 1096 1097 return *this; 1098 } 1099 1100 1101 BString& 1102 BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset) 1103 { 1104 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1105 for (int32 pos = min_clamp0(fromOffset, Length());;) { 1106 pos = FindFirst(replaceThis, pos); 1107 if (pos < 0) 1108 break; 1109 fPrivateData[pos] = withThis; 1110 } 1111 1112 return *this; 1113 } 1114 1115 1116 BString& 1117 BString::Replace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset) 1118 { 1119 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1120 if (maxReplaceCount > 0) { 1121 for (int32 pos = min_clamp0(fromOffset, Length()); 1122 maxReplaceCount > 0; maxReplaceCount--) { 1123 pos = FindFirst(replaceThis, pos); 1124 if (pos < 0) 1125 break; 1126 fPrivateData[pos] = withThis; 1127 } 1128 } 1129 return *this; 1130 } 1131 1132 1133 BString& 1134 BString::ReplaceFirst(const char *replaceThis, const char *withThis) 1135 { 1136 return _DoReplace( replaceThis, withThis, 1, 0, KEEP_CASE); 1137 } 1138 1139 1140 BString& 1141 BString::ReplaceLast(const char *replaceThis, const char *withThis) 1142 { 1143 if (replaceThis == NULL) 1144 return *this; 1145 1146 int32 firstStringLength = strlen(replaceThis); 1147 int32 pos = _FindBefore(replaceThis, Length(), firstStringLength); 1148 1149 if (pos >= 0) { 1150 int32 len = (withThis ? strlen(withThis) : 0); 1151 int32 difference = len - firstStringLength; 1152 1153 if (difference > 0) { 1154 if (!_OpenAtBy(pos, difference)) 1155 return *this; 1156 } else if (difference < 0) { 1157 if (!_ShrinkAtBy(pos, -difference)) 1158 return *this; 1159 } 1160 memcpy(fPrivateData + pos, withThis, len); 1161 } 1162 1163 return *this; 1164 } 1165 1166 1167 BString& 1168 BString::ReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset) 1169 { 1170 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1171 return _DoReplace(replaceThis, withThis, REPLACE_ALL, 1172 min_clamp0(fromOffset,Length()), KEEP_CASE); 1173 } 1174 1175 1176 BString& 1177 BString::Replace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset) 1178 { 1179 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1180 return _DoReplace(replaceThis, withThis, maxReplaceCount, 1181 min_clamp0(fromOffset,Length()), KEEP_CASE); 1182 } 1183 1184 1185 BString& 1186 BString::IReplaceFirst(char replaceThis, char withThis) 1187 { 1188 char tmp[2] = { replaceThis, '\0' }; 1189 1190 int32 pos = _IFindAfter(tmp, 0, 1); 1191 if (pos >= 0) 1192 fPrivateData[pos] = withThis; 1193 1194 return *this; 1195 } 1196 1197 1198 BString& 1199 BString::IReplaceLast(char replaceThis, char withThis) 1200 { 1201 char tmp[2] = { replaceThis, '\0' }; 1202 1203 int32 pos = _IFindBefore(tmp, Length(), 1); 1204 if (pos >= 0) 1205 fPrivateData[pos] = withThis; 1206 1207 return *this; 1208 } 1209 1210 1211 BString& 1212 BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset) 1213 { 1214 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1215 1216 char tmp[2] = { replaceThis, '\0' }; 1217 1218 for (int32 pos = min_clamp0(fromOffset, Length());;) { 1219 pos = _IFindAfter(tmp, pos, 1); 1220 if (pos < 0) 1221 break; 1222 fPrivateData[pos] = withThis; 1223 } 1224 return *this; 1225 } 1226 1227 1228 BString& 1229 BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset) 1230 { 1231 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1232 1233 char tmp[2] = { replaceThis, '\0' }; 1234 1235 if (fPrivateData == NULL) 1236 return *this; 1237 1238 for (int32 pos = min_clamp0(fromOffset,Length()); 1239 maxReplaceCount > 0; maxReplaceCount--) { 1240 pos = _IFindAfter(tmp, pos, 1); 1241 if (pos < 0) 1242 break; 1243 fPrivateData[pos] = withThis; 1244 } 1245 return *this; 1246 } 1247 1248 1249 BString& 1250 BString::IReplaceFirst(const char *replaceThis, const char *withThis) 1251 { 1252 return _DoReplace(replaceThis, withThis, 1, 0, IGNORE_CASE); 1253 } 1254 1255 1256 BString& 1257 BString::IReplaceLast(const char *replaceThis, const char *withThis) 1258 { 1259 if (replaceThis == NULL) 1260 return *this; 1261 1262 int32 firstStringLength = strlen(replaceThis); 1263 int32 pos = _IFindBefore(replaceThis, Length(), firstStringLength); 1264 1265 if (pos >= 0) { 1266 int32 len = (withThis ? strlen(withThis) : 0); 1267 int32 difference = len - firstStringLength; 1268 1269 if (difference > 0) { 1270 if (!_OpenAtBy(pos, difference)) 1271 return *this; 1272 } else if (difference < 0) { 1273 if (!_ShrinkAtBy(pos, -difference)) 1274 return *this; 1275 } 1276 memcpy(fPrivateData + pos, withThis, len); 1277 } 1278 1279 return *this; 1280 } 1281 1282 1283 BString& 1284 BString::IReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset) 1285 { 1286 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1287 return _DoReplace(replaceThis, withThis, REPLACE_ALL, 1288 min_clamp0(fromOffset, Length()), IGNORE_CASE); 1289 } 1290 1291 1292 BString& 1293 BString::IReplace(const char *replaceThis, const char *withThis, 1294 int32 maxReplaceCount, int32 fromOffset) 1295 { 1296 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1297 return _DoReplace(replaceThis, withThis, maxReplaceCount, 1298 min_clamp0(fromOffset, Length()), IGNORE_CASE); 1299 } 1300 1301 1302 BString& 1303 BString::ReplaceSet(const char *setOfChars, char with) 1304 { 1305 if (setOfChars == NULL) 1306 return *this; 1307 1308 int32 offset = 0; 1309 int32 length = Length(); 1310 1311 for (int32 pos;;) { 1312 pos = strcspn(String() + offset, setOfChars); 1313 1314 offset += pos; 1315 if (offset >= length) 1316 break; 1317 1318 fPrivateData[offset] = with; 1319 offset++; 1320 } 1321 1322 return *this; 1323 } 1324 1325 1326 BString& 1327 BString::ReplaceSet(const char *setOfChars, const char *with) 1328 { 1329 int32 withLen = with ? strlen(with) : 0; 1330 if (withLen == 1) { 1331 // delegate simple case: 1332 return ReplaceSet(setOfChars, *with); 1333 } 1334 1335 if (setOfChars == NULL || fPrivateData == NULL) 1336 return *this; 1337 1338 PosVect positions; 1339 1340 int32 searchLen = 1; 1341 int32 len = Length(); 1342 int32 pos = 0; 1343 for (int32 offset = 0; offset < len; offset += (pos+searchLen)) { 1344 pos = strcspn(fPrivateData + offset, setOfChars); 1345 if (pos + offset >= len) 1346 break; 1347 if (!positions.Add(offset + pos)) 1348 return *this; 1349 } 1350 1351 _ReplaceAtPositions(&positions, searchLen, with, withLen); 1352 return *this; 1353 } 1354 1355 1356 /*---- Unchecked char access -----------------------------------------------*/ 1357 1358 // operator[] 1359 char & 1360 BString::operator[](int32 index) 1361 { 1362 return fPrivateData[index]; 1363 } 1364 1365 1366 /*---- Fast low-level manipulation -----------------------------------------*/ 1367 char* 1368 BString::LockBuffer(int32 maxLength) 1369 { 1370 _SetUsingAsCString(true); 1371 1372 int32 len = Length(); 1373 1374 if (maxLength > len) { 1375 if (!_GrowBy(maxLength - len)) 1376 return NULL; 1377 if (!len && fPrivateData) 1378 // if string was empty before call to LockBuffer(), we make sure the 1379 // buffer represents an empty c-string: 1380 *fPrivateData = '\0'; 1381 } else if (!maxLength && !len) { 1382 // special case for unallocated string, we return an empty c-string: 1383 return const_cast<char*>(String()); 1384 } 1385 1386 return fPrivateData; 1387 } 1388 1389 1390 BString& 1391 BString::UnlockBuffer(int32 length) 1392 { 1393 _SetUsingAsCString(false); 1394 1395 if (length < 0) 1396 length = (fPrivateData == NULL) ? 0 : strlen(fPrivateData); 1397 1398 if (length != Length()) 1399 _GrowBy(length - Length()); 1400 1401 return *this; 1402 } 1403 1404 1405 /*---- Uppercase<->Lowercase ------------------------------------------------*/ 1406 // ToLower 1407 BString& 1408 BString::ToLower() 1409 { 1410 int32 length = Length(); 1411 for (int32 count = 0; count < length; count++) { 1412 fPrivateData[count] = tolower(fPrivateData[count]); 1413 } 1414 1415 return *this; 1416 } 1417 1418 1419 // ToUpper 1420 BString& 1421 BString::ToUpper() 1422 { 1423 int32 length = Length(); 1424 for (int32 count = 0; count < length; count++) { 1425 fPrivateData[count] = toupper(fPrivateData[count]); 1426 } 1427 1428 return *this; 1429 } 1430 1431 1432 // Capitalize 1433 BString& 1434 BString::Capitalize() 1435 { 1436 if (fPrivateData == NULL) 1437 return *this; 1438 1439 fPrivateData[0] = toupper(fPrivateData[0]); 1440 int32 length = Length(); 1441 1442 for (int32 count = 1; count < length; count++) { 1443 fPrivateData[count] = tolower(fPrivateData[count]); 1444 } 1445 1446 return *this; 1447 } 1448 1449 1450 // CapitalizeEachWord 1451 BString& 1452 BString::CapitalizeEachWord() 1453 { 1454 if (fPrivateData == NULL) 1455 return *this; 1456 1457 int32 count = 0; 1458 int32 length = Length(); 1459 1460 do { 1461 // Find the first alphabetical character... 1462 for (; count < length; count++) { 1463 if (isalpha(fPrivateData[count])) { 1464 // ...found! Convert it to uppercase. 1465 fPrivateData[count] = toupper(fPrivateData[count]); 1466 count++; 1467 break; 1468 } 1469 } 1470 1471 // Now find the first non-alphabetical character, 1472 // and meanwhile, turn to lowercase all the alphabetical ones 1473 for (; count < length; count++) { 1474 if (isalpha(fPrivateData[count])) 1475 fPrivateData[count] = tolower(fPrivateData[count]); 1476 else 1477 break; 1478 } 1479 } while (count < length); 1480 1481 return *this; 1482 } 1483 1484 1485 /*----- Escaping and Deescaping --------------------------------------------*/ 1486 BString& 1487 BString::CharacterEscape(const char *original, const char *setOfCharsToEscape, 1488 char escapeWith) 1489 { 1490 SetTo(original); 1491 CharacterEscape(setOfCharsToEscape, escapeWith); 1492 1493 return *this; 1494 } 1495 1496 1497 BString& 1498 BString::CharacterEscape(const char *setOfCharsToEscape, char escapeWith) 1499 { 1500 if (setOfCharsToEscape == NULL || fPrivateData == NULL) 1501 return *this; 1502 1503 PosVect positions; 1504 int32 len = Length(); 1505 int32 pos = 0; 1506 for (int32 offset = 0; offset < len; offset += pos + 1) { 1507 if ((pos = strcspn(fPrivateData + offset, setOfCharsToEscape)) < len - offset) { 1508 if (!positions.Add(offset + pos)) 1509 return *this; 1510 } 1511 } 1512 1513 uint32 count = positions.CountItems(); 1514 int32 newLength = len + count; 1515 if (!newLength) { 1516 _Alloc(0); 1517 return *this; 1518 } 1519 1520 int32 lastPos = 0; 1521 char* oldAdr = fPrivateData; 1522 char* newData = (char*)malloc(newLength + sizeof(int32) + 1); 1523 if (newData) { 1524 newData += sizeof(int32); 1525 char* newAdr = newData; 1526 for (uint32 i = 0; i < count; ++i) { 1527 pos = positions.ItemAt( i); 1528 len = pos-lastPos; 1529 if (len > 0) { 1530 memcpy(newAdr, oldAdr, len); 1531 oldAdr += len; 1532 newAdr += len; 1533 } 1534 *newAdr++ = escapeWith; 1535 *newAdr++ = *oldAdr++; 1536 lastPos = pos + 1; 1537 } 1538 len = Length() + 1 - lastPos; 1539 if (len > 0) 1540 memcpy(newAdr, oldAdr, len); 1541 1542 free(fPrivateData - sizeof(int32)); 1543 fPrivateData = newData; 1544 fPrivateData[newLength] = 0; 1545 _SetLength( newLength); 1546 } 1547 1548 return *this; 1549 } 1550 1551 1552 BString& 1553 BString::CharacterDeescape(const char *original, char escapeChar) 1554 { 1555 SetTo(original); 1556 CharacterDeescape(escapeChar); 1557 1558 return *this; 1559 } 1560 1561 1562 BString& 1563 BString::CharacterDeescape(char escapeChar) 1564 { 1565 const char temp[2] = {escapeChar, 0}; 1566 return _DoReplace(temp, "", REPLACE_ALL, 0, KEEP_CASE); 1567 } 1568 1569 1570 /*---- Simple sprintf replacement calls ------------------------------------*/ 1571 /*---- Slower than sprintf but type and overflow safe ----------------------*/ 1572 BString& 1573 BString::operator<<(const char *str) 1574 { 1575 if (str != NULL) 1576 _DoAppend(str, strlen(str)); 1577 return *this; 1578 } 1579 1580 1581 BString& 1582 BString::operator<<(const BString &string) 1583 { 1584 _DoAppend(string.String(), string.Length()); 1585 return *this; 1586 } 1587 1588 1589 BString& 1590 BString::operator<<(char c) 1591 { 1592 _DoAppend(&c, 1); 1593 return *this; 1594 } 1595 1596 1597 BString& 1598 BString::operator<<(int i) 1599 { 1600 char num[32]; 1601 int32 length = snprintf(num, sizeof(num), "%d", i); 1602 1603 _DoAppend(num, length); 1604 return *this; 1605 } 1606 1607 1608 BString& 1609 BString::operator<<(unsigned int i) 1610 { 1611 char num[32]; 1612 int32 length = snprintf(num, sizeof(num), "%u", i); 1613 1614 _DoAppend(num, length); 1615 return *this; 1616 } 1617 1618 1619 BString& 1620 BString::operator<<(uint32 i) 1621 { 1622 char num[32]; 1623 int32 length = snprintf(num, sizeof(num), "%lu", i); 1624 1625 _DoAppend(num, length); 1626 return *this; 1627 } 1628 1629 1630 BString& 1631 BString::operator<<(int32 i) 1632 { 1633 char num[32]; 1634 int32 length = snprintf(num, sizeof(num), "%ld", i); 1635 1636 _DoAppend(num, length); 1637 return *this; 1638 } 1639 1640 1641 BString& 1642 BString::operator<<(uint64 i) 1643 { 1644 char num[64]; 1645 int32 length = snprintf(num, sizeof(num), "%llu", i); 1646 1647 _DoAppend(num, length); 1648 return *this; 1649 } 1650 1651 1652 BString& 1653 BString::operator<<(int64 i) 1654 { 1655 char num[64]; 1656 int32 length = snprintf(num, sizeof(num), "%lld", i); 1657 1658 _DoAppend(num, length); 1659 return *this; 1660 } 1661 1662 1663 BString& 1664 BString::operator<<(float f) 1665 { 1666 char num[64]; 1667 int32 length = snprintf(num, sizeof(num), "%.2f", f); 1668 1669 _DoAppend(num, length); 1670 return *this; 1671 } 1672 1673 1674 // #pragma mark - Private or reserved 1675 1676 1677 char * 1678 BString::_Alloc(int32 dataLength) 1679 { 1680 char *dataPtr = fPrivateData ? fPrivateData - sizeof(int32) : NULL; 1681 if (dataLength <= 0) { 1682 // release buffer 1683 #if 0 1684 free(dataPtr); 1685 fPrivateData = NULL; 1686 return NULL; 1687 #else 1688 // TODO: think about removing this work-around again; it lets 1689 // BeOS R5 NetPositive run on Haiku - this is obviously ignoring 1690 // the fact, that fPrivateData could be NULL at one point 1691 // (while building the menus from resources). 1692 dataLength = 0; 1693 #endif 1694 } 1695 1696 int32 allocLength = dataLength + sizeof(int32) + 1; 1697 dataPtr = (char *)realloc(dataPtr, allocLength); 1698 if (dataPtr) { 1699 dataPtr += sizeof(int32); 1700 fPrivateData = dataPtr; 1701 1702 _SetLength(dataLength); 1703 fPrivateData[dataLength] = '\0'; 1704 } 1705 1706 return dataPtr; 1707 } 1708 1709 void 1710 BString::_Init(const char *str, int32 len) 1711 { 1712 if (_Alloc(len)) 1713 memcpy(fPrivateData, str, len); 1714 } 1715 1716 1717 #if ENABLE_INLINES 1718 inline 1719 #endif 1720 void 1721 BString::_DoAssign(const char *str, int32 len) 1722 { 1723 int32 curLen = Length(); 1724 1725 if (len == curLen || _GrowBy(len - curLen)) 1726 memcpy(fPrivateData, str, len); 1727 } 1728 1729 1730 #if ENABLE_INLINES 1731 inline 1732 #endif 1733 void 1734 BString::_DoAppend(const char *str, int32 len) 1735 { 1736 int32 length = Length(); 1737 if (_GrowBy(len)) 1738 memcpy(fPrivateData + length, str, len); 1739 } 1740 1741 1742 char* 1743 BString::_GrowBy(int32 size) 1744 { 1745 return _Alloc(Length() + size); 1746 } 1747 1748 1749 char * 1750 BString::_OpenAtBy(int32 offset, int32 length) 1751 { 1752 int32 oldLength = Length(); 1753 1754 char* newData = _Alloc(oldLength + length); 1755 if (newData != NULL) { 1756 memmove(fPrivateData + offset + length, fPrivateData + offset, 1757 oldLength - offset); 1758 } 1759 1760 return newData; 1761 } 1762 1763 1764 char* 1765 BString::_ShrinkAtBy(int32 offset, int32 length) 1766 { 1767 if (!fPrivateData) 1768 return NULL; 1769 1770 int32 oldLength = Length(); 1771 1772 memmove(fPrivateData + offset, fPrivateData + offset + length, 1773 oldLength - offset - length); 1774 1775 // the following actually should never fail, since we are reducing the size... 1776 return _Alloc(oldLength - length); 1777 } 1778 1779 1780 #if ENABLE_INLINES 1781 inline 1782 #endif 1783 void 1784 BString::_DoPrepend(const char *str, int32 count) 1785 { 1786 if (_OpenAtBy(0, count)) 1787 memcpy(fPrivateData, str, count); 1788 } 1789 1790 1791 /* XXX: These could be inlined too, if they are too slow */ 1792 int32 1793 BString::_FindAfter(const char *str, int32 offset, int32 strlen) const 1794 { 1795 char *ptr = strstr(String() + offset, str); 1796 1797 if (ptr != NULL) 1798 return ptr - String(); 1799 1800 return B_ERROR; 1801 } 1802 1803 1804 int32 1805 BString::_IFindAfter(const char *str, int32 offset, int32 strlen) const 1806 { 1807 char *ptr = strcasestr(String() + offset, str); 1808 1809 if (ptr != NULL) 1810 return ptr - String(); 1811 1812 return B_ERROR; 1813 } 1814 1815 1816 int32 1817 BString::_ShortFindAfter(const char *str, int32 len) const 1818 { 1819 char *ptr = strstr(String(), str); 1820 1821 if (ptr != NULL) 1822 return ptr - String(); 1823 1824 return B_ERROR; 1825 } 1826 1827 1828 int32 1829 BString::_FindBefore(const char *str, int32 offset, int32 strlen) const 1830 { 1831 if (fPrivateData) { 1832 const char *ptr = fPrivateData + offset - strlen; 1833 1834 while (ptr >= fPrivateData) { 1835 if (!memcmp(ptr, str, strlen)) 1836 return ptr - fPrivateData; 1837 ptr--; 1838 } 1839 } 1840 return B_ERROR; 1841 } 1842 1843 1844 int32 1845 BString::_IFindBefore(const char *str, int32 offset, int32 strlen) const 1846 { 1847 if (fPrivateData) { 1848 char *ptr1 = fPrivateData + offset - strlen; 1849 1850 while (ptr1 >= fPrivateData) { 1851 if (!strncasecmp(ptr1, str, strlen)) 1852 return ptr1 - fPrivateData; 1853 ptr1--; 1854 } 1855 } 1856 return B_ERROR; 1857 } 1858 1859 1860 BString& 1861 BString::_DoReplace(const char *findThis, const char *replaceWith, 1862 int32 maxReplaceCount, int32 fromOffset, bool ignoreCase) 1863 { 1864 if (findThis == NULL || maxReplaceCount <= 0 1865 || fromOffset < 0 || fromOffset >= Length()) 1866 return *this; 1867 1868 typedef int32 (BString::*TFindMethod)(const char *, int32, int32) const; 1869 TFindMethod findMethod = ignoreCase ? &BString::_IFindAfter : &BString::_FindAfter; 1870 int32 findLen = strlen(findThis); 1871 1872 if (!replaceWith) 1873 replaceWith = ""; 1874 1875 int32 replaceLen = strlen(replaceWith); 1876 int32 lastSrcPos = fromOffset; 1877 PosVect positions; 1878 for(int32 srcPos = 0; 1879 maxReplaceCount > 0 1880 && (srcPos = (this->*findMethod)(findThis, lastSrcPos, findLen)) >= 0; 1881 maxReplaceCount-- ) { 1882 positions.Add(srcPos); 1883 lastSrcPos = srcPos + findLen; 1884 } 1885 _ReplaceAtPositions(&positions, findLen, replaceWith, replaceLen); 1886 return *this; 1887 } 1888 1889 1890 void 1891 BString::_ReplaceAtPositions(const PosVect* positions, 1892 int32 searchLen, const char* with, int32 withLen) 1893 { 1894 int32 len = Length(); 1895 uint32 count = positions->CountItems(); 1896 int32 newLength = len + count * (withLen - searchLen); 1897 if (!newLength) { 1898 _Alloc(0); 1899 return; 1900 } 1901 1902 int32 pos; 1903 int32 lastPos = 0; 1904 char *oldAdr = fPrivateData; 1905 char *newData = (char *)malloc(newLength + sizeof(int32) + 1); 1906 if (newData) { 1907 newData += sizeof(int32); 1908 char *newAdr = newData; 1909 for(uint32 i = 0; i < count; ++i) { 1910 pos = positions->ItemAt(i); 1911 len = pos - lastPos; 1912 if (len > 0) { 1913 memcpy(newAdr, oldAdr, len); 1914 oldAdr += len; 1915 newAdr += len; 1916 } 1917 memcpy(newAdr, with, withLen); 1918 oldAdr += searchLen; 1919 newAdr += withLen; 1920 lastPos = pos+searchLen; 1921 } 1922 len = Length() + 1 - lastPos; 1923 if (len > 0) 1924 memcpy(newAdr, oldAdr, len); 1925 1926 free(fPrivateData - sizeof(int32)); 1927 fPrivateData = newData; 1928 fPrivateData[newLength] = 0; 1929 _SetLength( newLength); 1930 } 1931 } 1932 1933 1934 #if ENABLE_INLINES 1935 inline 1936 #endif 1937 void 1938 BString::_SetLength(int32 length) 1939 { 1940 *((int32*)fPrivateData - 1) = length & 0x7fffffff; 1941 } 1942 1943 1944 #if DEBUG 1945 // AFAIK, these are not implemented in BeOS R5 1946 // XXX : Test these puppies 1947 void 1948 BString::_SetUsingAsCString(bool state) 1949 { 1950 //TODO: Implement ? 1951 } 1952 1953 1954 void 1955 BString::_AssertNotUsingAsCString() const 1956 { 1957 //TODO: Implement ? 1958 } 1959 #endif 1960 1961 1962 // #pragma mark - backwards compatibility 1963 1964 1965 /* 1966 Translates to (missing const): 1967 BString& BString::operator<<(BString& string) 1968 */ 1969 extern "C" BString& 1970 __ls__7BStringR7BString(BString* self, BString& string) 1971 { 1972 return self->operator<<(string); 1973 } 1974 1975 1976 // #pragma mark - Non-member compare for sorting, etc. 1977 1978 1979 int 1980 Compare(const BString &string1, const BString &string2) 1981 { 1982 return strcmp(string1.String(), string2.String()); 1983 } 1984 1985 1986 int 1987 ICompare(const BString &string1, const BString &string2) 1988 { 1989 return strcasecmp(string1.String(), string2.String()); 1990 } 1991 1992 1993 int 1994 Compare(const BString *string1, const BString *string2) 1995 { 1996 return strcmp(string1->String(), string2->String()); 1997 } 1998 1999 2000 int 2001 ICompare(const BString *string1, const BString *string2) 2002 { 2003 return strcasecmp(string1->String(), string2->String()); 2004 } 2005 2006