diff --git a/headers/os/support/String.h b/headers/os/support/String.h index 6d6fe86103..f5bf7e62ad 100644 --- a/headers/os/support/String.h +++ b/headers/os/support/String.h @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// Copyright (c) 2001-2002, OpenBeOS +// Copyright (c) 2001-2003, OpenBeOS // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), @@ -319,6 +319,14 @@ private: void _AssertNotUsingAsCString() const {} #endif + char *_Alloc( int32); + + struct PosVect; + void _ReplaceAtPositions( const PosVect* positions, + int32 searchLen, + const char* with, + int32 withLen); + protected: char *_privateData; }; diff --git a/src/kits/support/String.cpp b/src/kits/support/String.cpp index 3c65d60d7d..16a15ee010 100644 --- a/src/kits/support/String.cpp +++ b/src/kits/support/String.cpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// Copyright (c) 2001-2002, OpenBeOS +// Copyright (c) 2001-2003, OpenBeOS // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), @@ -19,17 +19,18 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // -// File Name: String.cpp -// Author(s): Marc Flerackers (mflerackers@androme.be) -// Stefano Ceccherini (burton666@libero.it) +// File Name: String.cpp +// Author(s): Marc Flerackers (mflerackers@androme.be) +// Stefano Ceccherini (burton666@libero.it) +// Oliver Tappe (openbeos@hirschkaefer.de) // -// Description: String class supporting common string operations. +// Description: String class supporting common string operations. //------------------------------------------------------------------------------ // Standard Includes ----------------------------------------------------------- -#include -#include -#include +#include +#include +#include // System Includes ------------------------------------------------------------- #include @@ -38,14 +39,120 @@ // Temporary Includes #include "string_helper.h" - #define ENABLE_INLINES 0 // Set this to 1 to make some private methods inline - // define proper names for case-option of _DoReplace() #define KEEP_CASE false #define IGNORE_CASE true +// define proper names for count-option of _DoReplace() +#define REPLACE_ALL 0x7FFFFFFF + + +// helper function, returns minimum of two given values (but clamps to 0): +static inline int32 +min_clamp0(int32 num1, int32 num2) +{ + if (num1 0 ? num1 : 0; + else + return num2 > 0 ? num2 : 0; +} + + +// helper function, returns length of given string (but clamps to given maximum): +static inline int32 +strlen_clamp(const char* str, int32 max) +{ // this should yield 0 for max<0: + int32 len=0; + while( lenStefano Ceccherini + \author = 0, "'fromOffset' must not be negative!", + into); + CHECK_PARAM_RET(fromOffset <= Length(), "'fromOffset' exceeds length!", + into); into.SetTo(String() + fromOffset, length); + } return into; } @@ -389,10 +493,10 @@ BString::CopyInto(BString &into, int32 fromOffset, int32 length) const void BString::CopyInto(char *into, int32 fromOffset, int32 length) const { - if (into != NULL) - { - int32 len = Length() - fromOffset; - len = min_c(len, length); + if (into != NULL) { + CHECK_PARAM_VOID(fromOffset >= 0, "'fromOffset' must not be negative!"); + CHECK_PARAM_VOID(fromOffset <= Length(), "'fromOffset' exceeds length!"); + int32 len = min_clamp0(length, Length() - fromOffset); memcpy(into, _privateData + fromOffset, len); } } @@ -421,9 +525,7 @@ BString::operator+=(const char *str) BString& BString::operator+=(char c) { - _GrowBy(1); - _privateData[Length() - 1] = c; - + _DoAppend(&c, 1); return *this; } @@ -437,7 +539,7 @@ BString::operator+=(char c) BString& BString::Append(const BString &string, int32 length) { - _DoAppend(string.String(), min_c(length, string.Length())); + _DoAppend(string.String(), min_clamp0(length, string.Length())); return *this; } @@ -451,10 +553,9 @@ BString::Append(const BString &string, int32 length) BString& BString::Append(const char *str, int32 length) { - if (str != NULL) - { - int32 len = (int32)strlen(str); - _DoAppend(str, min_c(len, length)); + if (str != NULL) { + int32 len = strlen_clamp(str, length); + _DoAppend(str, len); } return *this; } @@ -470,8 +571,8 @@ BString& BString::Append(char c, int32 count) { int32 len = Length(); - _GrowBy(count); - memset(_privateData + len, c, count); + if (count > 0 && _GrowBy(count)) + memset(_privateData + len, c, count); return *this; } @@ -515,10 +616,9 @@ BString::Prepend(const BString &string) BString& BString::Prepend(const char *str, int32 length) { - if (str != NULL) - { - int32 len = (int32)strlen(str); - _DoPrepend(str, min_c(len, length)); + if (str != NULL) { + int32 len = strlen_clamp(str, length); + _DoPrepend(str, len); } return *this; } @@ -534,7 +634,7 @@ BString& BString::Prepend(const BString &string, int32 len) { if (&string != this) - _DoPrepend(string.String(), min_c(len, string.Length())); + _DoPrepend(string.String(), min_clamp0(len, string.Length())); return *this; } @@ -548,8 +648,8 @@ BString::Prepend(const BString &string, int32 len) BString& BString::Prepend(char c, int32 count) { - _OpenAtBy(0, count); - memset(_privateData, c, count); + if (count > 0 && _OpenAtBy(0, count)) + memset(_privateData, c, count); return *this; } @@ -565,15 +665,18 @@ BString::Prepend(char c, int32 count) BString& BString::Insert(const char *str, int32 pos) { - if (str != NULL) - { - if (pos < 0) - { - str -= pos; + if (str != NULL) { + CHECK_PARAM(pos <= Length(), "'pos' exceeds length!"); + int32 len = (int32)strlen(str); + if (pos < 0) { + int32 skipLen = min_clamp0(-1 * pos, len); + str += skipLen; + len -= skipLen; pos = 0; - } - _privateData = _OpenAtBy(pos, strlen(str)); - memcpy(_privateData + pos, str, strlen(str)); + } else + pos = min_clamp0(pos, Length()); + if (_OpenAtBy(pos, len)) + memcpy(_privateData + pos, str, len); } return *this; } @@ -589,17 +692,18 @@ BString::Insert(const char *str, int32 pos) BString& BString::Insert(const char *str, int32 length, int32 pos) { - if (str != NULL) - { - if (pos < 0) - { - str -= pos; + if (str != NULL) { + CHECK_PARAM(pos <= Length(), "'pos' exceeds length!"); + int32 len = strlen_clamp(str, length); + if (pos < 0) { + int32 skipLen = min_clamp0(-1 * pos, len); + str += skipLen; + len -= skipLen; pos = 0; - } - int32 len = (int32)strlen(str); - len = min_c(len, length); - _OpenAtBy(pos, len); - memcpy(_privateData + pos, str, len); + } else + pos = min_clamp0(pos, Length()); + if (_OpenAtBy(pos, len)) + memcpy(_privateData + pos, str, len); } return *this; } @@ -616,14 +720,8 @@ BString::Insert(const char *str, int32 length, int32 pos) BString& BString::Insert(const char *str, int32 fromOffset, int32 length, int32 pos) { - if (str != NULL) - { - int32 len = (int32)strlen(str); - len = min_c(len - fromOffset, length); - _privateData = _OpenAtBy(pos, len); - memcpy(_privateData + pos, str + fromOffset, len); - } - return *this; + CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); + return Insert(str + fromOffset, length, pos); } @@ -669,8 +767,10 @@ BString::Insert(const BString &string, int32 length, int32 pos) BString& BString::Insert(const BString &string, int32 fromOffset, int32 length, int32 pos) { - if (&string != this) - Insert(string.String(), fromOffset, length, pos); //TODO: Optimize + if (&string != this) { + CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); + Insert(string.String() + fromOffset, length, pos); + } return *this; } @@ -685,8 +785,15 @@ BString::Insert(const BString &string, int32 fromOffset, int32 length, int32 pos BString& BString::Insert(char c, int32 count, int32 pos) { - _OpenAtBy(pos, count); - memset(_privateData + pos, c, count); + CHECK_PARAM(pos <= Length(), "'pos' exceeds length!"); + if (pos < 0) { + count = max_c(count + pos, 0); + pos = 0; + } else + pos = min_clamp0(pos, Length()); + + if (count > 0 && _OpenAtBy(pos, count)) + memset(_privateData + pos, c, count); return *this; } @@ -696,7 +803,7 @@ BString::Insert(char c, int32 count, int32 pos) // Truncate /*! \brief Truncate the string to the new length. \param newLength The new lenght of the string. - \param lazy Currently unused. (?) + \param lazy If true, the memory-optimisation is postponed to later \return This function always returns *this . */ BString& @@ -707,13 +814,15 @@ BString::Truncate(int32 newLength, bool lazy) int32 curLen = Length(); - if (newLength < curLen) - { - - //TODO: Implement lazy truncate? - - _GrowBy(newLength - curLen); //Negative - _privateData[newLength] = '\0'; + if (newLength < curLen) { + if (lazy) { + // don't free memory yet, just set new length: + // XXX: Uhm, where do we keep track of the amount + // of memory we allocated ? + _SetLength(newLength); + _privateData[newLength] = '\0'; + } else + _GrowBy(newLength - curLen); //Negative } return *this; } @@ -728,7 +837,14 @@ BString::Truncate(int32 newLength, bool lazy) BString& BString::Remove(int32 from, int32 length) { - _ShrinkAtBy(from, length); + int32 len = Length(); + if (from < 0) { + int32 skipLen = min_clamp0(from, len); + len -= skipLen; + from = 0; + } else + from = min_clamp0(from, len); + _ShrinkAtBy(from, min_clamp0(length, len - from)); return *this; } @@ -775,7 +891,7 @@ BString::RemoveLast(const BString &string) BString& BString::RemoveAll(const BString &string) { - return _DoReplace( string.String(), "", 0x7FFFFFFF, 0, KEEP_CASE); + return _DoReplace(string.String(), "", REPLACE_ALL, 0, KEEP_CASE); } @@ -787,8 +903,7 @@ BString::RemoveAll(const BString &string) BString& BString::RemoveFirst(const char *str) { - if (str != NULL) - { + if (str != NULL) { int32 pos = _ShortFindAfter(str, strlen(str)); if (pos >= 0) _ShrinkAtBy(pos, strlen(str)); @@ -805,8 +920,7 @@ BString::RemoveFirst(const char *str) BString& BString::RemoveLast(const char *str) { - if (str != NULL) - { + if (str != NULL) { int32 len = strlen(str); int32 pos = _FindBefore(str, Length(), len); if (pos >= 0) @@ -824,7 +938,7 @@ BString::RemoveLast(const char *str) BString& BString::RemoveAll(const char *str) { - return _DoReplace( str, "", 0x7FFFFFFF, 0, KEEP_CASE); + return _DoReplace(str, "", REPLACE_ALL, 0, KEEP_CASE); } @@ -836,26 +950,7 @@ BString::RemoveAll(const char *str) BString& BString::RemoveSet(const char *setOfCharsToRemove) { - char* buf; - if (setOfCharsToRemove && (buf=LockBuffer( Length())) != NULL) { - char* oldPos = buf; - char* newPos = buf; - int32 len; - int32 lenToGo = Length(); - while( (len = strcspn( oldPos, setOfCharsToRemove)) < lenToGo) { - if (oldPos>newPos) - memmove( newPos, oldPos, len); - newPos += len++; - oldPos += len; - lenToGo -= len; - } - if (oldPos>newPos) - memmove( newPos, oldPos, lenToGo); - newPos += lenToGo; - *newPos = 0; - UnlockBuffer( newPos-buf); - } - return *this; + return ReplaceSet(setOfCharsToRemove, ""); } @@ -864,24 +959,27 @@ BString::RemoveSet(const char *setOfCharsToRemove) \param into The BString where to move the object. \param from The offset (zero based) where to begin the move \param length The amount of bytes to move. - \return This function always returns *this . + \return This function always returns into. */ BString& BString::MoveInto(BString &into, int32 from, int32 length) { - if (&into == this) + CHECK_PARAM_RET(from >= 0, "'from' must not be negative!", into); + CHECK_PARAM_RET(from <= Length(), "'from' exceeds length!", into); + int32 len = min_clamp0(length, Length() - from); + if (&into == this) { + /* TODO: [zooey]: to be activated later (>R1): + // strings are identical, just move the data: + if (from>0 && _privateData) + memmove( _privateData, _privateData+from, len); + Truncate( len); + */ return *this; - - int32 len = Length() - from; - - len = min_c(len, length); - - into.SetTo(String() + from, length); - - if (from + length <= Length()) - _privateData = _ShrinkAtBy(from, len); + } + into.SetTo(String() + from, len); + _ShrinkAtBy(from, len); - return *this; + return into; } @@ -894,13 +992,14 @@ BString::MoveInto(BString &into, int32 from, int32 length) void BString::MoveInto(char *into, int32 from, int32 length) { - if (into != NULL) - { - memcpy(into, String() + from, length); - if (from + length <= Length()) - _privateData = _ShrinkAtBy(from, length); - into[length] = '\0'; - } + if (into != NULL) { + CHECK_PARAM_VOID(from >= 0, "'from' must not be negative!"); + CHECK_PARAM_VOID(from <= Length(), "'from' exceeds length!"); + int32 len = min_clamp0(length, Length() - from); + memcpy(into, String() + from, len); + into[len] = '\0'; + _ShrinkAtBy(from, len); + } } @@ -908,35 +1007,35 @@ BString::MoveInto(char *into, int32 from, int32 length) bool BString::operator<(const char *string) const { - return strcmp(String(), string) < 0; + return strcmp(String(), safestr(string)) < 0; } bool BString::operator<=(const char *string) const { - return strcmp(String(), string) <= 0; + return strcmp(String(), safestr(string)) <= 0; } bool BString::operator==(const char *string) const { - return strcmp(String(), string) == 0; + return strcmp(String(), safestr(string)) == 0; } bool BString::operator>=(const char *string) const { - return strcmp(String(), string) >= 0; + return strcmp(String(), safestr(string)) >= 0; } bool BString::operator>(const char *string) const { - return strcmp(String(), string) > 0; + return strcmp(String(), safestr(string)) > 0; } @@ -951,7 +1050,7 @@ BString::Compare(const BString &string) const int BString::Compare(const char *string) const { - return strcmp(String(), string); + return strcmp(String(), safestr(string)); } @@ -965,7 +1064,7 @@ BString::Compare(const BString &string, int32 n) const int BString::Compare(const char *string, int32 n) const { - return strncmp(String(), string, n); + return strncmp(String(), safestr(string), n); } @@ -979,7 +1078,7 @@ BString::ICompare(const BString &string) const int BString::ICompare(const char *str) const { - return strcasecmp(String(), str); + return strcasecmp(String(), safestr(str)); } @@ -993,7 +1092,7 @@ BString::ICompare(const BString &string, int32 n) const int BString::ICompare(const char *str, int32 n) const { - return strncasecmp(String(), str, n); + return strncasecmp(String(), safestr(str), n); } @@ -1037,7 +1136,10 @@ BString::FindFirst(const char *string) const int32 BString::FindFirst(const BString &string, int32 fromOffset) const { - return _FindAfter(string.String(), fromOffset, string.Length()); + if (fromOffset < 0) + return B_ERROR; + return _FindAfter(string.String(), min_clamp0(fromOffset, Length()), + string.Length()); } @@ -1054,7 +1156,9 @@ BString::FindFirst(const char *string, int32 fromOffset) const { if (string == NULL) return B_BAD_VALUE; - return _FindAfter(string, fromOffset, strlen(string)); + if (fromOffset < 0) + return B_ERROR; + return _FindAfter(string, min_clamp0(fromOffset, Length()), strlen(string)); } @@ -1067,10 +1171,10 @@ BString::FindFirst(const char *string, int32 fromOffset) const int32 BString::FindFirst(char c) const { - char *start = _privateData; - char *end = _privateData + Length(); /* String's end */ + const char *start = String(); + const char *end = String() + Length(); /* String's end */ - /* Scans the string until we found the character, */ + /* Scans the string until we find the character, */ /* or we hit the string's end */ while(start != end && *start != c) start++; @@ -1078,7 +1182,7 @@ BString::FindFirst(char c) const if (start == end) return B_ERROR; - return start - _privateData; + return start - String(); } @@ -1093,8 +1197,11 @@ BString::FindFirst(char c) const int32 BString::FindFirst(char c, int32 fromOffset) const { - char *start = _privateData + fromOffset; - char *end = _privateData + Length(); /* String's end */ + if (fromOffset < 0) + return B_ERROR; + + const char *start = String() + min_clamp0(fromOffset, Length()); + const char *end = String() + Length(); /* String's end */ /* Scans the string until we found the character, */ /* or we hit the string's end */ @@ -1104,7 +1211,7 @@ BString::FindFirst(char c, int32 fromOffset) const if (start >= end) return B_ERROR; - return start - _privateData; + return start - String(); } @@ -1147,7 +1254,10 @@ BString::FindLast(const char *string) const int32 BString::FindLast(const BString &string, int32 beforeOffset) const { - return _FindBefore(string.String(), beforeOffset, string.Length()); + if (beforeOffset < 0) + return B_ERROR; + return _FindBefore(string.String(), min_clamp0(beforeOffset, Length()), + string.Length()); } @@ -1163,7 +1273,9 @@ BString::FindLast(const char *string, int32 beforeOffset) const { if (string == NULL) return B_BAD_VALUE; - return _FindBefore(string, beforeOffset, strlen(string)); + if (beforeOffset < 0) + return B_ERROR; + return _FindBefore(string, min_clamp0(beforeOffset, Length()), strlen(string)); } @@ -1176,8 +1288,8 @@ BString::FindLast(const char *string, int32 beforeOffset) const int32 BString::FindLast(char c) const { - char *start = _privateData; - char *end = _privateData + Length(); /* String's end */ + const char *start = String(); + const char *end = String() + Length(); /* String's end */ /* Scans the string backwards until we found the character, */ /* or we reach the string's start */ @@ -1187,7 +1299,7 @@ BString::FindLast(char c) const if (end == start) return B_ERROR; - return end - _privateData; + return end - String(); } @@ -1202,8 +1314,11 @@ BString::FindLast(char c) const int32 BString::FindLast(char c, int32 beforeOffset) const { - char *start = _privateData; - char *end = _privateData + Length() - beforeOffset; + if (beforeOffset < 0) + return B_ERROR; + + const char *start = String(); + const char *end = String() + Length() - beforeOffset; /* Scans the string backwards until we found the character, */ /* or we reach the string's start */ @@ -1213,7 +1328,7 @@ BString::FindLast(char c, int32 beforeOffset) const if (end <= start) return B_ERROR; - return end - _privateData; + return end - String(); } @@ -1236,7 +1351,10 @@ BString::IFindFirst(const char *string) const int32 BString::IFindFirst(const BString &string, int32 fromOffset) const { - return _IFindAfter(string.String(), fromOffset, string.Length()); + if (fromOffset < 0) + return B_ERROR; + return _IFindAfter(string.String(), min_clamp0(fromOffset, Length()), + string.Length()); } @@ -1245,7 +1363,9 @@ BString::IFindFirst(const char *string, int32 fromOffset) const { if (string == NULL) return B_BAD_VALUE; - return _IFindAfter(string, fromOffset, strlen(string)); + if (fromOffset < 0) + return B_ERROR; + return _IFindAfter(string, min_clamp0(fromOffset,Length()), strlen(string)); } @@ -1268,7 +1388,10 @@ BString::IFindLast(const char *string) const int32 BString::IFindLast(const BString &string, int32 beforeOffset) const { - return _IFindBefore(string.String(), beforeOffset, string.Length()); + if (beforeOffset < 0) + return B_ERROR; + return _IFindBefore(string.String(), min_clamp0(beforeOffset, Length()), + string.Length()); } @@ -1277,7 +1400,10 @@ BString::IFindLast(const char *string, int32 beforeOffset) const { if (string == NULL) return B_BAD_VALUE; - return _IFindBefore(string, beforeOffset, strlen(string)); + if (beforeOffset < 0) + return B_ERROR; + return _IFindBefore(string, min_clamp0(beforeOffset,Length()), + strlen(string)); } @@ -1309,13 +1435,12 @@ BString::ReplaceLast(char replaceThis, char withThis) BString& BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset) { - for (int32 pos;;) - { - pos = FindFirst(replaceThis, fromOffset); + CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); + for (int32 pos = min_clamp0(fromOffset, Length());;) { + pos = FindFirst(replaceThis, pos); if (pos < 0) break; _privateData[pos] = withThis; - fromOffset = pos; } return *this; @@ -1325,15 +1450,15 @@ BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset) BString& BString::Replace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset) { - for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--) - { - pos = FindFirst(replaceThis, fromOffset); - if (pos < 0) - break; - - _privateData[pos] = withThis; - fromOffset = pos; - + CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); + if (maxReplaceCount > 0) { + for (int32 pos = min_clamp0(fromOffset, Length()); + maxReplaceCount > 0; maxReplaceCount--) { + pos = FindFirst(replaceThis, pos); + if (pos < 0) + break; + _privateData[pos] = withThis; + } } return *this; } @@ -1355,16 +1480,17 @@ BString::ReplaceLast(const char *replaceThis, const char *withThis) int32 firstStringLength = strlen(replaceThis); int32 pos = _FindBefore(replaceThis, Length(), firstStringLength); - if (pos >= 0) - { + if (pos >= 0) { int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; - if (difference > 0) - _OpenAtBy(pos, difference); - else if (difference < 0) - _ShrinkAtBy(pos, -difference); - + if (difference > 0) { + if (!_OpenAtBy(pos, difference)) + return *this; + } else if (difference < 0) { + if (!_ShrinkAtBy(pos, -difference)) + return *this; + } memcpy(_privateData + pos, withThis, len); } @@ -1375,14 +1501,18 @@ BString::ReplaceLast(const char *replaceThis, const char *withThis) BString& BString::ReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset) { - return _DoReplace( replaceThis, withThis, 0x7FFFFFFF, fromOffset, KEEP_CASE); + CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); + return _DoReplace(replaceThis, withThis, REPLACE_ALL, + min_clamp0(fromOffset,Length()), KEEP_CASE); } BString& BString::Replace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset) { - return _DoReplace( replaceThis, withThis, maxReplaceCount, fromOffset, KEEP_CASE); + CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); + return _DoReplace(replaceThis, withThis, maxReplaceCount, + min_clamp0(fromOffset,Length()), KEEP_CASE); } @@ -1415,15 +1545,15 @@ BString::IReplaceLast(char replaceThis, char withThis) BString& BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset) { + CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); + char tmp[2] = { replaceThis, '\0' }; - - for (int32 pos;;) - { - pos = _IFindAfter(tmp, fromOffset, 1); + + for (int32 pos = min_clamp0(fromOffset, Length());;) { + pos = _IFindAfter(tmp, pos, 1); if (pos < 0) break; _privateData[pos] = withThis; - fromOffset = pos; } return *this; } @@ -1432,19 +1562,19 @@ BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset) BString& BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset) { + CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); + char tmp[2] = { replaceThis, '\0' }; if (_privateData == NULL) return *this; - for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--) - { - pos = _IFindAfter(tmp, fromOffset, 1); + for (int32 pos = min_clamp0(fromOffset,Length()); + maxReplaceCount > 0; maxReplaceCount--) { + pos = _IFindAfter(tmp, pos, 1); if (pos < 0) break; - _privateData[pos] = withThis; - fromOffset = pos; } return *this; } @@ -1453,7 +1583,7 @@ BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount, int32 BString& BString::IReplaceFirst(const char *replaceThis, const char *withThis) { - return _DoReplace( replaceThis, withThis, 1, 0, IGNORE_CASE); + return _DoReplace(replaceThis, withThis, 1, 0, IGNORE_CASE); } @@ -1466,17 +1596,19 @@ BString::IReplaceLast(const char *replaceThis, const char *withThis) int32 firstStringLength = strlen(replaceThis); int32 pos = _IFindBefore(replaceThis, Length(), firstStringLength); - if (pos >= 0) - { + if (pos >= 0) { int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; - if (difference > 0) - _OpenAtBy(pos, difference); - else if (difference < 0) - _ShrinkAtBy(pos, -difference); - + if (difference > 0) { + if (!_OpenAtBy(pos, difference)) + return *this; + } else if (difference < 0) { + if (!_ShrinkAtBy(pos, -difference)) + return *this; + } memcpy(_privateData + pos, withThis, len); + } return *this; @@ -1486,31 +1618,34 @@ BString::IReplaceLast(const char *replaceThis, const char *withThis) BString& BString::IReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset) { - return _DoReplace( replaceThis, withThis, 0x7FFFFFFF, fromOffset, IGNORE_CASE); + CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); + return _DoReplace(replaceThis, withThis, REPLACE_ALL, + min_clamp0(fromOffset, Length()), IGNORE_CASE); } BString& BString::IReplace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset) { - return _DoReplace( replaceThis, withThis, maxReplaceCount, fromOffset, IGNORE_CASE); + CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); + return _DoReplace(replaceThis, withThis, maxReplaceCount, + min_clamp0(fromOffset, Length()), IGNORE_CASE); } BString& BString::ReplaceSet(const char *setOfChars, char with) { + if (setOfChars == NULL) + return *this; + int32 offset = 0; int32 length = Length(); - for (int32 pos;;) - { + for (int32 pos;;) { pos = strcspn(String() + offset, setOfChars); - if (pos >= length) - break; - + offset += pos; - if (offset >= length) break; @@ -1521,32 +1656,32 @@ BString::ReplaceSet(const char *setOfChars, char with) return *this; } - BString& BString::ReplaceSet(const char *setOfChars, const char *with) { - if (with == NULL) - return *this; //TODO: do something smart + int32 withLen = with ? strlen(with) : 0; + if (withLen == 1) + // delegate simple case: + return ReplaceSet( setOfChars, *with); + + if (setOfChars == NULL || _privateData == NULL) + return *this; - int32 offset = 0; - int32 withLen = strlen(with); - - for (int32 pos;;) + PosVect positions; + + int32 searchLen = 1; + int32 len = Length(); + int32 pos = 0; + for (int32 offset = 0; offset < len; offset += (pos+searchLen)) { - pos = strcspn(String() + offset, setOfChars); - if (pos >= Length()) + pos = strcspn(_privateData + offset, setOfChars); + if (pos + offset >= len) break; - - offset += pos; - - if (offset >= Length()) - break; - - _OpenAtBy(offset, withLen - 1); - memcpy(_privateData + offset, with, withLen); - offset += withLen; + if (!positions.Add(offset + pos)) + return *this; } - + + _ReplaceAtPositions(&positions, searchLen, with, withLen); return *this; } @@ -1575,8 +1710,17 @@ BString::LockBuffer(int32 maxLength) int32 len = Length(); - if (maxLength > len) - _GrowBy(maxLength - len); + if (maxLength > len) { + if (!_GrowBy(maxLength - len)) + return NULL; + if (!len && _privateData) + // if string was empty before call to LockBuffer(), we make sure the + // buffer represents an empty c-string: + *_privateData = '\0'; + } else if (!maxLength && !len) { + // special case for unallocated string, we return an empty c-string: + return const_cast(String()); + } return _privateData; } @@ -1668,10 +1812,8 @@ BString::CapitalizeEachWord() do { // Find the first alphabetical character... - for(; count < length; count++) - { - if (isalpha(_privateData[count])) - { + for(; count < length; count++) { + if (isalpha(_privateData[count])) { // ...found! Convert it to uppercase. _privateData[count] = toupper(_privateData[count]); count++; @@ -1680,8 +1822,7 @@ BString::CapitalizeEachWord() } // Now find the first non-alphabetical character, // and meanwhile, turn to lowercase all the alphabetical ones - for(; count < length; count++) - { + for(; count < length; count++) { if (isalpha(_privateData[count])) _privateData[count] = tolower(_privateData[count]); else @@ -1710,19 +1851,49 @@ BString::CharacterEscape(const char *setOfCharsToEscape, char escapeWith) if (setOfCharsToEscape == NULL || _privateData == NULL) return *this; - int32 offset = 0; - - for(int32 pos;;) - { - pos = strcspn(_privateData + offset, setOfCharsToEscape); - offset += pos; - if (offset >= Length()) - break; - _OpenAtBy(offset, 1); - memset(_privateData + offset, escapeWith, 1); - offset += 2; + PosVect positions; + int32 len = Length(); + int32 pos = 0; + for (int32 offset = 0; offset < len; offset += pos + 1) { + if ((pos = strcspn(_privateData + offset, setOfCharsToEscape)) < len - offset) + if (!positions.Add(offset + pos)) + return *this; } - + + uint32 count = positions.CountItems(); + int32 newLength = len + count; + if (!newLength) { + _GrowBy( -len); + return *this; + } + int32 lastPos = 0; + char* oldAdr = _privateData; + char* newData = (char*)malloc(newLength + sizeof(int32) + 1); + if (newData) { + newData += sizeof(int32); + char* newAdr = newData; + for (uint32 i = 0; i < count; ++i) { + pos = positions.ItemAt( i); + len = pos-lastPos; + if (len > 0) { + memcpy(newAdr, oldAdr, len); + oldAdr += len; + newAdr += len; + } + *newAdr++ = escapeWith; + *newAdr++ = *oldAdr++; + lastPos = pos + 1; + } + len = Length() + 1 - lastPos; + if (len > 0) + memcpy(newAdr, oldAdr, len); + + free(_privateData - sizeof(int32)); + _privateData = newData; + _privateData[newLength] = 0; + _SetLength( newLength); + } + return *this; } @@ -1740,11 +1911,8 @@ BString::CharacterDeescape(const char *original, char escapeChar) BString& BString::CharacterDeescape(char escapeChar) { - int32 pos; - while ((pos = FindFirst(escapeChar)) >= 0) - _ShrinkAtBy(pos, 1); - - return *this; + const char temp[2] = {escapeChar, 0}; + return _DoReplace(temp, "", REPLACE_ALL, 0, KEEP_CASE); } @@ -1846,19 +2014,32 @@ BString::operator<<(float f) /*---- Private or Reserved ------------------------------------------------*/ -void -BString::_Init(const char* str, int32 len) +char* +BString::_Alloc(int32 dataLen) { - ASSERT(str != NULL); - ASSERT(_privateData == NULL); + char *dataPtr = _privateData ? _privateData - sizeof(int32) : NULL; + if (dataLen <= 0) { // release buffer if requested size is 0: + free(dataPtr); + _privateData = NULL; + return NULL; + } + int32 allocLen = dataLen + sizeof(int32) + 1; + dataPtr = (char *)realloc(dataPtr, allocLen); + if (dataPtr) { + dataPtr += sizeof(int32); + _privateData = dataPtr; + int32 newLen = allocLen - sizeof(int32) - 1; + _SetLength(newLen); + _privateData[newLen] = '\0'; + } + return dataPtr; +} - _privateData = (char*)malloc(len + sizeof(int32) + 1); - _privateData += sizeof(int32); - - memcpy(_privateData, str, len); - - _SetLength(len); - _privateData[len] = '\0'; +void +BString::_Init(const char *str, int32 len) +{ + if (_Alloc(len)) + memcpy(_privateData, str, len); } @@ -1868,13 +2049,10 @@ inline void BString::_DoAssign(const char *str, int32 len) { - ASSERT(str != NULL); int32 curLen = Length(); - if (len != curLen) - _GrowBy(len - curLen); - - memcpy(_privateData, str, len); + if (len == curLen || _GrowBy(len - curLen)) + memcpy(_privateData, str, len); } @@ -1884,11 +2062,9 @@ inline void BString::_DoAppend(const char *str, int32 len) { - ASSERT(str != NULL); - int32 length = Length(); - _GrowBy(len); - memcpy(_privateData + length, str, len); + if (_GrowBy(len)) + memcpy(_privateData + length, str, len); } @@ -1896,65 +2072,36 @@ char* BString::_GrowBy(int32 size) { int32 newLen = Length() + size; - ASSERT(newLen >= 0); - - if (_privateData != NULL) - _privateData -= sizeof(int32); - - _privateData = (char*)realloc(_privateData, - newLen + sizeof(int32) + 1); - - _privateData += sizeof(int32); - - _SetLength(newLen); - _privateData[newLen] = '\0'; - - return _privateData; + return _Alloc(newLen); } char * BString::_OpenAtBy(int32 offset, int32 length) { - ASSERT(offset >= 0); - int32 oldLength = Length(); - if (_privateData != NULL) - _privateData -= sizeof(int32); + char* newData = _Alloc(oldLength + length); + if (newData != NULL) + memmove(_privateData + offset + length, _privateData + offset, + oldLength - offset); - _privateData = (char*)realloc(_privateData, oldLength + length + sizeof(int32) + 1); - _privateData += sizeof(int32); - - memmove(_privateData + offset + length, _privateData + offset, - oldLength - offset); - - _SetLength(oldLength + length); - _privateData[Length()] = '\0'; - - return _privateData; + return newData; } char* BString::_ShrinkAtBy(int32 offset, int32 length) { + if (!_privateData) + return NULL; int32 oldLength = Length(); - - if (offset > oldLength || offset + length > oldLength) - return _privateData; memmove(_privateData + offset, _privateData + offset + length, - oldLength - offset - length); - - _privateData -= sizeof(int32); - _privateData = (char*)realloc(_privateData, oldLength - length + sizeof(int32) + 1); - _privateData += sizeof(int32); - - _SetLength(oldLength - length); - _privateData[Length()] = '\0'; - - return _privateData; + oldLength - offset - length); + + // the following actually should never fail, since we are reducing the size... + return _Alloc(oldLength - length); } @@ -1964,9 +2111,8 @@ inline void BString::_DoPrepend(const char *str, int32 count) { - ASSERT(str != NULL); - _OpenAtBy(0, count); - memcpy(_privateData, str, count); + if (_OpenAtBy(0, count)) + memcpy(_privateData, str, count); } @@ -1974,11 +2120,6 @@ BString::_DoPrepend(const char *str, int32 count) int32 BString::_FindAfter(const char *str, int32 offset, int32 strlen) const { - ASSERT(str != NULL); - - if (offset > Length()) - return B_ERROR; - char *ptr = strstr(String() + offset, str); if (ptr != NULL) @@ -1991,11 +2132,6 @@ BString::_FindAfter(const char *str, int32 offset, int32 strlen) const int32 BString::_IFindAfter(const char *str, int32 offset, int32 strlen) const { - ASSERT(str != NULL); - - if (offset > Length()) - return B_ERROR; - char *ptr = strcasestr(String() + offset, str); if (ptr != NULL) @@ -2008,8 +2144,6 @@ BString::_IFindAfter(const char *str, int32 offset, int32 strlen) const int32 BString::_ShortFindAfter(const char *str, int32 len) const { - ASSERT(str != NULL); - char *ptr = strstr(String(), str); if (ptr != NULL) @@ -2022,20 +2156,15 @@ BString::_ShortFindAfter(const char *str, int32 len) const int32 BString::_FindBefore(const char *str, int32 offset, int32 strlen) const { - ASSERT(str != NULL); - - if (offset <= 0) - return B_ERROR; - - const char *ptr = _privateData + offset - strlen; - - while (ptr >= _privateData) - { - if (!memcmp(ptr, str, strlen)) - return ptr - _privateData; - ptr--; + if (_privateData) { + const char *ptr = _privateData + offset - strlen; + + while (ptr >= _privateData) { + if (!memcmp(ptr, str, strlen)) + return ptr - _privateData; + ptr--; + } } - return B_ERROR; } @@ -2043,94 +2172,93 @@ BString::_FindBefore(const char *str, int32 offset, int32 strlen) const int32 BString::_IFindBefore(const char *str, int32 offset, int32 strlen) const { - ASSERT(str != NULL); - - if (offset <= 0) - return B_ERROR; - - char *ptr1 = _privateData + offset - strlen; - - while (ptr1 >= _privateData) - { - if (!strncasecmp(ptr1, str, strlen)) - return ptr1 - _privateData; - ptr1--; + if (_privateData) { + char *ptr1 = _privateData + offset - strlen; + + while (ptr1 >= _privateData) { + if (!strncasecmp(ptr1, str, strlen)) + return ptr1 - _privateData; + ptr1--; + } } - return B_ERROR; } -/*! - BStringOBuf is helper classed used by _DoReplace() -*/ -class BStringOBuf -{ - -public: - BStringOBuf( uint32 startLen, float growFactor=1.5); - ~BStringOBuf(); - - // methods to write into buffer (always append): - uint32 Write( const char* data, uint32 len); - - // getters: - BString& TheString(); - inline bool HasData() const { return mBuf!=NULL; } - -private: - bool GrowBufferToFit( uint32 len); - - uint32 mBufLen; - float mGrowFactor; - char* mBuf; - uint32 mCurrPos; - BString mStr; - - // Hide copy-constructor and assignment: - BStringOBuf( const BStringOBuf&); - BStringOBuf operator=( const BStringOBuf&); -}; - - BString& BString::_DoReplace(const char *findThis, const char *replaceWith, int32 maxReplaceCount, int32 fromOffset, bool ignoreCase) { - if (findThis == NULL || maxReplaceCount <= 0 || fromOffset < 0 || fromOffset >= Length()) + if (findThis == NULL || maxReplaceCount <= 0 + || fromOffset < 0 || fromOffset >= Length()) return *this; typedef int32 (BString::*TFindMethod)(const char *, int32, int32) const; - TFindMethod findMethod = ignoreCase - ? &BString::_IFindAfter - : &BString::_FindAfter; - int32 findLen = strlen( findThis); - int32 replaceLen = replaceWith ? strlen( replaceWith) : 0; - BStringOBuf tempIO( (int32)max_c( max_c( findLen, 128), Length()*1.2), 1.2); + TFindMethod findMethod = ignoreCase ? &BString::_IFindAfter : &BString::_FindAfter; + int32 findLen = strlen(findThis); + + if (!replaceWith) + replaceWith = ""; + + int32 replaceLen = strlen(replaceWith); int32 lastSrcPos = fromOffset; - int32 len; - for( int32 srcPos=0; - maxReplaceCount>0 && (srcPos = (this->*findMethod)( findThis, lastSrcPos, findLen))!=B_ERROR; + PosVect positions; + for(int32 srcPos = 0; + maxReplaceCount > 0 + && (srcPos = (this->*findMethod)(findThis, lastSrcPos, findLen)) >= 0; maxReplaceCount-- ) { - len = srcPos-lastSrcPos; - if (fromOffset && !tempIO.HasData()) - tempIO.Write( String(), fromOffset); - tempIO.Write( String()+lastSrcPos, len); - tempIO.Write( replaceWith, replaceLen); - lastSrcPos = srcPos+findLen; - } - if (tempIO.HasData()) { - // only copy remainder if we have actually changed anything - if ((len = Length()-lastSrcPos)!=0) { - if (fromOffset && !tempIO.HasData()) - tempIO.Write( String(), fromOffset); - tempIO.Write( String()+lastSrcPos, len); - } - Adopt( tempIO.TheString()); + positions.Add(srcPos); + lastSrcPos = srcPos + findLen; } + _ReplaceAtPositions(&positions, findLen, replaceWith, replaceLen); return *this; } + +void +BString::_ReplaceAtPositions(const PosVect* positions, + int32 searchLen, const char* with, + int32 withLen) +{ + int32 len = Length(); + uint32 count = positions->CountItems(); + int32 newLength = len + count * (withLen - searchLen); + if (!newLength) { + _GrowBy(-len); + return; + } + int32 pos; + int32 lastPos = 0; + char *oldAdr = _privateData; + char *newData = (char *)malloc(newLength + sizeof(int32) + 1); + if (newData) { + newData += sizeof(int32); + char *newAdr = newData; + for(uint32 i = 0; i < count; ++i) { + pos = positions->ItemAt(i); + len = pos - lastPos; + if (len > 0) { + memcpy(newAdr, oldAdr, len); + oldAdr += len; + newAdr += len; + } + memcpy(newAdr, with, withLen); + oldAdr += searchLen; + newAdr += withLen; + lastPos = pos+searchLen; + } + len = Length() + 1 - lastPos; + if (len > 0) + memcpy(newAdr, oldAdr, len); + + free(_privateData - sizeof(int32)); + _privateData = newData; + _privateData[newLength] = 0; + _SetLength( newLength); + } +} + + #if ENABLE_INLINES inline #endif @@ -2187,60 +2315,3 @@ ICompare(const BString *string1, const BString *string2) return strcasecmp(string1->String(), string2->String()); } - -/*----- Implementation of BStringOBuf ------------------------------*/ -BStringOBuf::BStringOBuf(uint32 startLen, float growFactor) - :mBufLen(startLen), - mGrowFactor(max_c((float)1.0, growFactor)), - mBuf(NULL), - mCurrPos(0) -{ -} - - -BStringOBuf::~BStringOBuf() -{ - if (mBuf) - mStr.UnlockBuffer(mCurrPos); -} - - -bool -BStringOBuf::GrowBufferToFit(uint32 len) -{ - if (!mBuf || mCurrPos+len > mBufLen) { - if (mBuf) { - mStr.UnlockBuffer(mBufLen); - mBufLen = (uint32)max_c(mGrowFactor*mBufLen, mGrowFactor*(mCurrPos+len)); - } else - mBufLen = (uint32)max_c(mBufLen, mCurrPos+len); - mBuf = mStr.LockBuffer(mBufLen); - if (!mBuf) - return false; - } - return true; -} - - -uint32 -BStringOBuf::Write(const char* data, uint32 len) -{ - if (!len || !GrowBufferToFit( len)) - return 0; - memcpy( mBuf+mCurrPos, data, len); - mCurrPos += len; - return len; -} - - -BString& -BStringOBuf::TheString() -{ - if (mBuf) { - mBuf[mCurrPos] = '\0'; - mStr.UnlockBuffer( mCurrPos); - mBuf = NULL; - } - return mStr; -} - diff --git a/src/tests/kits/support/bstring/StringAppendTest.cpp b/src/tests/kits/support/bstring/StringAppendTest.cpp index 3429779571..1fac7e73ab 100644 --- a/src/tests/kits/support/bstring/StringAppendTest.cpp +++ b/src/tests/kits/support/bstring/StringAppendTest.cpp @@ -99,7 +99,7 @@ StringAppendTest::PerformTest(void) str1 = new BString("Base"); str1->Append("APPENDED", 40); CPPUNIT_ASSERT(strcmp(str1->String(), "BaseAPPENDED") == 0); - CPPUNIT_ASSERT(str1->Length() == strlen("BaseAPPENDED")); + CPPUNIT_ASSERT(str1->Length() == (int32)strlen("BaseAPPENDED")); delete str1; //char ptr is NULL @@ -115,6 +115,25 @@ StringAppendTest::PerformTest(void) str1->Append('C', 5); CPPUNIT_ASSERT(strcmp(str1->String(), "BaseCCCCC") == 0); delete str1; + + const int32 OUT_OF_MEM_VAL = 2*1000*1000*1000; +#ifndef TEST_R5 + //Append(char, int32) with excessive length: + NextSubTest(); + str1 = new BString("Base"); + str1->Append('C', OUT_OF_MEM_VAL); + CPPUNIT_ASSERT(strcmp(str1->String(), "Base") == 0); + delete str1; +#endif + +#ifndef TEST_R5 + //Append(char*, int32) with excessive length: + NextSubTest(); + str1 = new BString("Base"); + str1->Append("some more text", OUT_OF_MEM_VAL); + CPPUNIT_ASSERT(strcmp(str1->String(), "Basesome more text") == 0); + delete str1; +#endif } diff --git a/src/tests/kits/support/bstring/StringAssignTest.cpp b/src/tests/kits/support/bstring/StringAssignTest.cpp index b132124835..9fe5742d66 100644 --- a/src/tests/kits/support/bstring/StringAssignTest.cpp +++ b/src/tests/kits/support/bstring/StringAssignTest.cpp @@ -99,6 +99,25 @@ StringAssignTest::PerformTest(void) CPPUNIT_ASSERT(str->Length() == 2); CPPUNIT_ASSERT(strcmp(newstring.String(), "") == 0); delete str; + + const int32 OUT_OF_MEM_VAL = 2*1000*1000*1000; +#ifndef TEST_R5 + //SetTo(char, int32) with excessive length: + NextSubTest(); + str = new BString("dummy"); + str->SetTo('C', OUT_OF_MEM_VAL); + CPPUNIT_ASSERT(strcmp(str->String(), "dummy") == 0); + delete str; +#endif + +#ifndef TEST_R5 + //SetTo(char*, int32) with excessive length: + NextSubTest(); + str = new BString("dummy"); + str->SetTo("some more text", OUT_OF_MEM_VAL); + CPPUNIT_ASSERT(strcmp(str->String(), "some more text") == 0); + delete str; +#endif } diff --git a/src/tests/kits/support/bstring/StringEscapeTest.cpp b/src/tests/kits/support/bstring/StringEscapeTest.cpp index 8be4066fba..1722982a3a 100644 --- a/src/tests/kits/support/bstring/StringEscapeTest.cpp +++ b/src/tests/kits/support/bstring/StringEscapeTest.cpp @@ -17,7 +17,7 @@ StringEscapeTest::~StringEscapeTest() void StringEscapeTest::PerformTest(void) { - BString *string1, *string2; + BString *string1; //CharacterEscape(char*, char) NextSubTest(); diff --git a/src/tests/kits/support/bstring/StringInsertTest.cpp b/src/tests/kits/support/bstring/StringInsertTest.cpp index 9b94d111ac..30fd1975bf 100644 --- a/src/tests/kits/support/bstring/StringInsertTest.cpp +++ b/src/tests/kits/support/bstring/StringInsertTest.cpp @@ -26,12 +26,15 @@ StringInsertTest::PerformTest(void) CPPUNIT_ASSERT(strcmp(str1->String(), "StrINSERTEDing") == 0); delete str1; - //This test crashes both implementations - //NextSubTest(); - //str1 = new BString("String"); - //str1->Insert("INSERTED", 10); - //CPPUNIT_ASSERT(strcmp(str1->String(), "string") == 0); - //delete str1; +#ifndef TEST_R5 + // This test crashes R5 and should drop into the debugger in OpenBeOS + // (if compiled with DEBUG): + NextSubTest(); + str1 = new BString("String"); + str1->Insert("INSERTED", 10); + CPPUNIT_ASSERT(strcmp(str1->String(), "String") == 0); + delete str1; +#endif NextSubTest(); str1 = new BString; @@ -39,6 +42,15 @@ StringInsertTest::PerformTest(void) CPPUNIT_ASSERT(strcmp(str1->String(), "NSERTED") == 0); delete str1; +#ifndef TEST_R5 + // check limitation of negative values (R5 doesn't): + NextSubTest(); + str1 = new BString; + str1->Insert("INSERTED", -142364253); + CPPUNIT_ASSERT(strcmp(str1->String(), "") == 0); + delete str1; +#endif + //&Insert(const char *, int32 length, int32 pos); NextSubTest(); str1 = new BString("string"); @@ -46,12 +58,15 @@ StringInsertTest::PerformTest(void) CPPUNIT_ASSERT(strcmp(str1->String(), "stINring") == 0); delete str1; - //This test crashes both implementations - //NextSubTest(); - //str1 = new BString("string"); - //str1->Insert("INSERTED", 2, 30); - //CPPUNIT_ASSERT(strcmp(str1->String(), "stINring") == 0); - //delete str1; +#ifndef TEST_R5 + // This test crashes R5 and should drop into the debugger in OpenBeOS + // (if compiled with DEBUG): + NextSubTest(); + str1 = new BString("string"); + str1->Insert("INSERTED", 2, 30); + CPPUNIT_ASSERT(strcmp(str1->String(), "string") == 0); + delete str1; +#endif NextSubTest(); str1 = new BString("string"); @@ -73,6 +88,13 @@ StringInsertTest::PerformTest(void) CPPUNIT_ASSERT(strcmp(str1->String(), "strPPPPPing") == 0); delete str1; + //Insert(char c, int32 count, int32 pos) + NextSubTest(); + str1 = new BString("string"); + str1->Insert('P', 5, -2); + CPPUNIT_ASSERT(strcmp(str1->String(), "PPPstring") == 0); + delete str1; + //Insert(BString&) NextSubTest(); str1 = new BString("string"); diff --git a/src/tests/kits/support/bstring/StringRemoveTest.cpp b/src/tests/kits/support/bstring/StringRemoveTest.cpp index ba23b3eb38..cf387e8916 100644 --- a/src/tests/kits/support/bstring/StringRemoveTest.cpp +++ b/src/tests/kits/support/bstring/StringRemoveTest.cpp @@ -86,11 +86,11 @@ StringRemoveTest::PerformTest(void) CPPUNIT_ASSERT(strcmp(string1->String(), "a String") == 0); delete string1; - //from + length is > Length() + //from + length exceeds Length() (R5 fails) NextSubTest(); string1 = new BString("a String"); string1->Remove(4, 30); - CPPUNIT_ASSERT(strcmp(string1->String(), "a String") == 0); + CPPUNIT_ASSERT(strcmp(string1->String(), "a St") == 0); delete string1; NextSubTest(); @@ -223,7 +223,7 @@ StringRemoveTest::PerformTest(void) string2 = new BString("string"); string2->MoveInto(*string1, 0, 200); CPPUNIT_ASSERT(strcmp(string1->String(), "string") == 0); - CPPUNIT_ASSERT(strcmp(string2->String(), "string") == 0); + CPPUNIT_ASSERT(strcmp(string2->String(), "") == 0); delete string1; delete string2; @@ -242,7 +242,7 @@ StringRemoveTest::PerformTest(void) memset(dest, 0, 100); string1->MoveInto(dest, 0, 50); CPPUNIT_ASSERT(strcmp(dest, "some text") == 0); - CPPUNIT_ASSERT(strcmp(string1->String(), "some text") == 0); + CPPUNIT_ASSERT(strcmp(string1->String(), "") == 0); delete string1; } diff --git a/src/tests/kits/support/bstring/StringReplaceTest.cpp b/src/tests/kits/support/bstring/StringReplaceTest.cpp index 8dc4b4404e..23c0a6d89d 100644 --- a/src/tests/kits/support/bstring/StringReplaceTest.cpp +++ b/src/tests/kits/support/bstring/StringReplaceTest.cpp @@ -17,7 +17,9 @@ StringReplaceTest::~StringReplaceTest() void StringReplaceTest::PerformTest(void) { - BString *str1, *str2; + BString *str1; + const int32 sz = 1024*50; + char* buf; //&ReplaceFirst(char, char); NextSubTest(); @@ -253,6 +255,15 @@ StringReplaceTest::PerformTest(void) CPPUNIT_ASSERT(strcmp(str1->String(), "ccccccccccccccc") == 0); delete str1; +#ifndef TEST_R5 + //ReplaceSet(const char*, const char*) + NextSubTest(); + str1 = new BString("abcd abcd abcd"); + str1->ReplaceSet("abcd ", ""); + CPPUNIT_ASSERT(strcmp(str1->String(), "") == 0); + delete str1; +#endif + #ifndef TEST_R5 //ReplaceSet(const char*, const char*) NextSubTest(); @@ -261,6 +272,66 @@ StringReplaceTest::PerformTest(void) CPPUNIT_ASSERT(strcmp(str1->String(), "dabcda dabcda dabcda") == 0); delete str1; #endif + +#ifndef TEST_R5 + //ReplaceSet(const char*, const char*) + NextSubTest(); + str1 = new BString("abcd abcd abcd"); + str1->ReplaceSet("ad", ""); + CPPUNIT_ASSERT(strcmp(str1->String(), "bc bc bc") == 0); + delete str1; +#endif + + // we repeat some test, but this time with a bit of data + // to test the performance: + + // ReplaceSet(const char*, const char*) + NextSubTest(); + str1 = new BString(); + buf = str1->LockBuffer(sz); + memset( buf, 'x', sz); + str1->UnlockBuffer( sz); + str1->ReplaceSet("x", "y"); + CPPUNIT_ASSERT(str1->Length() == sz); + delete str1; + + NextSubTest(); + str1 = new BString(); + buf = str1->LockBuffer(sz); + memset( buf, 'x', sz); + str1->UnlockBuffer( sz); + str1->ReplaceSet("x", ""); + CPPUNIT_ASSERT(str1->Length() == 0); + delete str1; + + // ReplaceAll(const char*, const char*) + NextSubTest(); + str1 = new BString(); + buf = str1->LockBuffer(sz); + memset( buf, 'x', sz); + str1->UnlockBuffer( sz); + str1->ReplaceAll("x", "y"); + CPPUNIT_ASSERT(str1->Length() == sz); + delete str1; + + NextSubTest(); + str1 = new BString(); + buf = str1->LockBuffer(sz); + memset( buf, 'x', sz); + str1->UnlockBuffer( sz); + str1->ReplaceAll("xx", "y"); + CPPUNIT_ASSERT(str1->Length() == sz/2); + delete str1; + + NextSubTest(); + str1 = new BString(); + buf = str1->LockBuffer(sz); + memset( buf, 'x', sz); + str1->UnlockBuffer( sz); + str1->ReplaceSet("xx", ""); + CPPUNIT_ASSERT(str1->Length() == 0); + delete str1; + }