// CString使用的是引用技术,可以共享数据(这个大家都知道),另外空的CStirng是指向一个固定的地址的(_afxInitData).
// 另外CStirng是有长度限制的2147483647(无符号int 的最大值).
// 数据格式
struct CStringData
{
long nRefs; //引用记数
int nDataLength; //字符使用长度
int nAllocLength; //分配长度
TCHAR* data() { return (TCHAR*)(this+1); } //存放字符串的地方
//this+1 相当与是CStringData[1];所以TCHAR* data()指的是CStringData[1]的地址
};
//基本和网络通讯的数据包差不多
typedef struct tagAnsMarketData //统一的应答结构
{
WORD wStkNum; //数目
char iData[1]; //数据
}ANS_MARKET_DATA,*PANS_MARKET_DATA;
//下面是代码了
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <malloc.h>
#include <tchar.h>
string.h
#ifndef __JONES__STRING__
#define __JONES__STRING__
struct CStringData
{
long nRefs; //引用记数
int nDataLength; //字符使用长度
int nAllocLength; //分配长度
TCHAR* data() { return (TCHAR*)(this+1); } //存放字符串的地方
//this+1 相当与是CStringData[1];所以TCHAR* data()指的是CStringData[1]的地址
};
class CString
{
public:
//构造函数
CString();
CString(const CString& stringSrc);
CString(TCHAR ch, int nLength =1);
CString(LPCTSTR lpsz); // CString(LPCSTR lpsz); ANSI下版本
//CString(LPCWSTR lpsz);UNICODE下版本
CString(LPCTSTR lpch, int nLength); //CString(LPCSTR lpch, int nLength);ANSI下版本
//CString(LPCWSTR lpch, int nLength);//UNICODE下版本
CString(const unsigned char* psz);
~CString();
//CStringData的属性
int GetLength() const; //得到字符长度
int GetAllocLength() const; //得到分配的内存长度
BOOL IsEmpty() const; //判断字符长度是否为0
operator LPCTSTR() const; //类型转换
void Empty(); //清空CStringData
//操作符重载
const CString& operator=(const CString& stringSrc);
const CString& operator=(LPCTSTR lpsz);
const CString& operator=(TCHAR ch);
const CString& operator+=(const CString& string);
const CString& operator+=(TCHAR ch);
const CString& operator+=(LPCTSTR lpsz);
TCHAR operator[](int nIndex) const;
friend CString operator+(const CString& string1,const CString& string2);
friend CString operator+(const CString& string, TCHAR ch);
friend CString operator+(TCHAR ch, const CString& string);
friend CString operator+(const CString& string, LPCTSTR lpsz);
friend CString operator+(LPCTSTR lpsz, const CString& string);
//操作,脱离共享数据块
int Delete(int nIndex, int nCount = 1);//删除从nIndex开始长度为nCount的数据
int Insert(int nIndex, TCHAR ch); //插入一个字符
int Insert(int nIndex, LPCTSTR pstr); //插入一个字符串
int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew); //替换数据
int Replace(TCHAR chOld, TCHAR chNew); //替换数据
int Remove(TCHAR chRemove); //移除一个字符
void TrimRight(LPCTSTR lpszTargetList);
void TrimRight(TCHAR chTarget);//去掉右边chTarget
void TrimRight(); //去掉右边空格
void TrimLeft(LPCTSTR lpszTargets);
void TrimLeft(TCHAR chTarget); //去掉左边chTarget
void TrimLeft(); //去掉左边空格
//取某段字符串
void SetAt(int nIndex, TCHAR ch);
TCHAR GetAt(int nIndex) const;
CString Mid(int nFirst) const; //取某段字符串
CString Mid(int nFirst, int nCount) const; //取某段字符串
CString Right(int nCount) const; //取右边字符串
CString Left(int nCount) const; //取左边字符串
void CString::MakeUpper(); //大写
void CString::MakeLower(); //小写
void CString::MakeReverse(); //????不知道干什么的 strrev
//查找
int Find(TCHAR ch) const;
int Find(TCHAR ch, int nStart) const;
int ReverseFind(TCHAR ch) const;
int Find(LPCTSTR lpszSub) const;
int Find(LPCTSTR lpszSub, int nStart) const;
int FindOneOf(LPCTSTR lpszCharSet) const;//得到第一个匹配lpszCharSet中其中一个字符的位置 调用_tcspbrk
//高级操作
LPTSTR GetBuffer(int nMinBufLength); //重新分配内存,在拷贝原来的数据
void ReleaseBuffer(int nNewLength=-1); //在[nNewLength]='/0',对内存大小没有改变
LPTSTR GetBufferSetLength(int nNewLength); //重新分配内存,在拷贝原来的数据
void FreeExtra(); //深拷贝自己,然后--原来的引用记数器
LPTSTR LockBuffer(); //引用计数器=-1,加锁
void UnlockBuffer(); //解锁,引用计数器=1
//比较
int Compare(LPCTSTR lpsz) const; //区分大小写比较
int CompareNoCase(LPCTSTR lpsz) const; //不区分大小写比较
//比较速度没有Compare快
int Collate(LPCTSTR lpsz) const; //区分大小写比较
int CollateNoCase(LPCTSTR lpsz) const; //不区分大小写比较
//格式化字符串
void Format(LPCTSTR lpszFormat, ...);//CSting中最长的函数了,完全是自己分析的(牛啊)
private:
void Init();
CStringData* GetData() const; //通过m_pchData-1 得到CStringData
void AllocBuffer(int nLen); //给CStringData分配内存,不带记数器
void CopyBeforeWrite(); //带引用记数的复制自己深拷贝
void AllocBeforeWrite(int nLen); //给CStringData分配内存,带记数器
void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);//分配内存,并拷贝lpszSrcData内容
//把nCopyIndex开始的nCopyLen长度的数据拷贝给dest,nExtraLen扩充的长度,次函数好像没下面用
void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,int nExtraLen) const;
void Release(); //--引用记数器并判断是否删除内存,如删除并初始化
void FormatV(LPCTSTR lpszFormat, va_list argList);//格式化字符串
void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
int nSrc2Len, LPCTSTR lpszSrc2Data);//连接数据lpszSrc1Data+lpszSrc2Data
void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData); //连接字符串
static void Release(CStringData* pData); //--引用记数器并判断是否删除内存
static void FreeData(CStringData* pData); //释放内存
static int SafeStrlen(LPCTSTR lpsz); //得到长度
LPTSTR m_pchData; //指向CStringData的数据区
};
/*调用CString::Compare比较大小,如果比较中有CStirng的话用
调用operator LPCTSTR()转化类型为LPCTSTR
*/
bool operator==(const CString& s1, const CString& s2);
bool operator==(const CString& s1, LPCTSTR s2);
bool operator==(LPCTSTR s1, const CString& s2);
bool operator!=(const CString& s1, const CString& s2);
bool operator!=(const CString& s1, LPCTSTR s2);
bool operator!=(LPCTSTR s1, const CString& s2);
bool operator<(const CString& s1, const CString& s2);
bool operator<(const CString& s1, LPCTSTR s2);
bool operator<(LPCTSTR s1, const CString& s2);
bool operator>(const CString& s1, const CString& s2);
bool operator>(const CString& s1, LPCTSTR s2);
bool operator>(LPCTSTR s1, const CString& s2);
bool operator<=(const CString& s1, const CString& s2);
bool operator<=(const CString& s1, LPCTSTR s2);
bool operator<=(LPCTSTR s1, const CString& s2);
bool operator>=(const CString& s1, const CString& s2);
bool operator>=(const CString& s1, LPCTSTR s2);
bool operator>=(LPCTSTR s1, const CString& s2);
//
//检测lpsz是否有效,调用了IsBadStringPtr
BOOL AfxIsValidString(LPCTSTR lpsz, int nLength = -1);
//检测lp是否能读写权限,调用了IsBadReadPtr,IsBadStringPtr
BOOL AfxIsValidAddress(const void* lp,UINT nBytes, BOOL bReadWrite = TRUE);
//CStirng数组操作
void ConstructElements(CString* pElements, int nCount); //初始化CStirng数组
void DestructElements(CString* pElements, int nCount); //删除CStirng数组
void CopyElements(CString* pDest, const CString* pSrc, int nCount); //CString数组拷贝
#endif
string.cpp
#include "stdafx.h"
#include "string.h"
TCHAR afxChNil = '/0';
int _afxInitData[] = { -1, 0, 0, 0 }; //初始化CStringData的地址
CStringData* _afxDataNil = (CStringData*)&_afxInitData; //地址转化为CStringData*
LPCTSTR _afxPchNil = (LPCTSTR)(((BYTE*)&_afxInitData)+sizeof(CStringData));
const CString& AfxGetEmptyString() //建立一个空的CString
{ return *(CString*)&_afxPchNil; }
BOOL AfxIsValidString(LPCTSTR lpsz, int nLength /* = -1 */)
{
if (lpsz == NULL)
return FALSE;
return ::IsBadStringPtr(lpsz, nLength) == 0;
}
BOOL AfxIsValidAddress(const void* lp, UINT nBytes,BOOL bReadWrite /* = TRUE */)
{
return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
(!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
}
void CString::Init()
{ m_pchData=AfxGetEmptyString().m_pchData; }
CString::CString()
{ Init(); }
int CString::GetLength() const
{ return GetData()->nDataLength; }
int CString::GetAllocLength() const
{ return GetData()->nAllocLength; }
BOOL CString::IsEmpty() const
{ return GetData()->nDataLength == 0; }
CStringData* CString::GetData() const
{
assert(m_pchData != NULL);
return ((CStringData*)m_pchData)-1;
}
CString::operator LPCTSTR() const
{ return m_pchData; }
int CString::SafeStrlen(LPCTSTR lpsz)
{ return (lpsz == NULL) ? 0 : lstrlen(lpsz); }
void CString::AllocBuffer(int nLen)
{
assert(nLen >= 0);
assert(nLen <= 2147483647-1); // (signed) int 的最大值
if (nLen == 0)
Init();
else
{
CStringData* pData;
{
pData = (CStringData*)
new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
pData->nAllocLength = nLen;
}
pData->nRefs = 1;
pData->data()[nLen] = '/0';
pData->nDataLength = nLen;
m_pchData = pData->data();
}
}
void CString::FreeData(CStringData* pData)
{
delete[] (BYTE*)pData;
}
void CString::CopyBeforeWrite()
{
if (GetData()->nRefs > 1)
{
CStringData* pData = GetData();
Release();
AllocBuffer(pData->nDataLength);
memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR));
}
assert(GetData()->nRefs <= 1);
}
void CString::AllocBeforeWrite(int nLen)
{
if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
{
Release();
AllocBuffer(nLen);
}
assert(GetData()->nRefs <= 1);
}
void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
{
AllocBeforeWrite(nSrcLen);
memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
GetData()->nDataLength = nSrcLen;
m_pchData[nSrcLen] = '/0';
}
void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
int nExtraLen) const
{
int nNewLen = nCopyLen + nExtraLen;
if (nNewLen == 0)
{
dest.Init();
}
else
{
dest.AllocBuffer(nNewLen);
memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));
}
}
CString::~CString()
{
if (GetData() != _afxDataNil)
{
if (InterlockedDecrement(&GetData()->nRefs) <= 0)
FreeData(GetData());
}
}
CString::CString(const CString& stringSrc)
{
assert(stringSrc.GetData()->nRefs != 0);
if (stringSrc.GetData()->nRefs >= 0)
{
assert(stringSrc.GetData() != _afxDataNil);
m_pchData = stringSrc.m_pchData;
InterlockedIncrement(&GetData()->nRefs);
}
else
{
Init();
*this = stringSrc.m_pchData;
}
}
CString::CString(LPCTSTR lpsz)
{
Init();
int nLen = SafeStrlen(lpsz);
if (nLen != 0)
{
AllocBuffer(nLen);
memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
}
}
CString::CString(LPCTSTR lpch, int nLength)
{
Init();
if (nLength != 0)
{
assert(AfxIsValidAddress(lpch, nLength, FALSE));
AllocBuffer(nLength);
memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
}
}
void CString::Release()
{
if (GetData() != _afxDataNil)
{
assert(GetData()->nRefs != 0);
if (InterlockedDecrement(&GetData()->nRefs) <= 0)
FreeData(GetData());
Init();
}
}
void CString::Release(CStringData* pData)
{
if (pData != _afxDataNil)
{
assert(pData->nRefs != 0);
if (InterlockedDecrement(&pData->nRefs) <= 0)
FreeData(pData);
}
}
void CString::Empty()
{
if (GetData()->nDataLength == 0)
return;
if (GetData()->nRefs >= 0)
Release();
else
*this = &afxChNil;
assert(GetData()->nDataLength == 0);
assert(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
}
const CString& CString::operator=(const CString& stringSrc)
{
if (m_pchData != stringSrc.m_pchData)
{
if ((GetData()->nRefs < 0 && GetData() != _afxDataNil) ||
stringSrc.GetData()->nRefs < 0)
{
//新建一快数据
AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
}
else
{
//只拷贝指针
Release();
assert(stringSrc.GetData() != _afxDataNil);
m_pchData = stringSrc.m_pchData;
InterlockedIncrement(&GetData()->nRefs);
}
}
return *this;
}
const CString& CString::operator=(LPCTSTR lpsz)
{
assert(lpsz == NULL || AfxIsValidString(lpsz));
AssignCopy(SafeStrlen(lpsz), lpsz);
return *this;
}
const CString& CString::operator=(TCHAR ch)
{
AssignCopy(1, &ch);
return *this;
}
int CString::Delete(int nIndex, int nCount /* = 1 */)
{
if (nIndex < 0)
nIndex = 0;
int nNewLength = GetData()->nDataLength;
if (nCount > 0 && nIndex < nNewLength)
{
CopyBeforeWrite(); //脱离共享数据块,
int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;
//移动数据
memcpy(m_pchData + nIndex,
m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
GetData()->nDataLength = nNewLength - nCount;
}
return nNewLength;
}
int CString::Insert(int nIndex, TCHAR ch)
{
CopyBeforeWrite(); //脱离共享数据
if (nIndex < 0)
nIndex = 0;
int nNewLength = GetData()->nDataLength;
if (nIndex > nNewLength)
nIndex = nNewLength;
nNewLength++;
if (GetData()->nAllocLength < nNewLength)
{ //动态分配内存,并拷贝原来的数据
CStringData* pOldData = GetData();
LPTSTR pstr = m_pchData;
AllocBuffer(nNewLength);
memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));
CString::Release(pOldData);
}
//插入数据
memcpy(m_pchData + nIndex + 1,
m_pchData + nIndex, (nNewLength-nIndex)*sizeof(TCHAR));
m_pchData[nIndex] = ch;
GetData()->nDataLength = nNewLength;
return nNewLength;
}
int CString::Insert(int nIndex, LPCTSTR pstr)
{
if (nIndex < 0)
nIndex = 0;
int nInsertLength = SafeStrlen(pstr);
int nNewLength = GetData()->nDataLength;
if (nInsertLength > 0)
{
CopyBeforeWrite(); //脱离共享数据
if (nIndex > nNewLength)
nIndex = nNewLength;
nNewLength += nInsertLength;
if (GetData()->nAllocLength < nNewLength)
{ //动态分配内存,并拷贝原来的数据
CStringData* pOldData = GetData();
LPTSTR pstr = m_pchData;
AllocBuffer(nNewLength);
memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));
CString::Release(pOldData);
}
//移动数据,留出插入的位子move也可以
memcpy(m_pchData + nIndex + nInsertLength,
m_pchData + nIndex,
(nNewLength-nIndex-nInsertLength+1)*sizeof(TCHAR));
//插入数据
memcpy(m_pchData + nIndex,
pstr, nInsertLength*sizeof(TCHAR));
GetData()->nDataLength = nNewLength;
}
return nNewLength;
}
int CString::Replace(TCHAR chOld, TCHAR chNew)
{
int nCount = 0;
if (chOld != chNew) //替换的不能相同
{
CopyBeforeWrite();
LPTSTR psz = m_pchData;
LPTSTR pszEnd = psz + GetData()->nDataLength;
while (psz < pszEnd)
{
if (*psz == chOld) //替换
{
*psz = chNew;
nCount++;
}
psz = _tcsinc(psz); //相当于++psz,考虑要UNICODE下版本才用的
}
}
return nCount;
}
int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
{
int nSourceLen = SafeStrlen(lpszOld);
if (nSourceLen == 0) //要替换的不能为空
return 0;
int nReplacementLen = SafeStrlen(lpszNew);
int nCount = 0;
LPTSTR lpszStart = m_pchData;
LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
LPTSTR lpszTarget;
while (lpszStart < lpszEnd) //检索要替换的个数
{
while ((lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
{
nCount++;
lpszStart = lpszTarget + nSourceLen;
}
lpszStart += lstrlen(lpszStart) + 1;
}
if (nCount > 0)
{
CopyBeforeWrite();
int nOldLength = GetData()->nDataLength;
int nNewLength = nOldLength + (nReplacementLen-nSourceLen)*nCount; //替换以后的长度
if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1)
{ //超出原来的内存长度动态分配
CStringData* pOldData = GetData();
LPTSTR pstr = m_pchData;
AllocBuffer(nNewLength);
memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(TCHAR));
CString::Release(pOldData);
}
lpszStart = m_pchData;
lpszEnd = m_pchData + GetData()->nDataLength;
while (lpszStart < lpszEnd) //这个循环好象没什么用
{
while ( (lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL) //开始替换
{
int nBalance = nOldLength - (lpszTarget - m_pchData + nSourceLen); //要往后移的长度
//移动数据,留出插入的位子
memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen,
nBalance * sizeof(TCHAR));
//插入替换数据
memcpy(lpszTarget, lpszNew, nReplacementLen*sizeof(TCHAR));
lpszStart = lpszTarget + nReplacementLen;
lpszStart[nBalance] = '/0';
nOldLength += (nReplacementLen - nSourceLen); //现有数据长度
}
lpszStart += lstrlen(lpszStart) + 1;
}
assert(m_pchData[nNewLength] == '/0');
GetData()->nDataLength = nNewLength;
}
return nCount;
}
int CString::Remove(TCHAR chRemove)
{
CopyBeforeWrite();
LPTSTR pstrSource = m_pchData;
LPTSTR pstrDest = m_pchData;
LPTSTR pstrEnd = m_pchData + GetData()->nDataLength;
while (pstrSource < pstrEnd)
{
if (*pstrSource != chRemove)
{
*pstrDest = *pstrSource; //把不移除的数据拷贝
pstrDest = _tcsinc(pstrDest);
}
pstrSource = _tcsinc(pstrSource);//++pstrSource
}
*pstrDest = '/0';
int nCount = pstrSource - pstrDest; //比较变态的计算替换个数,
GetData()->nDataLength -= nCount;
return nCount;
}
CString CString::Mid(int nFirst) const
{
return Mid(nFirst, GetData()->nDataLength - nFirst);
}
CString CString::Mid(int nFirst, int nCount) const
{
if (nFirst < 0)
nFirst = 0;
if (nCount < 0)
nCount = 0;
if (nFirst + nCount > GetData()->nDataLength)
nCount = GetData()->nDataLength - nFirst;
if (nFirst > GetData()->nDataLength)
nCount = 0;
assert(nFirst >= 0);
assert(nFirst + nCount <= GetData()->nDataLength);
//取去整个数据
if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
return *this;
CString dest;
AllocCopy(dest, nCount, nFirst, 0);
return dest;
}
CString CString::Right(int nCount) const
{
if (nCount < 0)
nCount = 0;
if (nCount >= GetData()->nDataLength)
return *this;
CString dest;
AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
return dest;
}
CString CString::Left(int nCount) const
{
if (nCount < 0)
nCount = 0;
if (nCount >= GetData()->nDataLength)
return *this;
CString dest;
AllocCopy(dest, nCount, 0, 0);
return dest;
}
int CString::ReverseFind(TCHAR ch) const
{
//从最后查找
LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR) ch);
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}
int CString::Find(TCHAR ch) const
{
return Find(ch, 0);
}
int CString::Find(TCHAR ch, int nStart) const
{
int nLength = GetData()->nDataLength;
if (nStart >= nLength)
return -1;
LPTSTR lpsz = _tcschr(m_pchData + nStart, (_TUCHAR)ch);
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}
int CString::Find(LPCTSTR lpszSub) const
{
return Find(lpszSub, 0);
}
int CString::Find(LPCTSTR lpszSub, int nStart) const
{
assert(AfxIsValidString(lpszSub));
int nLength = GetData()->nDataLength;
if (nStart > nLength)
return -1;
LPTSTR lpsz = _tcsstr(m_pchData + nStart, lpszSub);
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}
int CString::FindOneOf(LPCTSTR lpszCharSet) const
{
assert(AfxIsValidString(lpszCharSet));
LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}
void CString::MakeUpper()
{
CopyBeforeWrite();
_tcsupr(m_pchData);
}
void CString::MakeLower()
{
CopyBeforeWrite();
_tcslwr(m_pchData);
}
void CString::MakeReverse()
{
CopyBeforeWrite();
_tcsrev(m_pchData);
}
void CString::SetAt(int nIndex, TCHAR ch)
{
assert(nIndex >= 0);
assert(nIndex < GetData()->nDataLength);
CopyBeforeWrite();
m_pchData[nIndex] = ch;
}
void CString::TrimRight(LPCTSTR lpszTargetList)
{
CopyBeforeWrite();
LPTSTR lpsz = m_pchData;
LPTSTR lpszLast = NULL;
while (*lpsz != '/0')
{
if (_tcschr(lpszTargetList, *lpsz) != NULL)
{
if (lpszLast == NULL)
lpszLast = lpsz;
}
else
lpszLast = NULL;
lpsz = _tcsinc(lpsz);
}
if (lpszLast != NULL)
{
*lpszLast = '/0';
GetData()->nDataLength = lpszLast - m_pchData;
}
}
void CString::TrimRight(TCHAR chTarget)
{
CopyBeforeWrite();
LPTSTR lpsz = m_pchData;
LPTSTR lpszLast = NULL;
while (*lpsz != '/0')
{
if (*lpsz == chTarget)
{
if (lpszLast == NULL)
lpszLast = lpsz;
}
else
lpszLast = NULL;
lpsz = _tcsinc(lpsz);
}
if (lpszLast != NULL)
{
*lpszLast = '/0';
GetData()->nDataLength = lpszLast - m_pchData;
}
}
void CString::TrimRight()
{
CopyBeforeWrite();
LPTSTR lpsz = m_pchData;
LPTSTR lpszLast = NULL;
while (*lpsz != '/0')
{
if (_istspace(*lpsz))
{
if (lpszLast == NULL)
lpszLast = lpsz;
}
else
lpszLast = NULL;
lpsz = _tcsinc(lpsz);
}
if (lpszLast != NULL)
{
// truncate at trailing space start
*lpszLast = '/0';
GetData()->nDataLength = lpszLast - m_pchData;
}
}
void CString::TrimLeft(LPCTSTR lpszTargets)
{
// if we're not trimming anything, we're not doing any work
if (SafeStrlen(lpszTargets) == 0)
return;
CopyBeforeWrite();
LPCTSTR lpsz = m_pchData;
while (*lpsz != '/0')
{
if (_tcschr(lpszTargets, *lpsz) == NULL)
break;
lpsz = _tcsinc(lpsz);
}
if (lpsz != m_pchData)
{
// fix up data and length
int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
GetData()->nDataLength = nDataLength;
}
}
void CString::TrimLeft(TCHAR chTarget)
{
CopyBeforeWrite();
LPCTSTR lpsz = m_pchData;
while (chTarget == *lpsz)
lpsz = _tcsinc(lpsz);
if (lpsz != m_pchData)
{
int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
GetData()->nDataLength = nDataLength;
}
}
void CString::TrimLeft()
{
CopyBeforeWrite();
LPCTSTR lpsz = m_pchData;
while (_istspace(*lpsz))
lpsz = _tcsinc(lpsz);
if (lpsz != m_pchData)
{
int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
GetData()->nDataLength = nDataLength;
}
}
#define TCHAR_ARG TCHAR
#define WCHAR_ARG WCHAR
#define CHAR_ARG char
struct _AFX_DOUBLE { BYTE doubleBits[sizeof(double)]; };
#ifdef _X86_
#define DOUBLE_ARG _AFX_DOUBLE
#else
#define DOUBLE_ARG double
#endif
#define FORCE_ANSI 0x10000
#define FORCE_UNICODE 0x20000
#define FORCE_INT64 0x40000
void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
{
assert(AfxIsValidString(lpszFormat));
va_list argListSave = argList;
// make a guess at the maximum length of the resulting string
int nMaxLen = 0;
for (LPCTSTR lpsz = lpszFormat; *lpsz != '/0'; lpsz = _tcsinc(lpsz))
{
//查找%,对%%不在查找范围
if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
{
nMaxLen += _tclen(lpsz);
continue;
}
int nItemLen = 0;
//%后面的格式判断
int nWidth = 0;
for (; *lpsz != '/0'; lpsz = _tcsinc(lpsz))
{
if (*lpsz == '#')
nMaxLen += 2; // 16进制 '0x'
else if (*lpsz == '*')
nWidth = va_arg(argList, int);
else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
*lpsz == ' ')
;
else // hit non-flag character
break;
}
// get width and skip it
if (nWidth == 0)
{
// width indicated by
nWidth = _ttoi(lpsz);
for (; *lpsz != '/0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
;
}
assert(nWidth >= 0);
int nPrecision = 0;
if (*lpsz == '.')
{
// skip past '.' separator (width.precision)
lpsz = _tcsinc(lpsz);
// get precision and skip it
if (*lpsz == '*')
{
nPrecision = va_arg(argList, int);
lpsz = _tcsinc(lpsz);
}
else
{
nPrecision = _ttoi(lpsz);
for (; *lpsz != '/0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
;
}
assert(nPrecision >= 0);
}
// should be on type modifier or specifier
int nModifier = 0;
if (_tcsncmp(lpsz, _T("I64"), 3) == 0)
{
lpsz += 3;
nModifier = FORCE_INT64;
#if !defined(_X86_) && !defined(_ALPHA_)
// __int64 is only available on X86 and ALPHA platforms
ASSERT(FALSE);
#endif
}
else
{
switch (*lpsz)
{
// modifiers that affect size
case 'h':
nModifier = FORCE_ANSI;
lpsz = _tcsinc(lpsz);
break;
case 'l':
nModifier = FORCE_UNICODE;
lpsz = _tcsinc(lpsz);
break;
// modifiers that do not affect size
case 'F':
case 'N':
case 'L':
lpsz = _tcsinc(lpsz);
break;
}
}
// now should be on specifier
switch (*lpsz | nModifier)
{
// single characters
case 'c':
case 'C':
nItemLen = 2;
va_arg(argList, TCHAR_ARG);
break;
case 'c'|FORCE_ANSI:
case 'C'|FORCE_ANSI:
nItemLen = 2;
va_arg(argList, CHAR_ARG);
break;
case 'c'|FORCE_UNICODE:
case 'C'|FORCE_UNICODE:
nItemLen = 2;
va_arg(argList, WCHAR_ARG);
break;
// strings
case 's':
{
LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
if (pstrNextArg == NULL)
nItemLen = 6; // "(null)"
else
{
nItemLen = lstrlen(pstrNextArg);
nItemLen = max(1, nItemLen);
}
}
break;
case 'S':
{
#ifndef _UNICODE
LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
if (pstrNextArg == NULL)
nItemLen = 6; // "(null)"
else
{
nItemLen = wcslen(pstrNextArg);
nItemLen = max(1, nItemLen);
}
#else
LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
if (pstrNextArg == NULL)
nItemLen = 6; // "(null)"
else
{
nItemLen = lstrlenA(pstrNextArg);
nItemLen = max(1, nItemLen);
}
#endif
}
break;
case 's'|FORCE_ANSI:
case 'S'|FORCE_ANSI:
{
LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
if (pstrNextArg == NULL)
nItemLen = 6; // "(null)"
else
{
nItemLen = lstrlenA(pstrNextArg);
nItemLen = max(1, nItemLen);
}
}
break;
case 's'|FORCE_UNICODE:
case 'S'|FORCE_UNICODE:
{
LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
if (pstrNextArg == NULL)
nItemLen = 6; // "(null)"
else
{
nItemLen = wcslen(pstrNextArg);
nItemLen = max(1, nItemLen);
}
}
break;
}
// adjust nItemLen for strings
if (nItemLen != 0)
{
if (nPrecision != 0)
nItemLen = min(nItemLen, nPrecision);
nItemLen = max(nItemLen, nWidth);
}
else
{
switch (*lpsz)
{
// integers
case 'd':
case 'i':
case 'u':
case 'x':
case 'X':
case 'o':
if (nModifier & FORCE_INT64)
va_arg(argList, __int64);
else
va_arg(argList, int);
nItemLen = 32;
nItemLen = max(nItemLen, nWidth+nPrecision);
break;
case 'e':
case 'g':
case 'G':
va_arg(argList, DOUBLE_ARG);
nItemLen = 128;
nItemLen = max(nItemLen, nWidth+nPrecision);
break;
case 'f':
{
double f;
LPTSTR pszTemp;
// 312 == strlen("-1+(309 zeroes).")
// 309 zeroes == max precision of a double
// 6 == adjustment in case precision is not specified,
// which means that the precision defaults to 6
pszTemp = (LPTSTR)_alloca(max(nWidth, 312+nPrecision+6));
f = va_arg(argList, double);
_stprintf( pszTemp, _T( "%*.*f" ), nWidth, nPrecision+6, f );
nItemLen = _tcslen(pszTemp);
}
break;
case 'p':
va_arg(argList, void*);
nItemLen = 32;
nItemLen = max(nItemLen, nWidth+nPrecision);
break;
// no output
case 'n':
va_arg(argList, int*);
break;
default:
assert(FALSE); // unknown formatting option
}
}
// adjust nMaxLen for output nItemLen
nMaxLen += nItemLen;
}
GetBuffer(nMaxLen);
//VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());
_vstprintf(m_pchData, lpszFormat, argListSave);
ReleaseBuffer();
va_end(argListSave);
}
void CString::Format(LPCTSTR lpszFormat, ...)
{
assert(AfxIsValidString(lpszFormat));
va_list argList;
va_start(argList, lpszFormat);
FormatV(lpszFormat, argList);
va_end(argList);
}
//ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
void CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,int nSrc2Len, LPCTSTR lpszSrc2Data)
{
int nNewLen = nSrc1Len + nSrc2Len;
if (nNewLen != 0)
{
AllocBuffer(nNewLen);
memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
}
}
void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
{
if (nSrcLen == 0)
return;
if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
{//动态分配
CStringData* pOldData = GetData();
ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
assert(pOldData != NULL);
CString::Release(pOldData);
}
else
{//直接往后添加
memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(TCHAR));
GetData()->nDataLength += nSrcLen;
assert(GetData()->nDataLength <= GetData()->nAllocLength);
m_pchData[GetData()->nDataLength] = '/0';
}
}
const CString& CString::operator+=(LPCTSTR lpsz)
{
assert(lpsz == NULL || AfxIsValidString(lpsz));
ConcatInPlace(SafeStrlen(lpsz), lpsz);
return *this;
}
const CString& CString::operator+=(TCHAR ch)
{
ConcatInPlace(1, &ch);
return *this;
}
const CString& CString::operator+=(const CString& string)
{
ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
return *this;
}
LPTSTR CString::GetBuffer(int nMinBufLength)
{
assert(nMinBufLength >= 0);
if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
{ //重新动态分配
CStringData* pOldData = GetData();
int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
if (nMinBufLength < nOldLen)
nMinBufLength = nOldLen;
AllocBuffer(nMinBufLength);
memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
GetData()->nDataLength = nOldLen;
CString::Release(pOldData);
}
assert(GetData()->nRefs <= 1);
assert(m_pchData != NULL);
return m_pchData;
}
void CString::ReleaseBuffer(int nNewLength)
{
CopyBeforeWrite(); //脱离共享数据块,
if (nNewLength == -1)
nNewLength = lstrlen(m_pchData); // zero terminated
assert(nNewLength <= GetData()->nAllocLength);
GetData()->nDataLength = nNewLength;
m_pchData[nNewLength] = '/0';
}
LPTSTR CString::GetBufferSetLength(int nNewLength)
{
assert(nNewLength >= 0);
GetBuffer(nNewLength);
GetData()->nDataLength = nNewLength;
m_pchData[nNewLength] = '/0';
return m_pchData;
}
void CString::FreeExtra()
{
assert(GetData()->nDataLength <= GetData()->nAllocLength);
if (GetData()->nDataLength != GetData()->nAllocLength)
{
CStringData* pOldData = GetData();
AllocBuffer(GetData()->nDataLength);
memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(TCHAR));
assert(m_pchData[GetData()->nDataLength] == '/0');
CString::Release(pOldData);
}
assert(GetData() != NULL);
}
LPTSTR CString::LockBuffer()
{
LPTSTR lpsz = GetBuffer(0);
GetData()->nRefs = -1;
return lpsz;
}
void CString::UnlockBuffer()
{
assert(GetData()->nRefs == -1);
if (GetData() != _afxDataNil)
GetData()->nRefs = 1;
}
int CString::Compare(LPCTSTR lpsz) const
{
assert(AfxIsValidString(lpsz));
return _tcscmp(m_pchData, lpsz);
}
int CString::CompareNoCase(LPCTSTR lpsz) const
{
assert(AfxIsValidString(lpsz));
return _tcsicmp(m_pchData, lpsz);
}
// CString::Collate is often slower than Compare but is MBSC/Unicode
// aware as well as locale-sensitive with respect to sort order.
int CString::Collate(LPCTSTR lpsz) const
{
assert(AfxIsValidString(lpsz));
return _tcscoll(m_pchData, lpsz);
}
int CString::CollateNoCase(LPCTSTR lpsz) const
{
assert(AfxIsValidString(lpsz));
return _tcsicoll(m_pchData, lpsz);
}
TCHAR CString::GetAt(int nIndex) const
{
assert(nIndex >= 0);
assert(nIndex < GetData()->nDataLength);
return m_pchData[nIndex];
}
TCHAR CString::operator[](int nIndex) const
{
assert(nIndex >= 0);
assert(nIndex < GetData()->nDataLength);
return m_pchData[nIndex];
}
CString operator+(const CString& string1, const CString& string2)
{
CString s;
s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
string2.GetData()->nDataLength, string2.m_pchData);
return s;
}
CString operator+(const CString& string, LPCTSTR lpsz)
{
assert(lpsz == NULL || AfxIsValidString(lpsz));
CString s;
s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
CString::SafeStrlen(lpsz), lpsz);
return s;
}
CString operator+(LPCTSTR lpsz, const CString& string)
{
assert(lpsz == NULL || AfxIsValidString(lpsz));
CString s;
s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
string.m_pchData);
return s;
}
bool operator==(const CString& s1, const CString& s2)
{ return s1.Compare(s2) == 0; }
bool operator==(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) == 0; }
bool operator==(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) == 0; }
bool operator!=(const CString& s1, const CString& s2)
{ return s1.Compare(s2) != 0; }
bool operator!=(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) != 0; }
bool operator!=(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) != 0; }
bool operator<(const CString& s1, const CString& s2)
{ return s1.Compare(s2) < 0; }
bool operator<(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) < 0; }
bool operator<(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) > 0; }
bool operator>(const CString& s1, const CString& s2)
{ return s1.Compare(s2) > 0; }
bool operator>(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) > 0; }
bool operator>(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) < 0; }
bool operator<=(const CString& s1, const CString& s2)
{ return s1.Compare(s2) <= 0; }
bool operator<=(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) <= 0; }
bool operator<=(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) >= 0; }
bool operator>=(const CString& s1, const CString& s2)
{ return s1.Compare(s2) >= 0; }
bool operator>=(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) >= 0; }
bool operator>=(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) <= 0; }
void ConstructElements(CString* pElements, int nCount)
{
assert(nCount == 0 ||
AfxIsValidAddress(pElements, nCount * sizeof(CString)));
for (; nCount--; ++pElements)
memcpy(pElements, &AfxGetEmptyString(), sizeof(*pElements));
}
void DestructElements(CString* pElements, int nCount)
{
assert(nCount == 0 ||
AfxIsValidAddress(pElements, nCount * sizeof(CString)));
for (; nCount--; ++pElements)
pElements->~CString();
}
void CopyElements(CString* pDest, const CString* pSrc, int nCount)
{
assert(nCount == 0 ||
AfxIsValidAddress(pDest, nCount * sizeof(CString)));
assert(nCount == 0 ||
AfxIsValidAddress(pSrc, nCount * sizeof(CString)));
for (; nCount--; ++pDest, ++pSrc)
*pDest = *pSrc;
}