440 lines
9.9 KiB
C++
440 lines
9.9 KiB
C++
|
// Copyright (c) 1997-1999 Microsoft Corporation
|
|||
|
//
|
|||
|
// Enhancement of std::basic_string; Windows-aware version
|
|||
|
//
|
|||
|
// 8-14-97 sburns
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Users of this class should assume that none of the member functions here
|
|||
|
// are threadsafe: that is, that concurrent calls to member functions on the
|
|||
|
// same instance are not guaranteed to produce correct results. The static
|
|||
|
// class functions are, however, threadsafe.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
typedef
|
|||
|
std::basic_string<
|
|||
|
char,
|
|||
|
std::char_traits<char>,
|
|||
|
Burnslib::Heap::Allocator<char> >
|
|||
|
AnsiString;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
typedef
|
|||
|
std::basic_string<
|
|||
|
wchar_t,
|
|||
|
std::char_traits<wchar_t>,
|
|||
|
Burnslib::Heap::Allocator<wchar_t> >
|
|||
|
StringBase;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
class String : public StringBase
|
|||
|
{
|
|||
|
public:
|
|||
|
|
|||
|
typedef StringBase base;
|
|||
|
|
|||
|
// contructor pass-thrus: we support all of the constructors of the
|
|||
|
// base class.
|
|||
|
|
|||
|
explicit String()
|
|||
|
:
|
|||
|
base()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
//lint -e(1931) allow implicit type conversion with this ctor
|
|||
|
|
|||
|
String(const base& x)
|
|||
|
:
|
|||
|
base(x)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
String(const String& x, base::size_type p, base::size_type m)
|
|||
|
:
|
|||
|
base(x, p, m)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
String(base::const_pointer s, base::size_type n)
|
|||
|
:
|
|||
|
base(s, n)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
//lint -e(1931) allow implicit type conversion with this ctor
|
|||
|
|
|||
|
String(base::const_pointer s)
|
|||
|
:
|
|||
|
base(s)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
String(base::size_type n, base::value_type c)
|
|||
|
:
|
|||
|
base(n, c)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
String(base::const_iterator f, base::const_iterator l)
|
|||
|
:
|
|||
|
base(f, l)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Enhancements to the base class std::base
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// conversion from ANSI to Unicode
|
|||
|
|
|||
|
String(PCSTR lpsz);
|
|||
|
String(const AnsiString& s);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Same as compare, except case is ignored.
|
|||
|
|
|||
|
int
|
|||
|
icompare(const String& str) const;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// returns true if the string consists entirely of digits, false
|
|||
|
// otherwise.
|
|||
|
|
|||
|
bool
|
|||
|
is_numeric() const;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Overload of the replace() family of methods. Replaces all occurrances
|
|||
|
// of the substring 'from' with the string 'to'. Returns *this. All
|
|||
|
// characters of the string are examined exactly once. If the replacement
|
|||
|
// results in the creation of new occurrances of the 'from' substring,
|
|||
|
// these are not reconsidered.
|
|||
|
//
|
|||
|
// from - The substring to be replaced. If 'from' is the empty string,
|
|||
|
// then no change is made.
|
|||
|
//
|
|||
|
// to - The string to replace 'from'. If 'to' is the empty string, then
|
|||
|
// all occurrances of 'from' are removed from the string.
|
|||
|
|
|||
|
//lint -e(1511) we are properly overloading base::replace
|
|||
|
|
|||
|
String&
|
|||
|
replace(const String& from, const String& to);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
enum StripType
|
|||
|
{
|
|||
|
LEADING = 0x01,
|
|||
|
TRAILING = 0x02,
|
|||
|
BOTH = LEADING | TRAILING
|
|||
|
};
|
|||
|
|
|||
|
// Removes all consecutive occurrances of a given character from one or
|
|||
|
// more ends of the string. Returns *this.
|
|||
|
|
|||
|
String&
|
|||
|
strip(
|
|||
|
StripType type = TRAILING,
|
|||
|
wchar_t charToStrip = L' ');
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Converts all lower case characters of the string to upper case. Returns
|
|||
|
// *this.
|
|||
|
|
|||
|
String&
|
|||
|
to_upper();
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Converts all upper case characters of the string to lower case. Returns
|
|||
|
// *this.
|
|||
|
|
|||
|
String&
|
|||
|
to_lower();
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Copy the string into an OLESTR that has been allocated with
|
|||
|
// CoTaskMemAlloc, which the caller is responsible for deleting with
|
|||
|
// CoTaskMemFree. Returns S_OK on success, E_OUTOFMEMORY if CoTaskMemAlloc
|
|||
|
// fails.
|
|||
|
//
|
|||
|
// oleString - where to place the allocated copy.
|
|||
|
|
|||
|
HRESULT
|
|||
|
as_OLESTR(LPOLESTR& oleString) const;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
enum ConvertResult
|
|||
|
{
|
|||
|
CONVERT_SUCCESSFUL,
|
|||
|
CONVERT_FAILED,
|
|||
|
CONVERT_OVERFLOW,
|
|||
|
CONVERT_UNDERFLOW,
|
|||
|
CONVERT_OUT_OF_MEMORY,
|
|||
|
CONVERT_BAD_INPUT,
|
|||
|
CONVERT_BAD_RADIX
|
|||
|
};
|
|||
|
|
|||
|
// Converts the string from Unicode to the ANSI character set, for as many
|
|||
|
// characters as this can be done. See the restrictions for
|
|||
|
// WideCharToMultiByte.
|
|||
|
//
|
|||
|
// ansi - the string (i.e. basic_string<char>) in which the result is
|
|||
|
// placed. If the conversion fails, this is set to the empty string.
|
|||
|
|
|||
|
ConvertResult
|
|||
|
convert(AnsiString& ansi) const;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// For all numeric converions, the string is expected in the following
|
|||
|
// form:
|
|||
|
//
|
|||
|
// [whitespace] [{+ | <20>}] [0 [{ x | X }]] [digits]
|
|||
|
//
|
|||
|
// whitespace may consist of space and tab characters, which are ignored;
|
|||
|
//
|
|||
|
// digits are one or more decimal digits. The first character that does not
|
|||
|
// fit this form stops the scan.
|
|||
|
//
|
|||
|
// The default radix for the conversion is 10 (decimal). If radix is 0,
|
|||
|
// then the the initial characters of the string are used to determine the
|
|||
|
// radix for which the digits are to be interpreted. If the first character
|
|||
|
// is 0 and the second character is not 'x' or 'X', the string is
|
|||
|
// interpreted as an octal integer; otherwise, it is interpreted as a
|
|||
|
// decimal number. If the first character is '0' and the second character
|
|||
|
// is 'x' or 'X', the string is interpreted as a hexadecimal integer. If
|
|||
|
// the first character is '1' through '9', the string is interpreted as a
|
|||
|
// decimal integer. The letters 'a' through 'z' (or 'A' through 'Z') are
|
|||
|
// assigned the values 10 through 35; only letters whose assigned values
|
|||
|
// are less than the radix are permitted. The radix must be within the
|
|||
|
// range from 2 to 36, or the conversion will fail with an error
|
|||
|
// CONVERT_BAD_RADIX, and the result parameter is set to 0.
|
|||
|
//
|
|||
|
// If any additional, unrecognized characters appear in the string, the
|
|||
|
// conversion will fail with an error CONVERT_BAD_INPUT, and the result
|
|||
|
// parameter is set to 0.
|
|||
|
//
|
|||
|
// If the conversion would produce a result too large or too small for the
|
|||
|
// target type, then the conversion fails with error CONVERT_OVERFLOW or
|
|||
|
// CONVERT_UNDERFLOW, and the result parameter is set to 0.
|
|||
|
//
|
|||
|
// Conversions for unsigned types allow a plus (+) or minus (-) sign
|
|||
|
// prefix; a leading minus sign indicates that the result value is to be
|
|||
|
// negated.
|
|||
|
|
|||
|
ConvertResult
|
|||
|
convert(short& s, int radix = 10) const;
|
|||
|
|
|||
|
ConvertResult
|
|||
|
convert(unsigned short& us, int radix = 10) const;
|
|||
|
|
|||
|
ConvertResult
|
|||
|
convert(int& i, int radix = 10) const;
|
|||
|
|
|||
|
ConvertResult
|
|||
|
convert(long& l, int radix = 10) const;
|
|||
|
|
|||
|
ConvertResult
|
|||
|
convert(unsigned& ui, int radix = 10) const;
|
|||
|
|
|||
|
ConvertResult
|
|||
|
convert(unsigned long& ul, int radix = 10) const;
|
|||
|
|
|||
|
ConvertResult
|
|||
|
convert(double& d) const;
|
|||
|
|
|||
|
ConvertResult
|
|||
|
convert(LARGE_INTEGER& li) const;
|
|||
|
|
|||
|
|
|||
|
// Separates the tokens in the string and pushes them in left-to-right
|
|||
|
// order into the supplied container as a individual String instances. A
|
|||
|
// token is a sequence of characters separated by one or characters in the
|
|||
|
// set of delimiters. Similar to the strtok function. Returns the
|
|||
|
// number of tokens placed in the container.
|
|||
|
//
|
|||
|
// usage:
|
|||
|
// String s(L"a list of tokens");
|
|||
|
// StringList tokens;
|
|||
|
// size_t token_count = s.tokenize(back_inserter(tokens));
|
|||
|
// ASSERT(token_count == tokens.size())
|
|||
|
|
|||
|
template <class BackInsertableContainer>
|
|||
|
size_t
|
|||
|
tokenize(
|
|||
|
std::back_insert_iterator<BackInsertableContainer>& bii,
|
|||
|
const String& delimiters = String(L" \t") ) const
|
|||
|
{
|
|||
|
size_t tokenCount = 0;
|
|||
|
size_type p1 = 0;
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
p1 = find_first_not_of(delimiters, p1);
|
|||
|
if (p1 == npos)
|
|||
|
{
|
|||
|
// no more tokens
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
size_type p2 = find_first_of(delimiters, p1 + 1);
|
|||
|
if (p2 == npos)
|
|||
|
{
|
|||
|
// this is the last token
|
|||
|
|
|||
|
*bii++ = substr(p1);
|
|||
|
++tokenCount;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
// the region [p1..(p2 - 1)] is a token
|
|||
|
|
|||
|
*bii++ = substr(p1, p2 - p1);
|
|||
|
++tokenCount;
|
|||
|
p1 = p2 + 1;
|
|||
|
}
|
|||
|
|
|||
|
return tokenCount;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// static functions
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Returns the string resource as a new instance.
|
|||
|
//
|
|||
|
// resID - resource ID of the string resource to load.
|
|||
|
|
|||
|
static
|
|||
|
String
|
|||
|
load(unsigned resId, HINSTANCE hInstance = 0);
|
|||
|
|
|||
|
inline
|
|||
|
static
|
|||
|
String
|
|||
|
load(int resId, HINSTANCE hInstance = 0)
|
|||
|
{
|
|||
|
return String::load(static_cast<unsigned>(resId), hInstance);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// FormatMessage-style formatted output.
|
|||
|
|
|||
|
#if defined(ALPHA) || defined(IA64)
|
|||
|
//lint -e(1916) it's ok to use elipsis here
|
|||
|
static
|
|||
|
String __cdecl
|
|||
|
String::format(
|
|||
|
const String& fmt,
|
|||
|
...);
|
|||
|
#else
|
|||
|
|
|||
|
// the x86 compiler won't allow the first parameter to be a reference
|
|||
|
// type. This is a compiler bug.
|
|||
|
|
|||
|
//lint -e(1916) it's ok to use elipsis here
|
|||
|
|
|||
|
static
|
|||
|
String __cdecl
|
|||
|
String::format(
|
|||
|
const String fmt,
|
|||
|
...);
|
|||
|
#endif
|
|||
|
|
|||
|
static
|
|||
|
String __cdecl
|
|||
|
format(const wchar_t* qqfmt, ...);
|
|||
|
|
|||
|
//lint -e(1916) it's ok to use elipsis here
|
|||
|
static
|
|||
|
String __cdecl
|
|||
|
format(unsigned formatResID, ...);
|
|||
|
|
|||
|
static
|
|||
|
String __cdecl
|
|||
|
format(int formatResID, ...);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// STL support
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// Function object class for performing case-insensive comparisons of
|
|||
|
// Strings. Can be used with any STL template involving binary_function.
|
|||
|
|
|||
|
class EqualIgnoreCase
|
|||
|
:
|
|||
|
public std::binary_function<String, String, bool>
|
|||
|
{
|
|||
|
public:
|
|||
|
|
|||
|
// Returns true if f and s are equal, ignoring case in the comparison
|
|||
|
|
|||
|
inline
|
|||
|
bool
|
|||
|
operator()(
|
|||
|
const first_argument_type& f,
|
|||
|
const second_argument_type& s) const
|
|||
|
{
|
|||
|
return (f.icompare(s) == 0);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
class LessIgnoreCase
|
|||
|
:
|
|||
|
public std::binary_function<String, String, bool>
|
|||
|
{
|
|||
|
public:
|
|||
|
|
|||
|
// Returns true if f is less than s, ignoring case in the comparison
|
|||
|
|
|||
|
inline
|
|||
|
bool
|
|||
|
operator()(
|
|||
|
const first_argument_type& f,
|
|||
|
const second_argument_type& s) const
|
|||
|
{
|
|||
|
return (f.icompare(s) < 0);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
private:
|
|||
|
|
|||
|
// Causes this to control a distinct copy of the string, without any shared
|
|||
|
// references.
|
|||
|
|
|||
|
void
|
|||
|
_copy();
|
|||
|
|
|||
|
void
|
|||
|
assignFromAnsi(PCSTR lpsz, size_t len);
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|