* Added a work-around to _Alloc() to allow R5 NetPositive to work on Haiku;

dunno if we want to keep this, though.
* Improved some methods by no longer calling strlen() more than once.
* We're now using snprintf() instead of sprintf() in the << operators to
  make them more secure (even though the string lengths should be long
  enough).
* Improved << operators by taking the return (the resulting string length) of
  snprintf() into account.
* Replaced calls to _GrowBy() with a negative argument with calls to
  _Alloc() which actually safes some computation.
* Cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16783 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2006-03-14 12:43:46 +00:00
parent 3f047e87db
commit e6a6424e1c
+173 -151
View File
@@ -1,42 +1,27 @@
//------------------------------------------------------------------------------ /*
// Copyright (c) 2001-2003, OpenBeOS * Copyright 2001-2006, Haiku, Inc. All Rights Reserved.
// * Distributed under the terms of the MIT License.
// Permission is hereby granted, free of charge, to any person obtaining a *
// copy of this software and associated documentation files (the "Software"), * Authors:
// to deal in the Software without restriction, including without limitation * Marc Flerackers ([email protected])
// the rights to use, copy, modify, merge, publish, distribute, sublicense, * Stefano Ceccherini ([email protected])
// and/or sell copies of the Software, and to permit persons to whom the * Oliver Tappe ([email protected])
// Software is furnished to do so, subject to the following conditions: * Axel Dörfler, [email protected]
// */
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. /*! String class supporting common string operations. */
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// 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 ([email protected])
// Stefano Ceccherini ([email protected])
// Oliver Tappe ([email protected])
//
// Description: String class supporting common string operations.
//------------------------------------------------------------------------------
// Standard Includes -----------------------------------------------------------
#include <cctype>
#include <cstdio>
#include <cstdlib>
// System Includes -------------------------------------------------------------
#include <Debug.h> #include <Debug.h>
#include <String.h> #include <String.h>
#define ENABLE_INLINES 0 // Set this to 1 to make some private methods inline #include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
// Set this to 1 to make some private methods inline
#define ENABLE_INLINES 0
// define proper names for case-option of _DoReplace() // define proper names for case-option of _DoReplace()
#define KEEP_CASE false #define KEEP_CASE false
@@ -49,18 +34,18 @@
const char *B_EMPTY_STRING = ""; const char *B_EMPTY_STRING = "";
// helper function, returns minimum of two given values (but clamps to 0): //! helper function, returns minimum of two given values (but clamps to 0):
static inline int32 static inline int32
min_clamp0(int32 num1, int32 num2) min_clamp0(int32 num1, int32 num2)
{ {
if (num1 < num2) if (num1 < num2)
return num1 > 0 ? num1 : 0; return num1 > 0 ? num1 : 0;
else
return num2 > 0 ? num2 : 0; return num2 > 0 ? num2 : 0;
} }
// helper function, returns length of given string (but clamps to given maximum): //! helper function, returns length of given string (but clamps to given maximum):
static inline int32 static inline int32
strlen_clamp(const char* str, int32 max) strlen_clamp(const char* str, int32 max)
{ // this should yield 0 for max<0: { // this should yield 0 for max<0:
@@ -71,7 +56,7 @@ strlen_clamp(const char* str, int32 max)
} }
// helper function, massages given pointer into a legal c-string: //! helper function, massages given pointer into a legal c-string:
static inline const char * static inline const char *
safestr(const char* str) safestr(const char* str)
{ {
@@ -79,7 +64,7 @@ safestr(const char* str)
} }
// helper class for BString::_ReplaceAtPositions(): //! helper class for BString::_ReplaceAtPositions():
struct struct
BString::PosVect { BString::PosVect {
PosVect() PosVect()
@@ -151,7 +136,9 @@ private:
#define CHECK_PARAM_VOID( expr, msg) #define CHECK_PARAM_VOID( expr, msg)
#endif #endif
// -----------------------------------------------------------------------------
// #pragma mark -
/*! /*!
\class BString \class BString
@@ -211,10 +198,8 @@ BString::BString(const BString &string)
BString::BString(const char *str, int32 maxLength) BString::BString(const char *str, int32 maxLength)
: _privateData(NULL) : _privateData(NULL)
{ {
if (str != NULL) { if (str != NULL)
int32 len = strlen_clamp(str, maxLength); _Init(str, strlen_clamp(str, maxLength));
_Init(str, len);
}
} }
@@ -262,22 +247,8 @@ BString::CountChars() const
int32 count = 0; int32 count = 0;
const char *start = _privateData; const char *start = _privateData;
/* String's end. This way we don't have to check for '\0' */
/* but just compare two pointers (which should be faster) */
const char *end = _privateData + Length(); const char *end = _privateData + Length();
#if 0
// ejaesler: Left in memoriam of one man's foolish disregard for the
// maxim "Premature optimization is the root of all evil"
while (*ptr) {
// Jump to next UTF8 character
// ejaesler: BGA's nifty function
ptr += utf8_char_len(*ptr);
count++;
}
#endif
while (start++ != end) { while (start++ != end) {
count++; count++;
@@ -317,7 +288,7 @@ BString::operator=(const char *str)
if (str != NULL) if (str != NULL)
_DoAssign(str, strlen(str)); _DoAssign(str, strlen(str));
else else
_GrowBy(-Length()); // Empties the string _Alloc(0);
return *this; return *this;
} }
@@ -345,14 +316,12 @@ BString::operator=(char c)
The function always returns \c *this . The function always returns \c *this .
*/ */
BString& BString&
BString::SetTo(const char *str, int32 length) BString::SetTo(const char *str, int32 maxLength)
{ {
if (str != NULL) { if (str != NULL)
int32 len = strlen_clamp(str, length); _DoAssign(str, strlen_clamp(str, maxLength));
_DoAssign(str, len);
}
else else
_GrowBy(-Length()); // Empties the string _Alloc(0);
return *this; return *this;
} }
@@ -382,8 +351,10 @@ BString::SetTo(const BString &from)
BString& BString&
BString::Adopt(BString &from) BString::Adopt(BString &from)
{ {
if (&from == this) // Avoid auto-adoption if (&from == this) {
// Avoid auto-adoption
return *this; return *this;
}
if (_privateData) if (_privateData)
free(_privateData - sizeof(int32)); free(_privateData - sizeof(int32));
@@ -435,7 +406,7 @@ BString::Adopt(BString &from, int32 length)
from._privateData = NULL; from._privateData = NULL;
if (len < Length()) if (len < Length())
_GrowBy(len - Length()); // Negative, we truncate _Alloc(len);
return *this; return *this;
} }
@@ -578,8 +549,9 @@ BString::Append(char c, int32 count)
} }
/*---- Prepending ----------------------------------------------------------*/ // #pragma mark - Prepending
// Prepend
/*! \brief Prepends the given string to the object. /*! \brief Prepends the given string to the object.
\param str A pointer to the string to prepend. \param str A pointer to the string to prepend.
\return This function always returns *this . \return This function always returns *this .
@@ -655,8 +627,9 @@ BString::Prepend(char c, int32 count)
} }
/*---- Inserting ----------------------------------------------------------*/ // #pragma mark - Inserting
// Insert
/*! \brief Inserts the given string at the given position into the object's data. /*! \brief Inserts the given string at the given position into the object's data.
\param str A pointer to the string to insert. \param str A pointer to the string to insert.
\param pos The offset into the BString's data where to insert the string. \param pos The offset into the BString's data where to insert the string.
@@ -799,8 +772,9 @@ BString::Insert(char c, int32 count, int32 pos)
} }
/*---- Removing -----------------------------------------------------------*/ // #pragma mark - Removing
// Truncate
/*! \brief Truncate the string to the new length. /*! \brief Truncate the string to the new length.
\param newLength The new lenght of the string. \param newLength The new lenght of the string.
\param lazy If true, the memory-optimisation is postponed to later \param lazy If true, the memory-optimisation is postponed to later
@@ -816,14 +790,13 @@ BString::Truncate(int32 newLength, bool lazy)
if (newLength < curLen) { if (newLength < curLen) {
if (lazy) { if (lazy) {
// don't free memory yet, just set new length: // 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); _SetLength(newLength);
_privateData[newLength] = '\0'; _privateData[newLength] = '\0';
} else } else
_GrowBy(newLength - curLen); //Negative _Alloc(newLength);
} }
return *this; return *this;
} }
@@ -857,11 +830,11 @@ BString::Remove(int32 from, int32 length)
BString& BString&
BString::RemoveFirst(const BString &string) BString::RemoveFirst(const BString &string)
{ {
if (string.Length() > 0) {
int32 pos = _ShortFindAfter(string.String(), string.Length()); int32 pos = _ShortFindAfter(string.String(), string.Length());
if (pos >= 0) if (pos >= 0)
_ShrinkAtBy(pos, string.Length()); _ShrinkAtBy(pos, string.Length());
}
return *this; return *this;
} }
@@ -875,7 +848,6 @@ BString&
BString::RemoveLast(const BString &string) BString::RemoveLast(const BString &string)
{ {
int32 pos = _FindBefore(string.String(), Length(), string.Length()); int32 pos = _FindBefore(string.String(), Length(), string.Length());
if (pos >= 0) if (pos >= 0)
_ShrinkAtBy(pos, string.Length()); _ShrinkAtBy(pos, string.Length());
@@ -901,12 +873,13 @@ BString::RemoveAll(const BString &string)
\return This function always returns *this . \return This function always returns *this .
*/ */
BString& BString&
BString::RemoveFirst(const char *str) BString::RemoveFirst(const char *string)
{ {
if (str != NULL) { int32 length = string ? strlen(string) : 0;
int32 pos = _ShortFindAfter(str, strlen(str)); if (length > 0) {
int32 pos = _ShortFindAfter(string, length);
if (pos >= 0) if (pos >= 0)
_ShrinkAtBy(pos, strlen(str)); _ShrinkAtBy(pos, length);
} }
return *this; return *this;
} }
@@ -918,13 +891,13 @@ BString::RemoveFirst(const char *str)
\return This function always returns *this . \return This function always returns *this .
*/ */
BString& BString&
BString::RemoveLast(const char *str) BString::RemoveLast(const char *string)
{ {
if (str != NULL) { int32 length = string ? strlen(string) : 0;
int32 len = strlen(str); if (length > 0) {
int32 pos = _FindBefore(str, Length(), len); int32 pos = _FindBefore(string, Length(), length);
if (pos >= 0) if (pos >= 0)
_ShrinkAtBy(pos, len); _ShrinkAtBy(pos, length);
} }
return *this; return *this;
} }
@@ -1039,7 +1012,9 @@ BString::operator>(const char *string) const
} }
/*---- strcmp-style compare functions --------------------------------------*/ // #pragma mark - Comparison
int int
BString::Compare(const BString &string) const BString::Compare(const BString &string) const
{ {
@@ -1096,8 +1071,9 @@ BString::ICompare(const char *str, int32 n) const
} }
/*---- Searching -----------------------------------------------------------*/ // #pragma mark - Searching
// FindFirst
/*! \brief Find the first occurrence of the given BString. /*! \brief Find the first occurrence of the given BString.
\param string The BString to search for. \param string The BString to search for.
\return The offset(zero based) into the data \return The offset(zero based) into the data
@@ -1121,6 +1097,7 @@ BString::FindFirst(const char *string) const
{ {
if (string == NULL) if (string == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
return _ShortFindAfter(string, strlen(string)); return _ShortFindAfter(string, strlen(string));
} }
@@ -1138,6 +1115,7 @@ BString::FindFirst(const BString &string, int32 fromOffset) const
{ {
if (fromOffset < 0) if (fromOffset < 0)
return B_ERROR; return B_ERROR;
return _FindAfter(string.String(), min_clamp0(fromOffset, Length()), return _FindAfter(string.String(), min_clamp0(fromOffset, Length()),
string.Length()); string.Length());
} }
@@ -1158,7 +1136,9 @@ BString::FindFirst(const char *string, int32 fromOffset) const
return B_BAD_VALUE; return B_BAD_VALUE;
if (fromOffset < 0) if (fromOffset < 0)
return B_ERROR; return B_ERROR;
return _FindAfter(string, min_clamp0(fromOffset, Length()), strlen(string));
return _FindAfter(string, min_clamp0(fromOffset, Length()),
strlen(string));
} }
@@ -1172,12 +1152,13 @@ int32
BString::FindFirst(char c) const BString::FindFirst(char c) const
{ {
const char *start = String(); const char *start = String();
const char *end = String() + Length(); /* String's end */ const char *end = String() + Length();
/* Scans the string until we find the character, */ /* Scans the string until we find the character, */
/* or we hit the string's end */ /* or we hit the string's end */
while(start != end && *start != c) while (start != end && *start != c) {
start++; start++;
}
if (start == end) if (start == end)
return B_ERROR; return B_ERROR;
@@ -1201,12 +1182,13 @@ BString::FindFirst(char c, int32 fromOffset) const
return B_ERROR; return B_ERROR;
const char *start = String() + min_clamp0(fromOffset, Length()); const char *start = String() + min_clamp0(fromOffset, Length());
const char *end = String() + Length(); /* String's end */ const char *end = String() + Length();
/* Scans the string until we found the character, */ /* Scans the string until we found the character, */
/* or we hit the string's end */ /* or we hit the string's end */
while(start < end && *start != c) while (start < end && *start != c) {
start++; start++;
}
if (start >= end) if (start >= end)
return B_ERROR; return B_ERROR;
@@ -1239,6 +1221,7 @@ BString::FindLast(const char *string) const
{ {
if (string == NULL) if (string == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
return _FindBefore(string, Length(), strlen(string)); return _FindBefore(string, Length(), strlen(string));
} }
@@ -1256,6 +1239,7 @@ BString::FindLast(const BString &string, int32 beforeOffset) const
{ {
if (beforeOffset < 0) if (beforeOffset < 0)
return B_ERROR; return B_ERROR;
return _FindBefore(string.String(), min_clamp0(beforeOffset, Length()), return _FindBefore(string.String(), min_clamp0(beforeOffset, Length()),
string.Length()); string.Length());
} }
@@ -1275,6 +1259,7 @@ BString::FindLast(const char *string, int32 beforeOffset) const
return B_BAD_VALUE; return B_BAD_VALUE;
if (beforeOffset < 0) if (beforeOffset < 0)
return B_ERROR; return B_ERROR;
return _FindBefore(string, min_clamp0(beforeOffset, Length()), strlen(string)); return _FindBefore(string, min_clamp0(beforeOffset, Length()), strlen(string));
} }
@@ -1289,12 +1274,13 @@ int32
BString::FindLast(char c) const BString::FindLast(char c) const
{ {
const char *start = String(); const char *start = String();
const char *end = String() + Length(); /* String's end */ const char *end = String() + Length();
/* Scans the string backwards until we found the character, */ /* Scans the string backwards until we found the character, */
/* or we reach the string's start */ /* or we reach the string's start */
while(end != start && *end != c) while (end != start && *end != c) {
end--; end--;
}
if (end == start) if (end == start)
return B_ERROR; return B_ERROR;
@@ -1322,8 +1308,9 @@ BString::FindLast(char c, int32 beforeOffset) const
/* Scans the string backwards until we found the character, */ /* Scans the string backwards until we found the character, */
/* or we reach the string's start */ /* or we reach the string's start */
while(end > start && *end != c) while (end > start && *end != c) {
end--; end--;
}
if (end <= start) if (end <= start)
return B_ERROR; return B_ERROR;
@@ -1344,6 +1331,7 @@ BString::IFindFirst(const char *string) const
{ {
if (string == NULL) if (string == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
return _IFindAfter(string, 0, strlen(string)); return _IFindAfter(string, 0, strlen(string));
} }
@@ -1353,6 +1341,7 @@ BString::IFindFirst(const BString &string, int32 fromOffset) const
{ {
if (fromOffset < 0) if (fromOffset < 0)
return B_ERROR; return B_ERROR;
return _IFindAfter(string.String(), min_clamp0(fromOffset, Length()), return _IFindAfter(string.String(), min_clamp0(fromOffset, Length()),
string.Length()); string.Length());
} }
@@ -1365,6 +1354,7 @@ BString::IFindFirst(const char *string, int32 fromOffset) const
return B_BAD_VALUE; return B_BAD_VALUE;
if (fromOffset < 0) if (fromOffset < 0)
return B_ERROR; return B_ERROR;
return _IFindAfter(string, min_clamp0(fromOffset,Length()), strlen(string)); return _IFindAfter(string, min_clamp0(fromOffset,Length()), strlen(string));
} }
@@ -1381,6 +1371,7 @@ BString::IFindLast(const char *string) const
{ {
if (string == NULL) if (string == NULL)
return B_BAD_VALUE; return B_BAD_VALUE;
return _IFindBefore(string, Length(), strlen(string)); return _IFindBefore(string, Length(), strlen(string));
} }
@@ -1390,6 +1381,7 @@ BString::IFindLast(const BString &string, int32 beforeOffset) const
{ {
if (beforeOffset < 0) if (beforeOffset < 0)
return B_ERROR; return B_ERROR;
return _IFindBefore(string.String(), min_clamp0(beforeOffset, Length()), return _IFindBefore(string.String(), min_clamp0(beforeOffset, Length()),
string.Length()); string.Length());
} }
@@ -1402,17 +1394,19 @@ BString::IFindLast(const char *string, int32 beforeOffset) const
return B_BAD_VALUE; return B_BAD_VALUE;
if (beforeOffset < 0) if (beforeOffset < 0)
return B_ERROR; return B_ERROR;
return _IFindBefore(string, min_clamp0(beforeOffset, Length()), return _IFindBefore(string, min_clamp0(beforeOffset, Length()),
strlen(string)); strlen(string));
} }
/*---- Replacing -----------------------------------------------------------*/ // #pragma mark - Replacing
BString& BString&
BString::ReplaceFirst(char replaceThis, char withThis) BString::ReplaceFirst(char replaceThis, char withThis)
{ {
int32 pos = FindFirst(replaceThis); int32 pos = FindFirst(replaceThis);
if (pos >= 0) if (pos >= 0)
_privateData[pos] = withThis; _privateData[pos] = withThis;
@@ -1424,7 +1418,6 @@ BString&
BString::ReplaceLast(char replaceThis, char withThis) BString::ReplaceLast(char replaceThis, char withThis)
{ {
int32 pos = FindLast(replaceThis); int32 pos = FindLast(replaceThis);
if (pos >= 0) if (pos >= 0)
_privateData[pos] = withThis; _privateData[pos] = withThis;
@@ -1520,8 +1513,8 @@ BString&
BString::IReplaceFirst(char replaceThis, char withThis) BString::IReplaceFirst(char replaceThis, char withThis)
{ {
char tmp[2] = { replaceThis, '\0' }; char tmp[2] = { replaceThis, '\0' };
int32 pos = _IFindAfter(tmp, 0, 1);
int32 pos = _IFindAfter(tmp, 0, 1);
if (pos >= 0) if (pos >= 0)
_privateData[pos] = withThis; _privateData[pos] = withThis;
@@ -1533,8 +1526,8 @@ BString&
BString::IReplaceLast(char replaceThis, char withThis) BString::IReplaceLast(char replaceThis, char withThis)
{ {
char tmp[2] = { replaceThis, '\0' }; char tmp[2] = { replaceThis, '\0' };
int32 pos = _IFindBefore(tmp, Length(), 1);
int32 pos = _IFindBefore(tmp, Length(), 1);
if (pos >= 0) if (pos >= 0)
_privateData[pos] = withThis; _privateData[pos] = withThis;
@@ -1608,7 +1601,6 @@ BString::IReplaceLast(const char *replaceThis, const char *withThis)
return *this; return *this;
} }
memcpy(_privateData + pos, withThis, len); memcpy(_privateData + pos, withThis, len);
} }
return *this; return *this;
@@ -1625,7 +1617,8 @@ BString::IReplaceAll(const char *replaceThis, const char *withThis, int32 fromOf
BString& BString&
BString::IReplace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset) BString::IReplace(const char *replaceThis, const char *withThis,
int32 maxReplaceCount, int32 fromOffset)
{ {
CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!"); CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!");
return _DoReplace(replaceThis, withThis, maxReplaceCount, return _DoReplace(replaceThis, withThis, maxReplaceCount,
@@ -1656,13 +1649,15 @@ BString::ReplaceSet(const char *setOfChars, char with)
return *this; return *this;
} }
BString& BString&
BString::ReplaceSet(const char *setOfChars, const char *with) BString::ReplaceSet(const char *setOfChars, const char *with)
{ {
int32 withLen = with ? strlen(with) : 0; int32 withLen = with ? strlen(with) : 0;
if (withLen == 1) if (withLen == 1) {
// delegate simple case: // delegate simple case:
return ReplaceSet(setOfChars, *with); return ReplaceSet(setOfChars, *with);
}
if (setOfChars == NULL || _privateData == NULL) if (setOfChars == NULL || _privateData == NULL)
return *this; return *this;
@@ -1672,8 +1667,7 @@ BString::ReplaceSet(const char *setOfChars, const char *with)
int32 searchLen = 1; int32 searchLen = 1;
int32 len = Length(); int32 len = Length();
int32 pos = 0; int32 pos = 0;
for (int32 offset = 0; offset < len; offset += (pos+searchLen)) for (int32 offset = 0; offset < len; offset += (pos+searchLen)) {
{
pos = strcspn(_privateData + offset, setOfChars); pos = strcspn(_privateData + offset, setOfChars);
if (pos + offset >= len) if (pos + offset >= len)
break; break;
@@ -1706,7 +1700,7 @@ BString::operator[](int32 index)
char* char*
BString::LockBuffer(int32 maxLength) BString::LockBuffer(int32 maxLength)
{ {
_SetUsingAsCString(true); //debug _SetUsingAsCString(true);
int32 len = Length(); int32 len = Length();
@@ -1729,7 +1723,7 @@ BString::LockBuffer(int32 maxLength)
BString& BString&
BString::UnlockBuffer(int32 length) BString::UnlockBuffer(int32 length)
{ {
_SetUsingAsCString(false); //debug _SetUsingAsCString(false);
if (length < 0) if (length < 0)
length = (_privateData == NULL) ? 0 : strlen(_privateData); length = (_privateData == NULL) ? 0 : strlen(_privateData);
@@ -1750,8 +1744,9 @@ BString&
BString::ToLower() BString::ToLower()
{ {
int32 length = Length(); int32 length = Length();
for (int32 count = 0; count < length; count++) for (int32 count = 0; count < length; count++) {
_privateData[count] = tolower(_privateData[count]); _privateData[count] = tolower(_privateData[count]);
}
return *this; return *this;
} }
@@ -1765,8 +1760,9 @@ BString&
BString::ToUpper() BString::ToUpper()
{ {
int32 length = Length(); int32 length = Length();
for (int32 count = 0; count < length; count++) for (int32 count = 0; count < length; count++) {
_privateData[count] = toupper(_privateData[count]); _privateData[count] = toupper(_privateData[count]);
}
return *this; return *this;
} }
@@ -1785,8 +1781,9 @@ BString::Capitalize()
_privateData[0] = toupper(_privateData[0]); _privateData[0] = toupper(_privateData[0]);
int32 length = Length(); int32 length = Length();
for (int32 count = 1; count < length; count++) for (int32 count = 1; count < length; count++) {
_privateData[count] = tolower(_privateData[count]); _privateData[count] = tolower(_privateData[count]);
}
return *this; return *this;
} }
@@ -1818,6 +1815,7 @@ BString::CapitalizeEachWord()
break; break;
} }
} }
// Now find the first non-alphabetical character, // Now find the first non-alphabetical character,
// and meanwhile, turn to lowercase all the alphabetical ones // and meanwhile, turn to lowercase all the alphabetical ones
for (; count < length; count++) { for (; count < length; count++) {
@@ -1834,7 +1832,8 @@ BString::CapitalizeEachWord()
/*----- Escaping and Deescaping --------------------------------------------*/ /*----- Escaping and Deescaping --------------------------------------------*/
BString& BString&
BString::CharacterEscape(const char *original, const char *setOfCharsToEscape, char escapeWith) BString::CharacterEscape(const char *original, const char *setOfCharsToEscape,
char escapeWith)
{ {
SetTo(original); SetTo(original);
CharacterEscape(setOfCharsToEscape, escapeWith); CharacterEscape(setOfCharsToEscape, escapeWith);
@@ -1853,17 +1852,19 @@ BString::CharacterEscape(const char *setOfCharsToEscape, char escapeWith)
int32 len = Length(); int32 len = Length();
int32 pos = 0; int32 pos = 0;
for (int32 offset = 0; offset < len; offset += pos + 1) { for (int32 offset = 0; offset < len; offset += pos + 1) {
if ((pos = strcspn(_privateData + offset, setOfCharsToEscape)) < len - offset) if ((pos = strcspn(_privateData + offset, setOfCharsToEscape)) < len - offset) {
if (!positions.Add(offset + pos)) if (!positions.Add(offset + pos))
return *this; return *this;
} }
}
uint32 count = positions.CountItems(); uint32 count = positions.CountItems();
int32 newLength = len + count; int32 newLength = len + count;
if (!newLength) { if (!newLength) {
_GrowBy( -len); _Alloc(0);
return *this; return *this;
} }
int32 lastPos = 0; int32 lastPos = 0;
char* oldAdr = _privateData; char* oldAdr = _privateData;
char* newData = (char*)malloc(newLength + sizeof(int32) + 1); char* newData = (char*)malloc(newLength + sizeof(int32) + 1);
@@ -1944,40 +1945,44 @@ BString::operator<<(char c)
BString& BString&
BString::operator<<(int i) BString::operator<<(int i)
{ {
char num[64]; char num[32];
sprintf(num, "%d", i); int32 length = snprintf(num, sizeof(num), "%d", i);
return *this << num; _DoAppend(num, length);
return *this;
} }
BString& BString&
BString::operator<<(unsigned int i) BString::operator<<(unsigned int i)
{ {
char num[64]; char num[32];
sprintf(num, "%u", i); int32 length = snprintf(num, sizeof(num), "%u", i);
return *this << num; _DoAppend(num, length);
return *this;
} }
BString& BString&
BString::operator<<(uint32 i) BString::operator<<(uint32 i)
{ {
char num[64]; char num[32];
sprintf(num, "%lu", i); int32 length = snprintf(num, sizeof(num), "%lu", i);
return *this << num; _DoAppend(num, length);
return *this;
} }
BString& BString&
BString::operator<<(int32 i) BString::operator<<(int32 i)
{ {
char num[64]; char num[32];
sprintf(num, "%ld", i); int32 length = snprintf(num, sizeof(num), "%ld", i);
return *this << num; _DoAppend(num, length);
return *this;
} }
@@ -1985,9 +1990,10 @@ BString&
BString::operator<<(uint64 i) BString::operator<<(uint64 i)
{ {
char num[64]; char num[64];
sprintf(num, "%llu", i); int32 length = snprintf(num, sizeof(num), "%llu", i);
return *this << num; _DoAppend(num, length);
return *this;
} }
@@ -1995,9 +2001,10 @@ BString&
BString::operator<<(int64 i) BString::operator<<(int64 i)
{ {
char num[64]; char num[64];
sprintf(num, "%lld", i); int32 length = snprintf(num, sizeof(num), "%lld", i);
return *this << num; _DoAppend(num, length);
return *this;
} }
@@ -2005,31 +2012,45 @@ BString&
BString::operator<<(float f) BString::operator<<(float f)
{ {
char num[64]; char num[64];
sprintf(num, "%.2f", f); int32 length = snprintf(num, sizeof(num), "%.2f", f);
return *this << num; _DoAppend(num, length);
return *this;
} }
/*---- Private or Reserved ------------------------------------------------*/ // #pragma mark - Private or reserved
char * char *
BString::_Alloc(int32 dataLen) BString::_Alloc(int32 dataLength)
{ {
char *dataPtr = _privateData ? _privateData - sizeof(int32) : NULL; char *dataPtr = _privateData ? _privateData - sizeof(int32) : NULL;
if (dataLen <= 0) { // release buffer if requested size is 0: if (dataLength <= 0) {
// release buffer
#if 0
free(dataPtr); free(dataPtr);
_privateData = NULL; _privateData = NULL;
return NULL; return NULL;
#else
// TODO: think about removing this work-around again; it lets
// BeOS R5 NetPositive run on Haiku - this is obviously ignoring
// the fact, that _privateData could be NULL at one point
// (while building the menus from resources).
dataLength = 0;
#endif
} }
int32 allocLen = dataLen + sizeof(int32) + 1;
dataPtr = (char *)realloc(dataPtr, allocLen); int32 allocLength = dataLength + sizeof(int32) + 1;
dataPtr = (char *)realloc(dataPtr, allocLength);
if (dataPtr) { if (dataPtr) {
dataPtr += sizeof(int32); dataPtr += sizeof(int32);
_privateData = dataPtr; _privateData = dataPtr;
_SetLength(dataLen); _SetLength(dataLength);
_privateData[dataLen] = '\0'; _privateData[dataLength] = '\0';
} }
return dataPtr; return dataPtr;
} }
@@ -2069,8 +2090,7 @@ BString::_DoAppend(const char *str, int32 len)
char* char*
BString::_GrowBy(int32 size) BString::_GrowBy(int32 size)
{ {
int32 newLen = Length() + size; return _Alloc(Length() + size);
return _Alloc(newLen);
} }
@@ -2080,9 +2100,10 @@ BString::_OpenAtBy(int32 offset, int32 length)
int32 oldLength = Length(); int32 oldLength = Length();
char* newData = _Alloc(oldLength + length); char* newData = _Alloc(oldLength + length);
if (newData != NULL) if (newData != NULL) {
memmove(_privateData + offset + length, _privateData + offset, memmove(_privateData + offset + length, _privateData + offset,
oldLength - offset); oldLength - offset);
}
return newData; return newData;
} }
@@ -2093,6 +2114,7 @@ BString::_ShrinkAtBy(int32 offset, int32 length)
{ {
if (!_privateData) if (!_privateData)
return NULL; return NULL;
int32 oldLength = Length(); int32 oldLength = Length();
memmove(_privateData + offset, _privateData + offset + length, memmove(_privateData + offset, _privateData + offset + length,
@@ -2184,8 +2206,8 @@ BString::_IFindBefore(const char *str, int32 offset, int32 strlen) const
BString& BString&
BString::_DoReplace(const char *findThis, const char *replaceWith, int32 maxReplaceCount, BString::_DoReplace(const char *findThis, const char *replaceWith,
int32 fromOffset, bool ignoreCase) int32 maxReplaceCount, int32 fromOffset, bool ignoreCase)
{ {
if (findThis == NULL || maxReplaceCount <= 0 if (findThis == NULL || maxReplaceCount <= 0
|| fromOffset < 0 || fromOffset >= Length()) || fromOffset < 0 || fromOffset >= Length())
@@ -2215,16 +2237,16 @@ BString::_DoReplace(const char *findThis, const char *replaceWith, int32 maxRepl
void void
BString::_ReplaceAtPositions(const PosVect* positions, BString::_ReplaceAtPositions(const PosVect* positions,
int32 searchLen, const char* with, int32 searchLen, const char* with, int32 withLen)
int32 withLen)
{ {
int32 len = Length(); int32 len = Length();
uint32 count = positions->CountItems(); uint32 count = positions->CountItems();
int32 newLength = len + count * (withLen - searchLen); int32 newLength = len + count * (withLen - searchLen);
if (!newLength) { if (!newLength) {
_GrowBy(-len); _Alloc(0);
return; return;
} }
int32 pos; int32 pos;
int32 lastPos = 0; int32 lastPos = 0;
char *oldAdr = _privateData; char *oldAdr = _privateData;