681 lines
28 KiB
C
681 lines
28 KiB
C
|
|
||
|
// FILE: tstring.h
|
||
|
// AUTHOR: Davepl
|
||
|
// REMARKS:
|
||
|
//
|
||
|
//
|
||
|
// This header file declares the tstring class. This string class is
|
||
|
// derived from the Standard C++ Libarary string classes (one of them)
|
||
|
// and adds to them the MFC CString conveniences of
|
||
|
//
|
||
|
// - UNICODE support and
|
||
|
// - implicit casts to PCTSTR
|
||
|
// - loading from resource files
|
||
|
// - formatting (via Format()) function.
|
||
|
// - writing to/reading from COM IStream interfaces
|
||
|
// - Functional objects for use in STL algorithms
|
||
|
//
|
||
|
// This header also declares our own version of the MFC/ATL UNICODE-MBCS
|
||
|
// conversion macros. Our version looks exactly like the originals in order
|
||
|
// facilitate portability.
|
||
|
//
|
||
|
// (c) 1999 Dave Plummer. Portions of this code derived from source
|
||
|
// produced by Joe O'Leary with the following license:
|
||
|
// > This code is free. Use it anywhere you want. Rewrite
|
||
|
// > it, restructure it, whatever you want.
|
||
|
|
||
|
|
||
|
#ifndef _STDSTRING_H_
|
||
|
#define _STDSTRING_H_
|
||
|
|
||
|
// Turn off browser references
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
#pragma component(browser, off, references, "tstring")
|
||
|
#endif
|
||
|
|
||
|
// Avoid legacy code mess up -- if _UNICODE is defined, then UNICODE must be as well
|
||
|
#if defined (_UNICODE) && !defined (UNICODE)
|
||
|
#define UNICODE
|
||
|
#endif
|
||
|
|
||
|
#include <locale>
|
||
|
#include <TCHAR.H>
|
||
|
#ifndef STRICT
|
||
|
#define STRICT
|
||
|
#endif
|
||
|
#include <windows.h>
|
||
|
|
||
|
// In non-MFC builds, ASSERT and VERIFY probably won't be defined, so
|
||
|
// check to see if they are defined and, if not, define them ourself.
|
||
|
|
||
|
#ifndef ASSERT
|
||
|
#include <crtdbg.h> // probably already included but do it just in case
|
||
|
#define ASSERT(f) _ASSERTE((f))
|
||
|
#endif
|
||
|
#ifndef VERIFY
|
||
|
#ifdef _DEBUG
|
||
|
#define VERIFY(x) ASSERT((x))
|
||
|
#else
|
||
|
#define VERIFY(x) x
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifndef TRACE
|
||
|
#define TRACE
|
||
|
#endif
|
||
|
|
||
|
#include <functional> // needed for tstring_lessnocase, et al
|
||
|
|
||
|
// If this is a recent enough version of VC include comdef.h, we can write many tstring
|
||
|
// functions to deal with COM types and compiler support classes like _bstr_t
|
||
|
|
||
|
#if defined (_MSC_VER) && (_MSC_VER >= 1100)
|
||
|
#include <comdef.h>
|
||
|
#define STDSTRING_INC_COMDEF // signal that we #included MS comdef.h file
|
||
|
#endif
|
||
|
|
||
|
#ifndef PCTSTR_DEFINED
|
||
|
typedef const TCHAR* PCTSTR;
|
||
|
#define PCTSTR_DEFINED
|
||
|
#endif
|
||
|
|
||
|
#ifndef PCOLESTR
|
||
|
#define PCOLESTR LPCOLESTR
|
||
|
#endif
|
||
|
#ifndef POLESTR
|
||
|
#define POLESTR LPOLESTR
|
||
|
#endif
|
||
|
|
||
|
// UNICODE/MBCS conversion macros. These are made to work just like the MFC/ATL ones. We
|
||
|
// will not define them if
|
||
|
// _NO_STDCONVERSION - the developer explicitly turned them off
|
||
|
// USES_CONVERSION - this is an ATL/MFC build and they are already defined
|
||
|
|
||
|
#ifndef _NO_STDCONVERSION
|
||
|
|
||
|
#if defined (USES_CONVERSION)
|
||
|
#define _NO_STDCONVERSION // Let StdString.cpp know it should not compile functions
|
||
|
#else
|
||
|
|
||
|
// In MFC builds we can just use the MFC UNICODE conversion macros.
|
||
|
// In NON-MFC builds will have to define them ourselves
|
||
|
|
||
|
#include <malloc.h>
|
||
|
|
||
|
#ifdef _MFC_VER
|
||
|
|
||
|
#include <afxconv.h>
|
||
|
#define _NO_STDCONVERSION // Let StdString.cpp know it should not compile functions
|
||
|
|
||
|
#else
|
||
|
|
||
|
// Define our conversion macros to look exactly like the originals
|
||
|
// using this stuff both with and without MFC/ATL. Avert your eyes,
|
||
|
// its not pretty
|
||
|
|
||
|
#ifndef _DEBUG
|
||
|
#define USES_CONVERSION int _convert; _convert
|
||
|
#else
|
||
|
#define USES_CONVERSION int _convert = 0
|
||
|
#endif
|
||
|
|
||
|
PWSTR StdA2WHelper(PWSTR pw, PCSTR pa, int nChars);
|
||
|
PSTR StdW2AHelper(PSTR pa, PCWSTR pw, int nChars);
|
||
|
|
||
|
#define A2W(pa) (\
|
||
|
((PCSTR)(pa) == NULL) ? NULL : (\
|
||
|
_convert = (strlen((pa))+1),\
|
||
|
StdA2WHelper((LPWSTR) alloca(_convert*2), (pa), _convert)))
|
||
|
|
||
|
#define W2A(pw) (\
|
||
|
((PCWSTR)(pw) == NULL) ? NULL : (\
|
||
|
_convert = (wcslen((pw))+1)*2,\
|
||
|
StdW2AHelper((PSTR) alloca(_convert), (pw), _convert)))
|
||
|
|
||
|
#define A2CW(pa) ((PCWSTR)A2W((pa)))
|
||
|
#define W2CA(pw) ((PCSTR)W2A((pw)))
|
||
|
|
||
|
#ifdef _UNICODE
|
||
|
#define T2A W2A
|
||
|
#define A2T A2W
|
||
|
inline PWSTR T2W(PTSTR p) { return p; }
|
||
|
inline PTSTR W2T(PWSTR p) { return p; }
|
||
|
#define T2CA W2CA
|
||
|
#define A2CT A2CW
|
||
|
inline PCWSTR T2CW(PCTSTR p) { return p; }
|
||
|
inline PCTSTR W2CT(PCWSTR p) { return p; }
|
||
|
#else
|
||
|
#define T2W A2W
|
||
|
#define W2T W2A
|
||
|
inline PSTR T2A(PTSTR p) { return p; }
|
||
|
inline PTSTR A2T(PSTR p) { return p; }
|
||
|
#define T2CW A2CW
|
||
|
#define W2CT W2CA
|
||
|
inline PCSTR T2CA(PCTSTR p) { return p; }
|
||
|
inline PCTSTR A2CT(PCSTR p) { return p; }
|
||
|
#endif // #ifdef _UNICODE
|
||
|
|
||
|
#if defined(_UNICODE)
|
||
|
// in these cases the default (TCHAR) is the same as OLECHAR
|
||
|
inline size_t ocslen(PCOLESTR x) { return wcslen(x); }
|
||
|
inline OLECHAR* ocscpy(POLESTR dest, PCOLESTR src) { return wcscpy(dest, src); }
|
||
|
inline PCOLESTR T2COLE(PCTSTR p) { return p; }
|
||
|
inline PCTSTR OLE2CT(PCOLESTR p) { return p; }
|
||
|
inline POLESTR T2OLE(PTSTR p) { return p; }
|
||
|
inline PTSTR OLE2T(POLESTR p) { return p; }
|
||
|
#elif defined(OLE2ANSI)
|
||
|
// in these cases the default (TCHAR) is the same as OLECHAR
|
||
|
inline size_t ocslen(PCOLESTR x) { return strlen(x); }
|
||
|
inline OLECHAR* ocscpy(POLESTR dest, LPCOLESTR src) { return strcpy(dest, src); }
|
||
|
inline PCOLESTR T2COLE(PCTSTR p) { return p; }
|
||
|
inline PCTSTR OLE2CT(PCOLESTR p) { return p; }
|
||
|
inline POLESTR T2OLE(PTSTR p) { return p; }
|
||
|
inline PTSTR OLE2T(POLESTR p) { return p; }
|
||
|
#else
|
||
|
inline size_t ocslen(PCOLESTR x) { return wcslen(x); }
|
||
|
inline OLECHAR* ocscpy(POLESTR dest, PCOLESTR src)
|
||
|
{return (POLESTR) memcpy(dest, src, (wcslen(src)+1)*sizeof(WCHAR));}
|
||
|
//CharNextW doesn't work on Win95 so we use this
|
||
|
#define T2COLE(pa) A2CW((pa))
|
||
|
#define T2OLE(pa) A2W((pa))
|
||
|
#define OLE2CT(po) W2CA((po))
|
||
|
#define OLE2T(po) W2A((po))
|
||
|
#endif
|
||
|
|
||
|
#ifdef OLE2ANSI
|
||
|
inline POLESTR A2OLE(PSTR p) { return p;}
|
||
|
inline PSTR OLE2A(POLESTR p) { return p;}
|
||
|
#define W2OLE W2A
|
||
|
#define OLE2W A2W
|
||
|
inline PCOLESTR A2COLE(PCSTR p) { return p;}
|
||
|
inline PCSTR OLE2CA(PCOLESTR p) { return p;}
|
||
|
#define W2COLE W2CA
|
||
|
#define OLE2CW A2CW
|
||
|
#else
|
||
|
inline POLESTR W2OLE(PWSTR p) { return p; }
|
||
|
inline PWSTR OLE2W(POLESTR p) { return p; }
|
||
|
#define A2OLE A2W
|
||
|
#define OLE2A W2A
|
||
|
inline PCOLESTR W2COLE(PCWSTR p) { return p; }
|
||
|
inline PCWSTR OLE2CW(PCOLESTR p) { return p; }
|
||
|
#define A2COLE A2CW
|
||
|
#define OLE2CA W2CA
|
||
|
#endif
|
||
|
|
||
|
inline BSTR OLE2BSTR(PCOLESTR p) {return ::SysAllocString(p);}
|
||
|
#if defined(_UNICODE)
|
||
|
// in these cases the default (TCHAR) is the same as OLECHAR
|
||
|
inline BSTR T2BSTR(PCTSTR p) {return ::SysAllocString(p);}
|
||
|
inline BSTR A2BSTR(PCSTR p) {USES_CONVERSION; return ::SysAllocString(A2COLE(p));}
|
||
|
inline BSTR W2BSTR(PCWSTR p) {return ::SysAllocString(p);}
|
||
|
#elif defined(OLE2ANSI)
|
||
|
// in these cases the default (TCHAR) is the same as OLECHAR
|
||
|
inline BSTR T2BSTR(PCTSTR p) {return ::SysAllocString(p);}
|
||
|
inline BSTR A2BSTR(PCSTR p) {return ::SysAllocString(p);}
|
||
|
inline BSTR W2BSTR(PCWSTR p) {USES_CONVERSION; return ::SysAllocString(W2COLE(p));}
|
||
|
#else
|
||
|
inline BSTR T2BSTR(PCTSTR p) {USES_CONVERSION; return ::SysAllocString(T2COLE(p));}
|
||
|
inline BSTR A2BSTR(PCSTR p) {USES_CONVERSION; return ::SysAllocString(A2COLE(p));}
|
||
|
inline BSTR W2BSTR(PCWSTR p) {return ::SysAllocString(p);}
|
||
|
#endif
|
||
|
|
||
|
#endif // #ifdef _MFC_VER
|
||
|
|
||
|
#endif // #ifndef USES_CONVERSION
|
||
|
#endif // #ifndef _NO_STDCONVERSION
|
||
|
|
||
|
// Define our own macros for "other" type to TCHAR type conversion
|
||
|
// i.e. in a UNICODE build "other" would be char. In a non-UNICODE
|
||
|
// build, "other" would be wchar_t These macros make the declaration
|
||
|
// of the tstring class a lot cleaner
|
||
|
|
||
|
#ifdef _UNICODE
|
||
|
#define O2T A2T // "other" type string to generic text type string
|
||
|
#define O2CT A2CT // constant "other" type string to generic text type string
|
||
|
#define T2O T2A // generic text type string to "other" type string.
|
||
|
#define T2CO T2CA // generic text type string to constant "other type string.
|
||
|
#else
|
||
|
#define O2T W2T
|
||
|
#define O2CT W2CT
|
||
|
#define T2O T2W
|
||
|
#define T2CO T2CW
|
||
|
#endif
|
||
|
|
||
|
// Define some short names for types that we will refer to in our definition of
|
||
|
// the tstring class.
|
||
|
|
||
|
#ifdef _UNICODE
|
||
|
#define TOTHER char // the "other" char type (opposite of TCHAR)
|
||
|
#define POSTR PSTR // the "other" string type (opposite of PTSTR)
|
||
|
#define PCOSTR PCSTR // the "other" const string type (oppsite of PCTSTR)
|
||
|
const PCOSTR szONull = ""; // an empty string of the "other" type.
|
||
|
#else
|
||
|
#define TOTHER wchar_t
|
||
|
#define POSTR PWSTR
|
||
|
#define PCOSTR PCWSTR
|
||
|
const PCOSTR szONull = L"";
|
||
|
#endif
|
||
|
|
||
|
const PCTSTR szTNull = _T(""); // an empty string of the TCHAR type
|
||
|
|
||
|
typedef std::basic_string<TCHAR> STRBASE; // our base class
|
||
|
typedef std::basic_string<TOTHER> STROTHER; // opposite of our base
|
||
|
|
||
|
// Define TSTRING -- this is a basic_string built around the TCHAR type, kind of like MFC CString
|
||
|
// It is also our base class.
|
||
|
|
||
|
#ifndef _TSTRING_DEFINED_
|
||
|
#define _TSTRING_DEFINED_
|
||
|
typedef std::basic_string<TCHAR> TSTRING;
|
||
|
#endif
|
||
|
|
||
|
// tstring class
|
||
|
//
|
||
|
// This class is a simplified version of the Standard C++ Library string or basic string class. It
|
||
|
// is derived from basic_string<TCHAR> and adds some MFC CString-like functionality
|
||
|
|
||
|
class tstring : public STRBASE
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
typedef std::allocator<TCHAR> MYALLOC;
|
||
|
// constructors
|
||
|
tstring();
|
||
|
tstring(const tstring& str);
|
||
|
tstring(const STRBASE& str);
|
||
|
tstring(const STROTHER& str);
|
||
|
tstring(PCTSTR pT);
|
||
|
tstring(PCOSTR pO);
|
||
|
tstring(const_iterator first, const_iterator last);
|
||
|
tstring(size_type nSize, value_type ch, const allocator_type& al=std::allocator<TCHAR>());
|
||
|
tstring(UINT nId);
|
||
|
|
||
|
#ifdef STDSTRING_INC_COMDEF
|
||
|
tstring(const _bstr_t& bstr); // takes the _bstr_t MS compiler COM support class
|
||
|
#endif
|
||
|
|
||
|
// assignment operators
|
||
|
tstring& operator=(const tstring& str); // copy constructor
|
||
|
tstring& operator=(const STRBASE& str); // takes a base std string type (string or wstring)
|
||
|
tstring& operator=(const STROTHER& str); // takes the other std string type (string or wstring)
|
||
|
tstring& operator=(PCTSTR pT); // takes const TCHAR pointer
|
||
|
tstring& operator=(PCOSTR pO); // takes const pointer to "other" type (opposite of PCTSTR)
|
||
|
tstring& operator=(TCHAR); // takes single character of TCHAR type
|
||
|
tstring& operator=(TOTHER); // takes single character of the "other" type
|
||
|
#ifdef STDSTRING_INC_COMDEF
|
||
|
tstring& operator=(const _bstr_t& bstr); // takes the _bstr_t MS compiler COM support class
|
||
|
#endif
|
||
|
|
||
|
// These overloads are also needed to fix the MSVC assignment bug (only for our STL - See KB: Q172398)
|
||
|
|
||
|
tstring& assign(const tstring& str, tstring::size_type nStart, tstring::size_type nChars);
|
||
|
tstring& assign(PCTSTR pT, tstring::size_type nChars);
|
||
|
tstring& assign(tstring::size_type nChars, tstring::value_type val);
|
||
|
tstring& assign(const tstring& str);
|
||
|
tstring& assign(PCTSTR pT);
|
||
|
tstring& assign(tstring::const_iterator iterFirst, tstring::const_iterator iterLast);
|
||
|
|
||
|
// comparison (equality)
|
||
|
|
||
|
bool operator==(const tstring& str) const;
|
||
|
bool operator==(const STRBASE& str) const;
|
||
|
bool operator==(const STROTHER& str) const;
|
||
|
bool operator==(PCTSTR pT) const;
|
||
|
bool operator==(PCOSTR pO) const;
|
||
|
bool operator==(TCHAR t) const;
|
||
|
bool operator==(TOTHER t) const;
|
||
|
|
||
|
// Note the default here is case INsensitive
|
||
|
bool Equals(PCTSTR pT, bool bUseCase=false) const;
|
||
|
|
||
|
// comparison operators (inequality)
|
||
|
|
||
|
bool operator!=(const tstring& str) const;
|
||
|
bool operator!=(const STRBASE& str) const;
|
||
|
bool operator!=(const STROTHER& str) const;
|
||
|
bool operator!=(PCTSTR pT) const;
|
||
|
bool operator!=(PCOSTR pO) const;
|
||
|
bool operator!=(TCHAR t) const;
|
||
|
bool operator!=(TOTHER t) const;
|
||
|
|
||
|
// comparison operator (less than)
|
||
|
|
||
|
bool operator<(const tstring& str) const;
|
||
|
bool operator<(PCTSTR str) const;
|
||
|
|
||
|
// concatenation.
|
||
|
|
||
|
const tstring& operator+=(const tstring& str);
|
||
|
const tstring& operator+=(const STRBASE& str);
|
||
|
const tstring& operator+=(const STROTHER& str);
|
||
|
const tstring& operator+=(PCTSTR pT);
|
||
|
const tstring& operator+=(PCOSTR pO);
|
||
|
const tstring& operator+=(TCHAR t);
|
||
|
const tstring& operator+=(TOTHER t);
|
||
|
|
||
|
#ifdef STDSTRING_INC_COMDEF
|
||
|
const tstring& operator+=(const _bstr_t& bstr);
|
||
|
#endif
|
||
|
|
||
|
// addition operators -- global friend functions.
|
||
|
friend tstring operator+(const tstring& str1, const tstring& str2);
|
||
|
friend tstring operator+(const tstring& str, TCHAR ch);
|
||
|
friend tstring operator+(TCHAR ch, const tstring& str);
|
||
|
friend tstring operator+(const tstring& str, TOTHER ch);
|
||
|
friend tstring operator+(TOTHER ch, const tstring& str);
|
||
|
friend tstring operator+(const tstring& str, PCTSTR sz);
|
||
|
friend tstring operator+(PCTSTR sz, const tstring& str);
|
||
|
friend tstring operator+(const tstring& str, PCOSTR sz);
|
||
|
friend tstring operator+(PCOSTR sz, const tstring& str);
|
||
|
|
||
|
#ifdef STDSTRING_INC_COMDEF
|
||
|
friend tstring operator+(const _bstr_t& bstr, const tstring& str);
|
||
|
friend tstring operator+(const tstring& str, const _bstr_t& bstr);
|
||
|
#endif
|
||
|
|
||
|
// Conversion to "other" type of string (i.e. to string if we're a wstring, to wstring if we're a string)
|
||
|
|
||
|
STROTHER Other() const
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
return T2CO(c_str());
|
||
|
};
|
||
|
|
||
|
|
||
|
// General utility stuff
|
||
|
|
||
|
LPTSTR GetBuffer(int n = -1)
|
||
|
{
|
||
|
if ( (-1 != n) && (n > (int)length()) )
|
||
|
resize(n);
|
||
|
return (LPTSTR) data();
|
||
|
}
|
||
|
|
||
|
void ReleaseBuffer( int n = -1 )
|
||
|
{
|
||
|
if (-1 == n)
|
||
|
n = _tcslen( data() );
|
||
|
resize(n);
|
||
|
}
|
||
|
|
||
|
operator CComBSTR() const
|
||
|
{
|
||
|
PCTSTR pFoo = *this;
|
||
|
return CComBSTR( pFoo );
|
||
|
}
|
||
|
operator PCTSTR() const; // implicit cast to const TCHAR*
|
||
|
bool Load(UINT nId); // load using resource id
|
||
|
tstring& Format(PCTSTR szFormat, ...); // format using literal string
|
||
|
tstring& Format(UINT nId, ...); // format using resource string identifier
|
||
|
tstring& FormatV(PCTSTR szFormat, va_list argList); // format using a va_list instead of ...
|
||
|
tstring& TrimRight(); // chop off all whitespace characters on right
|
||
|
tstring& TrimLeft(); // chop off all whitespace characters on left
|
||
|
tstring& ToUpper(); // make uppercase
|
||
|
tstring& ToLower(); // make lowercase
|
||
|
bool IsEmpty() const { return empty(); };
|
||
|
|
||
|
TCHAR& operator[](int nIdx);
|
||
|
const TCHAR& operator[](int nIdx) const;
|
||
|
|
||
|
#ifdef STDSTRING_INC_COMDEF
|
||
|
HRESULT StreamSave(IStream* pStream) const; // write to an IStream
|
||
|
HRESULT StreamLoad(IStream* pStream); // read from an IStream;
|
||
|
ULONG StreamSize() const; // how many bytes needed to write to an IStream?
|
||
|
#endif
|
||
|
|
||
|
// These static functions simplify copying one C-style string to another, either one or two byte.
|
||
|
|
||
|
static void CopyString(PCTSTR p_szSource, PTSTR p_szDest, int p_nMaxChars=0);
|
||
|
static void CopyString(PCOSTR p_szSource, POSTR p_szDest, int p_nMaxChars=0);
|
||
|
static void CopyString(PCSTR p_szSource, PWSTR p_szDest, int p_nMaxChars=0);
|
||
|
static void CopyString(PCWSTR p_szSource, PSTR, int p_nMaxChars=0);
|
||
|
|
||
|
// If this is NOT an MFC build, provide a SetResourceHandle function so that those who call
|
||
|
// the versions of Load(), Format(), or the constructor that take resource IDs can provide
|
||
|
// an alternate HINST of a DLL to search. This is not exactly the list of link libraries
|
||
|
// that MFC provides but it's better than nothing.
|
||
|
|
||
|
static void SetResourceHandle(HINSTANCE hNew);
|
||
|
static HINSTANCE GetResourceHandle();
|
||
|
|
||
|
protected:
|
||
|
|
||
|
#if !defined(_MFC_VER)
|
||
|
static HINSTANCE hInstResource; // implementation of Get/SetResourceHandle in non-MFC builds
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
#define _TRES(pctstr) (LOWORD((pctstr))) // shorthand conversion from PCTSTR to string resource ID
|
||
|
|
||
|
// tstring inline constructors
|
||
|
|
||
|
inline tstring::tstring() {}
|
||
|
inline tstring::tstring(const STRBASE& str) { *this = str; };
|
||
|
|
||
|
//inline tstring::tstring(PCTSTR pT) { *this = (pT == NULL ? szTNull : pT); };
|
||
|
|
||
|
inline tstring::tstring(PCOSTR pO) { *this = (pO == NULL ? szONull : pO); };
|
||
|
inline tstring::tstring(const tstring& str) { *this = str; };
|
||
|
inline tstring::tstring(const STROTHER& str) { *this = str; };
|
||
|
inline tstring::tstring(const_iterator first, const_iterator last) : STRBASE(first, last) {};
|
||
|
inline tstring::tstring(size_type nSize, value_type ch, const allocator_type& al) : STRBASE(nSize, ch, al) { }
|
||
|
#ifdef STDSTRING_INC_COMDEF
|
||
|
inline tstring::tstring(const _bstr_t& bstr) { *this = static_cast<PCTSTR>(bstr); }
|
||
|
#endif
|
||
|
|
||
|
// tstring inline assignment operators -- the erase() function
|
||
|
// call fixes the MSVC assignment bug (see knowledge base article Q172398).
|
||
|
|
||
|
inline tstring& tstring::operator=(const tstring& str)
|
||
|
{ if ( str.data() != data() ) { erase(); STRBASE::assign(str.data());} return *this; };
|
||
|
inline tstring& tstring::operator=(const STRBASE& str)
|
||
|
{ if ( str.data() != data() ) { erase(); STRBASE::assign(str.data());} return *this; };
|
||
|
inline tstring& tstring::operator=(const STROTHER& str)
|
||
|
{ erase(); USES_CONVERSION; STRBASE::assign(O2CT(str.data())); return *this; };
|
||
|
inline tstring& tstring::operator=(PCTSTR pT)
|
||
|
{ if ( pT != data() ) { erase(); if ( pT != NULL ) STRBASE::assign(pT); } return *this; };
|
||
|
inline tstring& tstring::operator=(PCOSTR pO)
|
||
|
{ erase(); if ( pO != NULL ) { USES_CONVERSION; STRBASE::assign(O2CT(pO)); } return *this; };
|
||
|
inline tstring& tstring::operator=(TOTHER t)
|
||
|
{ erase(); USES_CONVERSION; STRBASE::assign(O2CT(&t)); return *this; };
|
||
|
inline tstring& tstring::operator=(TCHAR t)
|
||
|
{ erase(); STRBASE::assign(1,t); return *this; };
|
||
|
#ifdef STDSTRING_INC_COMDEF
|
||
|
inline tstring& tstring::operator=(const _bstr_t& bstr)
|
||
|
{ return operator=(static_cast<PCTSTR>(bstr)); }
|
||
|
#endif
|
||
|
|
||
|
// These overloads are also needed to fix the MSVC assignment bug (KB: Q172398)
|
||
|
// *** Thanks to Pete The Plumber for catching this one ***
|
||
|
|
||
|
inline tstring& tstring::assign(const tstring& str, tstring::size_type nStart, tstring::size_type nChars)
|
||
|
{ if( str.data() != data() ) erase(); STRBASE::assign(str, nStart, nChars); return *this; }
|
||
|
inline tstring& tstring::assign(PCTSTR pT, tstring::size_type nChars)
|
||
|
{ if( pT != data() ) erase(); STRBASE::assign(pT, nChars); return *this; }
|
||
|
inline tstring& tstring::assign(tstring::size_type nChars, tstring::value_type val)
|
||
|
{ erase(); STRBASE::assign(nChars, val); return *this; }
|
||
|
inline tstring& tstring::assign(const tstring& str)
|
||
|
{ return assign(str, 0, npos); }
|
||
|
inline tstring& tstring::assign(PCTSTR pT)
|
||
|
{ return assign(pT, tstring::traits_type::length(pT)); }
|
||
|
inline tstring& tstring::assign(tstring::const_iterator iterFirst, tstring::const_iterator iterLast)
|
||
|
{ replace(begin(), end(), iterFirst, iterLast); return *this; }
|
||
|
|
||
|
|
||
|
// tstring inline comparison (equality)
|
||
|
|
||
|
inline bool tstring::operator==(const tstring& str) const
|
||
|
{ return compare(str.c_str()) == 0; };
|
||
|
inline bool tstring::operator==(const STRBASE& str) const
|
||
|
{ return compare(str.data()) == 0; };
|
||
|
inline bool tstring::operator==(const STROTHER& str) const
|
||
|
{ USES_CONVERSION; return compare(O2CT(str.data())) == 0; };
|
||
|
inline bool tstring::operator==(PCTSTR pT) const
|
||
|
{ return compare(pT) == 0; };
|
||
|
inline bool tstring::operator==(PCOSTR pO) const
|
||
|
{ USES_CONVERSION; return compare(O2CT(pO)) == 0; };
|
||
|
inline bool tstring::operator==(TCHAR t) const
|
||
|
{ return operator==(STRBASE(1,t)); };
|
||
|
inline bool tstring::operator==(TOTHER t) const
|
||
|
{ USES_CONVERSION; return operator==(tstring(O2CT(&t))); };
|
||
|
inline bool tstring::Equals(PCTSTR pT, bool bUseCase/*=false*/) const // defaults to case insensitive
|
||
|
{ return bUseCase ? compare(pT) == 0 : _tcsicmp(tstring(*this), pT) == 0; } // get copy, THEN compare (thread safe)
|
||
|
//inline bool tstring::WildcardEquals(PCTSTR pT, bool bUseCase/*=false*/) const // defaults to case insensitive
|
||
|
//{ tstring me(*this), mask(pT); if( !bUseCase ) { me.ToUpper(); mask.ToUpper(); } return Wildstrcmp(me, mask); } // get copy, THEN compare (thread safe)
|
||
|
|
||
|
|
||
|
// tstring inline comparison operators (inequality)
|
||
|
|
||
|
inline bool tstring::operator!=(const tstring& str) const
|
||
|
{ return compare(str.c_str()) != 0; };
|
||
|
inline bool tstring::operator!=(const STRBASE& str) const
|
||
|
{ return compare(str.data()) != 0; };
|
||
|
inline bool tstring::operator!=(const STROTHER& str) const
|
||
|
{ USES_CONVERSION; return compare(O2CT(str.data())) != 0; };
|
||
|
inline bool tstring::operator!=(PCTSTR pT) const
|
||
|
{ return compare(pT) != 0; };
|
||
|
inline bool tstring::operator!=(PCOSTR pO) const
|
||
|
{ USES_CONVERSION; return compare(O2CT(pO)) != 0; };
|
||
|
inline bool tstring::operator!=(TCHAR t) const
|
||
|
{ return operator!=(STRBASE(1,t)); };
|
||
|
inline bool tstring::operator!=(TOTHER t) const
|
||
|
{ USES_CONVERSION; return operator!=(tstring(O2CT(&t))); };
|
||
|
|
||
|
|
||
|
// tstring comparison operator (less than)
|
||
|
|
||
|
inline bool tstring::operator<(const tstring& str) const
|
||
|
{ return compare(str) < 0; };
|
||
|
inline bool tstring::operator<(PCTSTR str) const
|
||
|
{ return compare(str) < 0; };
|
||
|
|
||
|
// tstring inline concatenation.
|
||
|
|
||
|
inline const tstring& tstring::operator+=(const tstring& str)
|
||
|
{ append(str); return *this; };
|
||
|
inline const tstring& tstring::operator+=(const STRBASE& str)
|
||
|
{ append(str); return *this; };
|
||
|
inline const tstring& tstring::operator+=(const STROTHER& str)
|
||
|
{ USES_CONVERSION; *this += O2CT(str.c_str()); return *this; };
|
||
|
inline const tstring& tstring::operator+=(PCTSTR pT)
|
||
|
{ if ( pT != NULL ) append(pT); return *this; };
|
||
|
inline const tstring& tstring::operator+=(PCOSTR pO)
|
||
|
{ USES_CONVERSION; if ( pO != NULL ) append(O2CT(pO)); return *this; };
|
||
|
inline const tstring& tstring::operator+=(TCHAR t)
|
||
|
{ append(1, t); return *this; };
|
||
|
inline const tstring& tstring::operator+=(TOTHER t)
|
||
|
{ USES_CONVERSION; append(O2CT(&t)); return *this; };
|
||
|
#ifdef STDSTRING_INC_COMDEF
|
||
|
inline const tstring& tstring::operator+=(const _bstr_t& bstr)
|
||
|
{ return operator+=(static_cast<PCTSTR>(bstr)); }
|
||
|
#endif
|
||
|
|
||
|
// tstring friend addition functions defined as inline
|
||
|
|
||
|
inline tstring operator+(const tstring& str1, const tstring& str2)
|
||
|
{ tstring strRet(str1); return strRet.append(str2); }
|
||
|
inline tstring operator+(const tstring& str, TCHAR ch)
|
||
|
{ tstring strRet(str); return strRet.append(1, ch); }
|
||
|
inline tstring operator+(TCHAR ch, const tstring& str)
|
||
|
{ tstring strRet(1, ch); return strRet.append(str); }
|
||
|
inline tstring operator+(const tstring& str, TOTHER ch)
|
||
|
{ return str + STROTHER(1, ch).data(); }
|
||
|
inline tstring operator+(TOTHER ch, const tstring& str)
|
||
|
{ tstring strRet; strRet = ch; return strRet.append(str); }
|
||
|
inline tstring operator+(const tstring& str, PCTSTR sz)
|
||
|
{ tstring strRet(str); return sz == NULL ? strRet : strRet.append(sz); }
|
||
|
inline tstring operator+(PCTSTR sz, const tstring& str)
|
||
|
{ tstring strRet(sz); return strRet.append(str); }
|
||
|
inline tstring operator+(const tstring& str, PCOSTR sz)
|
||
|
{ tstring strRet(str); return strRet.append(tstring(sz)); }
|
||
|
inline tstring operator+(PCOSTR sz, const tstring& str)
|
||
|
{ tstring strRet(sz); return strRet.append(str); }
|
||
|
#ifdef STDSTRING_INC_COMDEF
|
||
|
inline tstring operator+(const _bstr_t& bstr, const tstring& str)
|
||
|
{ return tstring(static_cast<PCTSTR>(bstr)) + str; }
|
||
|
inline tstring operator+(const tstring& str, const _bstr_t& bstr)
|
||
|
{ return str + static_cast<PCTSTR>(bstr); }
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
inline TCHAR& tstring::operator[](int nIdx) { return STRBASE::operator[](nIdx); }
|
||
|
inline const TCHAR& tstring::operator[](int nIdx) const { return STRBASE::operator[](nIdx); }
|
||
|
inline tstring::operator PCTSTR() const { return c_str(); }; // implicit cast to const TCHAR*
|
||
|
|
||
|
|
||
|
// In MFC builds, define some global serialization operators
|
||
|
|
||
|
#ifdef _MFC_VER
|
||
|
CArchive& AFXAPI operator>>(CArchive& ar, tstring& string);
|
||
|
CArchive& AFXAPI operator<<(CArchive& ar, const tstring& string);
|
||
|
inline void tstring::SetResourceHandle(HINSTANCE hNew) { AfxSetResourceHandle(hNew); }
|
||
|
inline HINSTANCE tstring::GetResourceHandle() { return AfxGetResourceHandle(); };
|
||
|
#else
|
||
|
|
||
|
// Because we're a template with no C file, we can't simply have a glocal static
|
||
|
// HINSTANCE. Instead, we have a class-static function which in turn has a static
|
||
|
// HINSTANCE. Since only that class-static function has access to the HINSTANCE,
|
||
|
// it has the ability to set or retrieve its static HINSTANCE.
|
||
|
//
|
||
|
// In short, the HInstanceSingleton is static to the class, and its _hInstance
|
||
|
// variable is static to the HInstanceSingleton function, so the _hInstance variable
|
||
|
// is static to the class.
|
||
|
|
||
|
inline const HINSTANCE & HInstanceSingleton(HINSTANCE hNew = NULL, bool bSet = false)
|
||
|
{
|
||
|
static HINSTANCE _hInstance = ::GetModuleHandle(NULL);
|
||
|
if (bSet)
|
||
|
_hInstance = hNew;
|
||
|
return _hInstance;
|
||
|
}
|
||
|
inline void tstring::SetResourceHandle(HINSTANCE hNew)
|
||
|
{
|
||
|
HInstanceSingleton(hNew, true);
|
||
|
}
|
||
|
inline HINSTANCE tstring::GetResourceHandle()
|
||
|
{
|
||
|
return HInstanceSingleton();
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
// Some code still refers to old names of this class -- Account for this.
|
||
|
#define CSTLString tstring
|
||
|
#define CW32String tstring
|
||
|
|
||
|
// WUSysMessage -- return the system string corresponding to a system error or HRESULT value.
|
||
|
tstring WUSysMessage(DWORD dwError, DWORD p_dwLangId=MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT));
|
||
|
|
||
|
// WUFormat -- creates and formats a tstring with one line of code instead of the two it normally takes
|
||
|
tstring WUFormat(PCTSTR szFormat, ...);
|
||
|
tstring WUFormat(UINT nId, ...);
|
||
|
|
||
|
// Functional Comparators
|
||
|
//
|
||
|
// These structs are derived from the std::binary_function template. They give us functional
|
||
|
// classes (which may be used in Standard C++ Library collections and algorithms) that perform
|
||
|
// case-insensitive comparisons of tstring objects. This is useful for maps in which the key
|
||
|
// may be the proper string but in the wrong case.
|
||
|
|
||
|
#define tstring_lessnocase _SSLNC // define shorter name to avoid compiler warning 4786
|
||
|
#define tstring_comparenocase _SSENC // define shorter name to avoid compiler warning 4786
|
||
|
|
||
|
struct tstring_lessnocase : std::binary_function<tstring, tstring, bool>
|
||
|
{
|
||
|
bool operator()(const tstring& strFirst, const tstring& strSecond) const
|
||
|
{
|
||
|
return _tcsicmp(strFirst, strSecond) < 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct tstring_comparenocase : std::binary_function<tstring, tstring, bool>
|
||
|
{
|
||
|
bool operator()(const tstring& strFirst, const tstring& strSecond) const
|
||
|
{
|
||
|
return _tcsicmp(strFirst, strSecond) == 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#endif // #ifndef _STDSTRING_H_
|