// xlocale internal header (from ) #pragma once #ifndef _XLOCALE_ #define _XLOCALE_ #include #include #include #include #include #include #pragma pack(push,8) #pragma warning(push,3) _STD_BEGIN // TEMPLATE CLASS _Locbase template 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 const int _Locbase<_Dummy>::collate; template const int _Locbase<_Dummy>::ctype; template const int _Locbase<_Dummy>::monetary; template const int _Locbase<_Dummy>::numeric; template const int _Locbase<_Dummy>::time; template const int _Locbase<_Dummy>::messages; template const int _Locbase<_Dummy>::all; template const int _Locbase<_Dummy>::none; // CLASS locale class _CRTIMP2 locale : public _Locbase { // 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 #ifdef _CRTBLD_NATIVE_WCHAR_T static void __cdecl _Makeushloc(const _Locinfo&, category, _Locimp *, const locale *); // make unsigned short facets #endif 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 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 >(*this); return (_Fac.compare(_Left.c_str(), _Left.c_str() + _Left.size(), _Right.c_str(), _Right.c_str() + _Right.size()) < 0); } template 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 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 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(loc) /* get facet reference from locale */ template 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 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(V)) /* convert T to char */ template 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)); } #ifdef _CRTBLD_NATIVE_WCHAR_T template<> inline char _Narrow(unsigned short _Ch) { // convert unsigned short to char (using current locale, no state) return ((char)wctob(_Ch)); } #endif // TEMPLATE FUNCTION _Widen #define _WIDEN(T, V) _Widen(V, (T *)0) /* convert char to T */ template 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)); } #ifdef _CRTBLD_NATIVE_WCHAR_T template<> inline unsigned short _Widen(char _Ch, unsigned short *) { // convert char to unsigned short (using current locale, no state) return (btowc(_Ch)); } #endif // TEMPLATE FUNCTION _Getloctxt template 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 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); } #ifdef _CRTBLD_NATIVE_WCHAR_T template<> inline unsigned short *__cdecl _Maklocstr(const char *_Ptr, unsigned short *, const _Locinfo::_Cvtvec &_Cvt) { // convert C string to unsigned short 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 ((unsigned short *)_Ptrdest); } #endif // 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 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 }; // STATIC codecvt::id OBJECT template locale::id codecvt<_Elem, _Byte, _Statype>::id; // CLASS codecvt template<> class _CRTIMP2 codecvt : 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 }; #ifdef _CRTBLD_NATIVE_WCHAR_T // CLASS codecvt template<> class _CRTIMP2 codecvt : public codecvt_base { // facet for converting between unsigned short and char (_Byte) sequences public: typedef unsigned short _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((wchar_t *)_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 an unsigned short _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 unsigned short int _Bytes; _Elem _Ch; switch (_Bytes = _Mbrtowc((wchar_t *)&_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 an unsigned short _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 }; #endif // TEMPLATE CLASS codecvt_byname template 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_base(size_t _Refs = 0) : locale::facet(_Refs) { // default constructor } ~ctype_base() { // destroy the object } }; // TEMPLATE CLASS ctype template 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 locale::id ctype<_Elem>::id; // CLASS ctype template<> class _CRTIMP2 ctype : public ctype_base { // facet for classifying char elements, converting cases typedef ctype _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 template<> class _CRTIMP2 ctype : public ctype_base { // facet for classifying wchar_t elements, converting cases typedef ctype _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 }; #ifdef _CRTBLD_NATIVE_WCHAR_T // CLASS ctype template<> class _CRTIMP2 ctype : public ctype_base { // facet for classifying unsigned short elements, converting cases typedef ctype _Myt; public: typedef unsigned short _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 ((const _Elem *)_Getwctypes((const wchar_t *)_First, (const wchar_t *)_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); unsigned short _Wc; return (_Mbrtowc((wchar_t *)&_Wc, &_Byte, 1, &_Mbst, &_Cvt) <= 0 ? (unsigned short)(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((wchar_t *)_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 }; #endif // TEMPLATE CLASS ctype_byname template 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 #ifdef __FORCE_INSTANCE template class _CRTIMP2 codecvt; #endif // __FORCE_INSTANCE #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 */