📄 stdstring.cpp
字号:
// ===================================================================================================
// FILE: StdString.cpp
// AUTHOR: Joe O'Leary (with help -- see comments in StdString.h)
// REMARKS:
// This file implements the CStdString class which was declared in
// StdString.h. It also implements some helper functions used for
// our own UNICODE/ANSI conversion macros.
//
// COPYRIGHT:
// 1999 Joseph M. O'Leary. This code is free. Use it anywhere you want. Rewrite
// it, restructure it, whatever you want. Please don't blame me if it causes your
// $30 billion dollar satellite to explode. If you redistribute it in any form, I
// would appreciate it if you would leave this notice here.
//
// If you find any bugs, please let me know:
//
// jmoleary@earthlink.net
// ===================================================================================================
#include "StdAfx.h"
#include "StdString.h"
#include <xutility>
#if defined (max)
#undef max
#undef min
#endif
#define max(a,b) std::_cpp_max(a,b)
#define min(a,b)std::_cpp_min(a,b)
#include <algorithm>
#include <functional>
#include <locale>
// If conversion has not been explicitly turned off...
#ifndef _NO_STDCONVERSION
// Global MBCS-to-UNICODE helper function
PWSTR StdA2WHelper(PWSTR pw, PCSTR pa, int nChars)
{
if (pa == NULL)
return NULL;
ASSERT(pw != NULL);
pw[0] = '\0';
VERIFY(MultiByteToWideChar(CP_ACP, 0, pa, -1, pw, nChars));
return pw;
}
// Global UNICODE-to_MBCS helper function
PSTR StdW2AHelper(PSTR pa, PCWSTR pw, int nChars)
{
if (pw == NULL)
return NULL;
ASSERT(pa != NULL);
pa[0] = '\0';
VERIFY(WideCharToMultiByte(CP_ACP, 0, pw, -1, pa, nChars, NULL, NULL));
return pa;
}
#endif // _NO_STDCONVERSION
#if !defined(_MFC_VER)
HINSTANCE CStdString::hInstResource = ::GetModuleHandle(NULL);
#endif
// ---------------------------------------------------------------------------------------
// CONSTRUCTOR: CStdString::CStdString
// CStdString(PCTSTR pT)
//
// DESCRIPTION:
// This particular overload of the CStdString constructor takes either a real
// string or a resource ID which has been converted with the MAKEINTRESOURCE()
// macro
//
// PARAMETERS:
// pT - a NULL-terminated raw string with which the CStdString object should be
// initialized or a resource ID converted with MAKEINTRESOURCE (or NULL)
//
// RETURN VALUE: none -- it's a constructor
// ---------------------------------------------------------------------------------------
CStdString::CStdString(PCTSTR pT) : STRBASE(szTNull) // constructor for either a literal string or a resource ID
{
if ( pT == NULL )
;
else if ( HIWORD(pT) == NULL )
{
if ( !Load(_TRES(pT)) )
TRACE(_T("Can't load string %u\n"), _TRES(pT));
}
else
*this = pT;
}
// ---------------------------------------------------------------------------------------
// FUNCTION: CStdString::Load
// bool Load(UINT nId)
//
// DESCRIPTION:
// This function attempts to load the specified string resource from application's
// resource table.
//
// PARAMETERS:
// nId - the resource Identifier from the string table.
//
// RETURN VALUE:
// true if the function succeeds, false otherwise
// ---------------------------------------------------------------------------------------
#define MAX_LOAD_TRIES 5 // max # of times we'll attempt to load a string
#define LOAD_BUF_SIZE 256 // 256 characters should be more than enough for most strings
bool CStdString::Load(UINT nId)
{
#ifdef _MFC_VER
CString strRes(MAKEINTRESOURCE(nId));
*this = strRes;
return !empty();
#else
// Get the resource name via MAKEINTRESOURCE. This line is pretty much lifted from CString
PCTSTR szName = MAKEINTRESOURCE((nId>>4)+1);
HINSTANCE hModule = CStdString::GetResourceHandle();
// No sense continuing if we can't find the string resource.
if ( ::FindResource(hModule, szName, RT_STRING) == NULL )
return false;
int nMaxLen = 0;
int nRetLen = 0;
int nTries = 0;
PTSTR pBuf = NULL;
// Keep looping until:
// we have a buffer big enough to hold the string,
// or we exceed the maximum number of tries,
// or there is an error
do
{
nMaxLen += LOAD_BUF_SIZE;
pBuf = reinterpret_cast<PTSTR>(_alloca((nMaxLen) * sizeof(TCHAR)));
nRetLen = ::LoadString(hModule, nId, pBuf, nMaxLen);
if ( nRetLen == 0 )
TRACE(_T("Resource ID %d does not exist -- cannot load\n"), nId);
else if ( nRetLen < 1 )
TRACE(_T("Error 0x%X attempting to load resource %d\n"), ::GetLastError(), nId);
else if ( nRetLen+1 < nMaxLen )
*this = pBuf;
} while ( nRetLen+1 == nMaxLen && nTries++ < MAX_LOAD_TRIES );
return true;
#endif
}
// JMO -- not tested yet. Uncomment at your own risk
// ---------------------------------------------------------------------
// Wildstrcmp() - compares strings using DOS wildcards
// 'mask' may contain '*' and '?'
// returns true if 's' matches 'mask', otherwise false
// ---------------------------------------------------------------------
//bool CStdString::Wildstrcmp (PCTSTR c_s, PCTSTR c_mask)
//{
// PTSTR mask=(PTSTR)c_mask;
// PTSTR s=(PTSTR)c_s;
//
// while (*mask)
// {
// switch (*mask)
// {
// case _T('?'):
// if (!*s)
// return false;
// s++;
// mask++;
// break;
//
// case _T('*'):
// while (*mask == _T('*'))
// mask++;
// if (!*mask)
// return true;
// if (*mask == _T('?'))
// break;
// while (*s != *mask)
// {
// if (!*s)
// return false;
// s++;
// }
// s++;
// mask++;
// break;
//
// default:
// if ( *s != *mask )
// return false;
// s++;
// mask++;
// }
// }
//
// if ( !*s && *mask )
// return false;
//
// return true;
//}
// ---------------------------------------------------------------------------------------
// FUNCTION: CStdString::Format
// void _cdecl Formst(CStdString& PCTSTR szFormat, ...)
// void _cdecl Format(PCTSTR szFormat);
//
// DESCRIPTION:
// This function does sprintf/wsprintf style formatting on CStdString objects. It
// is very much a copy of the MFC CString::Format function. Some people might even
// call this identical. However all these people are now dead.
//
// PARAMETERS:
// nId - ID of string resource holding the format string
// szFormat - a PCTSTR holding the format specifiers
// argList - a va_list holding the arguments for the format specifiers.
//
// RETURN VALUE: None.
// ---------------------------------------------------------------------------------------
// formatting (using wsprintf style formatting)
void CStdString::Format(UINT nId, ...)
{
va_list argList;
va_start(argList, nId);
CStdString strFmt;
if ( strFmt.Load(nId) )
FormatV(strFmt, argList);
va_end(argList);
}
void CStdString::Format(PCTSTR szFormat, ...)
{
va_list argList;
va_start(argList, szFormat);
FormatV(szFormat, argList);
va_end(argList);
}
// ---------------------------------------------------------------------------------------
// FUNCTION: CStdString::FormatV
// void FormatV(PCTSTR szFormat, va_list, argList);
//
// DESCRIPTION:
// This function formats the string with sprintf style format-specifications. It
// makes a general guess at required buffer size and then tries successively larger
// buffers until it finds one big enough or a threshold (MAX_FMT_TRIES) is exceeded.
//
// PARAMETERS:
// szFormat - a PCTSTR holding the format of the output
// argList - a Microsoft specific va_list for variable argument lists
//
// RETURN VALUE:
// ---------------------------------------------------------------------------------------
#define MAX_FMT_TRIES 5
#define FMT_BLOCK_SIZE 256
void CStdString::FormatV(PCTSTR szFormat, va_list argList)
{
va_list argListSave = argList;
// We're just going to use the normal _vsntprintf function, assuming FMT_BLOCK_SIZE characters.
// However, if FMT_BLOCK_SIZE characters is not be enough, we will try 2 * FMT_BLOCK_SIZE, then
// 3 * FMT_BLOCK_SIZE, up to MAX_FMT_TRIES * FMT_BLOCK_SIZE characters.
int nTriesLeft = MAX_FMT_TRIES-1;
int nCharsUsed = - 1;
int nTChars = 0;
// Keep looping until either we succeed or we have exhausted the number of tries
do
{
nTChars += FMT_BLOCK_SIZE; // number of TCHARS in the string
// Allocate a buffer on the stack to hold the characters and NULL terminate it
TCHAR* szBuf = reinterpret_cast<TCHAR*>(_alloca((nTChars+1) * sizeof(TCHAR)));
szBuf[nTChars+1] = '\0';
// Now try the actual formatting. The docs say even the wide version takes the
// number of BYTES as the second argument, not the number of characters (TCHARs).
// However the docs are wrong. I checked the actual implementation of
// _vsnprintf and _vsnwprintf and they multiply count by sizeof TCHAR.
nCharsUsed = _vsntprintf(szBuf, nTChars+1, szFormat, argListSave);
if ( nCharsUsed >= 0 )
*this = szBuf;
} while ( nCharsUsed < 0 && nTriesLeft > 0);
va_end(argListSave);
}
// This class is used for TrimRight() and TrimLeft() function implementations.
// Thanks to Dave Plummer for catching a bug here (it's fixed now).
class NotSpace : public std::unary_function<TCHAR, bool>
{
public:
// The fast, unportable method of doing this is to simply call _istspace(). The
// slow, portable way is to use the Standard C++ library. Uncomment whichever
// one you need.
bool operator() (TCHAR tchar) { return !_istspace(tchar); }
// bool operator() (TCHAR tchar) { return !std::isspace(tchar, std::locale::classic());}
};
// ---------------------------------------------------------------------------------------
// FUNCTION: CStdString::TrimRight
// CStdString& TrimRight();
//
// DESCRIPTION:
// This function removes any whitespace characters from the right end of the string.
//
// PARAMETERS: none
// RETURN VALUE:
// a reference to this object (*this) -- allows chaining together of
// these calls, eg. strTest.TrimRight().TrimLeft().ToUpper();
// ---------------------------------------------------------------------------------------
CStdString& CStdString::TrimRight()
{
CStdString::reverse_iterator iter = std::find_if(rbegin(), rend(), NotSpace());
if ( iter != rend() )
{
CStdString::size_type nNewSize = find_last_of(*iter);
erase(nNewSize+1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -