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