Click here to Skip to main content
Click here to Skip to main content
 
Add your own
alternative version

XMLLib for PUGXML with XPath

, 29 Oct 2009
A library for PugXML which implements XPath
//************************************************************************************************************************** 
//* 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

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

JCrane2
Web Developer
United States United States
No Biography provided

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 29 Oct 2009
Article Copyright 2003 by JCrane2
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid