1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2003, OpenBeOS 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: String.cpp 23 // Author(s): Marc Flerackers (mflerackers@androme.be) 24 // Stefano Ceccherini (burton666@libero.it) 25 // Oliver Tappe (openbeos@hirschkaefer.de) 26 // 27 // Description: String class supporting common string operations. 28 //------------------------------------------------------------------------------ 29 30 // Standard Includes ----------------------------------------------------------- 31 #include <cctype> 32 #include <cstdio> 33 #include <cstdlib> 34 35 // System Includes ------------------------------------------------------------- 36 #include <Debug.h> 37 #include <String.h> 38 39 // Temporary Includes 40 #include "string_helper.h" 41 42 #define ENABLE_INLINES 0 // Set this to 1 to make some private methods inline 43 44 // define proper names for case-option of _DoReplace() 45 #define KEEP_CASE false 46 #define IGNORE_CASE true 47 48 // define proper names for count-option of _DoReplace() 49 #define REPLACE_ALL 0x7FFFFFFF 50 51 52 // helper function, returns minimum of two given values (but clamps to 0): 53 static inline int32 54 min_clamp0(int32 num1, int32 num2) 55 { 56 if (num1<num2) 57 return num1 > 0 ? num1 : 0; 58 else 59 return num2 > 0 ? num2 : 0; 60 } 61 62 63 // helper function, returns length of given string (but clamps to given maximum): 64 static inline int32 65 strlen_clamp(const char* str, int32 max) 66 { // this should yield 0 for max<0: 67 int32 len=0; 68 while( len<max && *str++) 69 len++; 70 return len; 71 } 72 73 74 // helper function, massages given pointer into a legal c-string: 75 static inline const char * 76 safestr(const char* str) 77 { 78 return str ? str : ""; 79 } 80 81 82 // helper class for BString::_ReplaceAtPositions(): 83 struct 84 BString::PosVect { 85 PosVect() 86 : 87 size(0), 88 bufSize(20), 89 buf(NULL) 90 { 91 } 92 93 ~PosVect() 94 { 95 free(buf); 96 } 97 98 bool Add(int32 pos) 99 { 100 if (!buf || size == bufSize) { 101 if (buf) 102 bufSize *= 2; 103 int32 *newBuf = (int32 *)realloc(buf, bufSize * sizeof(int32)); 104 if (!newBuf) 105 return false; 106 buf = newBuf; 107 } 108 buf[size++] = pos; 109 return true; 110 } 111 112 inline int32 ItemAt(int32 idx) const 113 { 114 return buf[idx]; 115 } 116 117 inline int32 CountItems() const 118 { 119 return size; 120 } 121 122 private: 123 int32 size; 124 int32 bufSize; 125 int32 *buf; 126 }; 127 128 129 // helper macro that is used to fall into debugger if a given param check fails: 130 #ifdef DEBUG 131 #define CHECK_PARAM( expr, msg) \ 132 if (!(expr)) \ 133 debugger( msg) 134 135 #define CHECK_PARAM_RET( expr, msg, retval) \ 136 if (!(expr)) \ 137 debugger( msg) 138 139 #define CHECK_PARAM_VOID( expr, msg) \ 140 if (!(expr)) \ 141 debugger( msg) 142 #else 143 #define CHECK_PARAM( expr, msg) \ 144 if (!(expr)) \ 145 return *this 146 147 #define CHECK_PARAM_RET( expr, msg, retval) \ 148 if (!(expr)) \ 149 return (retval); 150 151 #define CHECK_PARAM_VOID( expr, msg) 152 #endif 153 154 // ----------------------------------------------------------------------------- 155 156 /*! 157 \class BString 158 \brief String class supporting common string operations 159 160 BString is a string allocation and manipulation class. The object 161 takes care to allocate and free memory for you, so it will always be 162 "big enough" to store your strings. 163 164 \author <a href='mailto:mflerackers@androme.be>Marc Flerackers</a> 165 \author <a href='mailto:burton666@freemail.it>Stefano Ceccherini</a> 166 \author <a href='mailto:openbeos@hirschaefer.de>Oliver Tappe</a> 167 */ 168 169 /*! \var char* BString::_privateData 170 \brief BString's storage for data 171 */ 172 173 // constructor 174 /*! \brief Creates an uninitialized BString. 175 */ 176 BString::BString() 177 :_privateData(NULL) 178 { 179 } 180 181 182 // constructor 183 /*! \brief Creates a BString and initializes it to the given string. 184 \param str Pointer to a NULL terminated string. 185 */ 186 BString::BString(const char* str) 187 :_privateData(NULL) 188 { 189 if (str != NULL) 190 _Init(str, strlen(str)); 191 } 192 193 194 // copy constructor 195 /*! \brief Creates a BString and makes it a copy of the supplied one. 196 \param string the BString object to be copied. 197 */ 198 BString::BString(const BString &string) 199 :_privateData(NULL) 200 { 201 _Init(string.String(), string.Length()); 202 } 203 204 205 // constructor 206 /*! \brief Creates a BString and initializes it to the given string. 207 \param str Pointer to a NULL terminated string. 208 \param maxLength The amount of characters you want to copy from the original 209 string. 210 */ 211 BString::BString(const char *str, int32 maxLength) 212 :_privateData(NULL) 213 { 214 if (str != NULL) { 215 int32 len = strlen_clamp(str, maxLength); 216 _Init(str, len); 217 } 218 } 219 220 221 // destructor 222 /*! \brief Frees all resources associated with the object. 223 224 Frees the memory allocated by the BString object. 225 */ 226 BString::~BString() 227 { 228 if (_privateData) 229 free(_privateData - sizeof(int32)); 230 } 231 232 233 /*---- Access --------------------------------------------------------------*/ 234 // String, implemented inline in the header 235 /*! \fn const char* BString::String() const 236 \brief Returns a pointer to the object string, NULL terminated. 237 238 Returns a pointer to the object string, guaranteed to be NULL 239 terminated. You can't modify or free the pointer. Once the BString 240 object is deleted, the pointer becomes invalid. 241 242 \return A pointer to the object string. 243 */ 244 245 246 // Length, implemented inline in the header 247 /*! \fn int32 BString::Length() const 248 \brief Returns the length of the string, measured in bytes. 249 \return The length of the string, measured in bytes. 250 */ 251 252 253 // CountChars 254 /*! \brief Returns the length of the object measured in characters. 255 \return An integer which is the number of characters in the string. 256 257 Counts the number of UTF8 characters contained in the string. 258 */ 259 int32 260 BString::CountChars() const 261 { 262 int32 count = 0; 263 264 const char *start = _privateData; 265 266 /* String's end. This way we don't have to check for '\0' */ 267 /* but just compare two pointers (which should be faster) */ 268 const char *end = _privateData + Length(); 269 270 #if 0 271 // ejaesler: Left in memoriam of one man's foolish disregard for the 272 // maxim "Premature optimization is the root of all evil" 273 while (*ptr) { 274 // Jump to next UTF8 character 275 // ejaesler: BGA's nifty function 276 ptr += utf8_char_len(*ptr); 277 count++; 278 } 279 #endif 280 281 while (start++ != end) { 282 count++; 283 284 // Jump to next UTF8 character 285 for (; (*start & 0xc0) == 0x80; start++); 286 } 287 288 return count; 289 } 290 291 292 /*---- Assignment ----------------------------------------------------------*/ 293 // equal operator 294 /*! \brief Makes a copy of the given BString object. 295 \param string The string object to copy. 296 \return 297 The function always returns \c *this . 298 */ 299 BString& 300 BString::operator=(const BString &string) 301 { 302 if (&string != this) // Avoid auto-assignment 303 _DoAssign(string.String(), string.Length()); 304 return *this; 305 } 306 307 308 // equal operator 309 /*! \brief Re-initializes the object to the given string. 310 \param str Pointer to a string. 311 \return 312 The function always returns \c *this . 313 */ 314 BString& 315 BString::operator=(const char *str) 316 { 317 if (str != NULL) 318 _DoAssign(str, strlen(str)); 319 else 320 _GrowBy(-Length()); // Empties the string 321 322 return *this; 323 } 324 325 326 // equal operator 327 /*! \brief Re-initializes the object to the given character. 328 \param c The character which you want to initialize the string to. 329 \return 330 The function always returns \c *this . 331 */ 332 BString& 333 BString::operator=(char c) 334 { 335 _DoAssign(&c, 1); 336 return *this; 337 } 338 339 340 // SetTo 341 /*! \brief Re-initializes the object to the given string. 342 \param str Pointer to a string. 343 \param length Amount of characters to copy from the original string. 344 \return 345 The function always returns \c *this . 346 */ 347 BString& 348 BString::SetTo(const char *str, int32 length) 349 { 350 if (str != NULL) { 351 int32 len = strlen_clamp(str, length); 352 _DoAssign(str, len); 353 } 354 else 355 _GrowBy(-Length()); // Empties the string 356 357 return *this; 358 } 359 360 361 // SetTo 362 /*! \brief Makes a copy of the given BString object. 363 \param from The string object to copy. 364 \return 365 The function always returns \c *this . 366 */ 367 BString& 368 BString::SetTo(const BString &from) 369 { 370 if (&from != this) // Avoid auto-assignment 371 _DoAssign(from.String(), from.Length()); 372 return *this; 373 } 374 375 376 // Adopt 377 /*! \brief Adopt's data of the given BString object, freeing the original object. 378 \param from The string object to adopt. 379 \return 380 The function always returns \c *this . 381 */ 382 BString& 383 BString::Adopt(BString &from) 384 { 385 if (&from == this) // Avoid auto-adoption 386 return *this; 387 388 if (_privateData) 389 free(_privateData - sizeof(int32)); 390 391 /* "steal" the data from the given BString */ 392 _privateData = from._privateData; 393 from._privateData = NULL; 394 395 return *this; 396 } 397 398 399 // SetTo 400 /*! \brief Makes a copy of the given BString object. 401 \param from The string object to copy. 402 \param length Amount of characters to copy from the original BString. 403 \return 404 The function always returns \c *this . 405 */ 406 BString& 407 BString::SetTo(const BString &string, int32 length) 408 { 409 if (&string != this) // Avoid auto-assignment 410 _DoAssign(string.String(), min_clamp0(length, string.Length())); 411 return *this; 412 } 413 414 415 // Adopt 416 /*! \brief Adopt's data of the given BString object, freeing the original object. 417 \param from The string object to adopt. 418 \param length Amount of characters to get from the original BString. 419 \return 420 The function always returns \c *this . 421 */ 422 BString& 423 BString::Adopt(BString &from, int32 length) 424 { 425 if (&from == this) // Avoid auto-adoption 426 return *this; 427 428 int32 len = min_clamp0(length, from.Length()); 429 430 if (_privateData) 431 free(_privateData - sizeof(int32)); 432 433 /* "steal" the data from the given BString */ 434 _privateData = from._privateData; 435 from._privateData = NULL; 436 437 if (len < Length()) 438 _GrowBy(len - Length()); // Negative, we truncate 439 440 return *this; 441 } 442 443 444 // SetTo 445 /*! \brief Initializes the object to a string composed by a character you specify. 446 \param c The character you want to initialize the BString. 447 \param count The number of characters you want the BString to be composed by. 448 \return 449 The function always returns \c *this . 450 */ 451 BString& 452 BString::SetTo(char c, int32 count) 453 { 454 if (count < 0) 455 count = 0; 456 int32 curLen = Length(); 457 458 if (curLen == count || _GrowBy(count - curLen)) 459 memset(_privateData, c, count); 460 return *this; 461 } 462 463 464 /*---- Substring copying ---------------------------------------------------*/ 465 466 // CopyInto 467 /*! \brief Copy the BString data (or part of it) into another BString. 468 \param into The BString where to copy the object. 469 \param fromOffset The offset (zero based) where to begin the copy 470 \param length The amount of bytes to copy. 471 \return This function always returns *this . 472 */ 473 BString & 474 BString::CopyInto(BString &into, int32 fromOffset, int32 length) const 475 { 476 if (&into != this) { 477 CHECK_PARAM_RET(fromOffset >= 0, "'fromOffset' must not be negative!", 478 into); 479 CHECK_PARAM_RET(fromOffset <= Length(), "'fromOffset' exceeds length!", 480 into); 481 into.SetTo(String() + fromOffset, length); 482 } 483 return into; 484 } 485 486 487 // CopyInto 488 /*! \brief Copy the BString data (or part of it) into the supplied buffer. 489 \param into The buffer where to copy the object. 490 \param fromOffset The offset (zero based) where to begin the copy 491 \param length The amount of bytes to copy. 492 */ 493 void 494 BString::CopyInto(char *into, int32 fromOffset, int32 length) const 495 { 496 if (into != NULL) { 497 CHECK_PARAM_VOID(fromOffset >= 0, "'fromOffset' must not be negative!"); 498 CHECK_PARAM_VOID(fromOffset <= Length(), "'fromOffset' exceeds length!"); 499 int32 len = min_clamp0(length, Length() - fromOffset); 500 memcpy(into, _privateData + fromOffset, len); 501 } 502 } 503 504 505 /*---- Appending -----------------------------------------------------------*/ 506 // plus operator 507 /*! \brief Appends the given string to the object. 508 \param str A pointer to the string to append. 509 \return This function always returns *this . 510 */ 511 BString& 512 BString::operator+=(const char *str) 513 { 514 if (str != NULL) 515 _DoAppend(str, strlen(str)); 516 return *this; 517 } 518 519 520 // plus operator 521 /*! \brief Appends the given character to the object. 522 \param c The character to append. 523 \return This function always returns *this . 524 */ 525 BString& 526 BString::operator+=(char c) 527 { 528 _DoAppend(&c, 1); 529 return *this; 530 } 531 532 533 // Append 534 /*! \brief Appends the given BString to the object. 535 \param string The BString to append. 536 \param length The maximum bytes to get from the original object. 537 \return This function always returns *this . 538 */ 539 BString& 540 BString::Append(const BString &string, int32 length) 541 { 542 _DoAppend(string.String(), min_clamp0(length, string.Length())); 543 return *this; 544 } 545 546 547 // Append 548 /*! \brief Appends the given string to the object. 549 \param str A pointer to the string to append. 550 \param length The maximum bytes to get from the original string. 551 \return This function always returns *this . 552 */ 553 BString& 554 BString::Append(const char *str, int32 length) 555 { 556 if (str != NULL) { 557 int32 len = strlen_clamp(str, length); 558 _DoAppend(str, len); 559 } 560 return *this; 561 } 562 563 564 // Append 565 /*! \brief Appends the given character to the object. 566 \param c The character to append. 567 \param count The number of characters to append. 568 \return This function always returns *this . 569 */ 570 BString& 571 BString::Append(char c, int32 count) 572 { 573 int32 len = Length(); 574 if (count > 0 && _GrowBy(count)) 575 memset(_privateData + len, c, count); 576 577 return *this; 578 } 579 580 581 /*---- Prepending ----------------------------------------------------------*/ 582 // Prepend 583 /*! \brief Prepends the given string to the object. 584 \param str A pointer to the string to prepend. 585 \return This function always returns *this . 586 */ 587 BString& 588 BString::Prepend(const char *str) 589 { 590 if (str != NULL) 591 _DoPrepend(str, strlen(str)); 592 return *this; 593 } 594 595 596 // Prepend 597 /*! \brief Prepends the given BString to the object. 598 \param string The BString object to prepend. 599 \return This function always returns *this . 600 */ 601 BString& 602 BString::Prepend(const BString &string) 603 { 604 if (&string != this) 605 _DoPrepend(string.String(), string.Length()); 606 return *this; 607 } 608 609 610 // Prepend 611 /*! \brief Prepends the given string to the object. 612 \param str A pointer to the string to prepend. 613 \param length The maximum amount of bytes to get from the string. 614 \return This function always returns *this . 615 */ 616 BString& 617 BString::Prepend(const char *str, int32 length) 618 { 619 if (str != NULL) { 620 int32 len = strlen_clamp(str, length); 621 _DoPrepend(str, len); 622 } 623 return *this; 624 } 625 626 627 // Prepend 628 /*! \brief Prepends the given BString to the object. 629 \param string The BString object to prepend. 630 \param len The maximum amount of bytes to get from the BString. 631 \return This function always returns *this . 632 */ 633 BString& 634 BString::Prepend(const BString &string, int32 len) 635 { 636 if (&string != this) 637 _DoPrepend(string.String(), min_clamp0(len, string.Length())); 638 return *this; 639 } 640 641 642 // Prepend 643 /*! \brief Prepends the given character to the object. 644 \param c The character to prepend. 645 \param count The amount of characters to prepend. 646 \return This function always returns *this . 647 */ 648 BString& 649 BString::Prepend(char c, int32 count) 650 { 651 if (count > 0 && _OpenAtBy(0, count)) 652 memset(_privateData, c, count); 653 654 return *this; 655 } 656 657 658 /*---- Inserting ----------------------------------------------------------*/ 659 // Insert 660 /*! \brief Inserts the given string at the given position into the object's data. 661 \param str A pointer to the string to insert. 662 \param pos The offset into the BString's data where to insert the string. 663 \return This function always returns *this . 664 */ 665 BString& 666 BString::Insert(const char *str, int32 pos) 667 { 668 if (str != NULL) { 669 CHECK_PARAM(pos <= Length(), "'pos' exceeds length!"); 670 int32 len = (int32)strlen(str); 671 if (pos < 0) { 672 int32 skipLen = min_clamp0(-1 * pos, len); 673 str += skipLen; 674 len -= skipLen; 675 pos = 0; 676 } else 677 pos = min_clamp0(pos, Length()); 678 if (_OpenAtBy(pos, len)) 679 memcpy(_privateData + pos, str, len); 680 } 681 return *this; 682 } 683 684 685 // Insert 686 /*! \brief Inserts the given string at the given position into the object's data. 687 \param str A pointer to the string to insert. 688 \param length The amount of bytes to insert. 689 \param pos The offset into the BString's data where to insert the string. 690 \return This function always returns *this . 691 */ 692 BString& 693 BString::Insert(const char *str, int32 length, int32 pos) 694 { 695 if (str != NULL) { 696 CHECK_PARAM(pos <= Length(), "'pos' exceeds length!"); 697 int32 len = strlen_clamp(str, length); 698 if (pos < 0) { 699 int32 skipLen = min_clamp0(-1 * pos, len); 700 str += skipLen; 701 len -= skipLen; 702 pos = 0; 703 } else 704 pos = min_clamp0(pos, Length()); 705 if (_OpenAtBy(pos, len)) 706 memcpy(_privateData + pos, str, len); 707 } 708 return *this; 709 } 710 711 712 // Insert 713 /*! \brief Inserts the given string at the given position into the object's data. 714 \param str A pointer to the string to insert. 715 \param fromOffset 716 \param length The amount of bytes to insert. 717 \param pos The offset into the BString's data where to insert the string. 718 \return This function always returns *this . 719 */ 720 BString& 721 BString::Insert(const char *str, int32 fromOffset, int32 length, int32 pos) 722 { 723 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 724 return Insert(str + fromOffset, length, pos); 725 } 726 727 728 // Insert 729 /*! \brief Inserts the given BString at the given position into the object's data. 730 \param string The BString object to insert. 731 \param pos The offset into the BString's data where to insert the string. 732 \return This function always returns *this . 733 */ 734 BString& 735 BString::Insert(const BString &string, int32 pos) 736 { 737 if (&string != this) 738 Insert(string.String(), pos); //TODO: Optimize 739 return *this; 740 } 741 742 743 // Insert 744 /*! \brief Inserts the given BString at the given position into the object's data. 745 \param string The BString object to insert. 746 \param length The amount of bytes to insert. 747 \param pos The offset into the BString's data where to insert the string. 748 \return This function always returns *this . 749 */ 750 BString& 751 BString::Insert(const BString &string, int32 length, int32 pos) 752 { 753 if (&string != this) 754 Insert(string.String(), length, pos); //TODO: Optimize 755 return *this; 756 } 757 758 759 // Insert 760 /*! \brief Inserts the given string at the given position into the object's data. 761 \param string The BString object to insert. 762 \param fromOffset 763 \param length The amount of bytes to insert. 764 \param pos The offset into the BString's data where to insert the string. 765 \return This function always returns *this . 766 */ 767 BString& 768 BString::Insert(const BString &string, int32 fromOffset, int32 length, int32 pos) 769 { 770 if (&string != this) { 771 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 772 Insert(string.String() + fromOffset, length, pos); 773 } 774 return *this; 775 } 776 777 778 // Insert 779 /*! \brief Inserts the given character at the given position into the object's data. 780 \param c The character to insert. 781 \param count The amount of bytes to insert. 782 \param pos The offset into the BString's data where to insert the string. 783 \return This function always returns *this . 784 */ 785 BString& 786 BString::Insert(char c, int32 count, int32 pos) 787 { 788 CHECK_PARAM(pos <= Length(), "'pos' exceeds length!"); 789 if (pos < 0) { 790 count = max_c(count + pos, 0); 791 pos = 0; 792 } else 793 pos = min_clamp0(pos, Length()); 794 795 if (count > 0 && _OpenAtBy(pos, count)) 796 memset(_privateData + pos, c, count); 797 798 return *this; 799 } 800 801 802 /*---- Removing -----------------------------------------------------------*/ 803 // Truncate 804 /*! \brief Truncate the string to the new length. 805 \param newLength The new lenght of the string. 806 \param lazy If true, the memory-optimisation is postponed to later 807 \return This function always returns *this . 808 */ 809 BString& 810 BString::Truncate(int32 newLength, bool lazy) 811 { 812 if (newLength < 0) 813 newLength = 0; 814 815 int32 curLen = Length(); 816 817 if (newLength < curLen) { 818 if (lazy) { 819 // don't free memory yet, just set new length: 820 // XXX: Uhm, where do we keep track of the amount 821 // of memory we allocated ? 822 _SetLength(newLength); 823 _privateData[newLength] = '\0'; 824 } else 825 _GrowBy(newLength - curLen); //Negative 826 } 827 return *this; 828 } 829 830 831 // Remove 832 /*! \brief Removes some bytes, starting at the given offset 833 \param from The offset from which you want to start removing 834 \param length The number of bytes to remove 835 \return This function always returns *this . 836 */ 837 BString& 838 BString::Remove(int32 from, int32 length) 839 { 840 int32 len = Length(); 841 if (from < 0) { 842 int32 skipLen = min_clamp0(from, len); 843 len -= skipLen; 844 from = 0; 845 } else 846 from = min_clamp0(from, len); 847 _ShrinkAtBy(from, min_clamp0(length, len - from)); 848 return *this; 849 } 850 851 852 // Remove 853 /*! \brief Removes the first occurrence of the given BString. 854 \param string The BString to remove. 855 \return This function always returns *this . 856 */ 857 BString& 858 BString::RemoveFirst(const BString &string) 859 { 860 int32 pos = _ShortFindAfter(string.String(), string.Length()); 861 862 if (pos >= 0) 863 _ShrinkAtBy(pos, string.Length()); 864 865 return *this; 866 } 867 868 869 // Remove 870 /*! \brief Removes the last occurrence of the given BString. 871 \param string The BString to remove. 872 \return This function always returns *this . 873 */ 874 BString& 875 BString::RemoveLast(const BString &string) 876 { 877 int32 pos = _FindBefore(string.String(), Length(), string.Length()); 878 879 if (pos >= 0) 880 _ShrinkAtBy(pos, string.Length()); 881 882 return *this; 883 } 884 885 886 // Remove 887 /*! \brief Removes all occurrences of the given BString. 888 \param string The BString to remove. 889 \return This function always returns *this . 890 */ 891 BString& 892 BString::RemoveAll(const BString &string) 893 { 894 return _DoReplace(string.String(), "", REPLACE_ALL, 0, KEEP_CASE); 895 } 896 897 898 // Remove 899 /*! \brief Removes the first occurrence of the given string. 900 \param str A pointer to the string to remove. 901 \return This function always returns *this . 902 */ 903 BString& 904 BString::RemoveFirst(const char *str) 905 { 906 if (str != NULL) { 907 int32 pos = _ShortFindAfter(str, strlen(str)); 908 if (pos >= 0) 909 _ShrinkAtBy(pos, strlen(str)); 910 } 911 return *this; 912 } 913 914 915 // Remove 916 /*! \brief Removes the last occurrence of the given string. 917 \param str A pointer to the string to remove. 918 \return This function always returns *this . 919 */ 920 BString& 921 BString::RemoveLast(const char *str) 922 { 923 if (str != NULL) { 924 int32 len = strlen(str); 925 int32 pos = _FindBefore(str, Length(), len); 926 if (pos >= 0) 927 _ShrinkAtBy(pos, len); 928 } 929 return *this; 930 } 931 932 933 // Remove 934 /*! \brief Removes all occurrences of the given string. 935 \param str A pointer to the string to remove. 936 \return This function always returns *this . 937 */ 938 BString& 939 BString::RemoveAll(const char *str) 940 { 941 return _DoReplace(str, "", REPLACE_ALL, 0, KEEP_CASE); 942 } 943 944 945 // Remove 946 /*! \brief Removes all the characters specified. 947 \param setOfCharsToRemove The set of characters to remove. 948 \return This function always returns *this . 949 */ 950 BString& 951 BString::RemoveSet(const char *setOfCharsToRemove) 952 { 953 return ReplaceSet(setOfCharsToRemove, ""); 954 } 955 956 957 // MoveInto 958 /*! \brief Move the BString data (or part of it) into another BString. 959 \param into The BString where to move the object. 960 \param from The offset (zero based) where to begin the move 961 \param length The amount of bytes to move. 962 \return This function always returns into. 963 */ 964 BString& 965 BString::MoveInto(BString &into, int32 from, int32 length) 966 { 967 CHECK_PARAM_RET(from >= 0, "'from' must not be negative!", into); 968 CHECK_PARAM_RET(from <= Length(), "'from' exceeds length!", into); 969 int32 len = min_clamp0(length, Length() - from); 970 if (&into == this) { 971 /* TODO: [zooey]: to be activated later (>R1): 972 // strings are identical, just move the data: 973 if (from>0 && _privateData) 974 memmove( _privateData, _privateData+from, len); 975 Truncate( len); 976 */ 977 return *this; 978 } 979 into.SetTo(String() + from, len); 980 _ShrinkAtBy(from, len); 981 982 return into; 983 } 984 985 986 // MoveInto 987 /*! \brief Move the BString data (or part of it) into the given buffer. 988 \param into The buffer where to move the object. 989 \param from The offset (zero based) where to begin the move 990 \param length The amount of bytes to move. 991 */ 992 void 993 BString::MoveInto(char *into, int32 from, int32 length) 994 { 995 if (into != NULL) { 996 CHECK_PARAM_VOID(from >= 0, "'from' must not be negative!"); 997 CHECK_PARAM_VOID(from <= Length(), "'from' exceeds length!"); 998 int32 len = min_clamp0(length, Length() - from); 999 memcpy(into, String() + from, len); 1000 into[len] = '\0'; 1001 _ShrinkAtBy(from, len); 1002 } 1003 } 1004 1005 1006 /*---- Compare functions ---------------------------------------------------*/ 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 /*---- strcmp-style compare functions --------------------------------------*/ 1043 int 1044 BString::Compare(const BString &string) const 1045 { 1046 return strcmp(String(), string.String()); 1047 } 1048 1049 1050 int 1051 BString::Compare(const char *string) const 1052 { 1053 return strcmp(String(), safestr(string)); 1054 } 1055 1056 1057 int 1058 BString::Compare(const BString &string, int32 n) const 1059 { 1060 return strncmp(String(), string.String(), n); 1061 } 1062 1063 1064 int 1065 BString::Compare(const char *string, int32 n) const 1066 { 1067 return strncmp(String(), safestr(string), n); 1068 } 1069 1070 1071 int 1072 BString::ICompare(const BString &string) const 1073 { 1074 return strcasecmp(String(), string.String()); 1075 } 1076 1077 1078 int 1079 BString::ICompare(const char *str) const 1080 { 1081 return strcasecmp(String(), safestr(str)); 1082 } 1083 1084 1085 int 1086 BString::ICompare(const BString &string, int32 n) const 1087 { 1088 return strncasecmp(String(), string.String(), n); 1089 } 1090 1091 1092 int 1093 BString::ICompare(const char *str, int32 n) const 1094 { 1095 return strncasecmp(String(), safestr(str), n); 1096 } 1097 1098 1099 /*---- Searching -----------------------------------------------------------*/ 1100 // FindFirst 1101 /*! \brief Find the first occurrence of the given BString. 1102 \param string The BString to search for. 1103 \return The offset(zero based) into the data 1104 where the given BString has been found. 1105 */ 1106 int32 1107 BString::FindFirst(const BString &string) const 1108 { 1109 return _ShortFindAfter(string.String(), string.Length()); 1110 } 1111 1112 1113 // FindFirst 1114 /*! \brief Find the first occurrence of the given string. 1115 \param string The string to search for. 1116 \return The offset(zero based) into the data 1117 where the given string has been found. 1118 */ 1119 int32 1120 BString::FindFirst(const char *string) const 1121 { 1122 if (string == NULL) 1123 return B_BAD_VALUE; 1124 return _ShortFindAfter(string, strlen(string)); 1125 } 1126 1127 1128 // FindFirst 1129 /*! \brief Find the first occurrence of the given BString, 1130 starting from the given offset. 1131 \param string The BString to search for. 1132 \param fromOffset The offset where to start the search. 1133 \return An integer which is the offset(zero based) into the data 1134 where the given BString has been found. 1135 */ 1136 int32 1137 BString::FindFirst(const BString &string, int32 fromOffset) const 1138 { 1139 if (fromOffset < 0) 1140 return B_ERROR; 1141 return _FindAfter(string.String(), min_clamp0(fromOffset, Length()), 1142 string.Length()); 1143 } 1144 1145 1146 // FindFirst 1147 /*! \brief Find the first occurrence of the given string, 1148 starting from the given offset. 1149 \param string The string to search for. 1150 \param fromOffset The offset where to start the search. 1151 \return The offset(zero based) into the data 1152 where the given string has been found. 1153 */ 1154 int32 1155 BString::FindFirst(const char *string, int32 fromOffset) const 1156 { 1157 if (string == NULL) 1158 return B_BAD_VALUE; 1159 if (fromOffset < 0) 1160 return B_ERROR; 1161 return _FindAfter(string, min_clamp0(fromOffset, Length()), strlen(string)); 1162 } 1163 1164 1165 // FindFirst 1166 /*! \brief Find the first occurrence of the given character. 1167 \param c The character to search for. 1168 \return The offset(zero based) into the data 1169 where the given character has been found. 1170 */ 1171 int32 1172 BString::FindFirst(char c) const 1173 { 1174 const char *start = String(); 1175 const char *end = String() + Length(); /* String's end */ 1176 1177 /* Scans the string until we find the character, */ 1178 /* or we hit the string's end */ 1179 while(start != end && *start != c) 1180 start++; 1181 1182 if (start == end) 1183 return B_ERROR; 1184 1185 return start - String(); 1186 } 1187 1188 1189 // FindFirst 1190 /*! \brief Find the first occurrence of the given character, 1191 starting from the given offset. 1192 \param c The character to search for. 1193 \param fromOffset The offset where to start the search. 1194 \return The offset(zero based) into the data 1195 where the given character has been found. 1196 */ 1197 int32 1198 BString::FindFirst(char c, int32 fromOffset) const 1199 { 1200 if (fromOffset < 0) 1201 return B_ERROR; 1202 1203 const char *start = String() + min_clamp0(fromOffset, Length()); 1204 const char *end = String() + Length(); /* String's end */ 1205 1206 /* Scans the string until we found the character, */ 1207 /* or we hit the string's end */ 1208 while(start < end && *start != c) 1209 start++; 1210 1211 if (start >= end) 1212 return B_ERROR; 1213 1214 return start - String(); 1215 } 1216 1217 1218 // FindLast 1219 /*! \brief Find the last occurrence of the given BString. 1220 \param string The BString to search for. 1221 \return The offset(zero based) into the data 1222 where the given BString has been found. 1223 */ 1224 int32 1225 BString::FindLast(const BString &string) const 1226 { 1227 return _FindBefore(string.String(), Length(), string.Length()); 1228 } 1229 1230 1231 // FindLast 1232 /*! \brief Find the last occurrence of the given string. 1233 \param string The string to search for. 1234 \return The offset(zero based) into the data 1235 where the given string has been found. 1236 */ 1237 int32 1238 BString::FindLast(const char *string) const 1239 { 1240 if (string == NULL) 1241 return B_BAD_VALUE; 1242 return _FindBefore(string, Length(), strlen(string)); 1243 } 1244 1245 1246 // FindLast 1247 /*! \brief Find the last occurrence of the given BString, 1248 starting from the given offset, and going backwards. 1249 \param string The BString to search for. 1250 \param beforeOffset The offset where to start the search. 1251 \return An integer which is the offset(zero based) into the data 1252 where the given BString has been found. 1253 */ 1254 int32 1255 BString::FindLast(const BString &string, int32 beforeOffset) const 1256 { 1257 if (beforeOffset < 0) 1258 return B_ERROR; 1259 return _FindBefore(string.String(), min_clamp0(beforeOffset, Length()), 1260 string.Length()); 1261 } 1262 1263 1264 // FindLast 1265 /*! \brief Find the last occurrence of the given string, 1266 starting from the given offset, and going backwards. 1267 \param string The string to search for. 1268 \return The offset(zero based) into the data 1269 where the given string has been found. 1270 */ 1271 int32 1272 BString::FindLast(const char *string, int32 beforeOffset) const 1273 { 1274 if (string == NULL) 1275 return B_BAD_VALUE; 1276 if (beforeOffset < 0) 1277 return B_ERROR; 1278 return _FindBefore(string, min_clamp0(beforeOffset, Length()), strlen(string)); 1279 } 1280 1281 1282 // FindLast 1283 /*! \brief Find the last occurrence of the given character. 1284 \param c The character to search for. 1285 \return The offset(zero based) into the data 1286 where the given character has been found. 1287 */ 1288 int32 1289 BString::FindLast(char c) const 1290 { 1291 const char *start = String(); 1292 const char *end = String() + Length(); /* String's end */ 1293 1294 /* Scans the string backwards until we found the character, */ 1295 /* or we reach the string's start */ 1296 while(end != start && *end != c) 1297 end--; 1298 1299 if (end == start) 1300 return B_ERROR; 1301 1302 return end - String(); 1303 } 1304 1305 1306 // FindLast 1307 /*! \brief Find the last occurrence of the given character, 1308 starting from the given offset and going backwards. 1309 \param c The character to search for. 1310 \param beforeOffset The offset where to start the search. 1311 \return The offset(zero based) into the data 1312 where the given character has been found. 1313 */ 1314 int32 1315 BString::FindLast(char c, int32 beforeOffset) const 1316 { 1317 if (beforeOffset < 0) 1318 return B_ERROR; 1319 1320 const char *start = String(); 1321 const char *end = String() + Length() - beforeOffset; 1322 1323 /* Scans the string backwards until we found the character, */ 1324 /* or we reach the string's start */ 1325 while(end > start && *end != c) 1326 end--; 1327 1328 if (end <= start) 1329 return B_ERROR; 1330 1331 return end - String(); 1332 } 1333 1334 1335 int32 1336 BString::IFindFirst(const BString &string) const 1337 { 1338 return _IFindAfter(string.String(), 0, string.Length()); 1339 } 1340 1341 1342 int32 1343 BString::IFindFirst(const char *string) const 1344 { 1345 if (string == NULL) 1346 return B_BAD_VALUE; 1347 return _IFindAfter(string, 0, strlen(string)); 1348 } 1349 1350 1351 int32 1352 BString::IFindFirst(const BString &string, int32 fromOffset) const 1353 { 1354 if (fromOffset < 0) 1355 return B_ERROR; 1356 return _IFindAfter(string.String(), min_clamp0(fromOffset, Length()), 1357 string.Length()); 1358 } 1359 1360 1361 int32 1362 BString::IFindFirst(const char *string, int32 fromOffset) const 1363 { 1364 if (string == NULL) 1365 return B_BAD_VALUE; 1366 if (fromOffset < 0) 1367 return B_ERROR; 1368 return _IFindAfter(string, min_clamp0(fromOffset,Length()), strlen(string)); 1369 } 1370 1371 1372 int32 1373 BString::IFindLast(const BString &string) const 1374 { 1375 return _IFindBefore(string.String(), Length(), string.Length()); 1376 } 1377 1378 1379 int32 1380 BString::IFindLast(const char *string) const 1381 { 1382 if (string == NULL) 1383 return B_BAD_VALUE; 1384 return _IFindBefore(string, Length(), strlen(string)); 1385 } 1386 1387 1388 int32 1389 BString::IFindLast(const BString &string, int32 beforeOffset) const 1390 { 1391 if (beforeOffset < 0) 1392 return B_ERROR; 1393 return _IFindBefore(string.String(), min_clamp0(beforeOffset, Length()), 1394 string.Length()); 1395 } 1396 1397 1398 int32 1399 BString::IFindLast(const char *string, int32 beforeOffset) const 1400 { 1401 if (string == NULL) 1402 return B_BAD_VALUE; 1403 if (beforeOffset < 0) 1404 return B_ERROR; 1405 return _IFindBefore(string, min_clamp0(beforeOffset,Length()), 1406 strlen(string)); 1407 } 1408 1409 1410 /*---- Replacing -----------------------------------------------------------*/ 1411 BString& 1412 BString::ReplaceFirst(char replaceThis, char withThis) 1413 { 1414 int32 pos = FindFirst(replaceThis); 1415 1416 if (pos >= 0) 1417 _privateData[pos] = withThis; 1418 1419 return *this; 1420 } 1421 1422 1423 BString& 1424 BString::ReplaceLast(char replaceThis, char withThis) 1425 { 1426 int32 pos = FindLast(replaceThis); 1427 1428 if (pos >= 0) 1429 _privateData[pos] = withThis; 1430 1431 return *this; 1432 } 1433 1434 1435 BString& 1436 BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset) 1437 { 1438 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1439 for (int32 pos = min_clamp0(fromOffset, Length());;) { 1440 pos = FindFirst(replaceThis, pos); 1441 if (pos < 0) 1442 break; 1443 _privateData[pos] = withThis; 1444 } 1445 1446 return *this; 1447 } 1448 1449 1450 BString& 1451 BString::Replace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset) 1452 { 1453 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1454 if (maxReplaceCount > 0) { 1455 for (int32 pos = min_clamp0(fromOffset, Length()); 1456 maxReplaceCount > 0; maxReplaceCount--) { 1457 pos = FindFirst(replaceThis, pos); 1458 if (pos < 0) 1459 break; 1460 _privateData[pos] = withThis; 1461 } 1462 } 1463 return *this; 1464 } 1465 1466 1467 BString& 1468 BString::ReplaceFirst(const char *replaceThis, const char *withThis) 1469 { 1470 return _DoReplace( replaceThis, withThis, 1, 0, KEEP_CASE); 1471 } 1472 1473 1474 BString& 1475 BString::ReplaceLast(const char *replaceThis, const char *withThis) 1476 { 1477 if (replaceThis == NULL) 1478 return *this; 1479 1480 int32 firstStringLength = strlen(replaceThis); 1481 int32 pos = _FindBefore(replaceThis, Length(), firstStringLength); 1482 1483 if (pos >= 0) { 1484 int32 len = (withThis ? strlen(withThis) : 0); 1485 int32 difference = len - firstStringLength; 1486 1487 if (difference > 0) { 1488 if (!_OpenAtBy(pos, difference)) 1489 return *this; 1490 } else if (difference < 0) { 1491 if (!_ShrinkAtBy(pos, -difference)) 1492 return *this; 1493 } 1494 memcpy(_privateData + pos, withThis, len); 1495 } 1496 1497 return *this; 1498 } 1499 1500 1501 BString& 1502 BString::ReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset) 1503 { 1504 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1505 return _DoReplace(replaceThis, withThis, REPLACE_ALL, 1506 min_clamp0(fromOffset,Length()), KEEP_CASE); 1507 } 1508 1509 1510 BString& 1511 BString::Replace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset) 1512 { 1513 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1514 return _DoReplace(replaceThis, withThis, maxReplaceCount, 1515 min_clamp0(fromOffset,Length()), KEEP_CASE); 1516 } 1517 1518 1519 BString& 1520 BString::IReplaceFirst(char replaceThis, char withThis) 1521 { 1522 char tmp[2] = { replaceThis, '\0' }; 1523 int32 pos = _IFindAfter(tmp, 0, 1); 1524 1525 if (pos >= 0) 1526 _privateData[pos] = withThis; 1527 1528 return *this; 1529 } 1530 1531 1532 BString& 1533 BString::IReplaceLast(char replaceThis, char withThis) 1534 { 1535 char tmp[2] = { replaceThis, '\0' }; 1536 int32 pos = _IFindBefore(tmp, Length(), 1); 1537 1538 if (pos >= 0) 1539 _privateData[pos] = withThis; 1540 1541 return *this; 1542 } 1543 1544 1545 BString& 1546 BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset) 1547 { 1548 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1549 1550 char tmp[2] = { replaceThis, '\0' }; 1551 1552 for (int32 pos = min_clamp0(fromOffset, Length());;) { 1553 pos = _IFindAfter(tmp, pos, 1); 1554 if (pos < 0) 1555 break; 1556 _privateData[pos] = withThis; 1557 } 1558 return *this; 1559 } 1560 1561 1562 BString& 1563 BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset) 1564 { 1565 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1566 1567 char tmp[2] = { replaceThis, '\0' }; 1568 1569 if (_privateData == NULL) 1570 return *this; 1571 1572 for (int32 pos = min_clamp0(fromOffset,Length()); 1573 maxReplaceCount > 0; maxReplaceCount--) { 1574 pos = _IFindAfter(tmp, pos, 1); 1575 if (pos < 0) 1576 break; 1577 _privateData[pos] = withThis; 1578 } 1579 return *this; 1580 } 1581 1582 1583 BString& 1584 BString::IReplaceFirst(const char *replaceThis, const char *withThis) 1585 { 1586 return _DoReplace(replaceThis, withThis, 1, 0, IGNORE_CASE); 1587 } 1588 1589 1590 BString& 1591 BString::IReplaceLast(const char *replaceThis, const char *withThis) 1592 { 1593 if (replaceThis == NULL) 1594 return *this; 1595 1596 int32 firstStringLength = strlen(replaceThis); 1597 int32 pos = _IFindBefore(replaceThis, Length(), firstStringLength); 1598 1599 if (pos >= 0) { 1600 int32 len = (withThis ? strlen(withThis) : 0); 1601 int32 difference = len - firstStringLength; 1602 1603 if (difference > 0) { 1604 if (!_OpenAtBy(pos, difference)) 1605 return *this; 1606 } else if (difference < 0) { 1607 if (!_ShrinkAtBy(pos, -difference)) 1608 return *this; 1609 } 1610 memcpy(_privateData + pos, withThis, len); 1611 1612 } 1613 1614 return *this; 1615 } 1616 1617 1618 BString& 1619 BString::IReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset) 1620 { 1621 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1622 return _DoReplace(replaceThis, withThis, REPLACE_ALL, 1623 min_clamp0(fromOffset, Length()), IGNORE_CASE); 1624 } 1625 1626 1627 BString& 1628 BString::IReplace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset) 1629 { 1630 CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); 1631 return _DoReplace(replaceThis, withThis, maxReplaceCount, 1632 min_clamp0(fromOffset, Length()), IGNORE_CASE); 1633 } 1634 1635 1636 BString& 1637 BString::ReplaceSet(const char *setOfChars, char with) 1638 { 1639 if (setOfChars == NULL) 1640 return *this; 1641 1642 int32 offset = 0; 1643 int32 length = Length(); 1644 1645 for (int32 pos;;) { 1646 pos = strcspn(String() + offset, setOfChars); 1647 1648 offset += pos; 1649 if (offset >= length) 1650 break; 1651 1652 _privateData[offset] = with; 1653 offset++; 1654 } 1655 1656 return *this; 1657 } 1658 1659 BString& 1660 BString::ReplaceSet(const char *setOfChars, const char *with) 1661 { 1662 int32 withLen = with ? strlen(with) : 0; 1663 if (withLen == 1) 1664 // delegate simple case: 1665 return ReplaceSet( setOfChars, *with); 1666 1667 if (setOfChars == NULL || _privateData == NULL) 1668 return *this; 1669 1670 PosVect positions; 1671 1672 int32 searchLen = 1; 1673 int32 len = Length(); 1674 int32 pos = 0; 1675 for (int32 offset = 0; offset < len; offset += (pos+searchLen)) 1676 { 1677 pos = strcspn(_privateData + offset, setOfChars); 1678 if (pos + offset >= len) 1679 break; 1680 if (!positions.Add(offset + pos)) 1681 return *this; 1682 } 1683 1684 _ReplaceAtPositions(&positions, searchLen, with, withLen); 1685 return *this; 1686 } 1687 1688 1689 /*---- Unchecked char access -----------------------------------------------*/ 1690 1691 // operator[] 1692 /*! \brief Returns a reference to the data at the given offset. 1693 1694 This function can be used to read a byte or to change its value. 1695 \param index The index (zero based) of the byte to get. 1696 \return Returns a reference to the specified byte. 1697 */ 1698 char & 1699 BString::operator[](int32 index) 1700 { 1701 return _privateData[index]; 1702 } 1703 1704 1705 /*---- Fast low-level manipulation -----------------------------------------*/ 1706 char* 1707 BString::LockBuffer(int32 maxLength) 1708 { 1709 _SetUsingAsCString(true); //debug 1710 1711 int32 len = Length(); 1712 1713 if (maxLength > len) { 1714 if (!_GrowBy(maxLength - len)) 1715 return NULL; 1716 if (!len && _privateData) 1717 // if string was empty before call to LockBuffer(), we make sure the 1718 // buffer represents an empty c-string: 1719 *_privateData = '\0'; 1720 } else if (!maxLength && !len) { 1721 // special case for unallocated string, we return an empty c-string: 1722 return const_cast<char*>(String()); 1723 } 1724 1725 return _privateData; 1726 } 1727 1728 1729 BString& 1730 BString::UnlockBuffer(int32 length) 1731 { 1732 _SetUsingAsCString(false); //debug 1733 1734 if (length < 0) 1735 length = (_privateData == NULL) ? 0 : strlen(_privateData); 1736 1737 if (length != Length()) 1738 _GrowBy(length - Length()); 1739 1740 return *this; 1741 } 1742 1743 1744 /*---- Uppercase<->Lowercase ------------------------------------------------*/ 1745 // ToLower 1746 /*! \brief Converts the BString to lowercase 1747 \return This function always returns *this . 1748 */ 1749 BString& 1750 BString::ToLower() 1751 { 1752 int32 length = Length(); 1753 for (int32 count = 0; count < length; count++) 1754 _privateData[count] = tolower(_privateData[count]); 1755 1756 return *this; 1757 } 1758 1759 1760 // ToUpper 1761 /*! \brief Converts the BString to uppercase 1762 \return This function always returns *this . 1763 */ 1764 BString& 1765 BString::ToUpper() 1766 { 1767 int32 length = Length(); 1768 for (int32 count = 0; count < length; count++) 1769 _privateData[count] = toupper(_privateData[count]); 1770 1771 return *this; 1772 } 1773 1774 1775 // Capitalize 1776 /*! \brief Converts the first character to uppercase, rest to lowercase 1777 \return This function always returns *this . 1778 */ 1779 BString& 1780 BString::Capitalize() 1781 { 1782 if (_privateData == NULL) 1783 return *this; 1784 1785 _privateData[0] = toupper(_privateData[0]); 1786 int32 length = Length(); 1787 1788 for (int32 count = 1; count < length; count++) 1789 _privateData[count] = tolower(_privateData[count]); 1790 1791 return *this; 1792 } 1793 1794 1795 // CapitalizeEachWord 1796 /*! \brief Converts the first character of every word to uppercase, rest to lowercase. 1797 1798 Converts the first character of every "word" (series of alpabetical characters 1799 separated by non alphabetical characters) to uppercase, and the rest to lowercase. 1800 \return This function always returns *this . 1801 */ 1802 BString& 1803 BString::CapitalizeEachWord() 1804 { 1805 if (_privateData == NULL) 1806 return *this; 1807 1808 int32 count = 0; 1809 int32 length = Length(); 1810 1811 do { 1812 // Find the first alphabetical character... 1813 for(; count < length; count++) { 1814 if (isalpha(_privateData[count])) { 1815 // ...found! Convert it to uppercase. 1816 _privateData[count] = toupper(_privateData[count]); 1817 count++; 1818 break; 1819 } 1820 } 1821 // Now find the first non-alphabetical character, 1822 // and meanwhile, turn to lowercase all the alphabetical ones 1823 for(; count < length; count++) { 1824 if (isalpha(_privateData[count])) 1825 _privateData[count] = tolower(_privateData[count]); 1826 else 1827 break; 1828 } 1829 } while (count < length); 1830 1831 return *this; 1832 } 1833 1834 1835 /*----- Escaping and Deescaping --------------------------------------------*/ 1836 BString& 1837 BString::CharacterEscape(const char *original, const char *setOfCharsToEscape, char escapeWith) 1838 { 1839 SetTo(original); 1840 CharacterEscape(setOfCharsToEscape, escapeWith); 1841 1842 return *this; 1843 } 1844 1845 1846 BString& 1847 BString::CharacterEscape(const char *setOfCharsToEscape, char escapeWith) 1848 { 1849 if (setOfCharsToEscape == NULL || _privateData == NULL) 1850 return *this; 1851 1852 PosVect positions; 1853 int32 len = Length(); 1854 int32 pos = 0; 1855 for (int32 offset = 0; offset < len; offset += pos + 1) { 1856 if ((pos = strcspn(_privateData + offset, setOfCharsToEscape)) < len - offset) 1857 if (!positions.Add(offset + pos)) 1858 return *this; 1859 } 1860 1861 uint32 count = positions.CountItems(); 1862 int32 newLength = len + count; 1863 if (!newLength) { 1864 _GrowBy( -len); 1865 return *this; 1866 } 1867 int32 lastPos = 0; 1868 char* oldAdr = _privateData; 1869 char* newData = (char*)malloc(newLength + sizeof(int32) + 1); 1870 if (newData) { 1871 newData += sizeof(int32); 1872 char* newAdr = newData; 1873 for (uint32 i = 0; i < count; ++i) { 1874 pos = positions.ItemAt( i); 1875 len = pos-lastPos; 1876 if (len > 0) { 1877 memcpy(newAdr, oldAdr, len); 1878 oldAdr += len; 1879 newAdr += len; 1880 } 1881 *newAdr++ = escapeWith; 1882 *newAdr++ = *oldAdr++; 1883 lastPos = pos + 1; 1884 } 1885 len = Length() + 1 - lastPos; 1886 if (len > 0) 1887 memcpy(newAdr, oldAdr, len); 1888 1889 free(_privateData - sizeof(int32)); 1890 _privateData = newData; 1891 _privateData[newLength] = 0; 1892 _SetLength( newLength); 1893 } 1894 1895 return *this; 1896 } 1897 1898 1899 BString& 1900 BString::CharacterDeescape(const char *original, char escapeChar) 1901 { 1902 SetTo(original); 1903 CharacterDeescape(escapeChar); 1904 1905 return *this; 1906 } 1907 1908 1909 BString& 1910 BString::CharacterDeescape(char escapeChar) 1911 { 1912 const char temp[2] = {escapeChar, 0}; 1913 return _DoReplace(temp, "", REPLACE_ALL, 0, KEEP_CASE); 1914 } 1915 1916 1917 /*---- Simple sprintf replacement calls ------------------------------------*/ 1918 /*---- Slower than sprintf but type and overflow safe ----------------------*/ 1919 BString& 1920 BString::operator<<(const char *str) 1921 { 1922 if (str != NULL) 1923 _DoAppend(str, strlen(str)); 1924 return *this; 1925 } 1926 1927 1928 BString& 1929 BString::operator<<(const BString &string) 1930 { 1931 _DoAppend(string.String(), string.Length()); 1932 return *this; 1933 } 1934 1935 1936 BString& 1937 BString::operator<<(char c) 1938 { 1939 _DoAppend(&c, 1); 1940 return *this; 1941 } 1942 1943 1944 BString& 1945 BString::operator<<(int i) 1946 { 1947 char num[64]; 1948 sprintf(num, "%d", i); 1949 1950 return *this << num; 1951 } 1952 1953 1954 BString& 1955 BString::operator<<(unsigned int i) 1956 { 1957 char num[64]; 1958 sprintf(num, "%u", i); 1959 1960 return *this << num; 1961 } 1962 1963 1964 BString& 1965 BString::operator<<(uint32 i) 1966 { 1967 char num[64]; 1968 sprintf(num, "%lu", i); 1969 1970 return *this << num; 1971 } 1972 1973 1974 BString& 1975 BString::operator<<(int32 i) 1976 { 1977 char num[64]; 1978 sprintf(num, "%ld", i); 1979 1980 return *this << num; 1981 } 1982 1983 1984 BString& 1985 BString::operator<<(uint64 i) 1986 { 1987 char num[64]; 1988 sprintf(num, "%llu", i); 1989 1990 return *this << num; 1991 } 1992 1993 1994 BString& 1995 BString::operator<<(int64 i) 1996 { 1997 char num[64]; 1998 sprintf(num, "%lld", i); 1999 2000 return *this << num; 2001 } 2002 2003 2004 BString& 2005 BString::operator<<(float f) 2006 { 2007 char num[64]; 2008 sprintf(num, "%.2f", f); 2009 2010 return *this << num; 2011 } 2012 2013 2014 /*---- Private or Reserved ------------------------------------------------*/ 2015 char * 2016 BString::_Alloc(int32 dataLen) 2017 { 2018 char *dataPtr = _privateData ? _privateData - sizeof(int32) : NULL; 2019 if (dataLen <= 0) { // release buffer if requested size is 0: 2020 free(dataPtr); 2021 _privateData = NULL; 2022 return NULL; 2023 } 2024 int32 allocLen = dataLen + sizeof(int32) + 1; 2025 dataPtr = (char *)realloc(dataPtr, allocLen); 2026 if (dataPtr) { 2027 dataPtr += sizeof(int32); 2028 _privateData = dataPtr; 2029 2030 _SetLength(dataLen); 2031 _privateData[dataLen] = '\0'; 2032 } 2033 return dataPtr; 2034 } 2035 2036 void 2037 BString::_Init(const char *str, int32 len) 2038 { 2039 if (_Alloc(len)) 2040 memcpy(_privateData, str, len); 2041 } 2042 2043 2044 #if ENABLE_INLINES 2045 inline 2046 #endif 2047 void 2048 BString::_DoAssign(const char *str, int32 len) 2049 { 2050 int32 curLen = Length(); 2051 2052 if (len == curLen || _GrowBy(len - curLen)) 2053 memcpy(_privateData, str, len); 2054 } 2055 2056 2057 #if ENABLE_INLINES 2058 inline 2059 #endif 2060 void 2061 BString::_DoAppend(const char *str, int32 len) 2062 { 2063 int32 length = Length(); 2064 if (_GrowBy(len)) 2065 memcpy(_privateData + length, str, len); 2066 } 2067 2068 2069 char* 2070 BString::_GrowBy(int32 size) 2071 { 2072 int32 newLen = Length() + size; 2073 return _Alloc(newLen); 2074 } 2075 2076 2077 char * 2078 BString::_OpenAtBy(int32 offset, int32 length) 2079 { 2080 int32 oldLength = Length(); 2081 2082 char* newData = _Alloc(oldLength + length); 2083 if (newData != NULL) 2084 memmove(_privateData + offset + length, _privateData + offset, 2085 oldLength - offset); 2086 2087 return newData; 2088 } 2089 2090 2091 char* 2092 BString::_ShrinkAtBy(int32 offset, int32 length) 2093 { 2094 if (!_privateData) 2095 return NULL; 2096 int32 oldLength = Length(); 2097 2098 memmove(_privateData + offset, _privateData + offset + length, 2099 oldLength - offset - length); 2100 2101 // the following actually should never fail, since we are reducing the size... 2102 return _Alloc(oldLength - length); 2103 } 2104 2105 2106 #if ENABLE_INLINES 2107 inline 2108 #endif 2109 void 2110 BString::_DoPrepend(const char *str, int32 count) 2111 { 2112 if (_OpenAtBy(0, count)) 2113 memcpy(_privateData, str, count); 2114 } 2115 2116 2117 /* XXX: These could be inlined too, if they are too slow */ 2118 int32 2119 BString::_FindAfter(const char *str, int32 offset, int32 strlen) const 2120 { 2121 char *ptr = strstr(String() + offset, str); 2122 2123 if (ptr != NULL) 2124 return ptr - String(); 2125 2126 return B_ERROR; 2127 } 2128 2129 2130 int32 2131 BString::_IFindAfter(const char *str, int32 offset, int32 strlen) const 2132 { 2133 char *ptr = strcasestr(String() + offset, str); 2134 2135 if (ptr != NULL) 2136 return ptr - String(); 2137 2138 return B_ERROR; 2139 } 2140 2141 2142 int32 2143 BString::_ShortFindAfter(const char *str, int32 len) const 2144 { 2145 char *ptr = strstr(String(), str); 2146 2147 if (ptr != NULL) 2148 return ptr - String(); 2149 2150 return B_ERROR; 2151 } 2152 2153 2154 int32 2155 BString::_FindBefore(const char *str, int32 offset, int32 strlen) const 2156 { 2157 if (_privateData) { 2158 const char *ptr = _privateData + offset - strlen; 2159 2160 while (ptr >= _privateData) { 2161 if (!memcmp(ptr, str, strlen)) 2162 return ptr - _privateData; 2163 ptr--; 2164 } 2165 } 2166 return B_ERROR; 2167 } 2168 2169 2170 int32 2171 BString::_IFindBefore(const char *str, int32 offset, int32 strlen) const 2172 { 2173 if (_privateData) { 2174 char *ptr1 = _privateData + offset - strlen; 2175 2176 while (ptr1 >= _privateData) { 2177 if (!strncasecmp(ptr1, str, strlen)) 2178 return ptr1 - _privateData; 2179 ptr1--; 2180 } 2181 } 2182 return B_ERROR; 2183 } 2184 2185 2186 BString& 2187 BString::_DoReplace(const char *findThis, const char *replaceWith, int32 maxReplaceCount, 2188 int32 fromOffset, bool ignoreCase) 2189 { 2190 if (findThis == NULL || maxReplaceCount <= 0 2191 || fromOffset < 0 || fromOffset >= Length()) 2192 return *this; 2193 2194 typedef int32 (BString::*TFindMethod)(const char *, int32, int32) const; 2195 TFindMethod findMethod = ignoreCase ? &BString::_IFindAfter : &BString::_FindAfter; 2196 int32 findLen = strlen(findThis); 2197 2198 if (!replaceWith) 2199 replaceWith = ""; 2200 2201 int32 replaceLen = strlen(replaceWith); 2202 int32 lastSrcPos = fromOffset; 2203 PosVect positions; 2204 for(int32 srcPos = 0; 2205 maxReplaceCount > 0 2206 && (srcPos = (this->*findMethod)(findThis, lastSrcPos, findLen)) >= 0; 2207 maxReplaceCount-- ) { 2208 positions.Add(srcPos); 2209 lastSrcPos = srcPos + findLen; 2210 } 2211 _ReplaceAtPositions(&positions, findLen, replaceWith, replaceLen); 2212 return *this; 2213 } 2214 2215 2216 void 2217 BString::_ReplaceAtPositions(const PosVect* positions, 2218 int32 searchLen, const char* with, 2219 int32 withLen) 2220 { 2221 int32 len = Length(); 2222 uint32 count = positions->CountItems(); 2223 int32 newLength = len + count * (withLen - searchLen); 2224 if (!newLength) { 2225 _GrowBy(-len); 2226 return; 2227 } 2228 int32 pos; 2229 int32 lastPos = 0; 2230 char *oldAdr = _privateData; 2231 char *newData = (char *)malloc(newLength + sizeof(int32) + 1); 2232 if (newData) { 2233 newData += sizeof(int32); 2234 char *newAdr = newData; 2235 for(uint32 i = 0; i < count; ++i) { 2236 pos = positions->ItemAt(i); 2237 len = pos - lastPos; 2238 if (len > 0) { 2239 memcpy(newAdr, oldAdr, len); 2240 oldAdr += len; 2241 newAdr += len; 2242 } 2243 memcpy(newAdr, with, withLen); 2244 oldAdr += searchLen; 2245 newAdr += withLen; 2246 lastPos = pos+searchLen; 2247 } 2248 len = Length() + 1 - lastPos; 2249 if (len > 0) 2250 memcpy(newAdr, oldAdr, len); 2251 2252 free(_privateData - sizeof(int32)); 2253 _privateData = newData; 2254 _privateData[newLength] = 0; 2255 _SetLength( newLength); 2256 } 2257 } 2258 2259 2260 #if ENABLE_INLINES 2261 inline 2262 #endif 2263 void 2264 BString::_SetLength(int32 length) 2265 { 2266 *((int32*)_privateData - 1) = length & 0x7fffffff; 2267 } 2268 2269 2270 #if DEBUG 2271 // AFAIK, these are not implemented in BeOS R5 2272 // XXX : Test these puppies 2273 void 2274 BString::_SetUsingAsCString(bool state) 2275 { 2276 //TODO: Implement ? 2277 } 2278 2279 2280 void 2281 BString::_AssertNotUsingAsCString() const 2282 { 2283 //TODO: Implement ? 2284 } 2285 #endif 2286 2287 2288 /*----- Non-member compare for sorting, etc. ------------------------------*/ 2289 int 2290 Compare(const BString &string1, const BString &string2) 2291 { 2292 return strcmp(string1.String(), string2.String()); 2293 } 2294 2295 2296 int 2297 ICompare(const BString &string1, const BString &string2) 2298 { 2299 return strcasecmp(string1.String(), string2.String()); 2300 } 2301 2302 2303 int 2304 Compare(const BString *string1, const BString *string2) 2305 { 2306 return strcmp(string1->String(), string2->String()); 2307 } 2308 2309 2310 int 2311 ICompare(const BString *string1, const BString *string2) 2312 { 2313 return strcasecmp(string1->String(), string2->String()); 2314 } 2315 2316