📄 string.cpp
字号:
#define FORCE_INT64 0x40000
void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
{
ATLASSERT(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))
;
}
ATLASSERT(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))
;
}
ATLASSERT(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
ATLASSERT(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':
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:
ATLASSERT(FALSE); // unknown formatting option
}
}
// adjust nMaxLen for output nItemLen
nMaxLen += nItemLen;
}
GetBuffer(nMaxLen);
_vstprintf(m_pchData, lpszFormat, argListSave);
ReleaseBuffer();
va_end(argListSave);
}
// formatting (using wsprintf style formatting)
void AFX_CDECL CString::Format(LPCTSTR lpszFormat, ...)
{
ATLASSERT(AfxIsValidString(lpszFormat));
va_list argList;
va_start(argList, lpszFormat);
FormatV(lpszFormat, argList);
va_end(argList);
}
void AFX_CDECL CString::Format(UINT nFormatID, ...)
{
CString strFormat;
strFormat.LoadString(nFormatID);
va_list argList;
va_start(argList, nFormatID);
FormatV(strFormat, argList);
va_end(argList);
}
// formatting (using FormatMessage style formatting)
void AFX_CDECL CString::FormatMessage(LPCTSTR lpszFormat, ...)
{
// format message into temporary buffer lpszTemp
va_list argList;
va_start(argList, lpszFormat);
LPTSTR lpszTemp;
if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
lpszTemp == NULL)
{
ATLASSERT(0);
return;
}
// assign lpszTemp into the resulting string and free the temporary
*this = lpszTemp;
LocalFree(lpszTemp);
va_end(argList);
}
void AFX_CDECL CString::FormatMessage(UINT nFormatID, ...)
{
// get format string from string table
CString strFormat;
strFormat.LoadString(nFormatID);
// format message into temporary buffer lpszTemp
va_list argList;
va_start(argList, nFormatID);
LPTSTR lpszTemp;
if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
lpszTemp == NULL)
{
ATLASSERT(0);
return;
}
// assign lpszTemp into the resulting string and free lpszTemp
*this = lpszTemp;
LocalFree(lpszTemp);
va_end(argList);
}
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)
{
// truncate at left-most matching character
*lpszLast = '\0';
GetData()->nDataLength = lpszLast - m_pchData;
}
}
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;
}
}
void CString::TrimRight()
{
// find beginning of trailing spaces by starting at beginning (DBCS aware)
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)
{
// 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;
}
}
void CString::TrimLeft()
{
// find first non-space character
CopyBeforeWrite();
LPCTSTR lpsz = m_pchData;
while (_istspace(*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;
}
}
//------------------------------------------------------------------------------
#ifdef _UNICODE
#define CHAR_FUDGE 1 // one TCHAR unused is good enough
#else
#define CHAR_FUDGE 2 // two BYTES unused for case of DBC last char
#endif
BOOL CString::LoadString(UINT nID)
{
// try fixed buffer first (to avoid wasting space in the heap)
TCHAR szTemp[256];
int nLen = AfxLoadString(nID, szTemp, _countof(szTemp));
if (_countof(szTemp) - nLen > CHAR_FUDGE)
{
*this = szTemp;
return nLen > 0;
}
// try buffer size of 512, then larger size until entire string is retrieved
int nSize = 256;
do
{
nSize += 256;
nLen = AfxLoadString(nID, GetBuffer(nSize-1), nSize);
} while (nSize - nLen <= CHAR_FUDGE);
ReleaseBuffer();
return nLen > 0;
}
#ifndef _AFXDLL
int AFXAPI AfxLoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf)
{
ATLASSERT(AfxIsValidAddress(lpszBuf, nMaxBuf*sizeof(TCHAR)));
#ifdef _DEBUG
// LoadString without annoying warning from the Debug kernel if the
// segment containing the string is not present
if (::FindResource(_Module.GetResourceInstance(),
MAKEINTRESOURCE((nID>>4)+1), RT_STRING) == NULL)
{
lpszBuf[0] = '\0';
return 0; // not found
}
#endif //_DEBUG
int nLen = ::LoadString(_Module.GetResourceInstance(), nID, lpszBuf, nMaxBuf);
if (nLen == 0)
lpszBuf[0] = '\0';
return nLen;
}
#endif
//------------------------------------------------------------------------------
int AFX_CDECL _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
{
if (count == 0 && mbstr != NULL)
return 0;
int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1,
mbstr, count, NULL, NULL);
ATLASSERT(mbstr == NULL || result <= (int)count);
if (result > 0)
mbstr[result-1] = 0;
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -