// 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);
}