/* BString.cpp Replacement of the MFC CString class May 12 2004 Created by Bill arden www.billarden.com Relesed into public domain (have fun) ------------------------------------------------- Features 1. Pointer passing saves memory This class creates a structure (See BString.h) that is passed around so that the actuall data does not have to be copyed each time it's passed. BString ->BStringDataStruct m_StringData; long nCount; //how many classes have this? int nStrLen; //length with terminator int nAllocLen; //memory bytes allocated char* pstr; //pointer to the string Known issues 1. _vsnprintf is not supported under ANSI C++ 2. No unicode support *////////////////////////////////////////////////////////////////////// #include "stdafx.h" //includes #include "BString.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif //***************************************************************************************** // Construction/Destruction //***************************************************************************************** BString::BString(){ m_StringData = NULL; Create(); }; BString::BString(const BString& StrSrc){ //copy pointer m_StringData = StrSrc.m_StringData; m_StringData->nCount++; //we have it also }; BString::BString(char* CharStr){ m_StringData = NULL; Create(); CopyStr(0,CharStr); }; BString::BString(char AChar){ m_StringData = NULL; Create(); CopyStr(0,&AChar,1); }; //------------------------------------------------ BString::~BString(){ Destroy(); }; //***************************************************************************************8 //Internal functions //***************************************************************************************8 void BString::Create(void){ //make our pointer structure. if (m_StringData == NULL){ m_StringData = new BStringDataStruct; m_StringData->nCount =1 ; //we have it m_StringData->nStrLen = 1; m_StringData->nAllocLen = 0; m_StringData->pstr = NULL; }; }; //----------------------------------------------------- void BString::Destroy(void){ //Called to remove Structure on class distruction //also used in operator= if (m_StringData != NULL){ m_StringData->nCount--; if (m_StringData->nCount < 1){ Empty(); //remove the string delete m_StringData; m_StringData = NULL; }; };//if null }; //----------------------------------------------------- void BString::BreakTie(void){ //if linked to someone else, make a copy so that we don't modify someones elses string if (m_StringData == NULL) return; if (m_StringData->nCount >= 2){ BStringDataStruct* NewStringData; NewStringData = m_StringData; m_StringData = NULL; Create(); //create new CopyStr(0,NewStringData->pstr, NewStringData->nStrLen-1); NewStringData->nCount--; //we arn't using it anymore }; }; //----------------------------------------------------- void BString::GrowBuffer(int newSize){ //grow if nessessary for given request if (m_StringData == NULL) return; if (newSize+2 >= m_StringData->nAllocLen){ BreakTie(); //we are making changes int NewAllocLen; if (m_StringData->pstr == NULL){ //first time NewAllocLen = newSize+10 ; //try to predict groth so that we don't do this a lot }else{ NewAllocLen = newSize + 80 ; //try again }; char* NewBuffer = new char[NewAllocLen]; if (m_StringData->pstr !=NULL){ memcpy(NewBuffer,m_StringData->pstr,m_StringData->nStrLen); //save existing string delete[] m_StringData->pstr; //delete old }; m_StringData->nAllocLen = NewAllocLen; // m_StringData->pstr = NewBuffer; //swap in new buffer }; }; //----------------------------------------------------- void BString::CopyStr(int nStartIn, char* CharStr,int nCharLength ){ /* Copy a string into our buffer int nStartIn = start point in destination, 0 for start, -1 for append char* CharStr = String to add int nCharLength = lenght or -1 for null terminated */ if (CharStr != NULL){ int Strlen; int nStart = nStartIn; BreakTie(); if (nStartIn == -1) nStart = m_StringData->nStrLen -1; if (nCharLength == -1) { Strlen = strlen(CharStr) + 1; }else{ Strlen = nCharLength + 1; }; GrowBuffer(Strlen + nStart); memcpy(&(m_StringData->pstr[nStart]),CharStr,Strlen); m_StringData->nStrLen = Strlen + nStart; m_StringData->pstr[m_StringData->nStrLen-1] = (char) 0; }; }; //************************************************************************************** //************************************************************************************** //*************************************************************************************8 //----------------------------------------- char* BString::GetBuffer(int len){ if (m_StringData == NULL) return NULL; BreakTie(); //just in case they modify it GrowBuffer(len); //Enlarge as requested return m_StringData->pstr; }; void BString::ReleaseBuffer(int nNewLength ){ //length not including a null terminator if (m_StringData == NULL) return; if ( nNewLength == -1) { SetLength( strlen(m_StringData->pstr) ); //null terminated }else{ SetLength(nNewLength); //specifyed }; }; //*************************************************************************************8 void BString::Empty(void){ if (m_StringData == NULL) return; BreakTie(); //were modifying it if (m_StringData->pstr != NULL){ delete[] m_StringData->pstr; //delete string }; m_StringData->nStrLen = 1; m_StringData->nAllocLen = 0; m_StringData->pstr = NULL; }; //************************************************************************************* int BString::GetLength(){ //lenght in bytes if (m_StringData == NULL) return 0; return m_StringData->nStrLen -1; }; //-------------------------------------------------- void BString::SetLength(int len){ //internal function. not in CString if (m_StringData == NULL) return; BreakTie(); if (len < m_StringData->nAllocLen){ m_StringData->nStrLen = len + 1; //add terminating null m_StringData->pstr[len] = '\0'; }; }; //************************************** char BString::GetAt(int nIndex){ if ((m_StringData == NULL) || (m_StringData->pstr == NULL )) return 0; if (nIndex > (m_StringData->nStrLen-1)) return 0; //past end return m_StringData->pstr[nIndex]; }; char BString::operator[](int nIndex){ return GetAt(nIndex); }; //******************************************************************************************8 //operators //******************************************************************************************8 BString& BString::operator=( BString& StrSrc){ Destroy(); //Destroy our copy of the structure m_StringData = StrSrc.m_StringData; // Grab there pointer m_StringData->nCount++; //we have it also return *this; } BString& BString::operator=(char Achar){ CopyStr(0,&Achar,1); //Set to one char return *this; }; BString& BString::operator=(char* charStr){ CopyStr(0,charStr); //set to null terminated string return *this; }; //-------------------------------------------------------------- BString& BString::operator+=( BString& StrSrc){ CopyStr(-1,StrSrc.m_StringData->pstr, StrSrc.m_StringData->nStrLen-1); //append return *this; } BString& BString::operator+=(char Achar){ CopyStr(-1,&Achar,1); //append return *this; }; BString& BString::operator+=(char* charStr){ CopyStr(-1,charStr); //append return *this; }; //******************************************************************************************8 // Functions //******************************************************************************************8 BString BString::Left(int nCount) { //return left n bytes BString retstr; retstr = *this; retstr.SetLength(nCount); return retstr; }; BString BString::Right(int nCount){ //return right n bytes BString retstr; int RemoveCount; retstr = *this; RemoveCount = retstr.GetLength() - nCount; if (RemoveCount > 0 ) retstr.Delete(0,RemoveCount); return retstr; }; //******************************************************* int BString::Find(char ch,int nStart){ //find a char, zero based if ((m_StringData == NULL) || (m_StringData->pstr == NULL )) return -1; //error for (int i = nStart;i< (m_StringData->nStrLen-1);++i){ if (m_StringData->pstr[i] == ch){ return i; //found }; }; return -1; //not found }; //-------------------------------------------------------------------------- int BString::Find(char* ch, int nStart ){ //find a string int SrchStrLen; if ((m_StringData == NULL) || (m_StringData->pstr == NULL )) return -1; SrchStrLen = strlen(ch); for (int i = nStart;i< (m_StringData->nStrLen-1);++i){ if (m_StringData->pstr[i] == ch[0]){ for (int d=0;dpstr[i+d] != ch[d]){ break; //not found }; }; return i; //found }; };//i return -1; //not found }; //******************************************************* int BString::Delete(int nIndexIn, int nCountIn ){ //cut out chars, zero based, return resulting lenght //Used by most triming functions int nCount = nCountIn; int nIndex = nIndexIn; if ((m_StringData == NULL) || (m_StringData->pstr == NULL )) return -1; //error if (nCountIn == 0) return m_StringData->nStrLen; // nothing to do BreakTie(); //cut the connection to linked strings if (nIndex >= (m_StringData->nStrLen-1)){ nIndex = (m_StringData->nStrLen-1)-1;}; //0 to n-1 if ((nIndex + nCount) > (m_StringData->nStrLen-1) ){ nCount = (m_StringData->nStrLen -1) - nIndex ; };// int upperBytes; upperBytes = (m_StringData->nStrLen-1) - (nIndex + nCount); //end bytes to copy if (upperBytes >= 1){ //move high memmove(&(m_StringData->pstr[nIndex]),&(m_StringData->pstr[nIndex+nCount]),upperBytes); //copy ok even if overlapping }; m_StringData->nStrLen = nIndex + upperBytes + 1; m_StringData->pstr[m_StringData->nStrLen-1] = '\0'; //re add null return m_StringData->nStrLen; }; //*******************************************************8 void BString::TrimLeft(char chTarget){ //trim spaces if ((m_StringData == NULL) || (m_StringData->pstr == NULL )) return; //error int leftCount; leftCount = 0; for (int i = 0;i< (m_StringData->nStrLen-1);++i){ if (m_StringData->pstr[i] == chTarget){ ++leftCount; }else{ break; }; }; if (leftCount) Delete(0,leftCount); }; //------------------------------------------- void BString::TrimRight(char chTarget){ if ((m_StringData == NULL) || (m_StringData->pstr == NULL )) return; int RightCount; RightCount = 0; for (int i = (m_StringData->nStrLen-2); i >= 0 ;--i){ if (m_StringData->pstr[i] == chTarget){ ++RightCount; }else{ break; }; }; if (RightCount) Delete((m_StringData->nStrLen-1) - RightCount, RightCount); }; //***************************************************************************** BString BString::Mid(int nFirst, int nCountIn){ BString retstr; //new string retstr = *this; //copy me int nCount = nCountIn; if (nFirst >= 1){ retstr.Delete(0,nFirst); //trim the left size }; if (nCount == -1) { //run to end nCount = retstr.GetLength(); }; if (nCount > retstr.GetLength() ) nCount = retstr.GetLength(); retstr.SetLength(nCount); return retstr; }; //*******************************************************8 int BString::Remove(char chRemove){ if ((m_StringData == NULL) || (m_StringData->pstr == NULL )) return -1; int removeCount =0; int removedOne = -1; while (removedOne){ removedOne = 0; for (int i = 0;i< (m_StringData->nStrLen-1);++i){ if (m_StringData->pstr[i] == chRemove){ Delete(i); removedOne = -1; break; }; }; };//while return removeCount; }; //const BString& operator+=(const BString& string); //const BString& operator+=(char* charStr); //************************************************************************************** bool BString::FormatV(const char * pFormat,va_list ArgList){ static char Buffer[1000]; int Result = _vsnprintf(Buffer,1000,pFormat,ArgList); if (Result > 0){ CopyStr(0, Buffer,Result); return true; }else{ return false; }; } bool BString::Format(const char * pFormat,...){ va_list ArgList; va_start(ArgList,pFormat); bool result = FormatV(pFormat,ArgList); va_end(ArgList); return result; } //************************************************************************************** void BString::MakeUpper(){ if ((m_StringData == NULL) || (m_StringData->pstr == NULL )) return ; //error BreakTie(); _strupr(m_StringData->pstr); }; //_CRTIMP char * __cdecl _strrev(char *); //************************************************************************************** bool operator==(BString& s1, BString& s2){ return (strcmp(s1.GetBuffer(0), s2.GetBuffer(0)) == 0); }; bool operator==(BString& s1, char* s2){ return (strcmp(s1.GetBuffer(0), s2) == 0); }; bool operator==(char* s1, BString& s2){ return (strcmp(s1, s2.GetBuffer(0)) == 0); }; //----------------------------------------------------------- bool operator!=(BString& s1, BString& s2){ return (strcmp(s1.GetBuffer(0), s2.GetBuffer(0)) != 0); }; bool operator!=(BString& s1, char* s2){ return (strcmp(s1.GetBuffer(0), s2) != 0); }; bool operator!=(char* s1, BString& s2){ return (strcmp(s1, s2.GetBuffer(0)) != 0); }; //**************************************************************************************