// xlocinfo internal header // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #pragma once #ifndef _XLOCINFO_ #define _XLOCINFO_ #include #if _STL_COMPILER_PREPROCESSOR #include #include #include #include #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new _STD_BEGIN // CLASS _Timevec class _CRTIMP2_PURE_IMPORT _Timevec { // smart pointer to information used by _Strftime public: explicit __CLR_OR_THIS_CALL _Timevec(void* _Ptr = nullptr) : _Timeptr(_Ptr) {} __CLR_OR_THIS_CALL _Timevec(const _Timevec& _Right) : _Timeptr(nullptr) { *this = _Right; } __CLR_OR_THIS_CALL ~_Timevec() noexcept { _CSTD free(_Timeptr); } _Timevec& __CLR_OR_THIS_CALL operator=(const _Timevec& _Right) { // transfer ownership of _Timeptr from _Right if (this != &_Right) { _CSTD free(_Timeptr); _Timeptr = _Right._Timeptr; const_cast<_Timevec&>(_Right)._Timeptr = nullptr; // TRANSITION, should be movable-only } return *this; } void* __CLR_OR_THIS_CALL _Getptr() const { return _Timeptr; } private: void* _Timeptr; // pointer to time information }; // CLASS TEMPLATE _Yarn template class _CRTIMP2_PURE_IMPORT _Yarn { // wrap a NTCTS public: __CLR_OR_THIS_CALL _Yarn() noexcept : _Myptr(nullptr), _Nul(0) {} __CLR_OR_THIS_CALL _Yarn(const _Yarn& _Right) noexcept : _Myptr(nullptr), _Nul(0) { *this = _Right; } __CLR_OR_THIS_CALL _Yarn(const _Elem* _Right) noexcept : _Myptr(nullptr), _Nul(0) { *this = _Right; } _Yarn& __CLR_OR_THIS_CALL operator=(const _Yarn& _Right) noexcept { return *this = _Right._Myptr; } _Yarn& __CLR_OR_THIS_CALL operator=(const _Elem* _Right) noexcept { if (_Myptr != _Right) { // new value, discard old and copy new _Tidy(); if (_Right) { // new is not empty, copy it const _Elem* _Ptr = _Right; while (*_Ptr != _Elem{}) { ++_Ptr; } const auto _Count = (++_Ptr - _Right) * sizeof(_Elem); #ifdef _DEBUG _Myptr = static_cast<_Elem*>(_malloc_dbg(_Count, _CRT_BLOCK, __FILE__, __LINE__)); #else // _DEBUG _Myptr = static_cast<_Elem*>(_CSTD malloc(_Count)); #endif // _DEBUG if (_Myptr) { _CSTD memcpy(_Myptr, _Right, _Count); } } } return *this; } __CLR_OR_THIS_CALL ~_Yarn() noexcept { _Tidy(); } _NODISCARD bool __CLR_OR_THIS_CALL empty() const noexcept { return _Myptr == nullptr; } _Ret_z_ const _Elem* __CLR_OR_THIS_CALL c_str() const noexcept { return _Myptr ? _Myptr : &_Nul; } _NODISCARD bool __CLR_OR_THIS_CALL _Empty() const noexcept { return _Myptr == nullptr; } _Ret_z_ const _Elem* __CLR_OR_THIS_CALL _C_str() const noexcept { return _Myptr ? _Myptr : &_Nul; } private: void __CLR_OR_THIS_CALL _Tidy() noexcept { if (_Myptr) { #ifdef _DEBUG _free_dbg(_Myptr, _CRT_BLOCK); #else // _DEBUG _CSTD free(_Myptr); #endif // _DEBUG } _Myptr = nullptr; } _Elem* _Myptr; // pointer to allocated string _Elem _Nul; // nul terminator for unallocated string }; // CLASS _Locinfo class _CRTIMP2_PURE_IMPORT _Locinfo { // summary of all stuff specific to a locale used by standard facets public: using _Collvec = ::_Collvec; using _Ctypevec = ::_Ctypevec; using _Cvtvec = ::_Cvtvec; using _Timevec = _STD _Timevec; static void __CLRCALL_PURE_OR_CDECL _Locinfo_ctor(_Locinfo*, const char*); static void __CLRCALL_PURE_OR_CDECL _Locinfo_ctor(_Locinfo*, int, const char*); static void __CLRCALL_PURE_OR_CDECL _Locinfo_dtor(_Locinfo*); static _Locinfo& __CLRCALL_PURE_OR_CDECL _Locinfo_Addcats(_Locinfo*, int, const char*); __CLR_OR_THIS_CALL _Locinfo(const char* _Pch = "C") #ifndef _M_CEE : _Lock(_LOCK_LOCALE) #endif // _M_CEE { if (_Pch) { _Locinfo_ctor(this, _Pch); return; } _Xruntime_error("bad locale name"); } __CLR_OR_THIS_CALL _Locinfo(int _Cat, const char* _Pch) #ifndef _M_CEE : _Lock(_LOCK_LOCALE) #endif // _M_CEE { if (_Pch) { _Locinfo_ctor(this, _Cat, _Pch); return; } _Xruntime_error("bad locale name"); } __CLR_OR_THIS_CALL ~_Locinfo() noexcept { _Locinfo_dtor(this); } _Locinfo& __CLR_OR_THIS_CALL _Addcats(int _Cat, const char* _Pch) { // add facets matching category mask and NTBS if (_Pch) { return _Locinfo_Addcats(this, _Cat, _Pch); } _Xruntime_error("bad locale name"); } const char* __CLR_OR_THIS_CALL _Getname() const { return _Newlocname._C_str(); } _Collvec __CLR_OR_THIS_CALL _Getcoll() const { return ::_Getcoll(); } _Ctypevec __CLR_OR_THIS_CALL _Getctype() const { return ::_Getctype(); } _Cvtvec __CLR_OR_THIS_CALL _Getcvt() const { return ::_Getcvt(); } const lconv* __CLR_OR_THIS_CALL _Getlconv() const { return localeconv(); } _Timevec __CLR_OR_THIS_CALL _Gettnames() const { return _Timevec(::_Gettnames()); } const char* __CLR_OR_THIS_CALL _Getdays() const { const char* _Ptr = ::_Getdays(); if (_Ptr) { // capture names and free allocated C string const_cast<_Locinfo*>(this)->_Days = _Ptr; _CSTD free(const_cast(_Ptr)); } return !_Days._Empty() ? _Days._C_str() : ":Sun:Sunday:Mon:Monday:Tue:Tuesday:Wed:Wednesday" ":Thu:Thursday:Fri:Friday:Sat:Saturday"; } const char* __CLR_OR_THIS_CALL _Getmonths() const { const char* _Ptr = ::_Getmonths(); if (_Ptr) { // capture names and free allocated C string const_cast<_Locinfo*>(this)->_Months = _Ptr; _CSTD free(const_cast(_Ptr)); } return !_Months._Empty() ? _Months._C_str() : ":Jan:January:Feb:February:Mar:March" ":Apr:April:May:May:Jun:June" ":Jul:July:Aug:August:Sep:September" ":Oct:October:Nov:November:Dec:December"; } const char* __CLR_OR_THIS_CALL _Getfalse() const { return "false"; } const char* __CLR_OR_THIS_CALL _Gettrue() const { return "true"; } int __CLR_OR_THIS_CALL _Getdateorder() const { return ::_Getdateorder(); } _Timevec __CLR_OR_THIS_CALL _W_Gettnames() const { return _Timevec(::_W_Gettnames()); } const unsigned short* __CLR_OR_THIS_CALL _W_Getdays() const { const wchar_t* _Ptr = ::_W_Getdays(); if (_Ptr) { // capture names and free allocated C string const_cast<_Locinfo*>(this)->_W_Days = _Ptr; _CSTD free(const_cast(_Ptr)); } const wchar_t* _Ret; if (_W_Days._Empty()) { _Ret = L":Sun:Sunday:Mon:Monday:Tue:Tuesday:Wed:Wednesday:Thu:Thursday:Fri:Friday:Sat:Saturday"; } else { _Ret = _W_Days._C_str(); } return reinterpret_cast(_Ret); } const unsigned short* __CLR_OR_THIS_CALL _W_Getmonths() const { const wchar_t* _Ptr = ::_W_Getmonths(); if (_Ptr) { // capture names and free allocated C string const_cast<_Locinfo*>(this)->_W_Months = _Ptr; _CSTD free(const_cast(_Ptr)); } const wchar_t* _Ret; if (_W_Months._Empty()) { _Ret = L":Jan:January:Feb:February:Mar:March:Apr:April:May:May:Jun:June" L":Jul:July:Aug:August:Sep:September:Oct:October:Nov:November:Dec:December"; } else { _Ret = _W_Months._C_str(); } return reinterpret_cast(_Ret); } _Locinfo(const _Locinfo&) = delete; _Locinfo& operator=(const _Locinfo&) = delete; private: #ifdef _M_CEE _EmptyLockit _Empty_lock; // to maintain same size #else // _M_CEE _Lockit _Lock; // thread lock, because global locale is altered #endif // _M_CEE _Yarn _Days; // weekday names _Yarn _Months; // month names _Yarn _W_Days; // wide weekday names _Yarn _W_Months; // wide month names _Yarn _Oldlocname; // old locale name to revert to on destruction _Yarn _Newlocname; // new locale name for this object }; // FUNCTION TEMPLATE _LStrcoll template int __CRTDECL _LStrcoll(const _Elem* _First1, const _Elem* _Last1, const _Elem* _First2, const _Elem* _Last2, const _Locinfo::_Collvec*) { // perform locale-specific comparison of _Elem sequences for (; _First1 != _Last1 && _First2 != _Last2; ++_First1, ++_First2) { if (*_First1 < *_First2) { return -1; // [_First1, _Last1) < [_First2, _Last2) } else if (*_First2 < *_First1) { return +1; // [_First1, _Last1) > [_First2, _Last2) } } return _First2 != _Last2 ? -1 : _First1 != _Last1 ? +1 : 0; } template <> inline int __CRTDECL _LStrcoll(const char* _First1, const char* _Last1, const char* _First2, const char* _Last2, const _Locinfo::_Collvec* _Vector) { // perform locale-specific comparison of char sequences return _Strcoll(_First1, _Last1, _First2, _Last2, _Vector); } template <> inline int __CRTDECL _LStrcoll(const wchar_t* _First1, const wchar_t* _Last1, const wchar_t* _First2, const wchar_t* _Last2, const _Locinfo::_Collvec* _Vector) { // perform locale-specific comparison of wchar_t sequences return _Wcscoll(_First1, _Last1, _First2, _Last2, _Vector); } // FUNCTION TEMPLATE _LStrxfrm template size_t __CRTDECL _LStrxfrm(_Elem* _First1, _Elem* _Last1, const _Elem* _First2, const _Elem* _Last2, const _Locinfo::_Collvec*) { // perform locale-specific transform of _Elems [_First1, _Last1) const ptrdiff_t _Count = _Last2 - _First2; if (_Count <= _Last1 - _First1) { _CSTD memcpy(_First1, _First2, _Count * sizeof(_Elem)); } return _Count; } template <> inline size_t __CRTDECL _LStrxfrm(_Out_writes_(_Last1 - _First1) _Post_readable_size_(return ) char* _First1, _In_z_ char* _Last1, const char* _First2, const char* _Last2, const _Locinfo::_Collvec* _Vector) { // perform locale-specific transform of chars [_First1, _Last1) return _Strxfrm(_First1, _Last1, _First2, _Last2, _Vector); } template <> inline size_t __CRTDECL _LStrxfrm(_Out_writes_(_Last1 - _First1) _Post_readable_size_(return ) wchar_t* _First1, _In_z_ wchar_t* _Last1, const wchar_t* _First2, const wchar_t* _Last2, const _Locinfo::_Collvec* _Vector) { // perform locale-specific transform of wchar_ts [_First1, _Last1) return _Wcsxfrm(_First1, _Last1, _First2, _Last2, _Vector); } _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _STL_COMPILER_PREPROCESSOR #endif // _XLOCINFO_