// String.cpp: implementation of the CString class.
//
//////////////////////////////////////////////////////////////////////
#include "String.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#if defined(WIN32)
#include <windows.h>
#elif defined(linux)
#elif defined(_AIX)
#include <extension.h>
#else
#endif
#ifdef _xlC
#include <strings.h>
#endif
#include "macros.h"
#include "String.h"
using namespace clib;
// constructors
// allocate buffers
CString::CString(int iBufferNum)
{
m_pBuffer = new char[iBufferNum * STR_PAGE_SIZE]; //動態申請內存
m_nLength = 0; //長度
m_nSize = iBufferNum * STR_PAGE_SIZE; //字符串大小初始化為iBufferNum個4*1024
m_pDataStart = m_pDataEnd = m_pBuffer; //開始字符串指針全部指向m_pBuffer
}
// new one character
CString::CString(char c, int iBufferNum) //參數為字符c和iBufferNum,構造函數
{
char data[2], len = 2;
data[0] = c; //將c放在字符數組首位
data[1] = 0; //將字符數組data第二位置為0
if (len > iBufferNum * STR_PAGE_SIZE) //如果iBufferNum個4*1024小於3
{
m_pBuffer = new char[len + 1]; //為字符串類的主要字符串m_pBuffer動態申請內存空間
m_nSize = len + 1; //字符串大小為3
}
else
{
m_pBuffer = new char[iBufferNum * STR_PAGE_SIZE]; //字符串申請內存空間
m_nSize = iBufferNum * STR_PAGE_SIZE;
}
// copy data and set total length
CreateFromData(data, len); //根據字符數組data開始創建對象m_pDataStart和m_pDataEnd
}
// copy data from a null terminated string
CString::CString(const char *data, int iBufferNum)
{
long len = strlen(data);
if (len > iBufferNum * STR_PAGE_SIZE) //字符串的大小大於制定數量個4*1024
{
m_pBuffer = new char[len + 1]; // 動態申請內存空間
m_nSize = len + 1;
}
else
{
m_pBuffer = new char[iBufferNum * STR_PAGE_SIZE];
m_nSize = iBufferNum * STR_PAGE_SIZE;
}
// copy data and set total length
CreateFromData(data, len); //根據字符數組data開始創建對象m_pDataStart和m_pDataEnd
}
// copy data from a binary data
CString::CString(const char *data, long len, int iBufferNum) //構造函數的參數為字符串
{
if (len > iBufferNum * STR_PAGE_SIZE) //如果字符串的大小大於制定數量個4*1024
{
m_pBuffer = new char[len + 1]; // 動態申請內存空間
m_nSize = len + 1;
}
else
{
m_pBuffer = new char[iBufferNum * STR_PAGE_SIZE];
m_nSize = iBufferNum * STR_PAGE_SIZE;
}
// copy data and set total length
CreateFromData(data, len); //根據字符數組data開始創建對象m_pDataStart和m_pDataEnd
}
// destructor
CString::~CString(void)
{
SafeDestroy();
}
// destroy allocated memory space and init all pointers
void CString::SafeDestroy(void)
{
SAFEDELETE(m_pBuffer);
// Important for InitPointers()
m_nSize = 0;
Empty();
}
void CString::Empty(void)
{
#ifdef WIN32
ZeroMemory(m_pBuffer, m_nSize);
#else // Linux, AIX
memset(m_pBuffer, 0, m_nSize);
#endif
m_pDataStart = m_pDataEnd = m_pBuffer; //將該字符串的頭指針和尾指針全部指向字符串的頭部
m_nLength = 0; //字符串長度置為0
}
char *CString::GetData(void) const //獲得指向該字符串的頭部指針
{
return m_pDataStart;
}
int CString::CreateFromData(const char *data, long len) //根據data和長度len創建對象
{
Empty(); //清空
if (len <= 0)
return TRUE;
if (data == NULL)
return TRUE;
// actually, it's impossible
if (len > m_nSize)
return FALSE;
// copy data and set length
memcpy(m_pDataStart, data, len); //將字符數組復制給m_pDataStart指向內存空間
m_nLength = len;
m_pDataStart[m_nLength] = '\0';
m_pDataEnd = &(m_pDataStart[m_nLength]); //取得尾指針m_pDataEnd
return TRUE;
}
long CString::GetLength(void) const
{
return m_nLength;
}
int CString::IsEmpty(void) const
{
return !m_nLength;
}
int CString::Grow(int iBufferNum)
{
//unsigned char *pNewSpace = NULL;
if (iBufferNum <= 0)
return 0;
AssignNewSpace(m_nSize + iBufferNum * STR_PAGE_SIZE, 1); //分配新的內存空間,變為原來的兩倍,移動1倍
return 1;
}
int CString::Append(const char *pSrc, int iLen)
{
int total_len;
char *pNewStart = NULL;
if (iLen <= 0)
return 0;
total_len = m_nLength + iLen; //append後的總的字符串長度
// if some space avaliable, defrag it firstly.
if (m_nSize > total_len) //如果原來總內存空間長度大於append後的字符串長度
{
//如果原來剩余空閒空間小於新添加子字符串的長度,而且
if (m_nSize - (m_pDataEnd - m_pBuffer) < iLen && m_pDataStart - m_pBuffer > 0) //而且m_pDataStart在m_pBuffer的後面
{
Defrag(); //調節原來的字符串
}
}
else //如果原來總內存空間長小於append後的字符串長度,需要開辟新空間
{
// allocate new memory space and copy orignal data
AssignNewSpace(total_len + 1, 1); //分配新的內存空間,變為原來的兩倍,移動1倍
}
// get the merge point
pNewStart = m_pDataEnd; //將原來字符串的末尾指針轉變成新添加子串的開始指針
if (!pNewStart)
return 0;
// copy data and adjust some pointers
memcpy(pNewStart, pSrc, iLen); //將新添加串pSrc放置在原來串聯的末尾
m_nLength = total_len; //字符串的總長度變化
m_pDataStart[m_nLength] = 0; //新的字符串最後以為置為0
m_pDataEnd = &(m_pDataStart[m_nLength]); //讓m_pDataEnd指向新的字符串的末尾指針
return 1;
}
void CString::Defrag(void)
{
// Sure! 重新初始化原來字符串頭指針m_pDataStart,指向頭部
memmove(m_pBuffer, m_pDataStart, m_nLength); //將m_pDataStart復制給m_pBuffer
// adjust those related pointers
m_pDataStart = m_pBuffer; //m_pDataStart指向m_pBuffer
m_pDataStart[m_nLength] = 0;
m_pDataEnd = &(m_pDataStart[m_nLength]); //重新獲得原來的字符串尾指針m_pDataEnd
}
// Append another CString to this one
int CString::Append(CString *pNewStr)
{
char *pNewStart = NULL, *pSrc = NULL, *pDest = NULL;
int len = pNewStr->GetLength(); //新添加子串的長度
int total_len;
if (len <= 0)
return 0;
// const char *
pSrc = pNewStr->GetData(); //獲得要添加的字符串的頭指針
if (!pSrc)
return 0;
total_len = m_nLength + len; //新字符串的總長度 = 原來字符串長度 + 添加字符串長度
// if some space avaliable, defrag it firstly.
if (m_nSize - (m_pDataEnd - m_pBuffer) < len && m_pDataStart - m_pBuffer > 0)
{
Defrag();
}
// allocate new memory space
AssignNewSpace(total_len + 1, 1); // //根據total_len分配新的內存空間
// get the merge point
pNewStart = m_pDataEnd; //將原來字符串的末尾指針轉變成新添加子串的開始指針
if (!pNewStart)
return 0;
// copy data and adjust some pointers
memcpy(pNewStart, pSrc, len); //將新添加串pSrc放置在原來串聯的末尾
m_nLength = total_len;
m_pDataStart[m_nLength] = 0;
m_pDataEnd = &(m_pDataStart[m_nLength]); //讓m_pDataEnd指向新的字符串的末尾指針
return 1;
}
// Adjust start and end pointer of its buffer
// Get one character at give position
char CString::GetAt(int nIndex) const
{
if (nIndex >= m_nLength)
return -1;
if (nIndex < 0)
return -1;
return m_pDataStart[nIndex];
}
// return single character at zero-based index
char CString::operator[](int nIndex) const
{
if (nIndex >= m_nLength)
return -1;
return m_pDataStart[nIndex];
}
// return pointer to const string
CString::operator LPCTSTR() const //將該字符串轉變為const char*字符串常量
{
return (const char*)m_pDataStart;
}
// duplicate a string
CString *CString::Duplicate(int iBufferNum) const
{
CString *pCStr = NULL;
pCStr = new CString(m_pDataStart, m_nLength, iBufferNum);
return pCStr;
}
// copy from another CString
const CString& CString::operator=(CString& stringSrc) //賦值操作符
{
long len = stringSrc.GetLength(); //取得stringSrc字符串長度
if (len >= m_nSize) //如果空間大小不夠
{
AssignNewSpace(len + 1, 0); // don't copy orignal data //將會申請一塊新的內存空間
}
// copy data and adjust pointers
Empty(); //清空
memcpy(m_pDataStart, stringSrc.GetData(), len); //將字符串stringSrc復制給新的m_pDataStart
m_pDataStart[len] = 0;
m_pDataEnd = &(m_pDataStart[len]); //獲得新的m_pDataEnd
m_nLength = len;
return *this;
}
// set string content to single character
CString &CString::operator=(char c) //賦值操作符,將字符賦給字符串
{
if (m_nSize < 2) // c + '\0' length //如果內存空間不足
{ // it needs to realloc space, but we use new and delete pair
SafeDestroy();
m_pBuffer = new char[2]; //重新申請內存
m_nSize = 2;
//TODO, I don't check the value of this pointer, unkown result. :)
}
m_pDataStart = m_pBuffer; //獲得頭指針
m_pDataStart[0] = c;
m_pDataStart[1] = 0;
m_pDataEnd = &(m_pDataStart[1]); //獲得尾指針
m_nLength = 1;
return *this;
}
// Set one character at give position
void CString::SetAt(long pos, char ch)
{
if (pos < m_nLength)
m_pDataStart[pos] = ch;
return;
}
// Get the string started from give position
void CString::GetManyChars(char *buf, long pos, long len) const
{
if (buf == NULL)
return;
if (pos >= m_nLength)
return;
if (pos + len > m_nLength)
len = m_nLength - pos;
if (len > 0)
memcpy(buf, m_pDataStart + pos, len); //將 m_pDataStart + pos開始長為len的子串復制給buf
}
// Compare itself with a new string, case-sensitive
int CString::Compare(const char *pNewStr) const
{
if (pNewStr == NULL)
return -1;
return strcmp(m_pDataStart, pNewStr);
}
// Compare itself with a new string, case-ignored
int CString::CompareNoCase(const char *pNewStr) const
{
if (pNewStr == NULL)
return -1;
#ifndef WIN32
return strcasecmp(m_pDataStart, pNewStr);
#else
return stricmp(m_pDataStart, pNewStr);
#endif
}
// find a character start from a give position
int CString::Find(int ch, long pos) const
{
char *p = NULL;
if (ch < 0)
return -1;
if (ch > UCHAR_MAX)
return -1;
if (pos < 0)
return -1;
if (pos >= m_nLength)
return -1;
p = (char*)memchr(m_pDataStart + pos, ch, m_nLength - pos);
if (!p)
return -1;
return p - m_pDataStart;
}
// find a string start from a give position
int CString::Find(const char *str, long pos) const
{
long len;
char *p = NULL;
if (str == NULL)
return -1;
len = strlen(str);
if (len == 0)
return 0;
p = (char *)strstr(m_pDataStart + pos, str);
if (p == NULL)
return -1;
else
return p - m_pDataStart;
}
char *CString::GetBuffer(int nMinBufLength) //獲得該字符串頭指針,並且說明返回的內存空間最小值
{
Defrag();
if (nMinBufLength > m_nLength)
AssignNewSpace(nMinBufLength, 1);
return m_pDataStart;
}
void CString::ReleaseBuffer(int nNewLength)
{
return;
}
//Extracts the left part of a string.
CString CString::Left(int count) const
{
if (count < 0)
count = 0;
if (count >= m_nLength)
return *this;
CString dest(m_pDataStart, count); //調用構造函數新建一個
return dest;
}
//Extracts the right part of a string.
CString CString::Right(int count) const
{
if (count < 0)
count = 0;
if (count >= m_nLength)
return *this;
CString dest(&(m_pDataStart[m_nLength - count]), count);
return dest;
}
//Converts all the characters in this string to uppercase characters.
void CString::MakeUpper(void)
{
strupr(m_pDataStart);
}
//Converts all the characters in this string to lowercase characters.
void CString::MakeLower(void)
{
strlwr(m_pDataStart);
}
// TODO: check the space left in the two pading of the whole buffer
// trim the left spaces
void CString::TrimLeft(void) // //將字符串右邊的空格去掉
{
int start = 0;
while (isspace(m_pDataStart[start]) && start < m_nLength)
start ++;
if (start > 0)
{
m_pDataStart += start;
}
}
// trim the right spaces
void CString::TrimRight(void) //將字符串右邊的空格去掉
{
int end = m_nLength - 1;
while (isspace(m_pDataStart[end]) && end >= 0)
end --;
if (end < 0)
{
end = 0;
m_pDataEnd = &(m_pDataStart[end]);
}
else
{
m_pDataEnd = &(m_pDataStart[end]);
}
}
// trim both sides
void CString::Trim(void) // //將字符串的空格去掉
{
TrimLeft();
TrimRight();
}
int CString::Replace(const char *lpszOld, const char *lpszNew)
{
// can't have empty or NULL lpszOld
if (!lpszOld)
return 0;
int nOldLen = strlen(lpszOld); //獲得舊字符串的長度
if (nOldLen <= 0)
return 0;
int nNewLen = strlen(lpszNew); //獲得新字符串的長度
// loop once to figure out the size of the result string
int nCount = 0;
char *lpszStart = m_pDataStart;
char *lpszEnd = m_pDataEnd;
char *lpszTarget;
while (lpszStart < lpszEnd) //循環處理原有字符串
{
while ((lpszTarget = strstr(lpszStart, lpszOld)) != NULL) //如果在字符串lpszStart中發現子串lpszOld
{
nCount++; //子串數量+1
lpszStart = lpszTarget + nOldLen; //往後定位字符串lpszStart,從第一個子串後開始
}
lpszStart += strlen(lpszStart) + 1; //往後查找
}
// if any changes were made, make them
if (nCount > 0) //如果有重復的字符串
{
// allocate a new buffer (slow but sure)
int nNewLength = m_nLength + (nNewLen - nOldLen) * nCount; //覆蓋後總字符串的大小
AssignNewSpace(nNewLength + 1, 1); //為新的字符串分配內存空間
// then we just do it in-place
lpszStart = m_pDataStart; //重新初始化m_pDataStart,lpszStart,lpszEnd
lpszEnd = m_pDataEnd;
// loop again to actually do the work
while (lpszStart < lpszEnd) //循環處理原來的字符串
{
while ( (lpszTarget = strstr(lpszStart, lpszOld)) != NULL) //如果在字符串lpszStart中發現子串lpszOld
{
int nBalance = lpszEnd - (lpszTarget + nOldLen); //字符串lpszTarget後面的字符數量
memmove(lpszTarget + nNewLen, lpszTarget + nOldLen,
nBalance * sizeof(char)); //移走lpszTarget原來的字符串,並為lpszTarget重新設置為nNewLen大小內存
memcpy(lpszTarget, lpszNew, nNewLen * sizeof(char)); //將新字符串lpszNew覆蓋舊的子串lpszTarget
lpszStart = lpszTarget + nNewLen; //尋找目標字符串後移nNewLen
lpszStart[nBalance] = '\0';
}
lpszStart += strlen(lpszStart) + 1; //尋找目標字符串往後走
}
m_nLength = nNewLength;
}
return nCount;
}
// format a string
void CString::Format(char *fmt, ...)
{
char TmpBuffer[STR_PAGE_SIZE]; // TODO, should calculate this size dynamically.
va_list argList;
va_start(argList, fmt);
#ifdef WIN32
_vsnprintf(TmpBuffer, STR_PAGE_SIZE, fmt, argList); // just not overwrite something
#else
vsnprintf(TmpBuffer, STR_PAGE_SIZE, fmt, argList); // just not overwrite something
#endif
va_end(argList);
}
// copy string content from ANSI string (converts to TCHAR)
const CString& CString::operator=(const char *lpsz)
{
int len = strlen(lpsz);
if (m_nSize < len) // c + '\0' length
{ // it needs to realloc space, but we use new and delete pair
SafeDestroy();
m_pBuffer = new char[len + 1];
m_nSize = len + 1;
//TODO, I don't check the value of this pointer, unkown result. :)
}
m_pDataStart = m_pBuffer;
strcpy((char *)m_pDataStart, lpsz);
m_pDataStart[len] = 0;
m_pDataEnd = &(m_pDataStart[len]);
m_nLength = len;
return *this;
}
// concatenate a UNICODE character after converting it to TCHAR
const CString& CString::operator+=(const char *lpsz)
{
int len = strlen(lpsz);
if (m_nSize < m_nLength + len + 1)
{
AssignNewSpace(m_nLength + len + 1, 1); // allocate new space and move orignal data
}
Defrag();
memcpy(m_pDataEnd, lpsz, len);
m_pDataEnd += len;
*m_pDataEnd = 0;
return *this;
}
// concatenate a single character
const CString& CString::operator+=(char ch)
{
if (m_nSize < m_nLength + 1 + 1)
{
AssignNewSpace(m_nLength + 1 + 1, 1); // allocate new space and move orignal data
}
Defrag();
memcpy(m_pDataEnd, &ch, 1);
m_pDataEnd += 1;
*m_pDataEnd = 0;
return *this;
}
// concatenate from another CString
const CString& CString::operator+=(CString& string)
{
if (m_nSize < m_nLength + string.GetLength() + 1)
{
AssignNewSpace(m_nLength + string.GetLength() + 1, 1); // allocate new space and move orignal data
}
Defrag();
memcpy(m_pDataEnd, string.GetData(), string.GetLength());
m_pDataEnd += string.GetLength();
*m_pDataEnd = 0;
return *this;
}
void CString::AssignNewSpace(int iNewTotalSize, int iNeedMove)
{
char *pNewSpace = NULL; //新的字符串指針,初始化NULL
if (iNewTotalSize <= m_nSize) //確保新的內存空間大於原來的內存空間
return ;
// allocate new space
pNewSpace = new char [iNewTotalSize]; //pNewSpace動態申請內存空間
if (pNewSpace == NULL)
return ;
if (iNeedMove)
{
memcpy(pNewSpace, m_pDataStart, m_nLength + 1); //將原有字符串復制給新申請內存
}
SAFEDELETE(m_pBuffer); //安全刪除原有的字符串m_pBuffer
m_pBuffer = pNewSpace;
m_pDataStart = m_pBuffer;
m_pDataEnd = &(m_pDataStart[m_nLength]); //重置m_pBuffer,m_pDataStart,m_pDataEnd
// adjust new size
m_nSize = iNewTotalSize;
}
//////////////////////////////////////////////////////////////////////////////
// concatenation
// NOTE: "operator+" is done as friend functions for simplicity
// There are three variants:
// CString + CString
// and for ? = TCHAR, LPCTSTR
// CString + ?
// ? + CString
void CString::ConcatCopy(const char *str1, int nSrc1Len, const char *str2, int nSrc2Len)
{
int nNewLen = nSrc1Len + nSrc2Len;
AssignNewSpace(nNewLen + 1, 0);
// append two string
Append(str1, nSrc1Len);
Append(str2, nSrc2Len);
}
// friend methods
// Class + Class
CString operator+(const CString& string1, const CString& string2)
{
CString s;
s.ConcatCopy(string1.GetData(), string1.GetLength(), string2.GetData(), string2.GetLength());
return s;
}
// Class + char
CString operator+(const CString& string, char ch)
{
CString s;
char str[2];
str[0] = ch;
str[1] = 0;
s.ConcatCopy(string.GetData(), string.GetLength(), str, 1);
return s;
}
// char + Class
CString operator+(char ch, const CString& string)
{
CString s;
char str[2];
str[0] = ch;
str[1] = 0;
s.ConcatCopy(string.GetData(), string.GetLength(), str, 1);
return s;
}
// Class + char *
CString operator+(const CString& string, const char *lpsz)
{
CString s;
s.ConcatCopy(string.GetData(), string.GetLength(), lpsz, strlen(lpsz));
return s;
}
// char * + Class
CString operator+(const char *lpsz, const CString& string)
{
CString s;
s.ConcatCopy(string.GetData(), string.GetLength(), lpsz, strlen(lpsz));
return s;
}
// Compare operators
bool operator==(const CString& s1, const CString& s2)
{
return (s1.Compare(s2.GetData()) == 0);
}
bool operator==(const CString& s1, const char* s2)
{
return (s1.Compare(s2) == 0);
}
bool operator==(const char* s1, const CString& s2)
{
return (s2.Compare(s1) == 0);
}
bool operator!=(const CString& s1, const CString& s2)
{
return (s1.Compare(s2.GetData()) != 0);
}
bool operator!=(const CString& s1, const char* s2)
{
return (s1.Compare(s2) != 0);
}
bool operator!=(const char* s1, const CString& s2)
{
return (s2.Compare(s1) != 0);
}
bool operator>(const CString& s1, const CString& s2)
{
return (s1.Compare(s2.GetData()) > 0);
}
bool operator>(const CString& s1, const char* s2)
{
return (s1.Compare(s2) > 0);
}
bool operator>(const char* s1, const CString& s2)
{
return (s2.Compare(s1) < 0);
}
bool operator<(const CString& s1, const CString& s2)
{
return (s1.Compare(s2.GetData()) < 0);
}
bool operator<(const CString& s1, const char* s2)
{
return (s1.Compare(s2) < 0);
}
bool operator<(const char* s1, const CString& s2)
{
return (s2.Compare(s1) > 0);
}
bool operator>=(const CString& s1, const CString& s2)
{
return (s1.Compare(s2.GetData()) >= 0);
}
bool operator>=(const CString& s1, const char* s2)
{
return (s1.Compare(s2) >= 0);
}
bool operator>=(const char* s1, const CString& s2)
{
return (s2.Compare(s1) <= 0);
}
bool operator<=(const CString& s1, const CString& s2)
{
return (s1.Compare(s2.GetData()) <= 0);
}
bool operator<=(const CString& s1, const char* s2)
{
return (s1.Compare(s2) <= 0);
}
bool operator<=(const char* s1, const CString& s2)
{
return (s2.Compare(s1) >= 0);
}