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);
|
||
};
|
||
|
||
|
||
|