diff --git a/src/kits/support/String.cpp b/src/kits/support/String.cpp index 5105ed8d9f..b7e0447f20 100644 --- a/src/kits/support/String.cpp +++ b/src/kits/support/String.cpp @@ -27,35 +27,62 @@ //------------------------------------------------------------------------------ // Standard Includes ----------------------------------------------------------- -#include #include #include #include // System Includes ------------------------------------------------------------- -#define DEBUG 1 #include #include -#include // Temporary Includes #include "string_helper.h" -/*---- Construction --------------------------------------------------------*/ + +#define ENABLE_INLINES 0 // Set this to 1 to make some private methods inline + + +/*! + \class BString + \brief String class supporting common string operations + + BString is a string allocation and manipulation class. The object + takes care to allocate and free memory for you, so it will always be + "big enough" to store your strings. + + \author Stefano Ceccherini +*/ + +/*! \var char* BString::_privateData + \brief BString's storage for data +*/ + +// constructor +/*! \brief Creates an uninitialized BString. +*/ BString::BString() :_privateData(NULL) { } +// constructor +/*! \brief Creates a BString and initializes it to the given string. + \param str Pointer to a NULL terminated string. +*/ BString::BString(const char* str) :_privateData(NULL) { - if (str) + if (str!= NULL) _Init(str, strlen(str)); } +// copy constructor +/*! \brief Creates a BString and makes it a copy of the supplied one. + \param string the BString object to be copied. +*/ BString::BString(const BString &string) :_privateData(NULL) { @@ -63,17 +90,28 @@ BString::BString(const BString &string) } +// constructor +/*! \brief Creates a BString and initializes it to the given string. + \param str Pointer to a NULL terminated string. + \param maxLength The amount of characters you want to copy from the original + string. +*/ BString::BString(const char *str, int32 maxLength) :_privateData(NULL) { - if (str) { + if (str != NULL) + { int32 len = (int32)strlen(str); - _Init(str, min(len, maxLength)); + _Init(str, min_c(len, maxLength)); } } -/*---- Destruction ---------------------------------------------------------*/ +// destructor +/*! \brief Frees all resources associated with the object. + + Frees the memory allocated by the BString object. +*/ BString::~BString() { if (_privateData) @@ -82,12 +120,42 @@ BString::~BString() /*---- Access --------------------------------------------------------------*/ +// String, implemented inline in the header +/*! \fn const char* BString::String() const + \brief Returns a pointer to the object string, NULL terminated. + + Returns a pointer to the object string, guaranteed to be NULL + terminated. You can't modify or free the pointer. Once the BString + object is deleted, the pointer becomes invalid. + + \return A pointer to the object string. +*/ + + +// Length, implemented inline in the header +/*! \fn int32 BString::Length() const + \brief Returns the length of the string, measured in bytes. + \return The length of the string, measured in bytes. +*/ + + +// CountChars +/*! \brief Returns the length of the object measured in characters. + \return An integer which is the number of characters in the string. + + Counts the number of UTF8 characters contained in the string. +*/ int32 BString::CountChars() const { int32 count = 0; - const char *ptr = String(); - + + 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(); + #if 0 // ejaesler: Left in memoriam of one man's foolish disregard for the // maxim "Premature optimization is the root of all evil" @@ -99,31 +167,46 @@ BString::CountChars() const count++; } #endif - while (*ptr++) + + while (start++ != end) { count++; // Jump to next UTF8 character - for (; (*ptr & 0xc0) == 0x80; ptr++); + for (; (*start & 0xc0) == 0x80; start++); } + return count; } /*---- Assignment ----------------------------------------------------------*/ +// equal operator +/*! \brief Makes a copy of the given BString object. + \param string The string object to copy. + \return + The function always returns \c *this . +*/ BString& BString::operator=(const BString &string) { - _DoAssign(string.String(), string.Length()); + if (&string != this) // Avoid auto-assignment + _DoAssign(string.String(), string.Length()); return *this; } +// equal operator +/*! \brief Re-initializes the object to the given string. + \param str Pointer to a string. + \return + The function always returns \c *this . +*/ BString& BString::operator=(const char *str) { - if (str) + if (str != NULL) _DoAssign(str, strlen(str)); else _GrowBy(-Length()); // Empties the string @@ -132,41 +215,78 @@ BString::operator=(const char *str) } +// equal operator +/*! \brief Re-initializes the object to the given character. + \param c The character which you want to initialize the string to. + \return + The function always returns \c *this . +*/ BString& BString::operator=(char c) { - _DoAssign(&c, 1); + int32 curLen = Length(); + + if (curLen != 1) + _GrowBy(1 - curLen); + _privateData[0] = c; + return *this; } +// SetTo +/*! \brief Re-initializes the object to the given string. + \param str Pointer to a string. + \param length Amount of characters to copy from the original string. + \return + The function always returns \c *this . +*/ BString& BString::SetTo(const char *str, int32 length) { - if (str) { + if (str != NULL) + { int32 len = (int32)strlen(str); - _DoAssign(str, min(length, len)); - } else + _DoAssign(str, min_c(length, len)); + } + else _GrowBy(-Length()); // Empties the string return *this; } +// SetTo +/*! \brief Makes a copy of the given BString object. + \param from The string object to copy. + \return + The function always returns \c *this . +*/ BString& BString::SetTo(const BString &from) { - _DoAssign(from.String(), from.Length()); + if (&from != this) // Avoid auto-assignment + _DoAssign(from.String(), from.Length()); return *this; } +// Adopt +/*! \brief Adopt's data of the given BString object, freeing the original object. + \param from The string object to adopt. + \return + The function always returns \c *this . +*/ BString& BString::Adopt(BString &from) { + if (&from == this) // Avoid auto-adoption + return *this; + if (_privateData) free(_privateData - sizeof(int32)); + /* "steal" the data from the given BString */ _privateData = from._privateData; from._privateData = NULL; @@ -174,20 +294,39 @@ BString::Adopt(BString &from) } +// SetTo +/*! \brief Makes a copy of the given BString object. + \param from The string object to copy. + \param length Amount of characters to copy from the original BString. + \return + The function always returns \c *this . +*/ BString& BString::SetTo(const BString &string, int32 length) { - _DoAssign(string.String(), min(length, string.Length())); + if (&string != this) // Avoid auto-assignment + _DoAssign(string.String(), min_c(length, string.Length())); return *this; } +// Adopt +/*! \brief Adopt's data of the given BString object, freeing the original object. + \param from The string object to adopt. + \param length Amount of characters to get from the original BString. + \return + The function always returns \c *this . +*/ BString& BString::Adopt(BString &from, int32 length) { + if (&from == this) // Avoid auto-adoption + return *this; + if (_privateData) free(_privateData - sizeof(int32)); + /* "steal" the data from the given BString */ _privateData = from._privateData; from._privateData = NULL; @@ -198,10 +337,21 @@ BString::Adopt(BString &from, int32 length) } +// SetTo +/*! \brief Initializes the object to a string composed by a character you specify. + \param c The character you want to initialize the BString. + \param count The number of characters you want the BString to be composed by. + \return + The function always returns \c *this . +*/ BString& BString::SetTo(char c, int32 count) { - _GrowBy(count - Length()); + int32 curLen = Length(); + + if (curLen != count) + _GrowBy(count - curLen); + memset(_privateData, c, count); return *this; @@ -209,7 +359,16 @@ BString::SetTo(char c, int32 count) /*---- Substring copying ---------------------------------------------------*/ -BString &BString::CopyInto(BString &into, int32 fromOffset, int32 length) const + +// CopyInto +/*! \brief Copy the BString data (or part of it) into another BString. + \param into The BString where to copy the object. + \param fromOffset The offset (zero based) where to begin the copy + \param length The amount of bytes to copy. + \return This function always returns *this . +*/ +BString & +BString::CopyInto(BString &into, int32 fromOffset, int32 length) const { if (&into != this) into.SetTo(String() + fromOffset, length); @@ -217,54 +376,92 @@ BString &BString::CopyInto(BString &into, int32 fromOffset, int32 length) const } +// CopyInto +/*! \brief Copy the BString data (or part of it) into the supplied buffer. + \param into The buffer where to copy the object. + \param fromOffset The offset (zero based) where to begin the copy + \param length The amount of bytes to copy. +*/ void BString::CopyInto(char *into, int32 fromOffset, int32 length) const { - if (into) { + if (into != NULL) + { int32 len = Length() - fromOffset; - len = min(len, length); + len = min_c(len, length); memcpy(into, _privateData + fromOffset, len); } } /*---- Appending -----------------------------------------------------------*/ +// plus operator +/*! \brief Appends the given string to the object. + \param str A pointer to the string to append. + \return This function always returns *this . +*/ BString& BString::operator+=(const char *str) { - if (str) + if (str != NULL) _DoAppend(str, strlen(str)); return *this; } +// plus operator +/*! \brief Appends the given character to the object. + \param c The character to append. + \return This function always returns *this . +*/ BString& BString::operator+=(char c) { - _DoAppend(&c, 1); + _GrowBy(1); + _privateData[Length() - 1] = c; + return *this; } +// Append +/*! \brief Appends the given BString to the object. + \param string The BString to append. + \param length The maximum bytes to get from the original object. + \return This function always returns *this . +*/ BString& BString::Append(const BString &string, int32 length) { - _DoAppend(string.String(), min(length, string.Length())); + _DoAppend(string.String(), min_c(length, string.Length())); return *this; } +// Append +/*! \brief Appends the given string to the object. + \param str A pointer to the string to append. + \param length The maximum bytes to get from the original string. + \return This function always returns *this . +*/ BString& BString::Append(const char *str, int32 length) { - if (str) { + if (str != NULL) + { int32 len = (int32)strlen(str); - _DoAppend(str, min(len, length)); + _DoAppend(str, min_c(len, length)); } return *this; } +// Append +/*! \brief Appends the given character to the object. + \param c The character to append. + \param count The number of characters to append. + \return This function always returns *this . +*/ BString& BString::Append(char c, int32 count) { @@ -277,15 +474,25 @@ BString::Append(char c, int32 count) /*---- Prepending ----------------------------------------------------------*/ +// Prepend +/*! \brief Prepends the given string to the object. + \param str A pointer to the string to prepend. + \return This function always returns *this . +*/ BString& BString::Prepend(const char *str) { - if (str) + if (str != NULL) _DoPrepend(str, strlen(str)); return *this; } +// Prepend +/*! \brief Prepends the given BString to the object. + \param string The BString object to prepend. + \return This function always returns *this . +*/ BString& BString::Prepend(const BString &string) { @@ -295,26 +502,45 @@ BString::Prepend(const BString &string) } +// Prepend +/*! \brief Prepends the given string to the object. + \param str A pointer to the string to prepend. + \param length The maximum amount of bytes to get from the string. + \return This function always returns *this . +*/ BString& BString::Prepend(const char *str, int32 length) { - if (str) { + if (str != NULL) + { int32 len = (int32)strlen(str); - _DoPrepend(str, min(len, length)); + _DoPrepend(str, min_c(len, length)); } return *this; } +// Prepend +/*! \brief Prepends the given BString to the object. + \param string The BString object to prepend. + \param len The maximum amount of bytes to get from the BString. + \return This function always returns *this . +*/ BString& BString::Prepend(const BString &string, int32 len) { if (&string != this) - _DoPrepend(string.String(), min(len, string.Length())); + _DoPrepend(string.String(), min_c(len, string.Length())); return *this; } +// Prepend +/*! \brief Prepends the given character to the object. + \param c The character to prepend. + \param count The amount of characters to prepend. + \return This function always returns *this . +*/ BString& BString::Prepend(char c, int32 count) { @@ -326,11 +552,19 @@ BString::Prepend(char c, int32 count) /*---- Inserting ----------------------------------------------------------*/ +// Insert +/*! \brief Inserts the given string at the given position into the object's data. + \param str A pointer to the string to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const char *str, int32 pos) { - if (str) { - if (pos < 0) { + if (str != NULL) + { + if (pos < 0) + { str -= pos; pos = 0; } @@ -341,29 +575,47 @@ BString::Insert(const char *str, int32 pos) } +// Insert +/*! \brief Inserts the given string at the given position into the object's data. + \param str A pointer to the string to insert. + \param length The amount of bytes to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const char *str, int32 length, int32 pos) { - if (str) { - if (pos < 0) { + if (str != NULL) + { + if (pos < 0) + { str -= pos; pos = 0; } int32 len = (int32)strlen(str); - len = min(len, length); - _privateData = _OpenAtBy(pos, len); + len = min_c(len, length); + _OpenAtBy(pos, len); memcpy(_privateData + pos, str, len); } return *this; } +// Insert +/*! \brief Inserts the given string at the given position into the object's data. + \param str A pointer to the string to insert. + \param fromOffset + \param length The amount of bytes to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const char *str, int32 fromOffset, int32 length, int32 pos) { - if (str) { + if (str != NULL) + { int32 len = (int32)strlen(str); - len = min(len - fromOffset, length); + len = min_c(len - fromOffset, length); _privateData = _OpenAtBy(pos, len); memcpy(_privateData + pos, str + fromOffset, len); } @@ -371,6 +623,12 @@ BString::Insert(const char *str, int32 fromOffset, int32 length, int32 pos) } +// Insert +/*! \brief Inserts the given BString at the given position into the object's data. + \param string The BString object to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const BString &string, int32 pos) { @@ -380,6 +638,13 @@ BString::Insert(const BString &string, int32 pos) } +// Insert +/*! \brief Inserts the given BString at the given position into the object's data. + \param string The BString object to insert. + \param length The amount of bytes to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const BString &string, int32 length, int32 pos) { @@ -389,6 +654,14 @@ BString::Insert(const BString &string, int32 length, int32 pos) } +// Insert +/*! \brief Inserts the given string at the given position into the object's data. + \param string The BString object to insert. + \param fromOffset + \param length The amount of bytes to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const BString &string, int32 fromOffset, int32 length, int32 pos) { @@ -398,6 +671,13 @@ BString::Insert(const BString &string, int32 fromOffset, int32 length, int32 pos } +// Insert +/*! \brief Inserts the given character at the given position into the object's data. + \param c The character to insert. + \param count The amount of bytes to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(char c, int32 count, int32 pos) { @@ -409,23 +689,38 @@ BString::Insert(char c, int32 count, int32 pos) /*---- Removing -----------------------------------------------------------*/ +// Truncate +/*! \brief Truncate the string to the new length. + \param newLength The new lenght of the string. + \param lazy Currently unused. (?) + \return This function always returns *this . +*/ BString& -BString::Truncate(int32 newLength, bool lazy = true) +BString::Truncate(int32 newLength, bool lazy) { if (newLength < 0) - return *this; + newLength = 0; + + int32 curLen = Length(); - if (newLength < Length()) { + if (newLength < curLen) + { //TODO: Implement lazy truncate? - _privateData = _GrowBy(newLength - Length()); //Negative - _privateData[Length()] = '\0'; + _GrowBy(newLength - curLen); //Negative + _privateData[newLength] = '\0'; } return *this; } +// Remove +/*! \brief Removes some bytes, starting at the given offset + \param from The offset from which you want to start removing + \param length The number of bytes to remove + \return This function always returns *this . +*/ BString& BString::Remove(int32 from, int32 length) { @@ -434,30 +729,45 @@ BString::Remove(int32 from, int32 length) } +// Remove +/*! \brief Removes the first occurrence of the given BString. + \param string The BString to remove. + \return This function always returns *this . +*/ BString& BString::RemoveFirst(const BString &string) { int32 pos = _ShortFindAfter(string.String(), string.Length()); if (pos >= 0) - _privateData = _ShrinkAtBy(pos, string.Length()); + _ShrinkAtBy(pos, string.Length()); return *this; } +// Remove +/*! \brief Removes the last occurrence of the given BString. + \param string The BString to remove. + \return This function always returns *this . +*/ BString& BString::RemoveLast(const BString &string) { int32 pos = _FindBefore(string.String(), Length(), string.Length()); if (pos >= 0) - _privateData = _ShrinkAtBy(pos, string.Length()); + _ShrinkAtBy(pos, string.Length()); return *this; } +// Remove +/*! \brief Removes all occurrences of the given BString. + \param string The BString to remove. + \return This function always returns *this . +*/ BString& BString::RemoveAll(const BString &string) { @@ -469,10 +779,16 @@ BString::RemoveAll(const BString &string) } +// Remove +/*! \brief Removes the first occurrence of the given string. + \param str A pointer to the string to remove. + \return This function always returns *this . +*/ BString& BString::RemoveFirst(const char *str) { - if (str) { + if (str != NULL) + { int32 pos = _ShortFindAfter(str, strlen(str)); if (pos >= 0) _ShrinkAtBy(pos, strlen(str)); @@ -481,10 +797,16 @@ BString::RemoveFirst(const char *str) } +// Remove +/*! \brief Removes the last occurrence of the given string. + \param str A pointer to the string to remove. + \return This function always returns *this . +*/ BString& BString::RemoveLast(const char *str) { - if (str) { + if (str != NULL) + { int32 len = strlen(str); int32 pos = _FindBefore(str, Length(), len); if (pos >= 0) @@ -494,23 +816,35 @@ BString::RemoveLast(const char *str) } +// Remove +/*! \brief Removes all occurrences of the given string. + \param str A pointer to the string to remove. + \return This function always returns *this . +*/ BString& BString::RemoveAll(const char *str) { - if (str) { + if (str != NULL) + { int32 pos; int32 len = strlen(str); - while ((pos = _ShortFindAfter(str, len)) >= 0) + while ((pos = _ShortFindAfter(str, len)) >= 0) _ShrinkAtBy(pos, len); } return *this; } +// Remove +/*! \brief Removes all the characters specified. + \param setOfCharsToRemove The set of characters to remove. + \return This function always returns *this . +*/ BString& BString::RemoveSet(const char *setOfCharsToRemove) { - if (setOfCharsToRemove) { + if (setOfCharsToRemove != NULL) + { int32 pos; while ((pos = strcspn(String(), setOfCharsToRemove)) < Length()) _privateData = _ShrinkAtBy(pos, 1); @@ -519,12 +853,22 @@ BString::RemoveSet(const char *setOfCharsToRemove) } +// MoveInto +/*! \brief Move the BString data (or part of it) into another BString. + \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 . +*/ BString& BString::MoveInto(BString &into, int32 from, int32 length) { + if (&into == this) + return *this; + int32 len = Length() - from; - len = min(len, length); + len = min_c(len, length); into.SetTo(String() + from, length); @@ -535,10 +879,17 @@ BString::MoveInto(BString &into, int32 from, int32 length) } +// MoveInto +/*! \brief Move the BString data (or part of it) into the given buffer. + \param into The buffer where to move the object. + \param from The offset (zero based) where to begin the move + \param length The amount of bytes to move. +*/ void BString::MoveInto(char *into, int32 from, int32 length) { - if (into) { + if (into != NULL) + { memcpy(into, String() + from, length); if (from + length <= Length()) _privateData = _ShrinkAtBy(from, length); @@ -641,6 +992,12 @@ BString::ICompare(const char *str, int32 n) const /*---- Searching -----------------------------------------------------------*/ +// FindFirst +/*! \brief Find the first occurrence of the given BString. + \param string The BString to search for. + \return The offset(zero based) into the data + where the given BString has been found. +*/ int32 BString::FindFirst(const BString &string) const { @@ -648,6 +1005,12 @@ BString::FindFirst(const BString &string) const } +// FindFirst +/*! \brief Find the first occurrence of the given string. + \param string The string to search for. + \return The offset(zero based) into the data + where the given string has been found. +*/ int32 BString::FindFirst(const char *string) const { @@ -657,6 +1020,14 @@ BString::FindFirst(const char *string) const } +// FindFirst +/*! \brief Find the first occurrence of the given BString, + starting from the given offset. + \param string The BString to search for. + \param fromOffset The offset where to start the search. + \return An integer which is the offset(zero based) into the data + where the given BString has been found. +*/ int32 BString::FindFirst(const BString &string, int32 fromOffset) const { @@ -664,6 +1035,14 @@ BString::FindFirst(const BString &string, int32 fromOffset) const } +// FindFirst +/*! \brief Find the first occurrence of the given string, + starting from the given offset. + \param string The string to search for. + \param fromOffset The offset where to start the search. + \return The offset(zero based) into the data + where the given string has been found. +*/ int32 BString::FindFirst(const char *string, int32 fromOffset) const { @@ -673,24 +1052,62 @@ BString::FindFirst(const char *string, int32 fromOffset) const } +// FindFirst +/*! \brief Find the first occurrence of the given character. + \param c The character to search for. + \return The offset(zero based) into the data + where the given character has been found. +*/ int32 BString::FindFirst(char c) const -{ - char tmp[2] = { c, '\0' }; +{ + char *start = _privateData; + char *end = _privateData + Length(); /* String's end */ - return _ShortFindAfter(tmp, 1); + /* Scans the string until we found the character, */ + /* or we hit the string's end */ + while(start != end && *start != c) + start++; + + if (start == end) + return B_ERROR; + + return start - _privateData; } +// FindFirst +/*! \brief Find the first occurrence of the given character, + starting from the given offset. + \param c The character to search for. + \param fromOffset The offset where to start the search. + \return The offset(zero based) into the data + where the given character has been found. +*/ int32 BString::FindFirst(char c, int32 fromOffset) const { - char tmp[2] = { c, '\0' }; + char *start = _privateData + fromOffset; + char *end = _privateData + Length(); /* String's end */ - return _FindAfter(tmp, fromOffset, 1); + /* Scans the string until we found the character, */ + /* or we hit the string's end */ + while(start < end && *start != c) + start++; + + if (start >= end) + return B_ERROR; + + return start - _privateData; } +// FindLast +/*! \brief Find the last occurrence of the given BString. + \param string The BString to search for. + \return The offset(zero based) into the data + where the given BString has been found. +*/ int32 BString::FindLast(const BString &string) const { @@ -698,6 +1115,12 @@ BString::FindLast(const BString &string) const } +// FindLast +/*! \brief Find the last occurrence of the given string. + \param string The string to search for. + \return The offset(zero based) into the data + where the given string has been found. +*/ int32 BString::FindLast(const char *string) const { @@ -707,6 +1130,14 @@ BString::FindLast(const char *string) const } +// FindLast +/*! \brief Find the last occurrence of the given BString, + starting from the given offset, and going backwards. + \param string The BString to search for. + \param beforeOffset The offset where to start the search. + \return An integer which is the offset(zero based) into the data + where the given BString has been found. +*/ int32 BString::FindLast(const BString &string, int32 beforeOffset) const { @@ -714,6 +1145,13 @@ BString::FindLast(const BString &string, int32 beforeOffset) const } +// FindLast +/*! \brief Find the last occurrence of the given string, + starting from the given offset, and going backwards. + \param string The string to search for. + \return The offset(zero based) into the data + where the given string has been found. +*/ int32 BString::FindLast(const char *string, int32 beforeOffset) const { @@ -723,21 +1161,53 @@ BString::FindLast(const char *string, int32 beforeOffset) const } +// FindLast +/*! \brief Find the last occurrence of the given character. + \param c The character to search for. + \return The offset(zero based) into the data + where the given character has been found. +*/ int32 BString::FindLast(char c) const { - char tmp[2] = { c, '\0' }; + char *start = _privateData; + char *end = _privateData + Length(); /* String's end */ - return _FindBefore(tmp, Length(), 1); + /* Scans the string backwards until we found the character, */ + /* or we reach the string's start */ + while(end != start && *end != c) + end--; + + if (end == start) + return B_ERROR; + + return end - _privateData; } +// FindLast +/*! \brief Find the last occurrence of the given character, + starting from the given offset and going backwards. + \param c The character to search for. + \param beforeOffset The offset where to start the search. + \return The offset(zero based) into the data + where the given character has been found. +*/ int32 BString::FindLast(char c, int32 beforeOffset) const { - char tmp[2] = { c, '\0' }; + char *start = _privateData; + char *end = _privateData + Length() - beforeOffset; - return _FindBefore(tmp, beforeOffset, 1); + /* Scans the string backwards until we found the character, */ + /* or we reach the string's start */ + while(end > start && *end != c) + end--; + + if (end <= start) + return B_ERROR; + + return end - _privateData; } @@ -809,8 +1279,7 @@ BString::IFindLast(const char *string, int32 beforeOffset) const BString& BString::ReplaceFirst(char replaceThis, char withThis) { - char tmp[2] = { replaceThis, '\0' }; - int32 pos = _ShortFindAfter(tmp, 1); + int32 pos = FindFirst(replaceThis); if (pos >= 0) _privateData[pos] = withThis; @@ -822,8 +1291,7 @@ BString::ReplaceFirst(char replaceThis, char withThis) BString& BString::ReplaceLast(char replaceThis, char withThis) { - char tmp[2] = { replaceThis, '\0' }; - int32 pos = _FindBefore(tmp, Length(), 1); + int32 pos = FindLast(replaceThis); if (pos >= 0) _privateData[pos] = withThis; @@ -835,11 +1303,9 @@ BString::ReplaceLast(char replaceThis, char withThis) BString& BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset) { - int32 pos = B_ERROR; - char tmp[2] = { replaceThis, '\0' }; - - for (;;) { - pos = _FindAfter(tmp, fromOffset, 1); + for (int32 pos;;) + { + pos = FindFirst(replaceThis, fromOffset); if (pos < 0) break; _privateData[pos] = withThis; @@ -853,15 +1319,9 @@ BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset) BString& BString::Replace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset) { - - char tmp[2] = { replaceThis, '\0' }; - - if (maxReplaceCount <= 0) - return *this; - - for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--) { - - pos = _FindAfter(tmp, fromOffset, 1); + for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--) + { + pos = FindFirst(replaceThis, fromOffset); if (pos < 0) break; @@ -882,7 +1342,8 @@ BString::ReplaceFirst(const char *replaceThis, const char *withThis) int32 firstStringLength = strlen(replaceThis); int32 pos = _ShortFindAfter(replaceThis, firstStringLength); - if (pos >= 0) { + if (pos >= 0) + { int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; @@ -907,7 +1368,8 @@ 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; @@ -932,15 +1394,15 @@ BString::ReplaceAll(const char *replaceThis, const char *withThis, int32 fromOff int32 firstStringLength = strlen(replaceThis); int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; - - for (int32 pos;;) { - + + for (int32 pos;;) + { pos = _FindAfter(replaceThis, fromOffset, firstStringLength); if (pos < 0) break; if (difference > 0) - _OpenAtBy(pos, difference); + _OpenAtBy(pos, difference); else if (difference < 0) _ShrinkAtBy(pos, -difference); @@ -955,15 +1417,15 @@ BString::ReplaceAll(const char *replaceThis, const char *withThis, int32 fromOff BString& BString::Replace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset) { - if (replaceThis == NULL || maxReplaceCount <= 0) + if (replaceThis == NULL) return *this; int32 firstStringLength = strlen(replaceThis); int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; - for (int32 pos; maxReplaceCount > 0; maxReplaceCount--) { - + for (int32 pos; maxReplaceCount > 0; maxReplaceCount--) + { pos = _FindAfter(replaceThis, fromOffset, firstStringLength); if (pos < 0) break; @@ -984,7 +1446,7 @@ BString& BString::IReplaceFirst(char replaceThis, char withThis) { char tmp[2] = { replaceThis, '\0' }; - int32 pos = _FindAfter(tmp, 0, 1); + int32 pos = _IFindAfter(tmp, 0, 1); if (pos >= 0) _privateData[pos] = withThis; @@ -1011,7 +1473,8 @@ BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset) { char tmp[2] = { replaceThis, '\0' }; - for (int32 pos;;) { + for (int32 pos;;) + { pos = _IFindAfter(tmp, fromOffset, 1); if (pos < 0) break; @@ -1027,11 +1490,11 @@ BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount, int32 { char tmp[2] = { replaceThis, '\0' }; - if (_privateData == NULL || maxReplaceCount <= 0) + if (_privateData == NULL) return *this; - for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--) { - + for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--) + { pos = _IFindAfter(tmp, fromOffset, 1); if (pos < 0) break; @@ -1052,7 +1515,8 @@ BString::IReplaceFirst(const char *replaceThis, const char *withThis) int32 firstStringLength = strlen(replaceThis); int32 pos = _IFindAfter(replaceThis, 0, firstStringLength); - if (pos >= 0) { + if (pos >= 0) + { int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; @@ -1077,7 +1541,8 @@ 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; @@ -1103,7 +1568,8 @@ BString::IReplaceAll(const char *replaceThis, const char *withThis, int32 fromOf int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; - for (int32 pos;;) { + for (int32 pos;;) + { pos = _IFindAfter(replaceThis, fromOffset, firstStringLength); if (pos < 0) break; @@ -1124,15 +1590,15 @@ BString::IReplaceAll(const char *replaceThis, const char *withThis, int32 fromOf BString& BString::IReplace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset) { - if (replaceThis == NULL || maxReplaceCount <= 0) + if (replaceThis == NULL) return *this; int32 firstStringLength = strlen(replaceThis); int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; - for (int32 pos; maxReplaceCount > 0; maxReplaceCount--) { - + for (int32 pos; maxReplaceCount > 0; maxReplaceCount--) + { pos = _IFindAfter(replaceThis, fromOffset, firstStringLength); if (pos < 0) break; @@ -1155,17 +1621,19 @@ BString::ReplaceSet(const char *setOfChars, char with) 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()) + if (offset >= length) break; _privateData[offset] = with; + offset++; } return *this; @@ -1181,7 +1649,8 @@ BString::ReplaceSet(const char *setOfChars, const char *with) int32 offset = 0; int32 withLen = strlen(with); - for (int32 pos;;) { + for (int32 pos;;) + { pos = strcspn(String() + offset, setOfChars); if (pos >= Length()) break; @@ -1201,6 +1670,14 @@ BString::ReplaceSet(const char *setOfChars, const char *with) /*---- Unchecked char access -----------------------------------------------*/ + +// operator[] +/*! \brief Returns a reference to the data at the given offset. + + This function can be used to read a byte or to change its value. + \param index The index (zero based) of the byte to get. + \return Returns a reference to the specified byte. +*/ char & BString::operator[](int32 index) { @@ -1217,7 +1694,7 @@ BString::LockBuffer(int32 maxLength) int32 len = Length(); if (maxLength > len) - _privateData = _GrowBy(maxLength - len); + _GrowBy(maxLength - len); return _privateData; } @@ -1234,13 +1711,17 @@ BString::UnlockBuffer(int32 length) len = strlen(_privateData); if (len != Length()) - _privateData = _GrowBy(len - Length()); + _GrowBy(len - Length()); return *this; } /*---- Uppercase<->Lowercase ------------------------------------------------*/ +// ToLower +/*! \brief Converts the BString to lowercase + \return This function always returns *this . +*/ BString& BString::ToLower() { @@ -1252,6 +1733,10 @@ BString::ToLower() } +// ToUpper +/*! \brief Converts the BString to uppercase + \return This function always returns *this . +*/ BString& BString::ToUpper() { @@ -1263,6 +1748,10 @@ BString::ToUpper() } +// Capitalize +/*! \brief Converts the first character to uppercase, rest to lowercase + \return This function always returns *this . +*/ BString& BString::Capitalize() { @@ -1279,6 +1768,13 @@ BString::Capitalize() } +// CapitalizeEachWord +/*! \brief Converts the first character of every word to uppercase, rest to lowercase. + + Converts the first character of every "word" (series of alpabetical characters + separated by non alphabetical characters) to uppercase, and the rest to lowercase. + \return This function always returns *this . +*/ BString& BString::CapitalizeEachWord() { @@ -1289,17 +1785,21 @@ BString::CapitalizeEachWord() int32 length = Length(); do { - // Find the first alphabetical character - for(; count < length; count++) { - if (isalpha(_privateData[count])) { + // Find the first alphabetical character... + for(; count < length; count++) + { + if (isalpha(_privateData[count])) + { + // ...found! Convert it to uppercase. _privateData[count] = toupper(_privateData[count]); count++; break; } } - // Find the first non-alphabetical character, + // 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 @@ -1330,7 +1830,8 @@ BString::CharacterEscape(const char *setOfCharsToEscape, char escapeWith) int32 offset = 0; - for(int32 pos;;) { + for(int32 pos;;) + { pos = strcspn(_privateData + offset, setOfCharsToEscape); offset += pos; if (offset >= Length()) @@ -1357,12 +1858,10 @@ BString::CharacterDeescape(const char *original, char escapeChar) BString& BString::CharacterDeescape(char escapeChar) { - if (_privateData == NULL) - return *this; - - char tmp[2] = { escapeChar, '\0' }; - RemoveAll(tmp); - + int32 pos; + while ((pos = FindFirst(escapeChar)) >= 0) + _ShrinkAtBy(pos, 1); + return *this; } @@ -1372,7 +1871,7 @@ BString::CharacterDeescape(char escapeChar) BString& BString::operator<<(const char *str) { - if (str) + if (str != NULL) _DoAppend(str, strlen(str)); return *this; } @@ -1481,6 +1980,9 @@ BString::_Init(const char* str, int32 len) } +#if ENABLE_INLINES +inline +#endif void BString::_DoAssign(const char *str, int32 len) { @@ -1488,19 +1990,22 @@ BString::_DoAssign(const char *str, int32 len) int32 curLen = Length(); if (len != curLen) - _privateData = _GrowBy(len - curLen); + _GrowBy(len - curLen); memcpy(_privateData, str, len); } +#if ENABLE_INLINES +inline +#endif void BString::_DoAppend(const char *str, int32 len) { ASSERT(str != NULL); int32 length = Length(); - _privateData = _GrowBy(len); + _GrowBy(len); memcpy(_privateData + length, str, len); } @@ -1508,21 +2013,19 @@ BString::_DoAppend(const char *str, int32 len) char* BString::_GrowBy(int32 size) { - int32 curLen = Length(); - ASSERT(curLen + size >= 0); + int32 newLen = Length() + size; + ASSERT(newLen >= 0); if (_privateData != NULL) - { _privateData -= sizeof(int32); - } _privateData = (char*)realloc(_privateData, - curLen + size + sizeof(int32) + 1); + newLen + sizeof(int32) + 1); _privateData += sizeof(int32); - _SetLength(curLen + size); - _privateData[Length()] = '\0'; + _SetLength(newLen); + _privateData[newLen] = '\0'; return _privateData; } @@ -1538,7 +2041,7 @@ BString::_OpenAtBy(int32 offset, int32 length) if (_privateData != NULL) _privateData -= sizeof(int32); - _privateData = (char*)realloc(_privateData , oldLength + length + sizeof(int32) + 1); + _privateData = (char*)realloc(_privateData, oldLength + length + sizeof(int32) + 1); _privateData += sizeof(int32); memmove(_privateData + offset + length, _privateData + offset, @@ -1555,12 +2058,12 @@ char* BString::_ShrinkAtBy(int32 offset, int32 length) { int32 oldLength = Length(); - + if (offset > oldLength || offset + length > oldLength) return _privateData; memmove(_privateData + offset, _privateData + offset + length, - Length() - offset - length); + oldLength - offset - length); _privateData -= sizeof(int32); _privateData = (char*)realloc(_privateData, oldLength - length + sizeof(int32) + 1); @@ -1573,15 +2076,19 @@ BString::_ShrinkAtBy(int32 offset, int32 length) } +#if ENABLE_INLINES +inline +#endif void BString::_DoPrepend(const char *str, int32 count) { ASSERT(str != NULL); - _privateData = _OpenAtBy(0, count); + _OpenAtBy(0, count); memcpy(_privateData, str, count); } +/* XXX: These could be inlined too, if they are too slow */ int32 BString::_FindAfter(const char *str, int32 offset, int32 strlen) const { @@ -1617,15 +2124,15 @@ BString::_IFindAfter(const char *str, int32 offset, int32 strlen) const int32 -BString::_ShortFindAfter(const char *str, int32 strlen) const +BString::_ShortFindAfter(const char *str, int32 len) const { ASSERT(str != NULL); char *ptr = strstr(String(), str); - + if (ptr != NULL) return ptr - String(); - + return B_ERROR; } @@ -1637,13 +2144,14 @@ BString::_FindBefore(const char *str, int32 offset, int32 strlen) const if (offset <= 0) return B_ERROR; - - char *ptr1 = _privateData + offset - strlen; - while (ptr1 >= _privateData) { - if (!memcmp(ptr1, str, strlen)) - return ptr1 - _privateData; - ptr1--; + const char *ptr = _privateData + offset - strlen; + + while (ptr >= _privateData) + { + if (!memcmp(ptr, str, strlen)) + return ptr - _privateData; + ptr--; } return B_ERROR; @@ -1660,7 +2168,8 @@ BString::_IFindBefore(const char *str, int32 offset, int32 strlen) const char *ptr1 = _privateData + offset - strlen; - while (ptr1 >= _privateData) { + while (ptr1 >= _privateData) + { if (!strncasecmp(ptr1, str, strlen)) return ptr1 - _privateData; ptr1--; @@ -1670,6 +2179,9 @@ BString::_IFindBefore(const char *str, int32 offset, int32 strlen) const } +#if ENABLE_INLINES +inline +#endif void BString::_SetLength(int32 length) { @@ -1679,15 +2191,18 @@ BString::_SetLength(int32 length) #if DEBUG // AFAIK, these are not implemented in BeOS R5 +// XXX : Test these puppies void BString::_SetUsingAsCString(bool state) -{ +{ + //TODO: Implement ? } void BString::_AssertNotUsingAsCString() const { + //TODO: Implement ? } #endif