* Copyright 2001-2021 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stefano Ceccherini, burton666@libero.it
* Axel Dörfler, axeld@pinc-software.de
* Marc Flerackers, mflerackers@androme.be
* Julun, host.haiku@gmx.de
* Michael Lotz, mmlr@mlotz.ch
* Oliver Tappe, openbeos@hirschkaefer.de
*/
#include <String.h>
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <Debug.h>
#include <StringList.h>
#include <StringPrivate.h>
#include <utf8_functions.h>
#define KEEP_CASE false
#define IGNORE_CASE true
#define REPLACE_ALL 0x7FFFFFFF
static const uint32 kPrivateDataOffset = BString::Private::kPrivateDataOffset;
const char* B_EMPTY_STRING = "";
static inline int32
min_clamp0(int32 num1, int32 num2)
{
if (num1 < num2)
return num1 > 0 ? num1 : 0;
return num2 > 0 ? num2 : 0;
}
static inline int32
strlen_clamp(const char* string, int32 max)
{
return max <= 0 ? 0 : strnlen(string, max);
}
static inline size_t
string_length(const char* string)
{
return string != NULL ? strlen(string) : 0;
}
static inline const char*
safestr(const char* string)
{
return string != NULL ? string : "";
}
class BString::PosVect {
public:
PosVect()
:
fSize(0),
fBufferSize(20),
fBuffer(NULL)
{
}
~PosVect()
{
free(fBuffer);
}
bool Add(int32 pos)
{
if (fBuffer == NULL || fSize == fBufferSize) {
if (fBuffer != NULL)
fBufferSize *= 2;
int32* newBuffer =
(int32*)realloc(fBuffer, fBufferSize * sizeof(int32));
if (newBuffer == NULL)
return false;
fBuffer = newBuffer;
}
fBuffer[fSize++] = pos;
return true;
}
inline int32 ItemAt(int32 index) const
{
return fBuffer[index];
}
inline int32 CountItems() const
{
return fSize;
}
private:
int32 fSize;
int32 fBufferSize;
int32* fBuffer;
};
inline int32&
BString::_ReferenceCount()
{
return Private::DataRefCount(fPrivateData);
}
inline const int32&
BString::_ReferenceCount() const
{
return Private::DataRefCount(fPrivateData);
}
inline bool
BString::_IsShareable() const
{
return fPrivateData != NULL && _ReferenceCount() >= 0;
}
BString::BString()
:
fPrivateData(NULL)
{
_Init("", 0);
}
BString::BString(const char* string)
:
fPrivateData(NULL)
{
_Init(string, strlen(safestr(string)));
}
BString::BString(const BString& string)
:
fPrivateData(NULL)
{
if (string._IsShareable()) {
fPrivateData = string.fPrivateData;
atomic_add(&_ReferenceCount(), 1);
} else
_Init(string.String(), string.Length());
}
BString::BString(const char* string, int32 maxLength)
: fPrivateData(NULL)
{
_Init(string, strlen_clamp(safestr(string), maxLength));
}
#if __cplusplus >= 201103L
BString::BString(BString&& string) noexcept
{
fPrivateData = string.fPrivateData;
string.fPrivateData = NULL;
}
#endif
BString::~BString()
{
_ReleasePrivateData();
}
int32
BString::CountChars() const
{
return UTF8CountChars(fPrivateData, Length());
}
int32
BString::CountBytes(int32 fromCharOffset, int32 charCount) const
{
return UTF8CountBytes(
fPrivateData + UTF8CountBytes(fPrivateData, fromCharOffset), charCount);
}
uint32
BString::HashValue(const char* _string)
{
const uint8* string = (const uint8*)_string;
if (string == NULL)
return 0;
uint32 h = 5381;
char c;
while ((c = *string++) != 0)
h = (h * 33) + c;
return h;
}
BString&
BString::operator=(const BString& string)
{
return SetTo(string);
}
BString&
BString::operator=(const char* string)
{
if (!string)
string = "";
if (string != String())
SetTo(string, strlen(string));
return *this;
}
BString&
BString::operator=(char c)
{
return SetTo(c, 1);
}
#if __cplusplus >= 201103L
BString&
BString::operator=(BString&& string) noexcept
{
if (this != &string) {
_ReleasePrivateData();
fPrivateData = string.fPrivateData;
string.fPrivateData = NULL;
}
return *this;
}
#endif
BString&
BString::SetTo(const char* string, int32 maxLength)
{
if (maxLength < 0)
maxLength = INT32_MAX;
maxLength = strlen_clamp(safestr(string), maxLength);
if (_MakeWritable(maxLength, false) == B_OK)
memcpy(fPrivateData, string, maxLength);
return *this;
}
BString&
BString::SetTo(const BString& string)
{
if (fPrivateData == string.fPrivateData)
return *this;
_ReleasePrivateData();
if (string._IsShareable()) {
fPrivateData = string.fPrivateData;
atomic_add(&_ReferenceCount(), 1);
} else
_Init(string.String(), string.Length());
return *this;
}
BString&
BString::Adopt(BString& from)
{
SetTo(from);
from.SetTo("");
return *this;
}
BString&
BString::SetTo(const BString& string, int32 maxLength)
{
if (maxLength < 0)
maxLength = INT32_MAX;
if (fPrivateData != string.fPrivateData
|| (fPrivateData == string.fPrivateData && Length() > maxLength)) {
maxLength = min_clamp0(maxLength, string.Length());
if (_MakeWritable(maxLength, false) == B_OK)
memcpy(fPrivateData, string.String(), maxLength);
}
return *this;
}
BString&
BString::Adopt(BString& from, int32 maxLength)
{
SetTo(from, maxLength);
from.SetTo("");
return *this;
}
BString&
BString::SetTo(char c, int32 count)
{
if (count < 0)
count = 0;
if (_MakeWritable(count, false) == B_OK)
memset(fPrivateData, c, count);
return *this;
}
BString&
BString::SetToChars(const char* string, int32 charCount)
{
return SetTo(string, UTF8CountBytes(string, charCount));
}
BString&
BString::SetToChars(const BString& string, int32 charCount)
{
return SetTo(string, UTF8CountBytes(string.String(), charCount));
}
BString&
BString::AdoptChars(BString& string, int32 charCount)
{
return Adopt(string, UTF8CountBytes(string.String(), charCount));
}
BString&
BString::SetToFormat(const char* format, ...)
{
va_list args;
va_start(args, format);
SetToFormatVarArgs(format, args);
va_end(args);
return *this;
}
BString&
BString::SetToFormatVarArgs(const char* format, va_list args)
{
int32 bufferSize = 1024;
char buffer[bufferSize];
va_list clonedArgs;
#if __GNUC__ == 2
__va_copy(clonedArgs, args);
#else
va_copy(clonedArgs, args);
#endif
int32 bytes = vsnprintf(buffer, bufferSize, format, clonedArgs);
va_end(clonedArgs);
if (bytes < 0)
return Truncate(0);
if (bytes < bufferSize) {
SetTo(buffer);
return *this;
}
bytes = vsnprintf(LockBuffer(bytes), bytes + 1, format, args);
if (bytes < 0)
bytes = 0;
UnlockBuffer(bytes);
return *this;
}
int
BString::ScanWithFormat(const char* format, ...)
{
va_list args;
va_start(args, format);
int result = ScanWithFormatVarArgs(format, args);
va_end(args);
return result;
}
int
BString::ScanWithFormatVarArgs(const char* format, va_list args)
{
return vsscanf(fPrivateData, format, args);
}
BString&
BString::CopyInto(BString& into, int32 fromOffset, int32 length) const
{
if (this != &into)
into.SetTo(fPrivateData + fromOffset, length);
return into;
}
void
BString::CopyInto(char* into, int32 fromOffset, int32 length) const
{
if (into) {
length = min_clamp0(length, Length() - fromOffset);
memcpy(into, fPrivateData + fromOffset, length);
}
}
BString&
BString::CopyCharsInto(BString& into, int32 fromCharOffset,
int32 charCount) const
{
int32 fromOffset = UTF8CountBytes(fPrivateData, fromCharOffset);
int32 length = UTF8CountBytes(fPrivateData + fromOffset, charCount);
return CopyInto(into, fromOffset, length);
}
bool
BString::CopyCharsInto(char* into, int32* intoLength, int32 fromCharOffset,
int32 charCount) const
{
if (into == NULL)
return false;
int32 fromOffset = UTF8CountBytes(fPrivateData, fromCharOffset);
int32 length = UTF8CountBytes(fPrivateData + fromOffset, charCount);
length = min_clamp0(length, Length() - fromOffset);
if (intoLength != NULL) {
if (*intoLength < length)
return false;
*intoLength = length;
}
memcpy(into, fPrivateData + fromOffset, length);
return true;
}
bool
BString::Split(const char* separator, bool noEmptyStrings,
BStringList& _list) const
{
int32 separatorLength = strlen(separator);
int32 length = Length();
if (separatorLength == 0 || length == 0 || separatorLength > length) {
if (length == 0 && noEmptyStrings)
return true;
return _list.Add(*this);
}
int32 index = 0;
for (;;) {
int32 endIndex = index < length ? FindFirst(separator, index) : length;
if (endIndex < 0)
endIndex = length;
if (endIndex > index || !noEmptyStrings) {
BString toAppend(String() + index, endIndex - index);
if (toAppend.Length() != endIndex - index
|| !_list.Add(toAppend)) {
return false;
}
}
if (endIndex == length)
break;
index = endIndex + separatorLength;
}
return true;
}
BString&
BString::operator+=(const char* string)
{
if (string) {
int32 length = strlen(string);
if (length > 0)
_DoAppend(string, length);
}
return *this;
}
BString&
BString::operator+=(char c)
{
_DoAppend(&c, 1);
return *this;
}
BString&
BString::Append(const BString& string, int32 length)
{
if (&string != this) {
length = min_clamp0(length, string.Length());
if (length > 0)
_DoAppend(string.fPrivateData, length);
}
return *this;
}
BString&
BString::Append(const char* string, int32 length)
{
if (string) {
length = strlen_clamp(string, length);
if (length > 0)
_DoAppend(string, length);
}
return *this;
}
BString&
BString::Append(char c, int32 count)
{
int32 oldLength = Length();
if (count > 0 && _DoAppend("", count))
memset(fPrivateData + oldLength, c, count);
return *this;
}
BString&
BString::AppendChars(const BString& string, int32 charCount)
{
return Append(string, UTF8CountBytes(string.String(), charCount));
}
BString&
BString::AppendChars(const char* string, int32 charCount)
{
return Append(string, UTF8CountBytes(string, charCount));
}
BString&
BString::Prepend(const char* string)
{
if (string)
_DoPrepend(string, strlen(string));
return *this;
}
BString&
BString::Prepend(const BString& string)
{
if (&string != this)
_DoPrepend(string.String(), string.Length());
return *this;
}
BString&
BString::Prepend(const char* string, int32 length)
{
if (string)
_DoPrepend(string, strlen_clamp(string, length));
return *this;
}
BString&
BString::Prepend(const BString& string, int32 length)
{
if (&string != this)
_DoPrepend(string.fPrivateData, min_clamp0(length, string.Length()));
return *this;
}
BString&
BString::Prepend(char c, int32 count)
{
if (count > 0 && _DoPrepend("", count))
memset(fPrivateData, c, count);
return *this;
}
BString&
BString::PrependChars(const char* string, int32 charCount)
{
return Prepend(string, UTF8CountBytes(string, charCount));
}
BString&
BString::PrependChars(const BString& string, int32 charCount)
{
return Prepend(string, UTF8CountBytes(string.String(), charCount));
}
BString&
BString::Insert(const char* string, int32 position)
{
if (string != NULL && position <= Length()) {
int32 len = int32(strlen(string));
if (position < 0) {
int32 skipLen = min_clamp0(-1 * position, len);
string += skipLen;
len -= skipLen;
position = 0;
} else {
position = min_clamp0(position, Length());
}
_DoInsert(string, position, len);
}
return *this;
}
BString&
BString::Insert(const char* string, int32 length, int32 position)
{
if (string != NULL && position <= Length()) {
int32 len = strlen_clamp(string, length);
if (position < 0) {
int32 skipLen = min_clamp0(-1 * position, len);
string += skipLen;
len -= skipLen;
position = 0;
} else {
position = min_clamp0(position, Length());
}
_DoInsert(string, position, len);
}
return *this;
}
BString&
BString::Insert(const char* string, int32 fromOffset, int32 length,
int32 position)
{
if (string)
Insert(string + fromOffset, length, position);
return *this;
}
BString&
BString::Insert(const BString& string, int32 position)
{
if (&string != this && string.Length() > 0)
Insert(string.fPrivateData, position);
return *this;
}
BString&
BString::Insert(const BString& string, int32 length, int32 position)
{
if (&string != this && string.Length() > 0)
Insert(string.String(), length, position);
return *this;
}
BString&
BString::Insert(const BString& string, int32 fromOffset, int32 length,
int32 position)
{
if (&string != this && string.Length() > 0)
Insert(string.String() + fromOffset, length, position);
return *this;
}
BString&
BString::Insert(char c, int32 count, int32 position)
{
if (position < 0) {
count = MAX(count + position, 0);
position = 0;
} else
position = min_clamp0(position, Length());
if (count > 0 && _DoInsert("", position, count))
memset(fPrivateData + position, c, count);
return *this;
}
BString&
BString::InsertChars(const char* string, int32 charPosition)
{
return Insert(string, UTF8CountBytes(fPrivateData, charPosition));
}
BString&
BString::InsertChars(const char* string, int32 charCount, int32 charPosition)
{
return Insert(string, UTF8CountBytes(string, charCount),
UTF8CountBytes(fPrivateData, charPosition));
}
BString&
BString::InsertChars(const char* string, int32 fromCharOffset,
int32 charCount, int32 charPosition)
{
int32 fromOffset = UTF8CountBytes(string, fromCharOffset);
return Insert(string, fromOffset,
UTF8CountBytes(string + fromOffset, charCount),
UTF8CountBytes(fPrivateData, charPosition));
}
BString&
BString::InsertChars(const BString& string, int32 charPosition)
{
return Insert(string, UTF8CountBytes(fPrivateData, charPosition));
}
BString&
BString::InsertChars(const BString& string, int32 charCount, int32 charPosition)
{
return Insert(string, UTF8CountBytes(string.String(), charCount),
UTF8CountBytes(fPrivateData, charPosition));
}
BString&
BString::InsertChars(const BString& string, int32 fromCharOffset,
int32 charCount, int32 charPosition)
{
int32 fromOffset = UTF8CountBytes(string.String(), fromCharOffset);
return Insert(string, fromOffset,
UTF8CountBytes(string.String() + fromOffset, charCount),
UTF8CountBytes(fPrivateData, charPosition));
}
BString&
BString::Truncate(int32 newLength, bool lazy)
{
if (newLength < 0)
newLength = 0;
if (newLength < Length()) {
_MakeWritable(newLength, true);
}
return *this;
}
BString&
BString::TruncateChars(int32 newCharCount, bool lazy)
{
return Truncate(UTF8CountBytes(fPrivateData, newCharCount));
}
BString&
BString::Remove(int32 from, int32 length)
{
if (length > 0 && from < Length())
_ShrinkAtBy(from, min_clamp0(length, (Length() - from)));
return *this;
}
BString&
BString::RemoveChars(int32 fromCharOffset, int32 charCount)
{
int32 fromOffset = UTF8CountBytes(fPrivateData, fromCharOffset);
return Remove(fromOffset,
UTF8CountBytes(fPrivateData + fromOffset, charCount));
}
BString&
BString::RemoveFirst(const BString& string)
{
if (string.Length() > 0) {
int32 pos = _ShortFindAfter(string.String(), string.Length());
if (pos >= 0)
_ShrinkAtBy(pos, string.Length());
}
return *this;
}
BString&
BString::RemoveLast(const BString& string)
{
int32 pos = _FindBefore(string.String(), Length(), string.Length());
if (pos >= 0)
_ShrinkAtBy(pos, string.Length());
return *this;
}
BString&
BString::RemoveAll(const BString& string)
{
if (string.Length() == 0 || Length() == 0 || FindFirst(string) < 0)
return *this;
if (_MakeWritable() != B_OK)
return *this;
return _DoReplace(string.String(), "", REPLACE_ALL, 0, KEEP_CASE);
}
BString&
BString::RemoveFirst(const char* string)
{
int32 length = string ? strlen(string) : 0;
if (length > 0) {
int32 pos = _ShortFindAfter(string, length);
if (pos >= 0)
_ShrinkAtBy(pos, length);
}
return *this;
}
BString&
BString::RemoveLast(const char* string)
{
int32 length = string ? strlen(string) : 0;
if (length > 0) {
int32 pos = _FindBefore(string, Length(), length);
if (pos >= 0)
_ShrinkAtBy(pos, length);
}
return *this;
}
BString&
BString::RemoveAll(const char* string)
{
if (!string || Length() == 0 || FindFirst(string) < 0)
return *this;
if (_MakeWritable() != B_OK)
return *this;
return _DoReplace(string, "", REPLACE_ALL, 0, KEEP_CASE);
}
BString&
BString::RemoveSet(const char* setOfBytesToRemove)
{
return ReplaceSet(setOfBytesToRemove, "");
}
BString&
BString::RemoveCharsSet(const char* setOfCharsToRemove)
{
return ReplaceCharsSet(setOfCharsToRemove, "");
}
BString&
BString::MoveInto(BString& into, int32 from, int32 length)
{
if (length) {
CopyInto(into, from, length);
Remove(from, length);
}
return into;
}
void
BString::MoveInto(char* into, int32 from, int32 length)
{
if (into) {
CopyInto(into, from, length);
Remove(from, length);
}
}
BString&
BString::MoveCharsInto(BString& into, int32 fromCharOffset, int32 charCount)
{
if (charCount > 0) {
CopyCharsInto(into, fromCharOffset, charCount);
RemoveChars(fromCharOffset, charCount);
}
return into;
}
bool
BString::MoveCharsInto(char* into, int32* intoLength, int32 fromCharOffset,
int32 charCount)
{
if (!CopyCharsInto(into, intoLength, fromCharOffset, charCount))
return false;
RemoveChars(fromCharOffset, charCount);
return true;
}
bool
BString::operator<(const char* string) const
{
return strcmp(String(), safestr(string)) < 0;
}
bool
BString::operator<=(const char* string) const
{
return strcmp(String(), safestr(string)) <= 0;
}
bool
BString::operator==(const char* string) const
{
return strcmp(String(), safestr(string)) == 0;
}
bool
BString::operator>=(const char* string) const
{
return strcmp(String(), safestr(string)) >= 0;
}
bool
BString::operator>(const char* string) const
{
return strcmp(String(), safestr(string)) > 0;
}
int
BString::Compare(const BString& string) const
{
return strcmp(String(), string.String());
}
int
BString::Compare(const char* string) const
{
return strcmp(String(), safestr(string));
}
int
BString::Compare(const BString& string, int32 length) const
{
return strncmp(String(), string.String(), length);
}
int
BString::Compare(const char* string, int32 length) const
{
return strncmp(String(), safestr(string), length);
}
int
BString::CompareAt(size_t offset, const BString& string, int32 length) const
{
return strncmp(String() + offset, string.String(), length);
}
int
BString::CompareChars(const BString& string, int32 charCount) const
{
return Compare(string, UTF8CountBytes(fPrivateData, charCount));
}
int
BString::CompareChars(const char* string, int32 charCount) const
{
return Compare(string, UTF8CountBytes(fPrivateData, charCount));
}
int
BString::ICompare(const BString& string) const
{
return strcasecmp(String(), string.String());
}
int
BString::ICompare(const char* string) const
{
return strcasecmp(String(), safestr(string));
}
int
BString::ICompare(const BString& string, int32 length) const
{
return strncasecmp(String(), string.String(), length);
}
int
BString::ICompare(const char* string, int32 length) const
{
return strncasecmp(String(), safestr(string), length);
}
int32
BString::FindFirst(const BString& string) const
{
return _ShortFindAfter(string.String(), string.Length());
}
int32
BString::FindFirst(const char* string) const
{
if (string == NULL)
return B_BAD_VALUE;
return _ShortFindAfter(string, strlen(string));
}
int32
BString::FindFirst(const BString& string, int32 fromOffset) const
{
if (fromOffset < 0)
return B_ERROR;
return _FindAfter(string.String(), min_clamp0(fromOffset, Length()),
string.Length());
}
int32
BString::FindFirst(const char* string, int32 fromOffset) const
{
if (string == NULL)
return B_BAD_VALUE;
if (fromOffset < 0)
return B_ERROR;
return _FindAfter(string, min_clamp0(fromOffset, Length()),
strlen(safestr(string)));
}
int32
BString::FindFirst(char c) const
{
const char* start = String();
const char* end = String() + Length();
while (start != end && *start != c) {
start++;
}
if (start == end)
return B_ERROR;
return start - String();
}
int32
BString::FindFirst(char c, int32 fromOffset) const
{
if (fromOffset < 0)
return B_ERROR;
const char* start = String() + min_clamp0(fromOffset, Length());
const char* end = String() + Length();
while (start < end && *start != c) {
start++;
}
if (start >= end)
return B_ERROR;
return start - String();
}
int32
BString::FindFirstChars(const BString& string, int32 fromCharOffset) const
{
return FindFirst(string, UTF8CountBytes(fPrivateData, fromCharOffset));
}
int32
BString::FindFirstChars(const char* string, int32 fromCharOffset) const
{
return FindFirst(string, UTF8CountBytes(fPrivateData, fromCharOffset));
}
int32
BString::FindLast(const BString& string) const
{
return _FindBefore(string.String(), Length(), string.Length());
}
int32
BString::FindLast(const char* string) const
{
if (string == NULL)
return B_BAD_VALUE;
return _FindBefore(string, Length(), strlen(safestr(string)));
}
int32
BString::FindLast(const BString& string, int32 beforeOffset) const
{
if (beforeOffset < 0)
return B_ERROR;
return _FindBefore(string.String(), min_clamp0(beforeOffset, Length()),
string.Length());
}
int32
BString::FindLast(const char* string, int32 beforeOffset) const
{
if (string == NULL)
return B_BAD_VALUE;
if (beforeOffset < 0)
return B_ERROR;
return _FindBefore(string, min_clamp0(beforeOffset, Length()),
strlen(safestr(string)));
}
int32
BString::FindLast(char c) const
{
const char* const start = String();
const char* end = String() + Length() - 1;
while (end >= start && *end != c) {
end--;
}
if (end < start)
return B_ERROR;
return end - start;
}
int32
BString::FindLast(char c, int32 beforeOffset) const
{
if (beforeOffset < 0)
return B_ERROR;
const char* const start = String();
const char* end = String() + min_clamp0(beforeOffset + 1, Length()) - 1;
while (end >= start && *end != c) {
end--;
}
if (end < start)
return B_ERROR;
return end - start;
}
int32
BString::FindLastChars(const BString& string, int32 beforeCharOffset) const
{
return FindLast(string, UTF8CountBytes(fPrivateData, beforeCharOffset));
}
int32
BString::FindLastChars(const char* string, int32 beforeCharOffset) const
{
return FindLast(string, UTF8CountBytes(fPrivateData, beforeCharOffset));
}
int32
BString::IFindFirst(const BString& string) const
{
return _IFindAfter(string.String(), 0, string.Length());
}
int32
BString::IFindFirst(const char* string) const
{
if (string == NULL)
return B_BAD_VALUE;
return _IFindAfter(string, 0, strlen(safestr(string)));
}
int32
BString::IFindFirst(const BString& string, int32 fromOffset) const
{
if (fromOffset < 0)
return B_ERROR;
return _IFindAfter(string.String(), min_clamp0(fromOffset, Length()),
string.Length());
}
int32
BString::IFindFirst(const char* string, int32 fromOffset) const
{
if (string == NULL)
return B_BAD_VALUE;
if (fromOffset < 0)
return B_ERROR;
return _IFindAfter(string, min_clamp0(fromOffset,Length()),
strlen(safestr(string)));
}
int32
BString::IFindLast(const BString& string) const
{
return _IFindBefore(string.String(), Length(), string.Length());
}
int32
BString::IFindLast(const char* string) const
{
if (string == NULL)
return B_BAD_VALUE;
return _IFindBefore(string, Length(), strlen(safestr(string)));
}
int32
BString::IFindLast(const BString& string, int32 beforeOffset) const
{
if (beforeOffset < 0)
return B_ERROR;
return _IFindBefore(string.String(), min_clamp0(beforeOffset, Length()),
string.Length());
}
int32
BString::IFindLast(const char* string, int32 beforeOffset) const
{
if (string == NULL)
return B_BAD_VALUE;
if (beforeOffset < 0)
return B_ERROR;
return _IFindBefore(string, min_clamp0(beforeOffset, Length()),
strlen(safestr(string)));
}
bool
BString::StartsWith(const BString& string) const
{
return StartsWith(string.String(), string.Length());
}
bool
BString::StartsWith(const char* string) const
{
return StartsWith(string, strlen(safestr(string)));
}
bool
BString::StartsWith(const char* string, int32 length) const
{
if (length > Length())
return false;
return memcmp(String(), string, length) == 0;
}
bool
BString::IStartsWith(const BString& string) const
{
return IStartsWith(string.String(), string.Length());
}
bool
BString::IStartsWith(const char* string) const
{
return IStartsWith(string, strlen(safestr(string)));
}
bool
BString::IStartsWith(const char* string, int32 length) const
{
if (length > Length() || length > (int32)strlen(safestr(string)))
return false;
return _IFindAfter(string, 0, length) == 0;
}
bool
BString::EndsWith(const BString& string) const
{
return EndsWith(string.String(), string.Length());
}
bool
BString::EndsWith(const char* string) const
{
return EndsWith(string, strlen(safestr(string)));
}
bool
BString::EndsWith(const char* string, int32 length) const
{
int32 offset = Length() - length;
if (offset < 0)
return false;
return memcmp(String() + offset, string, length) == 0;
}
bool
BString::IEndsWith(const BString& string) const
{
return IEndsWith(string.String(), string.Length());
}
bool
BString::IEndsWith(const char* string) const
{
return IEndsWith(string, strlen(safestr(string)));
}
bool
BString::IEndsWith(const char* string, int32 length) const
{
int32 offset = Length() - length;
if (offset < 0)
return false;
return _IFindBefore(string, Length(), length) == offset;
}
BString&
BString::ReplaceFirst(char replaceThis, char withThis)
{
int32 pos = FindFirst(replaceThis);
if (pos >= 0 && _MakeWritable() == B_OK)
fPrivateData[pos] = withThis;
return *this;
}
BString&
BString::ReplaceLast(char replaceThis, char withThis)
{
int32 pos = FindLast(replaceThis);
if (pos >= 0 && _MakeWritable() == B_OK)
fPrivateData[pos] = withThis;
return *this;
}
BString&
BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset)
{
fromOffset = min_clamp0(fromOffset, Length());
int32 pos = FindFirst(replaceThis, fromOffset);
if (pos >= 0 && _MakeWritable() == B_OK) {
for( ; pos >= 0; pos = FindFirst(replaceThis, pos + 1))
fPrivateData[pos] = withThis;
}
return *this;
}
BString&
BString::Replace(char replaceThis, char withThis, int32 maxReplaceCount,
int32 fromOffset)
{
fromOffset = min_clamp0(fromOffset, Length());
int32 pos = FindFirst(replaceThis, fromOffset);
if (maxReplaceCount > 0 && pos >= 0 && _MakeWritable() == B_OK) {
for( ; maxReplaceCount > 0 && pos >= 0;
pos = FindFirst(replaceThis, pos + 1)) {
fPrivateData[pos] = withThis;
maxReplaceCount--;
}
}
return *this;
}
BString&
BString::ReplaceFirst(const char* replaceThis, const char* withThis)
{
if (replaceThis == NULL || FindFirst(replaceThis) < 0)
return *this;
if (_MakeWritable() != B_OK)
return *this;
return _DoReplace(replaceThis, withThis, 1, 0, KEEP_CASE);
}
BString&
BString::ReplaceLast(const char* replaceThis, const char* withThis)
{
if (replaceThis == NULL)
return *this;
if (withThis == NULL)
withThis = "";
int32 replaceThisLength = strlen(replaceThis);
int32 pos = _FindBefore(replaceThis, Length(), replaceThisLength);
if (pos >= 0) {
int32 withThisLength = strlen(withThis);
int32 difference = withThisLength - replaceThisLength;
if (difference > 0) {
if (!_OpenAtBy(pos, difference))
return *this;
} else if (difference < 0) {
if (!_ShrinkAtBy(pos, -difference))
return *this;
} else {
if (_MakeWritable() != B_OK)
return *this;
}
memcpy(fPrivateData + pos, withThis, withThisLength);
}
return *this;
}
BString&
BString::ReplaceAll(const char* replaceThis, const char* withThis,
int32 fromOffset)
{
if (replaceThis == NULL || FindFirst(replaceThis) < 0)
return *this;
if (_MakeWritable() != B_OK)
return *this;
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)
{
if (replaceThis == NULL || maxReplaceCount <= 0
|| FindFirst(replaceThis) < 0)
return *this;
if (_MakeWritable() != B_OK)
return *this;
return _DoReplace(replaceThis, withThis, maxReplaceCount,
min_clamp0(fromOffset, Length()), KEEP_CASE);
}
BString&
BString::ReplaceAllChars(const char* replaceThis, const char* withThis,
int32 fromCharOffset)
{
return ReplaceAll(replaceThis, withThis,
UTF8CountBytes(fPrivateData, fromCharOffset));
}
BString&
BString::ReplaceChars(const char* replaceThis, const char* withThis,
int32 maxReplaceCount, int32 fromCharOffset)
{
return Replace(replaceThis, withThis, maxReplaceCount,
UTF8CountBytes(fPrivateData, fromCharOffset));
}
BString&
BString::IReplaceFirst(char replaceThis, char withThis)
{
char tmp[2] = { replaceThis, '\0' };
int32 pos = _IFindAfter(tmp, 0, 1);
if (pos >= 0 && _MakeWritable() == B_OK)
fPrivateData[pos] = withThis;
return *this;
}
BString&
BString::IReplaceLast(char replaceThis, char withThis)
{
char tmp[2] = { replaceThis, '\0' };
int32 pos = _IFindBefore(tmp, Length(), 1);
if (pos >= 0 && _MakeWritable() == B_OK)
fPrivateData[pos] = withThis;
return *this;
}
BString&
BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset)
{
char tmp[2] = { replaceThis, '\0' };
fromOffset = min_clamp0(fromOffset, Length());
int32 pos = _IFindAfter(tmp, fromOffset, 1);
if (pos >= 0 && _MakeWritable() == B_OK) {
for( ; pos >= 0; pos = _IFindAfter(tmp, pos + 1, 1))
fPrivateData[pos] = withThis;
}
return *this;
}
BString&
BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount,
int32 fromOffset)
{
char tmp[2] = { replaceThis, '\0' };
fromOffset = min_clamp0(fromOffset, Length());
int32 pos = _IFindAfter(tmp, fromOffset, 1);
if (maxReplaceCount > 0 && pos >= 0 && _MakeWritable() == B_OK) {
for( ; maxReplaceCount > 0 && pos >= 0;
pos = _IFindAfter(tmp, pos + 1, 1)) {
fPrivateData[pos] = withThis;
maxReplaceCount--;
}
}
return *this;
}
BString&
BString::IReplaceFirst(const char* replaceThis, const char* withThis)
{
if (replaceThis == NULL || IFindFirst(replaceThis) < 0)
return *this;
if (_MakeWritable() != B_OK)
return *this;
return _DoReplace(replaceThis, withThis, 1, 0, IGNORE_CASE);
}
BString&
BString::IReplaceLast(const char* replaceThis, const char* withThis)
{
if (replaceThis == NULL)
return *this;
if (withThis == NULL)
withThis = "";
int32 replaceThisLength = strlen(replaceThis);
int32 pos = _IFindBefore(replaceThis, Length(), replaceThisLength);
if (pos >= 0) {
int32 withThisLength = strlen(withThis);
int32 difference = withThisLength - replaceThisLength;
if (difference > 0) {
if (!_OpenAtBy(pos, difference))
return *this;
} else if (difference < 0) {
if (!_ShrinkAtBy(pos, -difference))
return *this;
} else {
if (_MakeWritable() != B_OK)
return *this;
}
memcpy(fPrivateData + pos, withThis, withThisLength);
}
return *this;
}
BString&
BString::IReplaceAll(const char* replaceThis, const char* withThis,
int32 fromOffset)
{
if (replaceThis == NULL || IFindFirst(replaceThis) < 0)
return *this;
if (_MakeWritable() != B_OK)
return *this;
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)
{
if (replaceThis == NULL || maxReplaceCount <= 0
|| FindFirst(replaceThis) < 0)
return *this;
if (_MakeWritable() != B_OK)
return *this;
return _DoReplace(replaceThis, withThis, maxReplaceCount,
min_clamp0(fromOffset, Length()), IGNORE_CASE);
}
BString&
BString::ReplaceSet(const char* setOfBytes, char with)
{
if (!setOfBytes || strcspn(fPrivateData, setOfBytes) >= uint32(Length()))
return *this;
if (_MakeWritable() != B_OK)
return *this;
int32 offset = 0;
int32 length = Length();
for (int32 pos;;) {
pos = strcspn(fPrivateData + offset, setOfBytes);
offset += pos;
if (offset >= length)
break;
fPrivateData[offset] = with;
offset++;
}
return *this;
}
BString&
BString::ReplaceSet(const char* setOfBytes, const char* with)
{
if (!setOfBytes || !with
|| strcspn(fPrivateData, setOfBytes) >= uint32(Length()))
return *this;
int32 withLen = strlen(with);
if (withLen == 1)
return ReplaceSet(setOfBytes, *with);
if (_MakeWritable() != B_OK)
return *this;
int32 pos = 0;
int32 searchLen = 1;
int32 len = Length();
PosVect positions;
for (int32 offset = 0; offset < len; offset += (pos + searchLen)) {
pos = strcspn(fPrivateData + offset, setOfBytes);
if (pos + offset >= len)
break;
if (!positions.Add(offset + pos))
return *this;
}
_ReplaceAtPositions(&positions, searchLen, with, withLen);
return *this;
}
BString&
BString::ReplaceCharsSet(const char* setOfChars, const char* with)
{
if (!setOfChars || !with)
return *this;
int32 setCharCount = UTF8CountChars(setOfChars, -1);
if ((uint32)setCharCount == strlen(setOfChars)) {
return ReplaceSet(setOfChars, with);
}
BString setString(setOfChars);
BString result;
int32 withLength = strlen(with);
int32 charCount = CountChars();
for (int32 i = 0; i < charCount; i++) {
int32 charLength;
const char* sourceChar = CharAt(i, &charLength);
bool match = false;
for (int32 j = 0; j < setCharCount; j++) {
int32 setCharLength;
const char* setChar = setString.CharAt(j, &setCharLength);
if (charLength == setCharLength
&& memcmp(sourceChar, setChar, charLength) == 0) {
match = true;
break;
}
}
if (match)
result.Append(with, withLength);
else
result.Append(sourceChar, charLength);
}
*this = result;
return *this;
}
#if __GNUC__ == 2
char&
BString::operator[](int32 index)
{
if (_MakeWritable() != B_OK) {
static char invalid;
return invalid;
}
_ReferenceCount() = -1;
return fPrivateData[index];
}
#endif
const char*
BString::CharAt(int32 charIndex, int32* bytes) const
{
int32 offset = UTF8CountBytes(fPrivateData, charIndex);
if (bytes != NULL)
*bytes = UTF8NextCharLen(fPrivateData + offset);
return fPrivateData + offset;
}
bool
BString::CharAt(int32 charIndex, char* buffer, int32* bytes) const
{
int32 length;
const char* charAt = CharAt(charIndex, &length);
if (bytes != NULL) {
if (*bytes < length)
return false;
*bytes = length;
}
memcpy(buffer, charAt, length);
return true;
}
char*
BString::LockBuffer(int32 maxLength)
{
int32 length = Length();
if (maxLength > length)
length = maxLength;
if (_MakeWritable(length, true) != B_OK)
return NULL;
_ReferenceCount() = -1;
return fPrivateData;
}
BString&
BString::UnlockBuffer(int32 length)
{
if (length > 0)
length = min_clamp0(length, Length());
else
length = fPrivateData == NULL ? 0 : strlen(fPrivateData);
if (_Resize(length) != NULL) {
fPrivateData[length] = '\0';
_ReferenceCount() = 1;
}
return *this;
}
BString&
BString::SetByteAt(int32 pos, char to)
{
if (pos < Length() && _MakeWritable() == B_OK)
fPrivateData[pos] = to;
return *this;
}
BString&
BString::ToLower()
{
int32 length = Length();
if (length > 0 && _MakeWritable() == B_OK) {
for (int32 count = 0; count < length; count++)
fPrivateData[count] = tolower(fPrivateData[count]);
}
return *this;
}
BString&
BString::ToUpper()
{
int32 length = Length();
if (length > 0 && _MakeWritable() == B_OK) {
for (int32 count = 0; count < length; count++)
fPrivateData[count] = toupper(fPrivateData[count]);
}
return *this;
}
BString&
BString::Capitalize()
{
int32 length = Length();
if (length > 0 && _MakeWritable() == B_OK) {
fPrivateData[0] = toupper(fPrivateData[0]);
for (int32 count = 1; count < length; count++)
fPrivateData[count] = tolower(fPrivateData[count]);
}
return *this;
}
BString&
BString::CapitalizeEachWord()
{
int32 length = Length();
if (length > 0 && _MakeWritable() == B_OK) {
int32 count = 0;
do {
for (; count < length; count++) {
if (isalpha(fPrivateData[count])) {
fPrivateData[count] = toupper(fPrivateData[count]);
count++;
break;
}
}
for (; count < length; count++) {
if (isalpha(fPrivateData[count]))
fPrivateData[count] = tolower(fPrivateData[count]);
else
break;
}
} while (count < length);
}
return *this;
}
BString&
BString::CharacterEscape(const char* original,
const char* setOfCharsToEscape, char escapeWith)
{
if (setOfCharsToEscape)
_DoCharacterEscape(original, setOfCharsToEscape, escapeWith);
return *this;
}
BString&
BString::CharacterEscape(const char* setOfCharsToEscape, char escapeWith)
{
if (setOfCharsToEscape && Length() > 0)
_DoCharacterEscape(fPrivateData, setOfCharsToEscape, escapeWith);
return *this;
}
BString&
BString::CharacterDeescape(const char* original, char escapeChar)
{
return _DoCharacterDeescape(original, escapeChar);
}
BString&
BString::CharacterDeescape(char escapeChar)
{
if (Length() > 0)
_DoCharacterDeescape(fPrivateData, escapeChar);
return *this;
}
BString&
BString::Trim()
{
if (Length() <= 0)
return *this;
const char* string = String();
int32 startCount = 0;
while (isspace(string[startCount]))
startCount++;
int32 endIndex = Length() - 1;
while (endIndex >= startCount && isspace(string[endIndex]))
endIndex--;
if (startCount == 0 && endIndex == Length() - 1)
return *this;
ssize_t length = endIndex + 1 - startCount;
ASSERT(length >= 0);
if (startCount == 0 || length == 0) {
_MakeWritable(length, true);
} else if (_MakeWritable() == B_OK) {
memmove(fPrivateData, fPrivateData + startCount, length);
fPrivateData[length] = '\0';
_SetLength(length);
}
return *this;
}
BString&
BString::operator<<(const char* string)
{
if (string != NULL) {
int32 length = strlen(string);
if (length > 0)
_DoAppend(string, length);
}
return *this;
}
BString&
BString::operator<<(const BString& string)
{
if (string.Length() > 0)
_DoAppend(string.String(), string.Length());
return *this;
}
BString&
BString::operator<<(char c)
{
_DoAppend(&c, 1);
return *this;
}
BString&
BString::operator<<(bool value)
{
if (value)
_DoAppend("true", 4);
else
_DoAppend("false", 5);
return *this;
}
BString&
BString::operator<<(int i)
{
char num[32];
int32 length = snprintf(num, sizeof(num), "%d", i);
_DoAppend(num, length);
return *this;
}
BString&
BString::operator<<(unsigned int i)
{
char num[32];
int32 length = snprintf(num, sizeof(num), "%u", i);
_DoAppend(num, length);
return *this;
}
BString&
BString::operator<<(unsigned long i)
{
char num[32];
int32 length = snprintf(num, sizeof(num), "%lu", i);
_DoAppend(num, length);
return *this;
}
BString&
BString::operator<<(long i)
{
char num[32];
int32 length = snprintf(num, sizeof(num), "%ld", i);
_DoAppend(num, length);
return *this;
}
BString&
BString::operator<<(unsigned long long i)
{
char num[64];
int32 length = snprintf(num, sizeof(num), "%llu", i);
_DoAppend(num, length);
return *this;
}
BString&
BString::operator<<(long long i)
{
char num[64];
int32 length = snprintf(num, sizeof(num), "%lld", i);
_DoAppend(num, length);
return *this;
}
BString&
BString::operator<<(float f)
{
char num[64];
int32 length = snprintf(num, sizeof(num), "%.2f", f);
_DoAppend(num, length);
return *this;
}
BString&
BString::operator<<(double value)
{
char num[64];
int32 length = snprintf(num, sizeof(num), "%.2f", value);
_DoAppend(num, length);
return *this;
}
BString::BString(char* privateData, PrivateDataTag tag)
:
fPrivateData(privateData)
{
if (fPrivateData != NULL)
atomic_add(&_ReferenceCount(), 1);
}
this string writable.
*/
status_t
BString::_MakeWritable()
{
if (fPrivateData == NULL)
return B_NO_INIT;
if (atomic_get(&_ReferenceCount()) > 1) {
char* newData = _Clone(fPrivateData, Length());
_ReleasePrivateData();
if (newData == NULL)
return B_NO_MEMORY;
fPrivateData = newData;
}
return B_OK;
}
including the terminating null).
@param length The length of the new buffer in bytes.
@param copy If true, the current string will be copied into the new string.
*/
status_t
BString::_MakeWritable(int32 length, bool copy)
{
char* newData = NULL;
if (fPrivateData != NULL && atomic_get(&_ReferenceCount()) > 1) {
if (copy)
newData = _Clone(fPrivateData, length);
else
newData = _Allocate(length);
if (newData == NULL)
return B_NO_MEMORY;
_ReleasePrivateData();
} else {
newData = _Resize(length);
if (newData == NULL)
return B_NO_MEMORY;
}
fPrivateData = newData;
return B_OK;
}
(not including the terminating null).
*/
char*
BString::_Allocate(int32 length)
{
if (length < 0)
return NULL;
char* newData = (char*)malloc(length + kPrivateDataOffset + 1);
if (newData == NULL)
return NULL;
newData += kPrivateDataOffset;
newData[length] = '\0';
Private::DataRefCount(newData) = 1;
Private::DataLength(newData) = length & 0x7fffffff;
return newData;
}
when you call this method.
*/
char*
BString::_Resize(int32 length)
{
ASSERT(_ReferenceCount() == 1 || _ReferenceCount() == -1);
if (length == Length())
return fPrivateData;
char* data = fPrivateData ? fPrivateData - kPrivateDataOffset : NULL;
if (length < 0)
length = 0;
data = (char*)realloc(data, length + kPrivateDataOffset + 1);
if (data == NULL)
return NULL;
data += kPrivateDataOffset;
fPrivateData = data;
fPrivateData[length] = '\0';
_SetLength(length);
_ReferenceCount() = 1;
return data;
}
void
BString::_Init(const char* src, int32 length)
{
fPrivateData = _Clone(src, length);
if (fPrivateData == NULL)
fPrivateData = _Clone(NULL, 0);
}
char*
BString::_Clone(const char* data, int32 length)
{
char* newData = _Allocate(length);
if (newData == NULL)
return NULL;
if (data != NULL && length > 0) {
strncpy(newData, data, length);
}
return newData;
}
char*
BString::_OpenAtBy(int32 offset, int32 length)
{
int32 oldLength = Length();
if (_MakeWritable() != B_OK)
return NULL;
memmove(fPrivateData + offset + length, fPrivateData + offset,
oldLength - offset);
return _Resize(oldLength + length);
}
char*
BString::_ShrinkAtBy(int32 offset, int32 length)
{
int32 oldLength = Length();
if (_MakeWritable() != B_OK)
return NULL;
memmove(fPrivateData + offset, fPrivateData + offset + length,
oldLength - offset - length);
return _Resize(oldLength - length);
}
void
BString::_SetLength(int32 length)
{
Private::DataLength(fPrivateData) = length & 0x7fffffff;
}
void
BString::_FreePrivateData()
{
if (fPrivateData != NULL) {
free(fPrivateData - kPrivateDataOffset);
fPrivateData = NULL;
}
}
void
BString::_ReleasePrivateData()
{
if (!_IsShareable() || atomic_add(&_ReferenceCount(), -1) == 1)
_FreePrivateData();
fPrivateData = NULL;
}
bool
BString::_DoAppend(const char* string, int32 length)
{
int32 oldLength = Length();
if (_MakeWritable(oldLength + length, true) == B_OK) {
strncpy(fPrivateData + oldLength, string, length);
return true;
}
return false;
}
bool
BString::_DoPrepend(const char* string, int32 length)
{
int32 oldLength = Length();
if (_MakeWritable(oldLength + length, true) == B_OK) {
memmove(fPrivateData + length, fPrivateData, oldLength);
if (string && length)
strncpy(fPrivateData, string, length);
return true;
}
return false;
}
bool
BString::_DoInsert(const char* string, int32 offset, int32 length)
{
int32 oldLength = Length();
if (_MakeWritable(oldLength + length, true) == B_OK) {
memmove(fPrivateData + offset + length, fPrivateData + offset,
oldLength - offset);
if (string != NULL && length)
strncpy(fPrivateData + offset, string, length);
return true;
}
return false;
}
int32
BString::_ShortFindAfter(const char* string, int32 len) const
{
const char* ptr = strstr(String(), string);
if (ptr != NULL)
return ptr - String();
return B_ERROR;
}
int32
BString::_FindAfter(const char* string, int32 offset, int32 length) const
{
const char* ptr = strstr(String() + offset, string);
if (ptr != NULL)
return ptr - String();
return B_ERROR;
}
int32
BString::_IFindAfter(const char* string, int32 offset, int32 length) const
{
const char* ptr = strcasestr(String() + offset, string);
if (ptr != NULL)
return ptr - String();
return B_ERROR;
}
int32
BString::_FindBefore(const char* string, int32 offset, int32 length) const
{
if (fPrivateData != NULL) {
const char* ptr = fPrivateData + offset - length;
while (ptr >= fPrivateData) {
if (!memcmp(ptr, string, length))
return ptr - fPrivateData;
ptr--;
}
}
return B_ERROR;
}
int32
BString::_IFindBefore(const char* string, int32 offset, int32 length) const
{
if (fPrivateData != NULL) {
char* ptr1 = fPrivateData + offset - length;
while (ptr1 >= fPrivateData) {
if (!strncasecmp(ptr1, string, length))
return ptr1 - fPrivateData;
ptr1--;
}
}
return B_ERROR;
}
BString&
BString::_DoCharacterEscape(const char* string, const char* setOfCharsToEscape,
char escapeChar)
{
if (_MakeWritable(string_length(string), false) != B_OK)
return *this;
memcpy(fPrivateData, string, Length());
PosVect positions;
int32 length = Length();
int32 pos;
for (int32 offset = 0; offset < length; offset += pos + 1) {
pos = strcspn(fPrivateData + offset, setOfCharsToEscape);
if (pos < length - offset && !positions.Add(offset + pos))
return *this;
}
uint32 count = positions.CountItems();
int32 newLength = length + count;
if (!newLength) {
_Resize(0);
return *this;
}
char* newData = _Allocate(newLength);
if (newData) {
char* oldString = fPrivateData;
char* newString = newData;
int32 lastPos = 0;
for (uint32 i = 0; i < count; ++i) {
pos = positions.ItemAt(i);
length = pos - lastPos;
if (length > 0) {
memcpy(newString, oldString, length);
oldString += length;
newString += length;
}
*newString++ = escapeChar;
*newString++ = *oldString++;
lastPos = pos + 1;
}
length = Length() + 1 - lastPos;
if (length > 0)
memcpy(newString, oldString, length);
_FreePrivateData();
fPrivateData = newData;
}
return *this;
}
BString&
BString::_DoCharacterDeescape(const char* string, char escapeChar)
{
if (_MakeWritable(string_length(string), false) != B_OK)
return *this;
memcpy(fPrivateData, string, Length());
const char escape[2] = { escapeChar, '\0' };
return _DoReplace(escape, "", REPLACE_ALL, 0, KEEP_CASE);
}
BString&
BString::_DoReplace(const char* findThis, const char* replaceWith,
int32 maxReplaceCount, int32 fromOffset, bool ignoreCase)
{
if (findThis == NULL || maxReplaceCount <= 0
|| fromOffset < 0 || fromOffset >= Length())
return *this;
int32 findLen = strlen(findThis);
if (findLen == 0)
return *this;
typedef int32 (BString::*TFindMethod)(const char*, int32, int32) const;
TFindMethod findMethod = ignoreCase
? &BString::_IFindAfter : &BString::_FindAfter;
if (replaceWith == NULL)
replaceWith = "";
int32 replaceLen = strlen(replaceWith);
int32 lastSrcPos = fromOffset;
PosVect positions;
for (int32 srcPos = 0; maxReplaceCount > 0
&& (srcPos = (this->*findMethod)(findThis, lastSrcPos, findLen)) >= 0;
maxReplaceCount--) {
positions.Add(srcPos);
lastSrcPos = srcPos + findLen;
}
_ReplaceAtPositions(&positions, findLen, replaceWith, replaceLen);
return *this;
}
void
BString::_ReplaceAtPositions(const PosVect* positions, int32 searchLength,
const char* with, int32 withLength)
{
int32 length = Length();
uint32 count = positions->CountItems();
int32 newLength = length + count * (withLength - searchLength);
if (!newLength) {
_Resize(0);
return;
}
char* newData = _Allocate(newLength);
if (newData == NULL)
return;
char* oldString = fPrivateData;
char* newString = newData;
int32 lastPos = 0;
for (uint32 i = 0; i < count; ++i) {
int32 pos = positions->ItemAt(i);
length = pos - lastPos;
if (length > 0) {
memcpy(newString, oldString, length);
oldString += length;
newString += length;
}
memcpy(newString, with, withLength);
oldString += searchLength;
newString += withLength;
lastPos = pos + searchLength;
}
length = Length() + 1 - lastPos;
if (length > 0)
memcpy(newString, oldString, length);
_FreePrivateData();
fPrivateData = newData;
}
BString& BString::operator<<(BString& string)
*/
extern "C" BString&
__ls__7BStringR7BString(BString* self, BString& string)
{
return self->operator<<(string);
}
#if __GNUC__ > 3
class BStringRef {
public:
BStringRef(BString& string, int32 position);
~BStringRef() {}
operator char() const;
char* operator&();
const char* operator&() const;
BStringRef& operator=(char c);
BStringRef& operator=(const BStringRef& rc);
private:
BString& fString;
int32 fPosition;
};
BStringRef::BStringRef(BString& string, int32 position)
:
fString(string), fPosition(position)
{
}
BStringRef::operator char() const
{
return fPosition < fString.Length() ? fString.fPrivateData[fPosition] : 0;
}
BStringRef&
BStringRef::operator=(char c)
{
fString._MakeWritable();
fString.fPrivateData[fPosition] = c;
return *this;
}
BStringRef&
BStringRef::operator=(const BStringRef &rc)
{
return operator=(rc.fString.fPrivateData[rc.fPosition]);
}
const char*
BStringRef::operator&() const
{
return &fString.fPrivateData[fPosition];
}
char*
BStringRef::operator&()
{
if (fString._MakeWritable() != B_OK)
return NULL;
fString._ReferenceCount() = -1;
return &fString.fPrivateData[fPosition];
}
extern "C" BStringRef
_ZN7BStringixEi(BString* self, int32 index)
{
return BStringRef(*self, index);
}
#endif
int
Compare(const BString& string1, const BString& string2)
{
return strcmp(string1.String(), string2.String());
}
int
ICompare(const BString& string1, const BString& string2)
{
return strcasecmp(string1.String(), string2.String());
}
int
Compare(const BString* string1, const BString* string2)
{
return strcmp(string1->String(), string2->String());
}
int
ICompare(const BString* string1, const BString* string2)
{
return strcasecmp(string1->String(), string2->String());
}