|
@@ -9,23 +9,14 @@
|
|
|
// Microsoft Foundation Classes product.
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
-// WINSCP
|
|
|
-#include <algorithm>
|
|
|
-#define max std::max
|
|
|
-#define min std::min
|
|
|
+#include <StrUtils.hpp>
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
// More sophisticated construction
|
|
|
|
|
|
CString::CString(LPCTSTR lpch, int nLength)
|
|
|
{
|
|
|
- Init();
|
|
|
- if (nLength != 0)
|
|
|
- {
|
|
|
- ASSERT(AfxIsValidAddress(lpch, nLength, FALSE));
|
|
|
- AllocBuffer(nLength);
|
|
|
- memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
|
|
|
- }
|
|
|
+ m_Data = UnicodeString(lpch, nLength);
|
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
@@ -33,13 +24,7 @@ CString::CString(LPCTSTR lpch, int nLength)
|
|
|
|
|
|
CString::CString(LPCSTR lpsz, int nLength)
|
|
|
{
|
|
|
- Init();
|
|
|
- if (nLength != 0)
|
|
|
- {
|
|
|
- AllocBuffer(nLength);
|
|
|
- int n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nLength, m_pchData, nLength+1);
|
|
|
- ReleaseBuffer(n >= 0 ? n : -1);
|
|
|
- }
|
|
|
+ m_Data = UnicodeString(AnsiString(lpsz, nLength));
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
@@ -47,7 +32,7 @@ CString::CString(LPCSTR lpsz, int nLength)
|
|
|
|
|
|
const CString& CString::operator=(TCHAR ch)
|
|
|
{
|
|
|
- AssignCopy(1, &ch);
|
|
|
+ m_Data = ch;
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
@@ -56,16 +41,12 @@ const CString& CString::operator=(TCHAR ch)
|
|
|
|
|
|
CString AFXAPI operator+(const CString& string1, TCHAR ch)
|
|
|
{
|
|
|
- CString s;
|
|
|
- s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
|
|
|
- return s;
|
|
|
+ return CString(string1.m_Data + ch);
|
|
|
}
|
|
|
|
|
|
CString AFXAPI operator+(TCHAR ch, const CString& string)
|
|
|
{
|
|
|
- CString s;
|
|
|
- s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
|
|
|
- return s;
|
|
|
+ return CString(UnicodeString(ch) + string.m_Data);
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
@@ -75,16 +56,8 @@ 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;
|
|
|
- }
|
|
|
+ int nNewLength = m_Data.Length();
|
|
|
+ m_Data.Delete(nIndex + 1, nCount);
|
|
|
|
|
|
return nNewLength;
|
|
|
}
|
|
@@ -97,9 +70,9 @@ int CString::Replace(TCHAR chOld, TCHAR chNew)
|
|
|
if (chOld != chNew)
|
|
|
{
|
|
|
// otherwise modify each character that matches in the string
|
|
|
- CopyBeforeWrite();
|
|
|
- LPTSTR psz = m_pchData;
|
|
|
- LPTSTR pszEnd = psz + GetData()->nDataLength;
|
|
|
+ m_Data.Unique();
|
|
|
+ LPTSTR psz = m_Data.c_str();
|
|
|
+ LPTSTR pszEnd = psz + m_Data.Length();
|
|
|
while (psz < pszEnd)
|
|
|
{
|
|
|
// replace instances of the specified character only
|
|
@@ -114,71 +87,11 @@ int CString::Replace(TCHAR chOld, TCHAR chNew)
|
|
|
return nCount;
|
|
|
}
|
|
|
|
|
|
-int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
|
|
|
+BOOL CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
|
|
|
{
|
|
|
- // can't have empty or NULL lpszOld
|
|
|
-
|
|
|
- int nSourceLen = SafeStrlen(lpszOld);
|
|
|
- if (nSourceLen == 0)
|
|
|
- return 0;
|
|
|
- int nReplacementLen = SafeStrlen(lpszNew);
|
|
|
-
|
|
|
- // loop once to figure out the size of the result string
|
|
|
- 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 any changes were made, make them
|
|
|
- if (nCount > 0)
|
|
|
- {
|
|
|
- CopyBeforeWrite();
|
|
|
-
|
|
|
- // if the buffer is too small, just
|
|
|
- // allocate a new buffer (slow but sure)
|
|
|
- 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);
|
|
|
- }
|
|
|
- // else, we just do it in-place
|
|
|
- lpszStart = m_pchData;
|
|
|
- lpszEnd = m_pchData + GetData()->nDataLength;
|
|
|
-
|
|
|
- // loop again to actually do the work
|
|
|
- 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;
|
|
|
+ UnicodeString prev = m_Data;
|
|
|
+ m_Data = ReplaceStr(m_Data, lpszOld, lpszNew);
|
|
|
+ return (prev != m_Data);
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
@@ -186,7 +99,7 @@ int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
|
|
|
|
|
|
CString CString::Mid(int nFirst) const
|
|
|
{
|
|
|
- return Mid(nFirst, GetData()->nDataLength - nFirst);
|
|
|
+ return Mid(nFirst, m_Data.Length() - nFirst);
|
|
|
}
|
|
|
|
|
|
CString CString::Mid(int nFirst, int nCount) const
|
|
@@ -197,45 +110,39 @@ CString CString::Mid(int nFirst, int nCount) const
|
|
|
if (nCount < 0)
|
|
|
nCount = 0;
|
|
|
|
|
|
- if (nFirst + nCount > GetData()->nDataLength)
|
|
|
- nCount = GetData()->nDataLength - nFirst;
|
|
|
- if (nFirst > GetData()->nDataLength)
|
|
|
+ if (nFirst + nCount > m_Data.Length())
|
|
|
+ nCount = m_Data.Length() - nFirst;
|
|
|
+ if (nFirst > m_Data.Length())
|
|
|
nCount = 0;
|
|
|
|
|
|
ASSERT(nFirst >= 0);
|
|
|
- ASSERT(nFirst + nCount <= GetData()->nDataLength);
|
|
|
+ ASSERT(nFirst + nCount <= m_Data.Length());
|
|
|
|
|
|
// optimize case of returning entire string
|
|
|
- if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
|
|
|
+ if (nFirst == 0 && nFirst + nCount == m_Data.Length())
|
|
|
return *this;
|
|
|
|
|
|
- CString dest;
|
|
|
- AllocCopy(dest, nCount, nFirst, 0);
|
|
|
- return dest;
|
|
|
+ return CString(m_Data.SubString(nFirst + 1, nCount));
|
|
|
}
|
|
|
|
|
|
CString CString::Right(int nCount) const
|
|
|
{
|
|
|
if (nCount < 0)
|
|
|
nCount = 0;
|
|
|
- if (nCount >= GetData()->nDataLength)
|
|
|
+ if (nCount >= m_Data.Length())
|
|
|
return *this;
|
|
|
|
|
|
- CString dest;
|
|
|
- AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
|
|
|
- return dest;
|
|
|
+ return CString(m_Data.SubString(m_Data.Length() - nCount + 1, nCount));
|
|
|
}
|
|
|
|
|
|
CString CString::Left(int nCount) const
|
|
|
{
|
|
|
if (nCount < 0)
|
|
|
nCount = 0;
|
|
|
- if (nCount >= GetData()->nDataLength)
|
|
|
+ if (nCount >= m_Data.Length())
|
|
|
return *this;
|
|
|
|
|
|
- CString dest;
|
|
|
- AllocCopy(dest, nCount, 0, 0);
|
|
|
- return dest;
|
|
|
+ return CString(m_Data.SubString(1, nCount));
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
@@ -244,10 +151,10 @@ CString CString::Left(int nCount) const
|
|
|
int CString::ReverseFind(TCHAR ch) const
|
|
|
{
|
|
|
// find last single character
|
|
|
- LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR) ch);
|
|
|
+ LPTSTR lpsz = _tcsrchr(m_Data.c_str(), (_TUCHAR) ch);
|
|
|
|
|
|
// return -1 if not found, distance from beginning otherwise
|
|
|
- return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
|
|
|
+ return (lpsz == NULL) ? -1 : (int)(lpsz - m_Data.c_str());
|
|
|
}
|
|
|
|
|
|
// find a sub-string (like strstr)
|
|
@@ -260,278 +167,25 @@ int CString::Find(LPCTSTR lpszSub, int nStart) const
|
|
|
{
|
|
|
ASSERT(AfxIsValidString(lpszSub));
|
|
|
|
|
|
- int nLength = GetData()->nDataLength;
|
|
|
+ int nLength = m_Data.Length();
|
|
|
if (nStart > nLength)
|
|
|
return -1;
|
|
|
|
|
|
// find first matching substring
|
|
|
- LPTSTR lpsz = _tcsstr(m_pchData + nStart, lpszSub);
|
|
|
+ LPTSTR lpsz = _tcsstr(m_Data.c_str() + nStart, lpszSub);
|
|
|
|
|
|
// return -1 for not found, distance from beginning otherwise
|
|
|
- return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
|
|
|
+ return (lpsz == NULL) ? -1 : (int)(lpsz - m_Data.c_str());
|
|
|
}
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
// CString formatting
|
|
|
|
|
|
-#define TCHAR_ARG TCHAR
|
|
|
-#define WCHAR_ARG WCHAR
|
|
|
-#define CHAR_ARG char
|
|
|
-
|
|
|
-#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
|
|
|
-#define _tclen(__a) (1)
|
|
|
-
|
|
|
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))
|
|
|
- {
|
|
|
- // handle '%' character, but watch out for '%%'
|
|
|
- if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
|
|
|
- {
|
|
|
- nMaxLen += _tclen(lpsz);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- int nItemLen = 0;
|
|
|
-
|
|
|
- // handle '%' character with format
|
|
|
- int nWidth = 0;
|
|
|
- for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
|
|
|
- {
|
|
|
- // check for valid flags
|
|
|
- if (*lpsz == '#')
|
|
|
- nMaxLen += 2; // for '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':
|
|
|
- {
|
|
|
- LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
|
|
|
- if (pstrNextArg == NULL)
|
|
|
- nItemLen = 6; // "(null)"
|
|
|
- else
|
|
|
- {
|
|
|
- nItemLen = lstrlenA(pstrNextArg);
|
|
|
- nItemLen = max(1, nItemLen);
|
|
|
- }
|
|
|
- }
|
|
|
- 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':
|
|
|
- va_arg(argList, DOUBLE_ARG);
|
|
|
- nItemLen = 128; // width isn't truncated
|
|
|
- // 312 == strlen("-1+(309 zeroes).")
|
|
|
- // 309 zeroes == max precision of a double
|
|
|
- nItemLen = max(nItemLen, 312+nPrecision);
|
|
|
- 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());
|
|
|
- ReleaseBuffer();
|
|
|
-
|
|
|
- va_end(argListSave);
|
|
|
+ m_Data.vprintf(lpszFormat, argList);
|
|
|
}
|
|
|
|
|
|
// formatting (using wsprintf style formatting)
|
|
@@ -558,104 +212,30 @@ void AFX_CDECL CString::Format(UINT nFormatID, ...)
|
|
|
|
|
|
void CString::TrimRight(LPCTSTR lpszTargetList)
|
|
|
{
|
|
|
- // find beginning of trailing matches
|
|
|
- // by starting at beginning (DBCS aware)
|
|
|
-
|
|
|
- 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)
|
|
|
+ UnicodeString TargetList(lpszTargetList);
|
|
|
+ while (!m_Data.IsEmpty() && m_Data.IsDelimiter(TargetList, m_Data.Length()))
|
|
|
{
|
|
|
- // truncate at left-most matching character
|
|
|
- *lpszLast = '\0';
|
|
|
- GetData()->nDataLength = lpszLast - m_pchData;
|
|
|
+ m_Data.SetLength(m_Data.Length() - 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void CString::TrimRight(TCHAR chTarget)
|
|
|
{
|
|
|
- // find beginning of trailing matches
|
|
|
- // by starting at beginning (DBCS aware)
|
|
|
-
|
|
|
- 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)
|
|
|
- {
|
|
|
- // truncate at left-most matching character
|
|
|
- *lpszLast = '\0';
|
|
|
- GetData()->nDataLength = lpszLast - m_pchData;
|
|
|
- }
|
|
|
+ TrimRight(UnicodeString(chTarget).c_str());
|
|
|
}
|
|
|
|
|
|
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')
|
|
|
+ UnicodeString Targets(lpszTargets);
|
|
|
+ while (!m_Data.IsEmpty() && m_Data.IsDelimiter(Targets, 1))
|
|
|
{
|
|
|
- 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;
|
|
|
+ m_Data.Delete(1, 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void CString::TrimLeft(TCHAR chTarget)
|
|
|
{
|
|
|
- // find first non-matching character
|
|
|
-
|
|
|
- CopyBeforeWrite();
|
|
|
- LPCTSTR lpsz = m_pchData;
|
|
|
-
|
|
|
- while (chTarget == *lpsz)
|
|
|
- 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;
|
|
|
- }
|
|
|
+ TrimLeft(UnicodeString(chTarget).c_str());
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|