1534 lines
40 KiB
Plaintext
1534 lines
40 KiB
Plaintext
// xlocale internal header (from <locale>)
|
|
#pragma once
|
|
#ifndef _XLOCALE_
|
|
#define _XLOCALE_
|
|
#include <climits>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#include <typeinfo>
|
|
#include <xlocinfo>
|
|
#include <xdebug>
|
|
|
|
#pragma pack(push,8)
|
|
#pragma warning(push,3)
|
|
|
|
_STD_BEGIN
|
|
|
|
// TEMPLATE CLASS _Locbase
|
|
template<class _Dummy>
|
|
class _Locbase
|
|
{ // define templatized category constants, instantiate on demand
|
|
public:
|
|
static const int collate = _M_COLLATE;
|
|
static const int ctype = _M_CTYPE;
|
|
static const int monetary = _M_MONETARY;
|
|
static const int numeric = _M_NUMERIC;
|
|
static const int time = _M_TIME;
|
|
static const int messages = _M_MESSAGE;
|
|
static const int all = _M_ALL;
|
|
static const int none = 0;
|
|
};
|
|
|
|
template<class _Dummy>
|
|
const int _Locbase<_Dummy>::collate;
|
|
template<class _Dummy>
|
|
const int _Locbase<_Dummy>::ctype;
|
|
template<class _Dummy>
|
|
const int _Locbase<_Dummy>::monetary;
|
|
template<class _Dummy>
|
|
const int _Locbase<_Dummy>::numeric;
|
|
template<class _Dummy>
|
|
const int _Locbase<_Dummy>::time;
|
|
template<class _Dummy>
|
|
const int _Locbase<_Dummy>::messages;
|
|
template<class _Dummy>
|
|
const int _Locbase<_Dummy>::all;
|
|
template<class _Dummy>
|
|
const int _Locbase<_Dummy>::none;
|
|
|
|
// CLASS locale
|
|
class _CRTIMP2 locale
|
|
: public _Locbase<int>
|
|
{ // nonmutable collection of facets that describe a locale
|
|
public:
|
|
typedef int category;
|
|
|
|
// CLASS id
|
|
class _CRTIMP2 id
|
|
{ // identifier stamp, unique for each distinct kind of facet
|
|
public:
|
|
id(size_t _Val = 0)
|
|
: _Id(_Val)
|
|
{ // construct with specified stamp value
|
|
}
|
|
|
|
operator size_t()
|
|
{ // get stamp, with lazy allocation
|
|
if (_Id == 0)
|
|
{ // still zero, allocate stamp
|
|
_Lockit _Lock(_LOCK_LOCALE);
|
|
if (_Id == 0)
|
|
_Id = ++_Id_cnt;
|
|
}
|
|
return (_Id);
|
|
}
|
|
|
|
private:
|
|
id(const id&); // not defined
|
|
id& operator=(const id&); // not defined
|
|
|
|
size_t _Id; // the identifier stamp
|
|
static int _Id_cnt; // static source of unique stamps
|
|
};
|
|
|
|
class _Locimp;
|
|
|
|
// class facet
|
|
class _CRTIMP2 facet
|
|
{ // base class for all locale facets, performs reference counting
|
|
friend class locale;
|
|
friend class _Locimp;
|
|
|
|
public:
|
|
static size_t __cdecl _Getcat(const facet ** = 0)
|
|
{ // get category value, or -1 if no corresponding C category
|
|
return ((size_t)(-1));
|
|
}
|
|
|
|
void _Incref()
|
|
{ // safely increment the reference count
|
|
_Lockit _Lock(_LOCK_LOCALE);
|
|
|
|
if (_Refs < (size_t)(-1))
|
|
++_Refs;
|
|
}
|
|
|
|
facet *_Decref()
|
|
{ // safely decrement the reference count, return this when dead
|
|
_Lockit _Lock(_LOCK_LOCALE);
|
|
|
|
if (0 < _Refs && _Refs < (size_t)(-1))
|
|
--_Refs;
|
|
return (_Refs == 0 ? this : 0);
|
|
}
|
|
|
|
void _Register(); // queue up lazy facet for destruction
|
|
|
|
// _PROTECTED:
|
|
virtual ~facet()
|
|
{ // destroy the object
|
|
}
|
|
|
|
protected:
|
|
explicit facet(size_t _Initrefs = 0)
|
|
: _Refs(_Initrefs)
|
|
{ // construct with initial reference count
|
|
}
|
|
|
|
private:
|
|
facet(const facet&); // not defined
|
|
facet& operator=(const facet&); // not defined
|
|
|
|
size_t _Refs; // the reference count
|
|
};
|
|
|
|
// CLASS _Locimp
|
|
class _Locimp
|
|
: public facet
|
|
{ // reference-counted actual implementation of a locale
|
|
_PROTECTED:
|
|
~_Locimp(); // destroy the object
|
|
|
|
private:
|
|
friend class locale;
|
|
|
|
_Locimp(bool _Transparent = false); // construct from current locale
|
|
|
|
_CRTIMP2 _Locimp(const _Locimp&); // copy a _Locimp
|
|
|
|
_CRTIMP2 void _Addfac(facet *, size_t); // add a facet
|
|
|
|
static _Locimp *__cdecl _Makeloc(const _Locinfo&,
|
|
category, _Locimp *, const locale *); // make essential facets
|
|
|
|
static void __cdecl _Makewloc(const _Locinfo&,
|
|
category, _Locimp *, const locale *); // make wchar_t facets
|
|
|
|
static void __cdecl _Makexloc(const _Locinfo&,
|
|
category, _Locimp *, const locale *); // make remaining facets
|
|
|
|
facet **_Facetvec; // pointer to vector of facets
|
|
size_t _Facetcount; // size of vector of facets
|
|
category _Catmask; // mask describing implemented categories
|
|
bool _Xparent; // true if locale is transparent
|
|
_STRING_CRT _Name; // locale name, or "*" if not known
|
|
static _CRTIMP2 _Locimp *_Clocptr; // pointer to "C" locale object
|
|
};
|
|
|
|
_DEPRECATED locale& _Addfac(facet *, size_t,
|
|
size_t); // add a facet, copying on write
|
|
|
|
template<class _Elem,
|
|
class _Traits,
|
|
class _Alloc>
|
|
bool operator()(const basic_string<_Elem, _Traits, _Alloc>& _Left,
|
|
const basic_string<_Elem, _Traits, _Alloc>& _Right) const
|
|
{ // compare _Left and _Right strings using collate facet in locale
|
|
const std::collate<_Elem>& _Fac =
|
|
std::use_facet<std::collate<_Elem> >(*this);
|
|
|
|
return (_Fac.compare(_Left.c_str(), _Left.c_str() + _Left.size(),
|
|
_Right.c_str(), _Right.c_str() + _Right.size()) < 0);
|
|
}
|
|
|
|
template<class _Facet>
|
|
locale combine(const locale& _Loc) const
|
|
{ // combine two locales
|
|
_Facet *_Facptr;
|
|
|
|
_TRY_BEGIN
|
|
_Facptr = (_Facet *)&std::use_facet<_Facet>(_Loc);
|
|
_CATCH_ALL
|
|
_THROW(runtime_error, "locale::combine facet missing");
|
|
_CATCH_END
|
|
|
|
_Locimp *_Newimp = _NEW_CRT _Locimp(*_Ptr);
|
|
_Newimp->_Addfac(_Facptr, _Facet::id);
|
|
if (_Facet::_Getcat() != (size_t)(-1))
|
|
{ // not a standard facet, result has no name
|
|
_Newimp->_Catmask = 0;
|
|
_Newimp->_Name = "*";
|
|
}
|
|
return (locale(_Newimp));
|
|
}
|
|
|
|
template<class _Facet>
|
|
locale(const locale& _Loc, _Facet *_Facptr)
|
|
: _Ptr(_NEW_CRT _Locimp(*_Loc._Ptr))
|
|
{ // construct from _Loc, replacing facet with *_Facptr
|
|
if (_Facptr != 0)
|
|
{ // replace facet
|
|
_Ptr->_Addfac(_Facptr, _Facet::id);
|
|
if (_Facet::_Getcat() != (size_t)(-1))
|
|
_Ptr->_Catmask = 0, _Ptr->_Name = "*"; // no C category
|
|
}
|
|
}
|
|
|
|
|
|
locale() _THROW0(); // construct from current locale
|
|
|
|
locale(_Uninitialized)
|
|
{ // defer construction
|
|
}
|
|
|
|
locale(const locale& _Right) _THROW0()
|
|
: _Ptr(_Right._Ptr)
|
|
{ // construct by copying
|
|
_Ptr->_Incref();
|
|
}
|
|
|
|
locale(const locale&, const locale&,
|
|
category); // construct from locale and category in another locale
|
|
|
|
explicit locale(const char *,
|
|
category = all); // construct from named locale for category
|
|
|
|
locale(const locale&, const char *,
|
|
category); // construct from locale and category in named locale
|
|
|
|
~locale() _THROW0()
|
|
{ // destroy the object
|
|
if (_Ptr != 0)
|
|
_DELETE_CRT(_Ptr->_Decref());
|
|
}
|
|
|
|
locale& operator=(const locale& _Right) _THROW0()
|
|
{ // assign a locale
|
|
if (_Ptr != _Right._Ptr)
|
|
{ // different implementation, point at new one
|
|
_DELETE_CRT(_Ptr->_Decref());
|
|
_Ptr = _Right._Ptr;
|
|
_Ptr->_Incref();
|
|
}
|
|
return (*this);
|
|
}
|
|
|
|
string name() const
|
|
{ // return locale name
|
|
return (_Ptr->_Name);
|
|
}
|
|
|
|
const facet *_Getfacet(size_t) const; // get facet by id
|
|
|
|
bool operator==(const locale&) const; // test for locale equality
|
|
|
|
bool operator!=(const locale& _Right) const
|
|
{ // test for locale inequality
|
|
return (!(*this == _Right));
|
|
}
|
|
|
|
static const locale& __cdecl classic(); // return classic "C" locale
|
|
|
|
static locale __cdecl global(const locale&); // return current locale
|
|
|
|
static locale __cdecl empty(); // return empty (transparent) locale
|
|
|
|
private:
|
|
locale(_Locimp *_Ptrimp)
|
|
: _Ptr(_Ptrimp)
|
|
{ // construct from _Locimp pointer
|
|
}
|
|
|
|
static _Locimp *__cdecl _Init(); // initialize locale
|
|
|
|
_Locimp *_Ptr; // pointer to locale implementation object
|
|
};
|
|
|
|
// SUPPORT TEMPLATES
|
|
template<class _Facet> inline _DEPRECATED
|
|
locale _Addfac(locale _Loc, _Facet *_Fac)
|
|
{ // add facet to locale -- retained
|
|
return (_Loc._Addfac(_Fac, _Facet::id, _Facet::_Getcat()));
|
|
}
|
|
|
|
#define _ADDFAC(loc, pfac) locale(loc, pfac) /* add facet to locale */
|
|
|
|
#define _USE(loc, fac) \
|
|
use_facet<fac >(loc) /* get facet reference from locale */
|
|
|
|
template<class _Facet> inline
|
|
const _Facet& __cdecl use_facet(const locale& _Loc)
|
|
{ // get facet reference from locale
|
|
_Lockit _Lock(_LOCK_LOCALE); // the thread lock, make get atomic
|
|
static const locale::facet *_Psave; // static pointer to lazy facet
|
|
|
|
size_t _Id = _Facet::id;
|
|
const locale::facet *_Pf = _Loc._Getfacet(_Id);
|
|
|
|
if (_Pf != 0)
|
|
; // got facet from locale
|
|
else if (_Psave != 0)
|
|
_Pf = _Psave; // lazy facet already allocated
|
|
else if (_Facet::_Getcat(&_Psave) == (size_t)(-1))
|
|
#if _HAS_EXCEPTIONS
|
|
throw bad_cast(); // lazy disallowed
|
|
#else /* _HAS_EXCEPTIONS */
|
|
abort(); // lazy disallowed
|
|
#endif /* _HAS_EXCEPTIONS */
|
|
else
|
|
{ // queue up lazy facet for destruction
|
|
_Pf = _Psave;
|
|
|
|
locale::facet *_Pfmod = (_Facet *)_Psave;
|
|
_Pfmod->_Incref();
|
|
_Pfmod->_Register();
|
|
}
|
|
|
|
return ((const _Facet&)(*_Pf)); // should be dynamic_cast
|
|
}
|
|
|
|
template<class _Facet> inline _DEPRECATED
|
|
const _Facet& __cdecl use_facet(const locale& _Loc, const _Facet *,
|
|
bool = false)
|
|
{ // get facet reference from locale -- retained, 2/3 arg versions
|
|
return use_facet<_Facet>(_Loc);
|
|
}
|
|
|
|
// TEMPLATE FUNCTION _Narrow
|
|
#define _NARROW(T, V) _Narrow(static_cast<T>(V)) /* convert T to char */
|
|
|
|
template<class _Elem> inline
|
|
char _Narrow(_Elem _Ch)
|
|
{ // convert _Elem to char
|
|
return ((char)_Ch); // needs _Elem::operator char()
|
|
}
|
|
|
|
template<> inline
|
|
char _Narrow(wchar_t _Ch)
|
|
{ // convert wchar_t to char (using current locale, no state)
|
|
return ((char)wctob(_Ch));
|
|
}
|
|
|
|
// TEMPLATE FUNCTION _Widen
|
|
#define _WIDEN(T, V) _Widen(V, (T *)0) /* convert char to T */
|
|
|
|
template<class _Elem> inline
|
|
_Elem _Widen(char _Ch, _Elem *)
|
|
{ // convert char to _Elem
|
|
return ((_Elem)(unsigned char)_Ch); // needs _Elem(char)
|
|
}
|
|
|
|
template<> inline
|
|
wchar_t _Widen(char _Ch, wchar_t *)
|
|
{ // convert char to wchar_t (using current locale, no state)
|
|
return (btowc(_Ch));
|
|
}
|
|
|
|
// TEMPLATE FUNCTION _Getloctxt
|
|
template<class _Elem,
|
|
class _InIt> inline
|
|
int __cdecl _Getloctxt(_InIt& _First, _InIt& _Last, size_t _Numfields,
|
|
const _Elem *_Ptr)
|
|
{ // find field at _Ptr that matches longest in [_First, _Last)
|
|
for (size_t _Off = 0; _Ptr[_Off] != (_Elem)0; ++_Off)
|
|
if (_Ptr[_Off] == _Ptr[0])
|
|
++_Numfields; // add fields with leading mark to initial count
|
|
string _Str(_Numfields, '\0'); // one column counter for each field
|
|
|
|
int _Ans = -2; // no candidates so far
|
|
for (size_t _Column = 1; ; ++_Column, ++_First, _Ans = -1)
|
|
{ // test each element against all viable fields
|
|
bool _Prefix = false; // seen at least one valid prefix
|
|
size_t _Off = 0; // offset into fields
|
|
size_t _Field = 0; // current field number
|
|
|
|
for (; _Field < _Numfields; ++_Field)
|
|
{ // test element at _Column in field _Field
|
|
for (; _Ptr[_Off] != (_Elem)0 && _Ptr[_Off] != _Ptr[0]; ++_Off)
|
|
; // find beginning of field
|
|
|
|
if (_Str[_Field] != '\0')
|
|
_Off += _Str[_Field]; // skip tested columns in field
|
|
else if (_Ptr[_Off += _Column] == _Ptr[0]
|
|
|| _Ptr[_Off] == (_Elem)0)
|
|
{ // matched all of field, save as possible answer
|
|
_Str[_Field] = (char)(_Column < 127
|
|
? _Column : 127); // save skip count if small enough
|
|
_Ans = (int)_Field; // save answer
|
|
}
|
|
else if (_First == _Last || _Ptr[_Off] != *_First)
|
|
_Str[_Field] = (char)(_Column < 127
|
|
? _Column : 127); // no match, just save skip count
|
|
else
|
|
_Prefix = true; // still a valid prefix
|
|
}
|
|
|
|
if (!_Prefix || _First == _Last)
|
|
break; // no pending prefixes or no input, give up
|
|
}
|
|
return (_Ans); // return field number or negative value on failure
|
|
}
|
|
|
|
// TEMPLATE FUNCTION _Maklocstr
|
|
#define _MAKLOCSTR(_Elem, _Str, _Cvt) \
|
|
_Maklocstr(_Str, (_Elem *)0, _Cvt) // convert C string to _Elem sequence
|
|
|
|
template<class _Elem> inline
|
|
_Elem *__cdecl _Maklocstr(const char *_Ptr, _Elem *,
|
|
const _Locinfo::_Cvtvec &)
|
|
{ // convert C string to _Elem sequence
|
|
size_t _Count = ::strlen(_Ptr) + 1;
|
|
_Elem *_Ptrdest = _NEW_CRT _Elem[_Count];
|
|
|
|
for (_Elem *_Ptrnext = _Ptrdest; 0 < _Count; --_Count, ++_Ptrnext, ++_Ptr)
|
|
*_Ptrnext = _WIDEN(_Elem, *_Ptr);
|
|
return (_Ptrdest);
|
|
}
|
|
|
|
template<> inline
|
|
wchar_t *__cdecl _Maklocstr(const char *_Ptr, wchar_t *,
|
|
const _Locinfo::_Cvtvec &_Cvt)
|
|
{ // convert C string to wchar_t sequence
|
|
size_t _Count, _Count1;
|
|
size_t _Wchars;
|
|
const char *_Ptr1;
|
|
wchar_t *_Ptrdest, *_Ptrnext;
|
|
|
|
_Mbstinit(_Mbst1);
|
|
_Count = _Count1 = ::strlen(_Ptr) + 1;
|
|
for (_Wchars = 0, _Ptr1 = _Ptr; 0 < _Count; ++_Wchars)
|
|
{ // determine length of wide string
|
|
int _Bytes;
|
|
if ((_Bytes = _Mbrtowc(0, _Ptr1, _Count, &_Mbst1, &_Cvt)) <= 0)
|
|
break;
|
|
_Ptr1 += _Bytes;
|
|
_Count -= _Bytes;
|
|
}
|
|
++_Wchars;
|
|
|
|
_Ptrdest = _NEW_CRT wchar_t[_Wchars];
|
|
_Mbstinit(_Mbst2);
|
|
for (_Ptrnext = _Ptrdest; 0 < _Wchars; --_Wchars, ++_Ptrnext)
|
|
{ // widen string
|
|
int _Bytes;
|
|
if ((_Bytes = _Mbrtowc(_Ptrnext, _Ptr, _Count1, &_Mbst1, &_Cvt)) <= 0)
|
|
break;
|
|
_Ptr += _Bytes;
|
|
_Count1 -= _Bytes;
|
|
}
|
|
*_Ptrnext = 0;
|
|
return (_Ptrdest);
|
|
}
|
|
|
|
// STRUCT codecvt_base
|
|
class _CRTIMP2 codecvt_base
|
|
: public locale::facet
|
|
{ // base class for codecvt
|
|
public:
|
|
enum
|
|
{ // constants for different parse states
|
|
ok, partial, error, noconv};
|
|
typedef int result;
|
|
|
|
codecvt_base(size_t _Refs = 0)
|
|
: locale::facet(_Refs)
|
|
{ // default constructor
|
|
}
|
|
|
|
bool always_noconv() const _THROW0()
|
|
{ // return true if conversions never change input (from codecvt)
|
|
return (do_always_noconv());
|
|
}
|
|
|
|
int max_length() const _THROW0()
|
|
{ // return maximum length required for a conversion (from codecvt)
|
|
return (do_max_length());
|
|
}
|
|
|
|
int encoding() const _THROW0()
|
|
{ // return length of code sequence (from codecvt)
|
|
return (do_encoding());
|
|
}
|
|
|
|
~codecvt_base()
|
|
{ // destroy the object
|
|
}
|
|
|
|
protected:
|
|
virtual bool do_always_noconv() const _THROW0()
|
|
{ // return true if conversions never change input (from codecvt)
|
|
return (true);
|
|
}
|
|
|
|
virtual int do_max_length() const _THROW0()
|
|
{ // return maximum length required for a conversion (from codecvt)
|
|
return (1);
|
|
}
|
|
|
|
virtual int do_encoding() const _THROW0()
|
|
{ // return length of code sequence (from codecvt)
|
|
return (1); // -1 ==> state dependent, 0 ==> varying length
|
|
}
|
|
};
|
|
|
|
// TEMPLATE CLASS codecvt
|
|
template<class _Elem,
|
|
class _Byte,
|
|
class _Statype>
|
|
class codecvt
|
|
: public codecvt_base
|
|
{ // facet for converting between _Elem and char (_Byte) sequences
|
|
public:
|
|
typedef _Elem intern_type;
|
|
typedef _Byte extern_type;
|
|
typedef _Statype state_type;
|
|
|
|
result in(_Statype& _State,
|
|
const _Byte *_First1, const _Byte *_Last1, const _Byte *& _Mid1,
|
|
_Elem *_First2, _Elem *_Last2, _Elem *& _Mid2) const
|
|
{ // convert bytes [_First1, _Last1) to [_First2, _Last)
|
|
return (do_in(_State,
|
|
_First1, _Last1, _Mid1, _First2, _Last2, _Mid2));
|
|
}
|
|
|
|
result out(_Statype& _State,
|
|
const _Elem *_First1, const _Elem *_Last1, const _Elem *& _Mid1,
|
|
_Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
|
|
{ // convert [_First1, _Last1) to bytes [_First2, _Last2)
|
|
return (do_out(_State,
|
|
_First1, _Last1, _Mid1, _First2, _Last2, _Mid2));
|
|
}
|
|
|
|
result unshift(_Statype& _State,
|
|
_Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
|
|
{ // generate bytes to return to default shift state
|
|
return (do_unshift(_State, _First2, _Last2, _Mid2));
|
|
}
|
|
|
|
int length(const _Statype& _State, const _Byte *_First1,
|
|
const _Byte *_Last1, size_t _Count) const _THROW0()
|
|
{ // return min(_Count, converted length of bytes [_First1, _Last1))
|
|
return (do_length(_State, _First1, _Last1, _Count));
|
|
}
|
|
|
|
static locale::id id; // unique facet id
|
|
|
|
explicit codecvt(size_t _Refs = 0)
|
|
: codecvt_base(_Refs)
|
|
{ // construct from current locale
|
|
_Init(_Locinfo());
|
|
}
|
|
|
|
codecvt(const _Locinfo& _Lobj, size_t _Refs = 0)
|
|
: codecvt_base(_Refs)
|
|
{ // construct from specified locale
|
|
_Init(_Lobj);
|
|
}
|
|
|
|
static size_t __cdecl _Getcat(const locale::facet **_Ppf = 0)
|
|
{ // return locale category mask and construct standard facet
|
|
if (_Ppf != 0 && *_Ppf == 0)
|
|
*_Ppf = _NEW_CRT codecvt<_Elem, _Byte, _Statype>;
|
|
return (_X_CTYPE);
|
|
}
|
|
|
|
_PROTECTED:
|
|
virtual ~codecvt()
|
|
{ // destroy the object
|
|
}
|
|
|
|
protected:
|
|
void _Init(const _Locinfo& _Lobj)
|
|
{ // initialize from _Lobj
|
|
_Cvt = _Lobj._Getcvt();
|
|
}
|
|
|
|
virtual result do_in(_Statype&,
|
|
const _Byte *_First1, const _Byte *, const _Byte *& _Mid1,
|
|
_Elem *_First2, _Elem *, _Elem *& _Mid2) const
|
|
{ // convert bytes [_First1, _Last1) to [_First2, _Last)
|
|
_Mid1 = _First1, _Mid2 = _First2;
|
|
return (noconv); // convert nothing
|
|
}
|
|
|
|
virtual result do_out(_Statype&,
|
|
const _Elem *_First1, const _Elem *, const _Elem *& _Mid1,
|
|
_Byte *_First2, _Byte *, _Byte *& _Mid2) const
|
|
{ // convert [_First1, _Last1) to bytes [_First2, _Last)
|
|
_Mid1 = _First1, _Mid2 = _First2;
|
|
return (noconv); // convert nothing
|
|
}
|
|
|
|
virtual result do_unshift(_Statype&,
|
|
_Byte *, _Byte *, _Byte *&) const
|
|
{ // generate bytes to return to default shift state
|
|
return (noconv); // convert nothing
|
|
}
|
|
|
|
virtual int do_length(const _Statype&, const _Byte *_First1,
|
|
const _Byte *_Last1, size_t _Count) const _THROW0()
|
|
{ // return min(_Count, converted length of bytes [_First1, _Last1))
|
|
return (int)(_Count < (size_t)(_Last1 - _First1)
|
|
? _Count : _Last1 - _First1); // assume one-to-one conversion
|
|
}
|
|
|
|
private:
|
|
_Locinfo::_Cvtvec _Cvt; // used by codecvt<wchar_t, char, mbstate_t>
|
|
};
|
|
|
|
// STATIC codecvt::id OBJECT
|
|
template<class _Elem,
|
|
class _Byte,
|
|
class _Statype>
|
|
locale::id codecvt<_Elem, _Byte, _Statype>::id;
|
|
|
|
// CLASS codecvt<wchar_t, char, mbstate_t>
|
|
template<> class _CRTIMP2 codecvt<wchar_t, char, mbstate_t>
|
|
: public codecvt_base
|
|
{ // facet for converting between wchar_t and char (_Byte) sequences
|
|
public:
|
|
typedef wchar_t _Elem;
|
|
typedef char _Byte;
|
|
typedef mbstate_t _Statype;
|
|
typedef _Elem intern_type;
|
|
typedef _Byte extern_type;
|
|
typedef _Statype state_type;
|
|
|
|
result in(_Statype& _State,
|
|
const _Byte *_First1, const _Byte *_Last1, const _Byte *& _Mid1,
|
|
_Elem *_First2, _Elem *_Last2, _Elem *& _Mid2) const
|
|
{ // convert bytes [_First1, _Last1) to [_First2, _Last)
|
|
return (do_in(_State,
|
|
_First1, _Last1, _Mid1, _First2, _Last2, _Mid2));
|
|
}
|
|
|
|
result out(_Statype& _State,
|
|
const _Elem *_First1, const _Elem *_Last1, const _Elem *& _Mid1,
|
|
_Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
|
|
{ // convert [_First1, _Last1) to bytes [_First2, _Last)
|
|
return (do_out(_State,
|
|
_First1, _Last1, _Mid1, _First2, _Last2, _Mid2));
|
|
}
|
|
|
|
result unshift(_Statype& _State,
|
|
_Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
|
|
{ // generate bytes to return to default shift state
|
|
return (do_unshift(_State,
|
|
_First2, _Last2, _Mid2));
|
|
}
|
|
|
|
int length(const _Statype& _State, const _Byte *_First1,
|
|
const _Byte *_Last1, size_t _N2) const _THROW0()
|
|
{ // return min(_Count, converted length of bytes [_First1, _Last1))
|
|
return (do_length(_State, _First1, _Last1, _N2));
|
|
}
|
|
|
|
static locale::id id; // unique facet id
|
|
|
|
explicit codecvt(size_t _Refs = 0)
|
|
: codecvt_base(_Refs)
|
|
{ // construct from current locale
|
|
_Init(_Locinfo());
|
|
}
|
|
|
|
codecvt(const _Locinfo& _Lobj, size_t _Refs = 0)
|
|
: codecvt_base(_Refs)
|
|
{ // construct from specified locale
|
|
_Init(_Lobj);
|
|
}
|
|
|
|
static size_t __cdecl _Getcat(const locale::facet **_Ppf = 0)
|
|
{ // return locale category mask and construct standard facet
|
|
if (_Ppf != 0 && *_Ppf == 0)
|
|
*_Ppf = _NEW_CRT codecvt<_Elem, _Byte, _Statype>;
|
|
return (_X_CTYPE);
|
|
}
|
|
|
|
_PROTECTED:
|
|
virtual ~codecvt()
|
|
{ // destroy the object
|
|
}
|
|
|
|
protected:
|
|
void _Init(const _Locinfo& _Lobj)
|
|
{ // initialize from _Lobj
|
|
_Cvt = _Lobj._Getcvt();
|
|
}
|
|
|
|
virtual result do_in(_Statype& _State,
|
|
const _Byte *_First1, const _Byte *_Last1, const _Byte *& _Mid1,
|
|
_Elem *_First2, _Elem *_Last2, _Elem *& _Mid2) const
|
|
{ // convert bytes [_First1, _Last1) to [_First2, _Last)
|
|
_Mid1 = _First1, _Mid2 = _First2;
|
|
result _Ans = _Mid1 == _Last1 ? ok : partial;
|
|
int _Bytes;
|
|
|
|
while (_Mid1 != _Last1 && _Mid2 != _Last2)
|
|
switch (_Bytes = _Mbrtowc(_Mid2, _Mid1, _Last1 - _Mid1,
|
|
&_State, &_Cvt))
|
|
{ // test result of locale-specific mbrtowc call
|
|
case -2: // partial conversion
|
|
_Mid1 = _Last1;
|
|
return (_Ans);
|
|
|
|
case -1: // failed conversion
|
|
return (error);
|
|
|
|
case 0: // converted null character
|
|
_Bytes = (int)::strlen(_Mid1) + 1;
|
|
// fall through
|
|
|
|
default: // converted _Bytes bytes to a wchar_t
|
|
_Mid1 += _Bytes, ++_Mid2, _Ans = ok;
|
|
}
|
|
return (_Ans);
|
|
}
|
|
|
|
virtual result do_out(_Statype& _State,
|
|
const _Elem *_First1, const _Elem *_Last1, const _Elem *& _Mid1,
|
|
_Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
|
|
{ // convert [_First1, _Last1) to bytes [_First2, _Last)
|
|
_Mid1 = _First1, _Mid2 = _First2;
|
|
result _Ans = _Mid1 == _Last1 ? ok : partial;
|
|
int _Bytes;
|
|
|
|
while (_Mid1 != _Last1 && _Mid2 != _Last2)
|
|
if (___mb_cur_max_func() <= _Last2 - _Mid2)
|
|
if ((_Bytes = _Wcrtomb(_Mid2, *_Mid1,
|
|
&_State, &_Cvt)) <= 0)
|
|
return (error); // locale-specific wcrtomb failed
|
|
else
|
|
++_Mid1, _Mid2 += _Bytes, _Ans = ok;
|
|
else
|
|
{ // destination too small, convert into buffer
|
|
_Byte _Buf[MB_LEN_MAX];
|
|
_Statype _Stsave = _State;
|
|
|
|
if ((_Bytes = _Wcrtomb(_Buf, *_Mid1,
|
|
&_State, &_Cvt)) <= 0)
|
|
return (error); // locale-specific wcrtomb failed
|
|
else if (_Last2 - _Mid2 < _Bytes)
|
|
{ // converted too many, roll back and return previous
|
|
_State = _Stsave;
|
|
return (_Ans);
|
|
}
|
|
else
|
|
{ // copy converted bytes from buffer
|
|
memcpy(_Mid2, _Buf, _Bytes);
|
|
++_Mid1, _Mid2 += _Bytes, _Ans = ok;
|
|
}
|
|
}
|
|
return (_Ans);
|
|
}
|
|
|
|
virtual result do_unshift(_Statype& _State,
|
|
_Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const
|
|
{ // generate bytes to return to default shift state
|
|
_Mid2 = _First2;
|
|
result _Ans = ok;
|
|
int _Bytes;
|
|
_Byte _Buf[MB_LEN_MAX];
|
|
_Statype _Stsave = _State;
|
|
|
|
if ((_Bytes = _Wcrtomb(_Buf, L'\0', &_State, &_Cvt)) <= 0)
|
|
_Ans = error; // locale-specific wcrtomb failed
|
|
else if (_Last2 - _Mid2 < --_Bytes)
|
|
{ // converted too many, roll back and return
|
|
_State = _Stsave;
|
|
_Ans = partial;
|
|
}
|
|
else if (0 < _Bytes)
|
|
{ // copy converted bytes from buffer
|
|
memcpy(_Mid2, _Buf, _Bytes);
|
|
_Mid2 += _Bytes;
|
|
}
|
|
return (_Ans);
|
|
}
|
|
|
|
virtual int do_length(const _Statype& _State, const _Byte *_First1,
|
|
const _Byte *_Last1, size_t _Count) const _THROW0()
|
|
{ // return min(_Count, converted length of bytes [_First1, _Last1))
|
|
int _Wchars;
|
|
const _Byte *_Mid1;
|
|
_Statype _Mystate = _State;
|
|
|
|
for (_Wchars = 0, _Mid1 = _First1;
|
|
(size_t)_Wchars < _Count && _Mid1 != _Last1; )
|
|
{ // convert another wchar_t
|
|
int _Bytes;
|
|
_Elem _Ch;
|
|
|
|
switch (_Bytes = _Mbrtowc(&_Ch, _Mid1, _Last1 - _Mid1,
|
|
&_Mystate, &_Cvt))
|
|
{ // test result of locale-specific mbrtowc call
|
|
case -2: // partial conversion
|
|
return (_Wchars);
|
|
|
|
case -1: // failed conversion
|
|
return (_Wchars);
|
|
|
|
case 0: // converted null character
|
|
_Bytes = (int)::strlen(_Mid1) + 1;
|
|
// fall through
|
|
|
|
default: // converted _Bytes bytes to a wchar_t
|
|
_Mid1 += _Bytes, ++_Wchars;
|
|
}
|
|
}
|
|
return (_Wchars);
|
|
}
|
|
|
|
virtual bool do_always_noconv() const _THROW0()
|
|
{ // return true if conversions never change input
|
|
return (false);
|
|
}
|
|
|
|
virtual int do_max_length() const _THROW0()
|
|
{ // return maximum length required for a conversion (from codecvt)
|
|
return (MB_LEN_MAX);
|
|
}
|
|
|
|
virtual int do_encoding() const _THROW0()
|
|
{ // return length of code sequence (from codecvt)
|
|
return (0);
|
|
}
|
|
|
|
private:
|
|
_Locinfo::_Cvtvec _Cvt; // locale info passed to _Mbrtowc, _Wcrtomb
|
|
};
|
|
|
|
// TEMPLATE CLASS codecvt_byname
|
|
template<class _Elem,
|
|
class _Byte,
|
|
class _Statype>
|
|
class codecvt_byname
|
|
: public codecvt<_Elem, _Byte, _Statype>
|
|
{ // codecvt for named locale
|
|
public:
|
|
explicit codecvt_byname(const char *_Locname, size_t _Refs = 0)
|
|
: codecvt<_Elem, _Byte, _Statype>(_Locinfo(_Locname), _Refs)
|
|
{ // construct for named locale
|
|
}
|
|
|
|
_PROTECTED:
|
|
virtual ~codecvt_byname()
|
|
{ // destroy the object
|
|
}
|
|
};
|
|
|
|
// STRUCT ctype_base
|
|
struct _CRTIMP2 ctype_base
|
|
: public locale::facet
|
|
{ // base for ctype
|
|
enum
|
|
{ // constants for character classifications
|
|
alnum = _DI|_LO|_UP|_XA, alpha = _LO|_UP|_XA,
|
|
cntrl = _BB, digit = _DI, graph = _DI|_LO|_PU|_UP|_XA,
|
|
lower = _LO, print = _DI|_LO|_PU|_SP|_UP|_XA|_XD,
|
|
punct = _PU, space = _CN|_SP|_XS, upper = _UP,
|
|
xdigit = _XD};
|
|
typedef short mask; // to match <ctype.h>
|
|
|
|
ctype_base(size_t _Refs = 0)
|
|
: locale::facet(_Refs)
|
|
{ // default constructor
|
|
}
|
|
|
|
~ctype_base()
|
|
{ // destroy the object
|
|
}
|
|
};
|
|
|
|
// TEMPLATE CLASS ctype
|
|
template<class _Elem>
|
|
class ctype
|
|
: public ctype_base
|
|
{ // facet for classifying elements, converting cases
|
|
public:
|
|
typedef _Elem char_type;
|
|
|
|
bool is(mask _Maskval, _Elem _Ch) const
|
|
{ // test if element fits any mask classifications
|
|
return (do_is(_Maskval, _Ch));
|
|
}
|
|
|
|
const _Elem *is(const _Elem *_First, const _Elem *_Last,
|
|
mask *_Dest) const
|
|
{ // get mask sequence for elements in [_First, _Last)
|
|
return (do_is(_First, _Last, _Dest));
|
|
}
|
|
|
|
const _Elem *scan_is(mask _Maskval, const _Elem *_First,
|
|
const _Elem *_Last) const
|
|
{ // find first in [_First, _Last) that fits mask classification
|
|
return (do_scan_is(_Maskval, _First, _Last));
|
|
}
|
|
|
|
const _Elem *scan_not(mask _Maskval, const _Elem *_First,
|
|
const _Elem *_Last) const
|
|
{ // find first in [_First, _Last) not fitting mask classification
|
|
return (do_scan_not(_Maskval, _First, _Last));
|
|
}
|
|
|
|
_Elem tolower(_Elem _Ch) const
|
|
{ // convert element to lower case
|
|
return (do_tolower(_Ch));
|
|
}
|
|
|
|
const _Elem *tolower(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to lower case
|
|
return (do_tolower(_First, _Last));
|
|
}
|
|
|
|
_Elem toupper(_Elem _Ch) const
|
|
{ // convert element to upper case
|
|
return (do_toupper(_Ch));
|
|
}
|
|
|
|
const _Elem *toupper(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to upper case
|
|
return (do_toupper(_First, _Last));
|
|
}
|
|
|
|
_Elem widen(char _Byte) const
|
|
{ // widen char
|
|
return (do_widen(_Byte));
|
|
}
|
|
|
|
const char *widen(const char *_First, const char *_Last,
|
|
_Elem *_Dest) const
|
|
{ // widen chars in [_First, _Last)
|
|
return (do_widen(_First, _Last, _Dest));
|
|
}
|
|
|
|
char narrow(_Elem _Ch, char _Dflt = '\0') const
|
|
{ // narrow element to char
|
|
return (do_narrow(_Ch, _Dflt));
|
|
}
|
|
|
|
const _Elem *narrow(const _Elem *_First, const _Elem *_Last,
|
|
char _Dflt, char *_Dest) const
|
|
{ // narrow elements in [_First, _Last) to chars
|
|
return (do_narrow(_First, _Last, _Dflt, _Dest));
|
|
}
|
|
|
|
static locale::id id; // unique facet id
|
|
|
|
explicit ctype(size_t _Refs = 0)
|
|
: ctype_base(_Refs)
|
|
{ // construct from current locale
|
|
_Init(_Locinfo());
|
|
}
|
|
|
|
ctype(const _Locinfo& _Lobj, size_t _Refs = 0)
|
|
: ctype_base(_Refs)
|
|
{ // construct from specified locale
|
|
_Init(_Lobj);
|
|
}
|
|
|
|
static size_t __cdecl _Getcat(const locale::facet **_Ppf = 0)
|
|
{ // return locale category mask and construct standard facet
|
|
if (_Ppf != 0 && *_Ppf == 0)
|
|
*_Ppf = _NEW_CRT ctype<_Elem>;
|
|
return (_X_CTYPE);
|
|
}
|
|
|
|
_PROTECTED:
|
|
virtual ~ctype()
|
|
{ // destroy the object
|
|
if (_Ctype._Delfl)
|
|
free((void *)_Ctype._Table);
|
|
}
|
|
|
|
protected:
|
|
void _Init(const _Locinfo& _Lobj)
|
|
{ // initialize from _Lobj
|
|
_Ctype = _Lobj._Getctype();
|
|
}
|
|
|
|
virtual bool do_is(mask _Maskval, _Elem _Ch) const
|
|
{ // test if element fits any mask classifications
|
|
return ((_Ctype._Table[(unsigned char)narrow(_Ch)]
|
|
& _Maskval) != 0);
|
|
}
|
|
|
|
virtual const _Elem *do_is(const _Elem *_First, const _Elem *_Last,
|
|
mask *_Dest) const
|
|
{ // get mask sequence for elements in [_First, _Last)
|
|
for (; _First != _Last; ++_First, ++_Dest)
|
|
*_Dest = _Ctype._Table[(unsigned char)narrow(*_First)];
|
|
return (_First);
|
|
}
|
|
|
|
virtual const _Elem *do_scan_is(mask _Maskval, const _Elem *_First,
|
|
const _Elem *_Last) const
|
|
{ // find first in [_First, _Last) that fits mask classification
|
|
for (; _First != _Last && !is(_Maskval, *_First); ++_First)
|
|
;
|
|
return (_First);
|
|
}
|
|
|
|
virtual const _Elem *do_scan_not(mask _Maskval, const _Elem *_First,
|
|
const _Elem *_Last) const
|
|
{ // find first in [_First, _Last) not fitting mask classification
|
|
for (; _First != _Last && is(_Maskval, *_First); ++_First)
|
|
;
|
|
return (_First);
|
|
}
|
|
|
|
virtual _Elem do_tolower(_Elem _Ch) const
|
|
{ // convert element to lower case
|
|
return (widen((char)_Tolower((unsigned char)narrow(_Ch),
|
|
&_Ctype)));
|
|
}
|
|
|
|
virtual const _Elem *do_tolower(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to lower case
|
|
for (; _First != _Last; ++_First)
|
|
*_First = widen((char)_Tolower((unsigned char)narrow(*_First),
|
|
&_Ctype));
|
|
return ((const _Elem *)_First);
|
|
}
|
|
|
|
virtual _Elem do_toupper(_Elem _Ch) const
|
|
{ // convert element to upper case
|
|
return (widen((char)_Toupper((unsigned char)narrow(_Ch),
|
|
&_Ctype)));
|
|
}
|
|
|
|
virtual const _Elem *do_toupper(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to upper case
|
|
for (; _First != _Last; ++_First)
|
|
*_First = widen((char)_Toupper((unsigned char)narrow(*_First),
|
|
&_Ctype));
|
|
return ((const _Elem *)_First);
|
|
}
|
|
|
|
virtual _Elem do_widen(char _Byte) const
|
|
{ // widen char
|
|
return (_WIDEN(_Elem, _Byte));
|
|
}
|
|
|
|
virtual const char *do_widen(const char *_First, const char *_Last,
|
|
_Elem *_Dest) const
|
|
{ // widen chars in [_First, _Last)
|
|
for (; _First != _Last; ++_First, ++_Dest)
|
|
*_Dest = _WIDEN(_Elem, *_First);
|
|
return (_First);
|
|
}
|
|
|
|
virtual char do_narrow(_Elem _Ch, char) const
|
|
{ // narrow element to char
|
|
return (_NARROW(_Elem, _Ch));
|
|
}
|
|
|
|
virtual const _Elem *do_narrow(const _Elem *_First, const _Elem *_Last,
|
|
char, char *_Dest) const
|
|
{ // narrow elements in [_First, _Last) to chars
|
|
for (; _First != _Last; ++_First, ++_Dest)
|
|
*_Dest = _NARROW(_Elem, *_First);
|
|
return (_First);
|
|
}
|
|
|
|
private:
|
|
_Locinfo::_Ctypevec _Ctype; // locale info passed to _Tolower, etc.
|
|
};
|
|
|
|
// STATIC ctype::id OBJECT
|
|
template<class _Elem>
|
|
locale::id ctype<_Elem>::id;
|
|
|
|
// CLASS ctype<char>
|
|
template<> class _CRTIMP2 ctype<char>
|
|
: public ctype_base
|
|
{ // facet for classifying char elements, converting cases
|
|
typedef ctype<char> _Myt;
|
|
|
|
public:
|
|
typedef char _Elem;
|
|
typedef _Elem char_type;
|
|
|
|
bool is(mask _Maskval, _Elem _Ch) const
|
|
{ // test if element fits any mask classifications
|
|
return ((_Ctype._Table[(unsigned char)_Ch] & _Maskval) != 0);
|
|
}
|
|
|
|
const _Elem *is(const _Elem *_First, const _Elem *_Last,
|
|
mask *_Dest) const
|
|
{ // get mask sequence for elements in [_First, _Last)
|
|
for (; _First != _Last; ++_First, ++_Dest)
|
|
*_Dest = _Ctype._Table[(unsigned char)*_First];
|
|
return (_First);
|
|
}
|
|
|
|
const _Elem *scan_is(mask _Maskval, const _Elem *_First,
|
|
const _Elem *_Last) const
|
|
{ // find first in [_First, _Last) that fits mask classification
|
|
for (; _First != _Last && !is(_Maskval, *_First); ++_First)
|
|
;
|
|
return (_First);
|
|
}
|
|
|
|
const _Elem *scan_not(mask _Maskval, const _Elem *_First,
|
|
const _Elem *_Last) const
|
|
{ // find first in [_First, _Last) not fitting mask classification
|
|
for (; _First != _Last && is(_Maskval, *_First); ++_First)
|
|
;
|
|
return (_First);
|
|
}
|
|
|
|
_Elem tolower(_Elem _Ch) const
|
|
{ // convert element to lower case
|
|
return (do_tolower(_Ch));
|
|
}
|
|
|
|
const _Elem *tolower(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to lower case
|
|
return (do_tolower(_First, _Last));
|
|
}
|
|
|
|
_Elem toupper(_Elem _Ch) const
|
|
{ // convert element to upper case
|
|
return (do_toupper(_Ch));
|
|
}
|
|
|
|
const _Elem *toupper(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to upper case
|
|
return (do_toupper(_First, _Last));
|
|
}
|
|
|
|
_Elem widen(char _Byte) const
|
|
{ // widen char
|
|
return (do_widen(_Byte));
|
|
}
|
|
|
|
const _Elem *widen(const char *_First, const char *_Last,
|
|
_Elem *_Dest) const
|
|
{ // widen chars in [_First, _Last)
|
|
return (do_widen(_First, _Last, _Dest));
|
|
}
|
|
|
|
_Elem narrow(_Elem _Ch, char _Dflt = '\0') const
|
|
{ // narrow element to char
|
|
return (do_narrow(_Ch, _Dflt));
|
|
}
|
|
|
|
const _Elem *narrow(const _Elem *_First, const _Elem *_Last,
|
|
char _Dflt, char *_Dest) const
|
|
{ // narrow elements in [_First, _Last) to chars
|
|
return (do_narrow(_First, _Last, _Dflt, _Dest));
|
|
}
|
|
|
|
static locale::id id; // unique facet id
|
|
|
|
explicit ctype(const mask *_Table = 0, bool _Deletetable = false,
|
|
size_t _Refs = 0)
|
|
: ctype_base(_Refs)
|
|
{ // construct with specified table and delete flag for table
|
|
_Init(_Locinfo());
|
|
if (_Table != 0)
|
|
{ // replace existing char to mask table
|
|
_Tidy();
|
|
_Ctype._Table = _Table;
|
|
_Ctype._Delfl = _Deletetable ? -1 : 0;
|
|
}
|
|
}
|
|
|
|
ctype(const _Locinfo& _Lobj, size_t _Refs = 0)
|
|
: ctype_base(_Refs)
|
|
{ // construct from current locale
|
|
_Init(_Lobj);
|
|
}
|
|
|
|
static size_t __cdecl _Getcat(const locale::facet **_Ppf = 0)
|
|
{ // construct from specified locale
|
|
if (_Ppf != 0 && *_Ppf == 0)
|
|
*_Ppf = _NEW_CRT ctype<_Elem>;
|
|
return (_X_CTYPE);
|
|
}
|
|
|
|
static const size_t table_size; // size of _Ctype._Table (char to mask)
|
|
|
|
_PROTECTED:
|
|
virtual ~ctype()
|
|
{ // destroy the object
|
|
_Tidy();
|
|
}
|
|
|
|
protected:
|
|
void _Init(const _Locinfo& _Lobj)
|
|
{ // initialize from _Lobj
|
|
_Ctype = _Lobj._Getctype();
|
|
}
|
|
|
|
void _Tidy()
|
|
{ // free any allocated storage
|
|
if (0 < _Ctype._Delfl)
|
|
free((void *)_Ctype._Table);
|
|
else if (_Ctype._Delfl < 0)
|
|
delete[] (void *)_Ctype._Table;
|
|
}
|
|
|
|
virtual _Elem do_tolower(_Elem _Ch) const
|
|
{ // convert element to lower case
|
|
return ((_Elem)_Tolower((unsigned char)_Ch, &_Ctype));
|
|
}
|
|
|
|
virtual const _Elem *do_tolower(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to lower case
|
|
for (; _First != _Last; ++_First)
|
|
*_First = (_Elem)_Tolower((unsigned char)*_First, &_Ctype);
|
|
return ((const _Elem *)_First);
|
|
}
|
|
|
|
virtual _Elem do_toupper(_Elem _Ch) const
|
|
{ // convert element to upper case
|
|
return ((_Elem)_Toupper((unsigned char)_Ch, &_Ctype));
|
|
}
|
|
|
|
virtual const _Elem *do_toupper(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to upper case
|
|
for (; _First != _Last; ++_First)
|
|
*_First = (_Elem)_Toupper((unsigned char)*_First, &_Ctype);
|
|
return ((const _Elem *)_First);
|
|
}
|
|
|
|
virtual _Elem do_widen(char _Byte) const
|
|
{ // widen char
|
|
return (_Byte);
|
|
}
|
|
|
|
virtual const _Elem *do_widen(const char *_First, const char *_Last,
|
|
_Elem *_Dest) const
|
|
{ // widen chars in [_First, _Last)
|
|
memcpy(_Dest, _First, _Last - _First);
|
|
return (_Last);
|
|
}
|
|
|
|
virtual _Elem do_narrow(_Elem _Ch, char) const
|
|
{ // narrow char
|
|
return (_Ch);
|
|
}
|
|
|
|
virtual const _Elem *do_narrow(const _Elem *_First, const _Elem *_Last,
|
|
char, char *_Dest) const
|
|
{ // narrow elements in [_First, _Last) to chars
|
|
memcpy(_Dest, _First, _Last - _First);
|
|
return (_Last);
|
|
}
|
|
|
|
const mask *table() const _THROW0()
|
|
{ // return address of char to mask table
|
|
return (_Ctype._Table);
|
|
}
|
|
|
|
static const mask *__cdecl classic_table() _THROW0()
|
|
{ // return address of char to mask table for "C" locale
|
|
const _Myt& _Fac = _USE(locale::classic(), _Myt);
|
|
return (_Fac.table());
|
|
}
|
|
|
|
private:
|
|
_Locinfo::_Ctypevec _Ctype; // information
|
|
};
|
|
|
|
// CLASS ctype<wchar_t>
|
|
template<> class _CRTIMP2 ctype<wchar_t>
|
|
: public ctype_base
|
|
{ // facet for classifying wchar_t elements, converting cases
|
|
typedef ctype<wchar_t> _Myt;
|
|
|
|
public:
|
|
typedef wchar_t _Elem;
|
|
typedef _Elem char_type;
|
|
|
|
bool is(mask _Maskval, _Elem _Ch) const
|
|
{ // test if element fits any mask classifications
|
|
return (do_is(_Maskval, _Ch));
|
|
}
|
|
|
|
const _Elem *is(const _Elem *_First, const _Elem *_Last,
|
|
mask *_Dest) const
|
|
{ // get mask sequence for elements in [_First, _Last)
|
|
return (do_is(_First, _Last, _Dest));
|
|
}
|
|
|
|
const _Elem *scan_is(mask _Maskval, const _Elem *_First,
|
|
const _Elem *_Last) const
|
|
{ // find first in [_First, _Last) that fits mask classification
|
|
return (do_scan_is(_Maskval, _First, _Last));
|
|
}
|
|
|
|
const _Elem *scan_not(mask _Maskval, const _Elem *_First,
|
|
const _Elem *_Last) const
|
|
{ // find first in [_First, _Last) not fitting mask classification
|
|
return (do_scan_not(_Maskval, _First, _Last));
|
|
}
|
|
|
|
_Elem tolower(_Elem _Ch) const
|
|
{ // convert element to lower case
|
|
return (do_tolower(_Ch));
|
|
}
|
|
|
|
const _Elem *tolower(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to lower case
|
|
return (do_tolower(_First, _Last));
|
|
}
|
|
|
|
_Elem toupper(_Elem _Ch) const
|
|
{ // convert element to upper case
|
|
return (do_toupper(_Ch));
|
|
}
|
|
|
|
const _Elem *toupper(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to upper case
|
|
return (do_toupper(_First, _Last));
|
|
}
|
|
|
|
_Elem widen(char _Byte) const
|
|
{ // widen char
|
|
return (do_widen(_Byte));
|
|
}
|
|
|
|
const char *widen(const char *_First, const char *_Last,
|
|
_Elem *_Dest) const
|
|
{ // widen chars in [_First, _Last)
|
|
return (do_widen(_First, _Last, _Dest));
|
|
}
|
|
|
|
char narrow(_Elem _Ch, char _Dflt = '\0') const
|
|
{ // narrow element to char
|
|
return (do_narrow(_Ch, _Dflt));
|
|
}
|
|
|
|
const _Elem *narrow(const _Elem *_First, const _Elem *_Last,
|
|
char _Dflt, char *_Dest) const
|
|
{ // narrow elements in [_First, _Last) to chars
|
|
return (do_narrow(_First, _Last, _Dflt, _Dest));
|
|
}
|
|
|
|
static locale::id id; // unique facet id
|
|
|
|
explicit ctype(size_t _Refs = 0)
|
|
: ctype_base(_Refs)
|
|
{ // construct from current locale
|
|
_Init(_Locinfo());
|
|
}
|
|
|
|
ctype(const _Locinfo& _Lobj, size_t _Refs = 0)
|
|
: ctype_base(_Refs)
|
|
{ // construct from specified locale
|
|
_Init(_Lobj);
|
|
}
|
|
|
|
static size_t __cdecl _Getcat(const locale::facet **_Ppf = 0)
|
|
{ // return locale category mask and construct standard facet
|
|
if (_Ppf != 0 && *_Ppf == 0)
|
|
*_Ppf = _NEW_CRT ctype<_Elem>;
|
|
return (_X_CTYPE);
|
|
}
|
|
|
|
_PROTECTED:
|
|
virtual ~ctype()
|
|
{ // destroy the object
|
|
if (_Ctype._Delfl)
|
|
free((void *)_Ctype._Table);
|
|
}
|
|
|
|
protected:
|
|
void _Init(const _Locinfo& _Lobj)
|
|
{ // initialize from _Lobj
|
|
_Ctype = _Lobj._Getctype();
|
|
_Cvt = _Lobj._Getcvt();
|
|
}
|
|
|
|
virtual bool do_is(mask _Maskval, _Elem _Ch) const
|
|
{ // test if element fits any mask classifications
|
|
return ((_Getwctype(_Ch, &_Ctype) & _Maskval) != 0);
|
|
}
|
|
|
|
virtual const _Elem *do_is(const _Elem *_First, const _Elem *_Last,
|
|
mask *_Dest) const
|
|
{ // get mask sequence for elements in [_First, _Last)
|
|
return (_Getwctypes(_First, _Last, _Dest, &_Ctype));
|
|
}
|
|
|
|
virtual const _Elem *do_scan_is(mask _Maskval, const _Elem *_First,
|
|
const _Elem *_Last) const
|
|
{ // find first in [_First, _Last) that fits mask classification
|
|
for (; _First != _Last && !is(_Maskval, *_First); ++_First)
|
|
;
|
|
return (_First);
|
|
}
|
|
|
|
virtual const _Elem *do_scan_not(mask _Maskval, const _Elem *_First,
|
|
const _Elem *_Last) const
|
|
{ // find first in [_First, _Last) not fitting mask classification
|
|
for (; _First != _Last && is(_Maskval, *_First); ++_First)
|
|
;
|
|
return (_First);
|
|
}
|
|
|
|
virtual _Elem do_tolower(_Elem _Ch) const
|
|
{ // convert element to lower case
|
|
return (widen((char)_Tolower((unsigned char)narrow(_Ch),
|
|
&_Ctype)));
|
|
}
|
|
|
|
virtual const _Elem *do_tolower(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to lower case
|
|
for (; _First != _Last; ++_First)
|
|
*_First = widen((char)_Tolower((unsigned char)narrow(*_First),
|
|
&_Ctype));
|
|
return ((const _Elem *)_First);
|
|
}
|
|
|
|
virtual _Elem do_toupper(_Elem _Ch) const
|
|
{ // convert element to upper case
|
|
return (widen((char)_Toupper((unsigned char)narrow(_Ch),
|
|
&_Ctype)));
|
|
}
|
|
|
|
virtual const _Elem *do_toupper(_Elem *_First, const _Elem *_Last) const
|
|
{ // convert [_First, _Last) in place to upper case
|
|
for (; _First != _Last; ++_First)
|
|
*_First = widen((char)_Toupper((unsigned char)narrow(*_First),
|
|
&_Ctype));
|
|
return ((const _Elem *)_First);
|
|
}
|
|
|
|
virtual _Elem do_widen(char _Byte) const
|
|
{ // widen char
|
|
_Mbstinit(_Mbst);
|
|
wchar_t _Wc;
|
|
return (_Mbrtowc(&_Wc, &_Byte, 1, &_Mbst, &_Cvt) <= 0
|
|
? (wchar_t)(unsigned char)_Byte : _Wc);
|
|
}
|
|
|
|
virtual const char *do_widen(const char *_First, const char *_Last,
|
|
_Elem *_Dest) const
|
|
{ // widen chars in [_First, _Last)
|
|
_Mbstinit(_Mbst);
|
|
while (_First != _Last)
|
|
{
|
|
int _Bytes;
|
|
|
|
switch (_Bytes = _Mbrtowc(_Dest, _First, _Last - _First,
|
|
&_Mbst, &_Cvt))
|
|
{ // test result of locale-specific mbrtowc call
|
|
case -2: // partial conversion
|
|
case -1: // failed conversion
|
|
return (_First);
|
|
|
|
case 0: // converted null character
|
|
_Bytes = (int)::strlen(_First) + 1;
|
|
// fall through
|
|
|
|
default: // converted _Bytes bytes to a wchar_t
|
|
_First += _Bytes, ++_Dest;
|
|
}
|
|
}
|
|
return (_First);
|
|
}
|
|
|
|
virtual char do_narrow(_Elem _Ch, char _Dflt) const
|
|
{ // narrow element to char
|
|
char _Buf[MB_LEN_MAX];
|
|
_Mbstinit(_Mbst);
|
|
return (_Wcrtomb(_Buf, _Ch, &_Mbst, &_Cvt) != 1
|
|
? _Dflt : _Buf[0]);
|
|
}
|
|
|
|
virtual const _Elem *do_narrow(const _Elem *_First, const _Elem *_Last,
|
|
char _Dflt, char *_Dest) const
|
|
{ // narrow elements in [_First, _Last) to chars
|
|
_Mbstinit(_Mbst);
|
|
for (; _First != _Last; ++_First)
|
|
{
|
|
int _Bytes;
|
|
if ((_Bytes = _Wcrtomb(_Dest, *_First, &_Mbst, &_Cvt)) <= 0)
|
|
{
|
|
_Bytes = 1;
|
|
*_Dest = _Dflt;
|
|
}
|
|
_Dest += _Bytes;
|
|
}
|
|
return (_First);
|
|
}
|
|
|
|
private:
|
|
_Locinfo::_Ctypevec _Ctype; // locale info passed to _Tolower, etc.
|
|
_Locinfo::_Cvtvec _Cvt; // conversion information
|
|
};
|
|
|
|
// TEMPLATE CLASS ctype_byname
|
|
template<class _Elem>
|
|
class ctype_byname
|
|
: public ctype<_Elem>
|
|
{ // ctype for named locale
|
|
public:
|
|
explicit ctype_byname(const char *_Locname, size_t _Refs = 0)
|
|
: ctype<_Elem>(_Locinfo(_Locname), _Refs)
|
|
{ // construct from named locale
|
|
}
|
|
|
|
_PROTECTED:
|
|
virtual ~ctype_byname()
|
|
{ // destroy the object
|
|
}
|
|
};
|
|
|
|
#ifdef _DLL_CPPLIB
|
|
template class _CRTIMP2 codecvt<char, char, int>;
|
|
#endif // _DLL_CPPLIB
|
|
_STD_END
|
|
#pragma warning(pop)
|
|
#pragma pack(pop)
|
|
|
|
#endif /* _XLOCALE_ */
|
|
|
|
/*
|
|
* Copyright (c) 1992-2001 by P.J. Plauger. ALL RIGHTS RESERVED.
|
|
* Consult your license regarding permissions and restrictions.
|
|
V3.10:0009 */
|