//**************************************************************************************************************************
//* Blue - General Purpose C++ Library
//* Copyright (c) 2002 Josh Harler
//*
//* This software is provided 'as-is', without any express or implied warranty. In no event
//* will the authors be held liable for any damages arising from the use of this software.
//*
//* Permission is granted to anyone to use this software for any purpose, including commercial
//* applications, and to alter it and redistribute it freely, subject to the following restrictions:
//*
//* 1. The origin of this software must not be misrepresented; you must not claim that you
//* wrote the original software. If you use this software in a product, an acknowledgment in the
//* product documentation would be appreciated but is not required.
//*
//* 2. Altered source versions must be plainly marked as such, and must not be misrepresented as
//* being the original software.
//*
//* 3. This notice may not be removed or altered from any source distribution.
//*
//*
//* file Common/BString.cpp
//**
// Private Headers =========================================================================================================
#define _CRT_SECURE_NO_WARNINGS 1
#if defined(BLUE_DLL) || defined(BLUE_LIB)
//# include "Blue.h"
#else
// matching header
# include "BString.h"
#endif
// system headers
#include <string.h> // for strlen, strcpy, strncpy and strstr
#include <stdio.h> // for sprintf
#include <ctype.h> // for isspace
#include <stdlib.h> // for toupper, tolower, strtol, strtod
#include <stdarg.h> // for va_args
#if defined(_MSC_VER)
#define strnicmp _strnicmp
#define vsnprintf _vsnprintf
#endif
// Private Defines/Enums/Typedefs/Etc ======================================================================================
// Private Classes/Structs =================================================================================================
// Private Global Variables ================================================================================================
// External Global Variables ===============================================================================================
namespace blue
{
namespace common
{
const BString BString::null;
}
} // namespaces
// Private Functions =======================================================================================================
namespace {
using namespace blue;
using namespace blue::common;
// ---------------------------------------------------------------------------------------------------------------------
template<typename cmpfunc_t>
inline int priv_findPos(const char* src, int srcLen, const char* sch, int schLen, int start, cmpfunc_t cmpfunc)
{
if (srcLen == 0 || schLen == 0 || start > srcLen - 1)
{
return (BString::npos);
}
start = (start < 0 ? 0 : start);
for (int i = start; i < srcLen - (schLen - 1); ++i)
{
if (cmpfunc(src + i, sch, schLen) == 0)
{
return (i);
}
}
return (BString::npos);
}
// ---------------------------------------------------------------------------------------------------------------------
template<typename cmpfunc_t>
inline int priv_findPosR(const char* src, int srcLen, const char* sch, int schLen, int start, cmpfunc_t cmpfunc)
{
if (srcLen == 0 || schLen == 0)
{
return (BString::npos);
}
if (start == BString::npos)
{
start = srcLen;
}
else
{
start = (start < 0 ? 0 : start > srcLen ? srcLen : start);
}
const char* pos = (src + start) - schLen;
while (pos >= src)
{
if (cmpfunc(pos, sch, schLen) == 0)
{
return (pos - src);
}
--pos;
}
return (BString::npos);
}
// ---------------------------------------------------------------------------------------------------------------------
template<typename cmpfunc_t>
inline int priv_count(const char* src, int srcLen, const char* sch, int schLen, cmpfunc_t cmpfunc)
{
if (schLen == 0)
{
return (0);
}
int pos = 0;
int cnt = 0;
while ((pos = priv_findPos(src, srcLen, sch, schLen, pos, cmpfunc)) != BString::npos)
{
++cnt;
pos += schLen;
}
return (cnt);
}
// ---------------------------------------------------------------------------------------------------------------------
template<typename cmpfunc_t>
inline bool priv_equals(const char* src, int srcLen, const char* tst, int tstLen, cmpfunc_t cmpfunc)
{
if (srcLen != tstLen)
{
return (false);
}
if (src == tst)
{
return (true);
}
return (cmpfunc(src, tst, tstLen) == 0);
}
// ---------------------------------------------------------------------------------------------------------------------
inline bool priv_cmpchar(char one, char two) { return one == two; }
inline bool priv_cmpichar(char one, char two) { return toupper(one) == toupper(two); }
template<typename cmpfunc_t>
inline bool priv_equalsWildCard(const char* src, int srcLen, const char* tst, int tstLen, cmpfunc_t cmpfunc)
{
if (srcLen == 0 || tstLen == 0)
{
return (false);
}
const char* srcEnd = src + srcLen;
const char* tstEnd = tst + tstLen;
const char* mp = 0;
const char* cp = 0;
while ((src < srcEnd) && (*tst != '*'))
{
if (!cmpfunc(*src, *tst) && (*tst != '?'))
{
return (false);
}
++src;
++tst;
}
while (src < srcEnd)
{
if (*tst == '*')
{
if (++tst >= tstEnd)
{
return (true);
}
mp = tst;
cp = src + 1;
}
else if (cmpfunc(*src, *tst) || (*tst == '?'))
{
++src;
++tst;
}
else
{
tst = mp;
src = cp++;
}
}
while (*tst == '*')
{
++tst;
}
return (tst == tstEnd);
}
// ---------------------------------------------------------------------------------------------------------------------
template<typename cmpfunc_t>
inline bool priv_beginsWith(const char* src, int srcLen, const char* tst, int tstLen, cmpfunc_t cmpfunc)
{
if (srcLen == 0 || tstLen == 0 || tstLen > srcLen)
{
return (tstLen == 0 ? true : false);
}
return (cmpfunc(src, tst, tstLen) == 0);
}
// ---------------------------------------------------------------------------------------------------------------------
template<typename cmpfunc_t>
inline bool priv_endsWith(const char* src, int srcLen, const char* tst, int tstLen, cmpfunc_t cmpfunc)
{
if (srcLen == 0 || tstLen == 0 || tstLen > srcLen)
{
return (tstLen == 0 ? true : false);
}
return (cmpfunc(src + (srcLen - tstLen), tst, tstLen) == 0);
}
// ---------------------------------------------------------------------------------------------------------------------
template<typename cmpfunc_t>
inline int priv_compare(const char* src, int srcLen, const char* tst, int tstLen, cmpfunc_t cmpfunc)
{
int minLen = (srcLen < tstLen ? srcLen : tstLen);
int cmp = cmpfunc(src, tst, minLen);
if (cmp != 0)
{
return (cmp);
}
if (srcLen < tstLen)
{
return (-1);
}
if (tstLen < srcLen)
{
return (1);
}
return (0);
}
// ---------------------------------------------------------------------------------------------------------------------
inline char* priv_insert(const char* src, int srcLen, const char* ins, int insLen, int before)
{
int len = srcLen + insLen;
char* ptr = new char[len + 1];
int i, cur = 0;
for (i = 0; i < before; ++i)
{
ptr[i] = src[cur++];
}
for (i = cur; i < cur + (len - srcLen); ++i)
{
ptr[i] = ins[i - cur];
}
for (i = cur + (len - srcLen); i < len; ++i)
{
ptr[i] = src[cur++];
}
ptr[len] = 0;
return (ptr);
}
// ---------------------------------------------------------------------------------------------------------------------
template<typename cmpfunc_t>
inline char* priv_removeAll(const char* src, int srcLen, const char* rem, int remLen, cmpfunc_t cmpfunc)
{
if (srcLen == 0 || remLen == 0)
{
return (0);
}
int count = priv_count(src, srcLen, rem, remLen, cmpfunc);
if (count <= 0)
{
char* ptr = new char[srcLen + 1];
strncpy(ptr, src, srcLen);
ptr[srcLen] = 0;
return (ptr);
}
int lenremTot = count * remLen;
int lenNew = srcLen - lenremTot;
char* ptr = new char[lenNew + 1];
int cur = 0;
int lst = 0, pos = 0;
while ((pos = priv_findPos(src, srcLen, rem, remLen, pos, cmpfunc)) != BString::npos)
{
for (int i = lst; i < pos; ++i)
{
ptr[cur++] = src[i];
}
lst = pos + remLen;
pos = lst;
}
if (cur != lenNew)
{
for (int i = lst; i < srcLen; ++i)
{
ptr[cur++] = src[i];
}
}
ptr[lenNew] = 0;
return (ptr);
}
// ---------------------------------------------------------------------------------------------------------------------
template<typename cmpfunc_t>
inline char* priv_replaceAll(const char* src, int srcLen, const char* rep, int repLen, const char* with, int withLen, cmpfunc_t cmpfunc)
{
if (srcLen == 0 || repLen == 0)
{
return (0);
}
int count = priv_count(src, srcLen, rep, repLen, cmpfunc);
if (count <= 0)
{
char* ptr = new char[srcLen + 1];
strncpy(ptr, src, srcLen);
ptr[srcLen] = 0;
return (ptr);
}
int lenNew = (srcLen - (repLen * count)) + (withLen * count);
char* ptr = new char[lenNew + 1];
int cur = 0;
int lst = 0, pos = 0;
while ((pos = priv_findPos(src, srcLen, rep, repLen, pos, cmpfunc)) != BString::npos)
{
for (int i = lst; i < pos; ++i)
{
ptr[cur++] = src[i];
}
for (int j = 0; j < withLen; ++j)
{
ptr[cur++] = with[j];
}
lst = pos + repLen;
pos = lst;
}
if (cur != lenNew)
{
for (int i = lst; i < srcLen; ++i)
{
ptr[cur++] = src[i];
}
}
ptr[lenNew] = 0;
return (ptr);
}
// ---------------------------------------------------------------------------------------------------------------------
inline BString priv_arg(const BString& src, const char* arg, int argLen)
{
int pos = src.findPos("{");
if (pos == BString::npos)
{
return (src + arg);
}
int lowest = 2000000000;
while (pos != BString::npos)
{
if (src.subString(pos, 2) != "{{")
{
int end = src.findPos("}", pos);
if (end != BString::npos)
{
BString sub = src.subString(pos + 1, end- (pos + 1));
if (sub.isValidInt())
{
int subInt = sub.getAsInt();
if (subInt > 0 && subInt < lowest)
{
lowest = subInt;
}
}
pos = end;
}
}
else
{
pos += 2;
}
pos = src.findPos("{", pos);
}
return src.replaceAll("{" + BString(lowest) + "}", BString(arg, argLen, BString::STATIC));
}
} // namespace
// Functions ===============================================================================================================
namespace blue
{
namespace common
{
// ---------------------------------------------------------------------------------------------------------------------
BString::BString()
:m_refCnt(0), m_refBuf(0), m_refLen(0), m_start(0), m_len(0)
{
}
// ---------------------------------------------------------------------------------------------------------------------
BString::BString(const BString& copy)
:m_refCnt(copy.m_refCnt), m_refBuf(copy.m_refBuf), m_refLen(copy.m_refLen), m_start(copy.m_start), m_len(copy.m_len)
{
refInc();
}
// ---------------------------------------------------------------------------------------------------------------------
BString::BString(const char* str, create_e create)
:m_refCnt(0), m_refBuf(0), m_refLen(0), m_start(0), m_len(0)
{
if (create == NORMAL)
{
refCreate(strlen(str));
if (m_refBuf != 0)
{
strcpy(m_refBuf, str);
}
}
else if (create == STATIC)
{
m_start = str;
m_len = strlen(str);
}
}
// ---------------------------------------------------------------------------------------------------------------------
BString::BString(const char* str, int len, create_e create)
:m_refCnt(0), m_refBuf(0), m_refLen(0), m_start(0), m_len(0)
{
if (create == NORMAL)
{
refCreate(len);
if (m_refBuf != 0)
{
strncpy(m_refBuf, str, len);
}
}
else if (create == STATIC)
{
m_start = str;
m_len = len;
}
}
// ---------------------------------------------------------------------------------------------------------------------
BString::BString(char ch)
:m_refCnt(0), m_refBuf(0), m_refLen(0), m_start(0), m_len(0)
{
refCreate(1);
if (m_refBuf != 0)
{
m_refBuf[0] = ch;
m_refBuf[1] = 0;
}
}
// ---------------------------------------------------------------------------------------------------------------------
BString::BString(int num)
:m_refCnt(0), m_refBuf(0), m_refLen(0), m_start(0), m_len(0)
{
char buffer[13]; // 12 == strlen("-2147483648")
sprintf(buffer, "%d", num);
refCreate(buffer, false);
}
// ---------------------------------------------------------------------------------------------------------------------
BString::BString(float num)
:m_refCnt(0), m_refBuf(0), m_refLen(0), m_start(0), m_len(0)
{
char buffer[16]; // 15 == strlen("-d.dddddd e-ddd")
sprintf(buffer, "%.6e", num);
refCreate(buffer, false);
}
// ---------------------------------------------------------------------------------------------------------------------
BString::BString(double num)
:m_refCnt(0), m_refBuf(0), m_refLen(0), m_start(0), m_len(0)
{
char buffer[16]; // 15 == strlen("-d.dddddd e-ddd")
sprintf(buffer, "%.6e", num);
refCreate(buffer, false);
}
// ---------------------------------------------------------------------------------------------------------------------
BString::BString(unsigned int num)
:m_refCnt(0), m_refBuf(0), m_refLen(0), m_start(0), m_len(0)
{
char buffer[12]; // 11 == strlen("4294967296")
sprintf(buffer, "%u", num);
refCreate(buffer, false);
}
// ---------------------------------------------------------------------------------------------------------------------
BString::BString(char* str, bool own)
:m_refCnt(0), m_refBuf(0), m_refLen(0), m_start(0), m_len(0)
{
refCreate(str, own);
}
// ---------------------------------------------------------------------------------------------------------------------
BString::~BString()
{
refDec();
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::findPos(const char* search, int start) const
{
return priv_findPos(m_start, m_len, search, strlen(search), start, strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::findPos(const BString& search, int start) const
{
return priv_findPos(m_start, m_len, search.m_start, search.m_len, start, strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::findPosIgnoreCase(const char* search, int start) const
{
return priv_findPos(m_start, m_len, search, strlen(search), start, strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::findPosIgnoreCase(const BString& search, int start) const
{
return priv_findPos(m_start, m_len, search.m_start, search.m_len, start, strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::findPosR(const char* search, int start) const
{
return priv_findPosR(m_start, m_len, search, strlen(search), start, strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::findPosR(const BString& search, int start) const
{
return priv_findPosR(m_start, m_len, search.m_start, search.m_len, start, strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::findPosRIgnoreCase(const char* search, int start) const
{
return priv_findPosR(m_start, m_len, search, strlen(search), start, strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::findPosRIgnoreCase(const BString& search, int start) const
{
return priv_findPosR(m_start, m_len, search.m_start, search.m_len, start, strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::count(const char* search) const
{
return priv_count(m_start, m_len, search, strlen(search), strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::count(const BString& search) const
{
return priv_count(m_start, m_len, search.m_start, search.m_len, strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::countIgnoreCase(const char* search) const
{
return priv_count(m_start, m_len, search, strlen(search), strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::countIgnoreCase(const BString& search) const
{
return priv_count(m_start, m_len, search.m_start, search.m_len, strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::getLength() const
{
return (m_len);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::equals(const char* str) const
{
return priv_equals(m_start, m_len, str, strlen(str), strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::equals(const BString& str) const
{
return priv_equals(m_start, m_len, str.m_start, str.m_len, strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::equalsIgnoreCase(const char* str) const
{
return priv_equals(m_start, m_len, str, strlen(str), strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::equalsIgnoreCase(const BString& str) const
{
return priv_equals(m_start, m_len, str.m_start, str.m_len, strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::equalsWildCard(const char* str) const
{
return priv_equalsWildCard(m_start, m_len, str, strlen(str), priv_cmpchar);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::equalsWildCard(const BString& str) const
{
return priv_equalsWildCard(m_start, m_len, str.m_start, str.m_len, priv_cmpchar);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::equalsWildCardIgnoreCase(const char* str) const
{
return priv_equalsWildCard(m_start, m_len, str, strlen(str), priv_cmpichar);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::equalsWildCardIgnoreCase(const BString& str) const
{
return priv_equalsWildCard(m_start, m_len, str.m_start, str.m_len, priv_cmpichar);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::beginsWith(const char* str) const
{
return priv_beginsWith(m_start, m_len, str, strlen(str), strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::beginsWith(const BString& str) const
{
return priv_beginsWith(m_start, m_len, str.m_start, str.m_len, strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::beginsWithIgnoreCase(const char* str) const
{
return priv_beginsWith(m_start, m_len, str, strlen(str), strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::beginsWithIgnoreCase(const BString& str) const
{
return priv_beginsWith(m_start, m_len, str.m_start, str.m_len, strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::endsWith(const char* str) const
{
return priv_endsWith(m_start, m_len, str, strlen(str), strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::endsWith(const BString& str) const
{
return priv_endsWith(m_start, m_len, str.m_start, str.m_len, strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::endsWithIgnoreCase(const char* str) const
{
return priv_endsWith(m_start, m_len, str, strlen(str), strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::endsWithIgnoreCase(const BString& str) const
{
return priv_endsWith(m_start, m_len, str.m_start, str.m_len, strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::compare(const char* str) const
{
return priv_compare(m_start, m_len, str, strlen(str), strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::compare(const BString& str) const
{
return priv_compare(m_start, m_len, str.m_start, str.m_len, strncmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::compareIgnoreCase(const char* str) const
{
return priv_compare(m_start, m_len, str, strlen(str), strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::compareIgnoreCase(const BString& str) const
{
return priv_compare(m_start, m_len, str.m_start, str.m_len, strnicmp);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::isEmpty() const
{
return (m_refCnt == 0);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::insert(const char* str, int before) const
{
return BString(priv_insert(m_start, m_len, str, strlen(str), before), true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::insert(const BString& str, int before) const
{
return BString(priv_insert(m_start, m_len, str.m_start, str.m_len, before), true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::remove(int start, int chars) const
{
if (m_len == 0)
{
return (BString::null);
}
start = (start < 0 ? 0 : start > m_len - 1 ? m_len - 1 : start);
chars = (chars < 0 ? 0 : chars > m_len - start ? m_len - start : chars);
if (chars == 0)
{
return (*this);
}
char* ptr = new char[(m_len - chars) + 1];
int i, cur = 0;
for (i = 0; i < start; ++i)
{
ptr[cur++] = m_start[i];
}
for (i = (start + chars); i < m_len; ++i)
{
ptr[cur++] = m_start[i];
}
ptr[m_len - chars] = 0;
return BString(ptr, true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::removeAll(const char* str) const
{
return BString(priv_removeAll(m_start, m_len, str, strlen(str), strncmp), true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::removeAll(const BString& str) const
{
return BString(priv_removeAll(m_start, m_len, str.m_start, str.m_len, strncmp), true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::removeAllIgnoreCase(const char* str) const
{
return BString(priv_removeAll(m_start, m_len, str, strlen(str), strnicmp), true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::removeAllIgnoreCase(const BString& str) const
{
return BString(priv_removeAll(m_start, m_len, str.m_start, str.m_len, strnicmp), true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::replaceAll(const char* str, const char* with) const
{
return BString(priv_replaceAll(m_start, m_len, str, strlen(str), with, strlen(with), strncmp), true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::replaceAll(const BString& str, const BString& with) const
{
return BString(priv_replaceAll(m_start, m_len, str.m_start, str.m_len, with.m_start, with.m_len, strncmp), true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::replaceAllIgnoreCase(const char* str, const char* with) const
{
return BString(priv_replaceAll(m_start, m_len, str, strlen(str), with, strlen(with), strnicmp), true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::replaceAllIgnoreCase(const BString& str, const BString& with) const
{
return BString(priv_replaceAll(m_start, m_len, str.m_start, str.m_len, with.m_start, with.m_len, strnicmp), true);
}
// ---------------------------------------------------------------------------------------------------------------------
// static
BString BString::format(const char* str, ...)
{
char buffer[512];
va_list args;
va_start(args, str);
vsnprintf(buffer, sizeof(buffer) - 1, str, args); // no buffer overflows allowed!
va_end(args);
return BString(buffer, false);
}
// ---------------------------------------------------------------------------------------------------------------------
// static
BString BString::format(const BString& str, ...)
{
char buffer[512];
va_list args;
BString fmt = str.makeUnique();
const char* fmtPtr = fmt.getAsCStr();
va_start(args, fmtPtr);
vsnprintf(buffer, sizeof(buffer) - 1, fmt.getAsCStr(), args); // no buffer overflows allowed!
va_end(args);
return BString(buffer, false);
}
// ---------------------------------------------------------------------------------------------------------------------
// static
BString BString::format(int maxSize, const char* str, ...)
{
char* buffer = new char[maxSize + 1];
memset(buffer, 0, maxSize + 1);
va_list args;
va_start(args, str);
vsnprintf(buffer, maxSize, str, args); // no buffer overflows allowed!
va_end(args);
BString ret(buffer, false);
delete[] buffer;
return (ret);
}
// ---------------------------------------------------------------------------------------------------------------------
// static
BString BString::format(int maxSize, const BString& str, ...)
{
char* buffer = new char[maxSize + 1];
memset(buffer, 0, maxSize + 1);
va_list args;
BString fmt = str.makeUnique();
const char* fmtPtr = fmt.getAsCStr();
va_start(args, fmtPtr);
vsnprintf(buffer, maxSize, fmtPtr, args); // no buffer overflows allowed!
va_end(args);
BString ret(buffer, false);
delete[] buffer;
return (ret);
}
// ---------------------------------------------------------------------------------------------------------------------
// static
BString BString::fill(int len, char ch)
{
if (len <= 0)
{
return (BString::null);
}
char* ptr = new char[len + 1];
for (int i = 0; i < len; ++i)
{
ptr[i] = ch;
}
ptr[len] = 0;
return BString(ptr, true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::trim() const
{
return trimLeft().trimRight();
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::trimLeft() const
{
if (m_len == 0)
{
return (BString::null);
}
const char* start = m_start;
if (start != 0)
{
while (isspace(*start) && (start - m_start) < m_len)
{
++start;
}
BString copy(*this);
int dif = start - m_start;
copy.m_start = start;
copy.m_len = m_len - dif;
return (copy);
}
return (BString::null);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::trimRight() const
{
if (m_len == 0)
{
return (BString::null);
}
const char* start = m_start;
if (start != 0)
{
start += m_len - 1;
int len = m_len;
while (isspace(*start) && (start - m_start) >= 0)
{
--start;
--len;
}
BString copy(*this);
copy.m_len = len;
return (copy);
}
return (BString::null);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::padLeft(int len, char ch) const
{
int dif = len - m_len;
if (dif <= 0)
{
return (*this);
}
BString filled = fill(dif, ch);
return (filled + *this);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::padRight(int len, char ch) const
{
int dif = len - m_len;
if (dif <= 0)
{
return (*this);
}
BString filled = fill(dif, ch);
return (*this + filled);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::arg(const char* arg) const
{
return priv_arg(*this, arg, strlen(arg));
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::arg(BString arg) const
{
return priv_arg(*this, arg.m_start, arg.m_len);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::makeUnique() const
{
if (m_len == 0)
{
return (BString::null);
}
char* ptr = new char[m_len + 1];
strncpy(ptr, m_start, m_len);
ptr[m_len] = 0;
return BString(ptr, true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::left(int chars) const
{
if (m_len == 0)
{
return (BString::null);
}
chars = (chars < 0 ? 0 : chars > m_len ? m_len : chars);
if (chars == 0)
{
return (BString::null);
}
BString copy(*this);
copy.m_len = chars;
return (copy);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::right(int chars) const
{
if (m_len == 0)
{
return (BString::null);
}
chars = (chars < 0 ? 0 : chars > m_len ? m_len : chars);
if (chars == 0)
{
return (BString::null);
}
BString copy(*this);
copy.m_start += m_len - chars;
copy.m_len = chars;
return (copy);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::subString(int start, int chars) const
{
if (m_len == 0)
{
return (BString::null);
}
start = (start < 0 ? 0 : start > m_len ? m_len : start);
if (chars == npos)
{
chars = m_len - start;
}
else
{
chars = (chars < 0 ? 0 : chars >(m_len - start) ?(m_len - start) : chars);
}
if (chars == 0)
{
return (BString::null);
}
BString copy(*this);
copy.m_start += start;
copy.m_len = chars;
return (copy);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::stripFromLeft(int characters) const
{
return subString(characters);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::stripFromRight(int characters) const
{
return left(getLength() - characters);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::reverse() const
{
if (m_len == 0)
{
return (BString::null);
}
char* ptr = new char[m_len + 1];
for (int i = 0; i < m_len; ++i)
{
ptr[(m_len - i) - 1] = m_start[i];
}
ptr[m_len] = 0;
return BString(ptr, true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::toUpper() const
{
if (m_len == 0)
{
return (BString::null);
}
char* ptr = new char[m_len + 1];
for (int i = 0; i < m_len; ++i)
{
ptr[i] = toupper(m_start[i]);
}
ptr[m_len] = 0;
return BString(ptr, true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::toLower() const
{
if (m_len == 0)
{
return (BString::null);
}
char* ptr = new char[m_len + 1];
for (int i = 0; i < m_len; ++i)
{
ptr[i] = tolower(m_start[i]);
}
ptr[m_len] = 0;
return BString(ptr, true);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::isValidInt(int base) const
{
if (m_len == 0)
{
return (false);
}
char buf[129];
int len = (sizeof(buf) < m_len ? sizeof(buf) : m_len);
strncpy(buf, m_start, len);
buf[len] = '\0';
char* end;
strtol(buf, &end, base);
if (end != buf + m_len)
{
return (false);
}
return (true);
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::isValidFloat() const
{
return isValidDouble();
}
// ---------------------------------------------------------------------------------------------------------------------
bool BString::isValidDouble() const
{
if (m_len == 0)
{
return (false);
}
char buf[129];
int len = (sizeof(buf) < m_len ? sizeof(buf) : m_len);
strncpy(buf, m_start, len);
buf[len] = '\0';
char* end;
strtod(buf, &end);
if (end != buf + m_len)
{
return (false);
}
return (true);
}
// ---------------------------------------------------------------------------------------------------------------------
int BString::getAsInt(int base) const
{
if (m_start != 0)
{
char buf[129];
int len = (sizeof(buf) < m_len ? sizeof(buf) : m_len);
strncpy(buf, m_start, len);
buf[len] = '\0';
char* dummy;
return strtol(buf, &dummy, base);
}
return (0);
}
// ---------------------------------------------------------------------------------------------------------------------
float BString::getAsFloat() const
{
if (m_start != 0)
{
char buf[129];
int len = (sizeof(buf) < m_len ? sizeof(buf) : m_len);
strncpy(buf, m_start, len);
buf[len] = '\0';
char* dummy;
return static_cast<float>(strtod(buf, &dummy));
}
return (0.0f);
}
// ---------------------------------------------------------------------------------------------------------------------
double BString::getAsDouble() const
{
if (m_start != 0)
{
char buf[129];
int len = (sizeof(buf) < m_len ? sizeof(buf) : m_len);
strncpy(buf, m_start, len);
buf[len] = '\0';
char* dummy;
return strtod(buf, &dummy);
}
return (0.0);
}
// ---------------------------------------------------------------------------------------------------------------------
const char* BString::getAsCStr() const
{
return (m_start);
}
// ---------------------------------------------------------------------------------------------------------------------
const char& BString::operator[](int index) const
{
return (m_start[index]);
}
// ---------------------------------------------------------------------------------------------------------------------
BString& BString::operator=(const char* str)
{
refDec();
refCreate(str, false);
return (*this);
}
// ---------------------------------------------------------------------------------------------------------------------
BString& BString::operator=(const BString& str)
{
refDec();
refCreate(str);
return (*this);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::operator+ (const char* str)
{
if (m_len == 0)
{
return BString(str);
}
int strLen = strlen(str);
int newLen = m_len + strLen;
char* ptr = new char[newLen + 1];
strncpy(ptr, m_start, m_len);
strncpy(ptr + m_len, str, strLen);
ptr[newLen] = 0;
return BString(ptr, true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString BString::operator+ (const BString& str)
{
if (m_len == 0)
{
return (str);
}
int strLen = str.m_len;
int newLen = m_len + strLen;
char* ptr = new char[newLen + 1];
strncpy(ptr, m_start, m_len);
strncpy(ptr + m_len, str.m_start, strLen);
ptr[newLen] = 0;
return BString(ptr, true);
}
// ---------------------------------------------------------------------------------------------------------------------
BString& BString::operator+=(const char* str)
{
*this = *this + str;
return (*this);
}
// ---------------------------------------------------------------------------------------------------------------------
BString& BString::operator+=(const BString& str)
{
*this = *this + str;
return (*this);
}
// ---------------------------------------------------------------------------------------------------------------------
void BString::refInc()
{
if (m_refCnt != 0)
{
++*m_refCnt;
}
}
// ---------------------------------------------------------------------------------------------------------------------
void BString::refDec()
{
if (m_refCnt != 0)
{
if (--*m_refCnt == 0)
{
delete m_refCnt;
delete m_refLen;
delete[] m_refBuf;
}
}
m_refCnt = 0;
m_refBuf = 0;
m_refLen = 0;
m_start = 0;
m_len = 0;
}
// ---------------------------------------------------------------------------------------------------------------------
void BString::refCreate(int len)
{
if (m_refCnt != 0)
{
refDec();
}
if (len <= 0)
{
return;
}
m_refCnt = new int;
m_refBuf = new char[len + 1];
m_refLen = new int;
*m_refCnt = 1;
*m_refLen = len;
m_start = m_refBuf;
m_len = len;
}
// ---------------------------------------------------------------------------------------------------------------------
void BString::refCreate(const BString& str)
{
m_refBuf = str.m_refBuf;
m_refCnt = str.m_refCnt;
m_refLen = str.m_refLen;
m_start = str.m_start;
m_len = str.m_len;
refInc();
}
// ---------------------------------------------------------------------------------------------------------------------
void BString::refCreate(const char* str, bool own)
{
int len;
if (str == 0 || (len = strlen(str)) == 0)
{
return;
}
if (own)
{
m_refBuf = (char*)str;
m_refCnt = new int;
m_refLen = new int;
*m_refCnt = 1;
*m_refLen = strlen(str);
m_start = m_refBuf;
m_len = *m_refLen;
}
else
{
refCreate(strlen(str));
if (m_refBuf)
{
strcpy(m_refBuf, str);
}
}
}
}
} // namespaces