STL/stl/inc/xloctime

1261 строка
48 KiB
C++
Исходник Обычный вид История

2019-09-05 01:57:56 +03:00
// xloctime internal header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef _XLOCTIME_
#define _XLOCTIME_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include <ctime>
#include <iterator>
2019-09-05 01:57:56 +03:00
#include <xlocnum>
#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
template <class _InIt, class _Elem>
ios_base::iostate _Getint_v2(_InIt& _First, _InIt& _Last, int _Lo, int _Hi, int& _Val, int& _Digits_read,
const ctype<_Elem>& _Ctype_fac) { // get integer in range [_Lo, _Hi] from [_First, _Last)
_STL_INTERNAL_CHECK(0 <= _Hi && _Hi <= 9999);
const int _Hi_digits = (_Hi <= 9 ? 1 : _Hi <= 99 ? 2 : _Hi <= 999 ? 3 : 4);
char _Ac[_Max_int_dig];
char* _Ep;
char* _Ptr = _Ac;
char _Ch;
_Digits_read = 0;
while (_First != _Last && _Digits_read < _Hi_digits && _Ctype_fac.is(ctype_base::space, *_First)) {
++_First;
++_Digits_read;
}
if (_First != _Last && _Digits_read < _Hi_digits) {
if ((_Ch = _Ctype_fac.narrow(*_First)) == '+') { // copy plus sign
*_Ptr++ = '+';
++_First;
} else if (_Ch == '-') { // copy minus sign
*_Ptr++ = '-';
++_First;
}
}
for (; _First != _Last && _Digits_read < _Hi_digits && _Ctype_fac.narrow(*_First) == '0'; ++_First) {
++_Digits_read; // strip leading zeros
}
if (_Digits_read > 0) {
*_Ptr++ = '0'; // replace one or more with single zero
}
for (char* const _Pe = &_Ac[_Max_int_dig - 1];
_First != _Last && '0' <= (_Ch = _Ctype_fac.narrow(*_First)) && _Ch <= '9' && _Digits_read < _Hi_digits;
++_Digits_read, (void) ++_First) { // copy digits
*_Ptr = _Ch;
if (_Ptr < _Pe) {
++_Ptr; // drop trailing digits if already too large
}
}
if (_Digits_read == 0) {
_Ptr = _Ac;
}
*_Ptr = '\0';
int _Errno = 0;
const long _Ans = _CSTD _Stolx(_Ac, &_Ep, 10, &_Errno);
ios_base::iostate _State = ios_base::goodbit;
if (_First == _Last) {
_State |= ios_base::eofbit;
}
if (_Ep == _Ac || _Errno != 0 || _Ans < _Lo || _Hi < _Ans) {
_State |= ios_base::failbit; // bad conversion
} else {
_Val = _Ans; // store valid result
}
return _State;
}
_EXPORT_STD extern "C++" struct _CRTIMP2_PURE_IMPORT time_base // base class for time_get
: locale::facet // TRANSITION, ABI, shouldn't be derived from locale::facet
{
2019-09-05 01:57:56 +03:00
enum dateorder { // constants for different orders of date components
no_order,
dmy,
mdy,
ymd,
ydm
};
__CLR_OR_THIS_CALL time_base(size_t _Refs = 0) noexcept // strengthened
: locale::facet(_Refs) {}
2019-09-05 01:57:56 +03:00
__CLR_OR_THIS_CALL ~time_base() noexcept override {}
2019-09-05 01:57:56 +03:00
};
_EXPORT_STD extern "C++" template <class _Elem, class _InIt = istreambuf_iterator<_Elem, char_traits<_Elem>>>
2019-09-05 01:57:56 +03:00
class time_get : public time_base { // facet for converting text to encoded times
private:
friend _Tidy_guard<time_get>;
public:
static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);
2019-09-05 01:57:56 +03:00
using char_type = _Elem;
using iter_type = _InIt;
using _Ctype = ctype<_Elem>;
__PURE_APPDOMAIN_GLOBAL static locale::id id; // unique facet id
dateorder __CLR_OR_THIS_CALL date_order() const {
return do_date_order();
}
_InIt __CLR_OR_THIS_CALL get_time(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
tm* _Pt) const { // get time of day from [_First, _Last) into _Pt
return do_get_time(_First, _Last, _Iosbase, _State, _Pt);
}
_InIt __CLR_OR_THIS_CALL get_date(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
tm* _Pt) const { // get date from [_First, _Last) into _Pt
return do_get_date(_First, _Last, _Iosbase, _State, _Pt);
}
_InIt __CLR_OR_THIS_CALL get_weekday(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
tm* _Pt) const { // get weekday from [_First, _Last) into _Pt
return do_get_weekday(_First, _Last, _Iosbase, _State, _Pt);
}
_InIt __CLR_OR_THIS_CALL get_monthname(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
tm* _Pt) const { // get month from [_First, _Last) into _Pt
return do_get_monthname(_First, _Last, _Iosbase, _State, _Pt);
}
_InIt __CLR_OR_THIS_CALL get_year(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
tm* _Pt) const { // get year from [_First, _Last) into _Pt
return do_get_year(_First, _Last, _Iosbase, _State, _Pt);
}
_InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State, tm* _Pt,
char _Specifier, char _Modifier = '\0') const { // get formatted time for _Specifier/_Modifier
return do_get(_First, _Last, _Iosbase, _State, _Pt, _Specifier, _Modifier);
}
_InIt __CLR_OR_THIS_CALL get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State, tm* _Pt,
const _Elem* _Fmtfirst, const _Elem* _Fmtlast) const { // get formatted time for format string
_Adl_verify_range(_Fmtfirst, _Fmtlast);
const _Ctype& _Ctype_fac = _STD use_facet<_Ctype>(_Iosbase.getloc());
_State = ios_base::goodbit;
for (; _Fmtfirst != _Fmtlast; ++_Fmtfirst) {
if (_State != ios_base::goodbit) {
// N4950 [locale.time.get.members]/8.2
// _State is fail, eof, or bad. Do not proceed to the next fields. Return with current _State.
break;
} else if (_First == _Last) {
// N4950 [locale.time.get.members]/8.3
_State = ios_base::eofbit | ios_base::failbit;
break;
} else if (_Ctype_fac.narrow(*_Fmtfirst) != '%') { // match literal element
2019-09-05 01:57:56 +03:00
if (_Ctype_fac.is(_Ctype::space, *_Fmtfirst)) {
while (_First != _Last && _Ctype_fac.is(_Ctype::space, *_First)) {
++_First;
}
} else if (_Ctype_fac.tolower(*_First) != _Ctype_fac.tolower(*_Fmtfirst)) { // bad literal match
2019-09-05 01:57:56 +03:00
_State |= ios_base::failbit;
break;
} else {
++_First;
}
} else if (++_Fmtfirst == _Fmtlast) {
// N4950 [locale.time.get.members]/8.4: "If the number of elements in the range [fmt, fmtend) is not
// sufficient to unambiguously determine whether the conversion specification is complete and valid,
// the function evaluates err = ios_base::failbit."
_State = ios_base::failbit;
2019-09-05 01:57:56 +03:00
break;
} else { // get specifier after %
char _Specifier = _Ctype_fac.narrow(*_Fmtfirst);
char _Modifier = '\0';
if (_Specifier == 'E' || _Specifier == 'O' || _Specifier == 'Q' || _Specifier == '#') {
if (++_Fmtfirst == _Fmtlast) { // no specifier
_State = ios_base::failbit;
2019-09-05 01:57:56 +03:00
break;
} else { // save both qualifier and specifier
_Modifier = _Specifier;
_Specifier = _Ctype_fac.narrow(*_Fmtfirst);
}
}
_First = do_get(_First, _Last, _Iosbase, _State, _Pt, _Specifier, _Modifier); // convert a single field
}
}
return _First;
}
explicit __CLR_OR_THIS_CALL time_get(size_t _Refs = 0) : time_base(_Refs) { // construct from current locale
_BEGIN_LOCINFO(_Lobj)
_Init(_Lobj);
_END_LOCINFO()
}
__CLR_OR_THIS_CALL time_get(const _Locinfo& _Lobj, size_t _Refs = 0) : time_base(_Refs) {
_Init(_Lobj);
}
static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr, const locale* _Ploc = nullptr) {
// return locale category mask and construct standard facet
if (_Ppf && !*_Ppf) {
*_Ppf = new time_get<_Elem, _InIt>(_Locinfo(_Ploc->_C_str()));
2019-09-05 01:57:56 +03:00
}
return _X_TIME;
}
protected:
__CLR_OR_THIS_CALL ~time_get() noexcept override {
2019-09-05 01:57:56 +03:00
_Tidy();
}
__CLR_OR_THIS_CALL time_get(const char* _Locname, size_t _Refs = 0) : time_base(_Refs) {
_BEGIN_LOCINFO(_Lobj(_Locname))
_Init(_Lobj);
_END_LOCINFO()
}
template <class _Elem2>
void __CLR_OR_THIS_CALL _Getvals(_Elem2, const _Locinfo& _Lobj) { // get values
_Cvt = _Lobj._Getcvt();
if constexpr (is_same_v<_Elem2, wchar_t>) {
2019-09-05 01:57:56 +03:00
_Days = reinterpret_cast<const _Elem*>(_Maklocwcs(reinterpret_cast<const wchar_t*>(_Lobj._W_Getdays())));
_Months =
reinterpret_cast<const _Elem*>(_Maklocwcs(reinterpret_cast<const wchar_t*>(_Lobj._W_Getmonths())));
_Ampm = reinterpret_cast<const _Elem*>(_Maklocwcs(L":AM:am:PM:pm"));
} else {
_Days = _Maklocstr(_Lobj._Getdays(), static_cast<_Elem*>(nullptr), _Cvt);
_Months = _Maklocstr(_Lobj._Getmonths(), static_cast<_Elem*>(nullptr), _Cvt);
_Ampm = _Maklocstr(":AM:am:PM:pm", static_cast<_Elem*>(nullptr), _Cvt);
}
}
void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj) { // initialize from _Lobj
_Days = nullptr;
_Months = nullptr;
_Ampm = nullptr;
_Tidy_guard<time_get> _Guard{this};
_Getvals(_Elem{}, _Lobj);
_Dateorder = static_cast<dateorder>(_Lobj._Getdateorder());
_Guard._Target = nullptr;
}
virtual dateorder __CLR_OR_THIS_CALL do_date_order() const {
return _Dateorder;
}
virtual _InIt __CLR_OR_THIS_CALL do_get_time(_InIt _First, _InIt _Last, ios_base& _Iosbase,
ios_base::iostate& _State, tm* _Pt) const { // get time of day from [_First, _Last) into _Pt
const _Ctype& _Ctype_fac = _STD use_facet<_Ctype>(_Iosbase.getloc());
_State |= _Getint(_First, _Last, 0, 23, _Pt->tm_hour, _Ctype_fac);
if (_State != ios_base::goodbit || _Ctype_fac.narrow(*_First) != ':') {
_State |= ios_base::failbit; // hour field is bad
} else {
_State |= _Getint(++_First, _Last, 0, 59, _Pt->tm_min, _Ctype_fac);
}
if (_State != ios_base::goodbit || _Ctype_fac.narrow(*_First) != ':') {
_State |= ios_base::failbit; // min field is bad
} else {
_State |= _Getint(++_First, _Last, 0, 60, _Pt->tm_sec, _Ctype_fac);
2019-09-05 01:57:56 +03:00
}
return _First;
}
virtual _InIt __CLR_OR_THIS_CALL do_get_date(_InIt _First, _InIt _Last, ios_base& _Iosbase,
ios_base::iostate& _State, tm* _Pt) const { // get date from [_First, _Last) into _Pt
const _Ctype& _Ctype_fac = _STD use_facet<_Ctype>(_Iosbase.getloc());
dateorder _Dorder = date_order();
if (_Dorder == no_order) {
_Dorder = mdy;
}
if (_First != _Last) {
if (!_Ctype_fac.is(_Ctype::digit, *_First)) { // begins with month name, assume mdy
_First = get_monthname(_First, _Last, _Iosbase, _State, _Pt);
_Dorder = mdy;
} else if (_Dorder == mdy) { // get month number
_State |= _Getint(_First, _Last, 1, 12, _Pt->tm_mon, _Ctype_fac);
--_Pt->tm_mon;
} else if (_Dorder == dmy) {
_State |= _Getint(_First, _Last, 1, 31, _Pt->tm_mday, _Ctype_fac);
} else { // ymd or ydm
_First = get_year(_First, _Last, _Iosbase, _State, _Pt);
}
}
while (_First != _Last && _Ctype_fac.is(_Ctype::space, *_First)) {
++_First; // skip spaces
}
if (_First != _Last) { // skip [:,/]
char _Ch = _Ctype_fac.narrow(*_First);
if (_Ch == ':' || _Ch == ',' || _Ch == '/') {
++_First;
}
}
while (_First != _Last && _Ctype_fac.is(_Ctype::space, *_First)) {
++_First; // skip spaces
}
if (_First != _Last) {
if (!_Ctype_fac.is(_Ctype::digit, *_First)) {
if (_Dorder == mdy) {
_State |= ios_base::failbit; // error, month already seen
} else { // month name is second, like it or not
_First = get_monthname(_First, _Last, _Iosbase, _State, _Pt);
if (_Dorder == ydm) {
_Dorder = ymd;
}
}
} else if (_Dorder == dmy || _Dorder == ymd) { // get month number
_State |= _Getint(_First, _Last, 1, 12, _Pt->tm_mon, _Ctype_fac);
--_Pt->tm_mon;
} else {
_State |= _Getint(_First, _Last, 1, 31, _Pt->tm_mday, _Ctype_fac);
}
}
while (_First != _Last && _Ctype_fac.is(_Ctype::space, *_First)) {
++_First; // skip spaces
}
if (_First != _Last) { // skip [:,/]
char _Ch = _Ctype_fac.narrow(*_First);
if (_Ch == ':' || _Ch == ',' || _Ch == '/') {
++_First;
}
}
while (_First != _Last && _Ctype_fac.is(_Ctype::space, *_First)) {
++_First; // skip spaces
}
if (_First == _Last) {
_State |= ios_base::failbit; // error, missing component(s)
} else if (!_Ctype_fac.is(_Ctype::digit, *_First)) {
if (_Dorder != ydm) {
_State |= ios_base::failbit; // error, month out of place
} else {
_First = get_monthname(_First, _Last, _Iosbase, _State, _Pt);
}
} else if (_Dorder == ydm) { // get month number
_State |= _Getint(_First, _Last, 1, 12, _Pt->tm_mon, _Ctype_fac);
--_Pt->tm_mon;
} else if (_Dorder == ymd) {
_State |= _Getint(_First, _Last, 1, 31, _Pt->tm_mday, _Ctype_fac);
} else { // mdy or dmy
_First = get_year(_First, _Last, _Iosbase, _State, _Pt);
}
if (_First == _Last) {
_State |= ios_base::eofbit;
}
return _First;
}
virtual _InIt __CLR_OR_THIS_CALL do_get_weekday(_InIt _First, _InIt _Last, ios_base&, ios_base::iostate& _State,
tm* _Pt) const { // get weekday from [_First, _Last) into _Pt
int _Num = _Getloctxt(_First, _Last, 0, _Days, _Case_sensitive::_Nope);
2019-09-05 01:57:56 +03:00
if (_Num < 0) {
_State |= ios_base::failbit;
} else {
_Pt->tm_wday = _Num >> 1; // set wday
}
return _First;
}
virtual _InIt __CLR_OR_THIS_CALL do_get_monthname(_InIt _First, _InIt _Last, ios_base&, ios_base::iostate& _State,
tm* _Pt) const { // get month from [_First, _Last) into _Pt
int _Num = _Getloctxt(_First, _Last, 0, _Months, _Case_sensitive::_Nope);
2019-09-05 01:57:56 +03:00
if (_Num < 0) {
_State |= ios_base::failbit;
} else {
_Pt->tm_mon = _Num >> 1; // set mon
}
return _First;
}
virtual _InIt __CLR_OR_THIS_CALL do_get_year(_InIt _First, _InIt _Last, ios_base& _Iosbase,
ios_base::iostate& _State, tm* _Pt) const { // get year from [_First, _Last) into _Pt
const _Ctype& _Ctype_fac = _STD use_facet<_Ctype>(_Iosbase.getloc());
int _Ans = 0;
int _Digits_read;
ios_base::iostate _Res = _Getint_v2(_First, _Last, 0, 9999, _Ans, _Digits_read, _Ctype_fac);
2019-09-05 01:57:56 +03:00
_State |= _Res; // pass on eofbit and failbit
if (!(_Res & ios_base::failbit)) {
if (_Digits_read <= 2) {
if (_Ans < 69) {
_Pt->tm_year = _Ans + 100; // [00, 68] parsed as [2000, 2068]
} else if (_Ans < 100) {
_Pt->tm_year = _Ans; // [69, 99] parsed as [1969, 1999]
}
2019-09-05 01:57:56 +03:00
} else {
_Pt->tm_year = _Ans - 1900; // parsed literally
2019-09-05 01:57:56 +03:00
}
}
return _First;
}
virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State,
tm* _Pt, char _Specifier, char = 0) const { // get formatted time for _Specifier (_Modifier ignored)
const _Ctype& _Ctype_fac = _STD use_facet<_Ctype>(_Iosbase.getloc());
int _Ans = 0;
_State = ios_base::goodbit;
switch (_Specifier) { // process format specifier
case 'a':
case 'A':
_First = get_weekday(_First, _Last, _Iosbase, _State, _Pt);
break;
case 'b':
case 'B':
case 'h':
_First = get_monthname(_First, _Last, _Iosbase, _State, _Pt);
break;
case 'c':
_First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt, "%b %d %H : %M : %S %Y");
break;
case 'C':
_State |= _Getint(_First, _Last, 0, 99, _Ans, _Ctype_fac);
if (!(_State & ios_base::failbit)) {
_Pt->tm_year = _Ans * 100 - 1900; // convert to century
}
break;
case 'd':
case 'e':
_State |= _Getint(_First, _Last, 1, 31, _Pt->tm_mday, _Ctype_fac);
break;
case 'D':
_First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt, "%m / %d / %y");
break;
case 'H':
_State |= _Getint(_First, _Last, 0, 23, _Pt->tm_hour, _Ctype_fac);
break;
case 'I':
_State |= _Getint(_First, _Last, 1, 12, _Ans, _Ctype_fac);
if (!(_State & ios_base::failbit)) {
_Pt->tm_hour = _Ans == 12 ? 0 : _Ans;
}
break;
case 'j':
_State |= _Getint(_First, _Last, 1, 366, _Pt->tm_yday, _Ctype_fac);
break;
case 'm':
_State |= _Getint(_First, _Last, 1, 12, _Ans, _Ctype_fac);
if (!(_State & ios_base::failbit)) {
_Pt->tm_mon = _Ans - 1;
}
break;
case 'M':
_State |= _Getint(_First, _Last, 0, 59, _Pt->tm_min, _Ctype_fac);
break;
case 'n':
case 't':
_First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt, " ");
break;
case 'p':
_Ans = _Getloctxt(_First, _Last, 0, ":AM:am:PM:pm", _Case_sensitive::_Nope);
2019-09-05 01:57:56 +03:00
if (_Ans < 0) {
_State |= ios_base::failbit;
} else if (1 < _Ans) {
_Pt->tm_hour += 12;
}
break;
case 'r':
_First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt, "%I : %M : %S %p");
break;
case 'R':
_First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt, "%H : %M");
break;
case 'S':
_State |= _Getint(_First, _Last, 0, 60, _Pt->tm_sec, _Ctype_fac);
break;
case 'T':
case 'X':
_First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt, "%H : %M : %S");
break;
case 'U':
_State |= _Getint(_First, _Last, 0, 53, _Pt->tm_yday, _Ctype_fac);
break;
case 'w':
_State |= _Getint(_First, _Last, 0, 6, _Pt->tm_wday, _Ctype_fac);
break;
case 'W':
_State |= _Getint(_First, _Last, 0, 53, _Pt->tm_yday, _Ctype_fac);
break;
case 'x':
_First = _Getfmt(_First, _Last, _Iosbase, _State, _Pt, "%d / %m / %y");
break;
case 'y':
_State |= _Getint(_First, _Last, 0, 99, _Ans, _Ctype_fac);
if (!(_State & ios_base::failbit)) {
_Pt->tm_year = _Ans < 69 ? _Ans + 100 : _Ans;
}
break;
case 'Y':
_State |= _Getint(_First, _Last, 0, 9999, _Ans, _Ctype_fac);
if (!(_State & ios_base::failbit)) {
_Pt->tm_year = _Ans - 1900;
}
2019-09-05 01:57:56 +03:00
break;
default:
_State |= ios_base::failbit; // unknown specifier
break;
2019-09-05 01:57:56 +03:00
}
if (_First == _Last) {
_State |= ios_base::eofbit;
}
return _First;
}
_InIt __CLR_OR_THIS_CALL _Getfmt(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State, tm* _Pt,
const char* _Fmtfirst) const { // get formatted time for format NTBS
const _Ctype& _Ctype_fac = _STD use_facet<_Ctype>(_Iosbase.getloc());
for (; *_Fmtfirst != '\0'; ++_Fmtfirst) {
if (_First == _Last) {
_State |= ios_base::failbit;
break;
} else if (*_Fmtfirst == '%') {
2019-09-05 01:57:56 +03:00
_First = do_get(_First, _Last, _Iosbase, _State, _Pt,
*++_Fmtfirst); // convert a single field
} else if (*_Fmtfirst == ' ') {
while (_First != _Last && _Ctype_fac.is(_Ctype::space, *_First)) {
++_First;
}
} else if (_Ctype_fac.narrow(*_First) != *_Fmtfirst) { // bad literal match
_State |= ios_base::failbit;
break;
} else {
++_First;
}
}
if (_First == _Last) {
_State |= ios_base::eofbit;
}
return _First;
}
private:
ios_base::iostate __CLRCALL_OR_CDECL _Getint(_InIt& _First, _InIt& _Last, int _Lo, int _Hi, int& _Val,
const _Ctype& _Ctype_fac) const { // get integer in range [_Lo, _Hi] from [_First, _Last)
// TRANSITION, ABI
int _Digits_read;
return _Getint_v2(_First, _Last, _Lo, _Hi, _Val, _Digits_read, _Ctype_fac);
2019-09-05 01:57:56 +03:00
}
void __CLR_OR_THIS_CALL _Tidy() noexcept { // free all storage
_CSTD free(const_cast<_Elem*>(_Days));
_CSTD free(const_cast<_Elem*>(_Months));
_CSTD free(const_cast<_Elem*>(_Ampm));
}
const _Elem* _Days; // ":Sun:Sunday:Mon:Monday..." for example
const _Elem* _Months; // "Jan:January:Feb:February..." for example
const _Elem* _Ampm; // ":AM:am:PM:pm"
dateorder _Dateorder;
_Locinfo::_Cvtvec _Cvt; // conversion information
};
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // defined(__clang__)
2019-09-05 01:57:56 +03:00
template <class _Elem, class _InIt>
__PURE_APPDOMAIN_GLOBAL locale::id time_get<_Elem, _InIt>::id;
#ifdef __clang__
#pragma clang diagnostic pop
#endif // defined(__clang__)
2019-09-05 01:57:56 +03:00
_EXPORT_STD template <class _Elem, class _InIt = istreambuf_iterator<_Elem, char_traits<_Elem>>>
2019-09-05 01:57:56 +03:00
class time_get_byname : public time_get<_Elem, _InIt> { // time_get for named locale
public:
static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);
explicit time_get_byname(const char* _Locname, size_t _Refs = 0)
2020-05-15 01:58:54 +03:00
: time_get<_Elem, _InIt>(_Locname, _Refs) {} // construct for named locale
2019-09-05 01:57:56 +03:00
explicit time_get_byname(const string& _Str, size_t _Refs = 0)
2020-05-15 01:58:54 +03:00
: time_get<_Elem, _InIt>(_Locinfo(_Str.c_str()), _Refs) {} // construct for named locale
2019-09-05 01:57:56 +03:00
protected:
__CLR_OR_THIS_CALL ~time_get_byname() noexcept override {}
2019-09-05 01:57:56 +03:00
};
// C23 7.29.3.5 "The strftime function"/3
_INLINE_VAR constexpr char _Valid_strftime_specifiers[] = {'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'F', 'g', 'G',
'h', 'H', 'I', 'j', 'm', 'M', 'n', 'p', 'r', 'R', 'S', 't', 'T', 'u', 'U', 'V', 'w', 'W', 'x', 'X', 'y', 'Y', 'z',
'Z'};
_NODISCARD constexpr bool _Is_valid_strftime_specifier(const char _Specifier) {
for (const auto& _Valid_specifier : _Valid_strftime_specifiers) {
if (_Specifier == _Valid_specifier) {
return true;
}
}
return false;
}
_NODISCARD constexpr bool _Is_valid_strftime_tm_sec(const tm* const _Pt) noexcept {
// seconds after the minute - [0, 60] including leap second
return _Pt->tm_sec >= 0 && _Pt->tm_sec <= 60;
}
_NODISCARD constexpr bool _Is_valid_strftime_tm_min(const tm* const _Pt) noexcept {
// minutes after the hour - [0, 59]
return _Pt->tm_min >= 0 && _Pt->tm_min <= 59;
}
_NODISCARD constexpr bool _Is_valid_strftime_tm_hour(const tm* const _Pt) noexcept {
// hours since midnight - [0, 23]
return _Pt->tm_hour >= 0 && _Pt->tm_hour <= 23;
}
_NODISCARD constexpr bool _Is_valid_strftime_tm_mday(const tm* const _Pt) noexcept {
// day of the month - [1, 31]
return _Pt->tm_mday >= 1 && _Pt->tm_mday <= 31;
}
_NODISCARD constexpr bool _Is_valid_strftime_tm_mon(const tm* const _Pt) noexcept {
// months since January - [0, 11]
return _Pt->tm_mon >= 0 && _Pt->tm_mon <= 11;
}
_NODISCARD constexpr bool _Is_valid_strftime_tm_year(const tm* const _Pt) noexcept {
// years since 1900 - UCRT max range is up until 8099
return _Pt->tm_year >= -1900 && _Pt->tm_year <= 8099;
}
_NODISCARD constexpr bool _Is_valid_strftime_tm_wday(const tm* const _Pt) noexcept {
// days since Sunday - [0, 6]
return _Pt->tm_wday >= 0 && _Pt->tm_wday <= 6;
}
_NODISCARD constexpr bool _Is_valid_strftime_tm_yday(const tm* const _Pt) noexcept {
// days since January 1 - [0, 365]
return _Pt->tm_yday >= 0 && _Pt->tm_yday <= 365;
}
_NODISCARD constexpr bool _Is_valid_strftime_tm_data(const char _Specifier, const tm* const _Pt) noexcept {
if (!_Pt) {
return false;
}
switch (_Specifier) {
case 'S':
return _Is_valid_strftime_tm_sec(_Pt);
case 'M':
return _Is_valid_strftime_tm_min(_Pt);
case 'H':
case 'I':
case 'p':
return _Is_valid_strftime_tm_hour(_Pt);
case 'd':
case 'e':
return _Is_valid_strftime_tm_mday(_Pt);
case 'b':
case 'B':
case 'm':
case 'h':
return _Is_valid_strftime_tm_mon(_Pt);
case 'C':
case 'y':
case 'Y':
return _Is_valid_strftime_tm_year(_Pt);
case 'j':
return _Is_valid_strftime_tm_yday(_Pt);
case 'a':
case 'A':
case 'u':
case 'w':
return _Is_valid_strftime_tm_wday(_Pt);
case 'U': // C23 7.29.3.5 "The strftime function"/3 says that %U and %W depend on tm_year,
case 'W': // but the UCRT neither uses nor validates it.
return _Is_valid_strftime_tm_wday(_Pt) && _Is_valid_strftime_tm_yday(_Pt);
case 'R':
return _Is_valid_strftime_tm_hour(_Pt) && _Is_valid_strftime_tm_min(_Pt);
case 'D':
case 'x':
case 'F':
return _Is_valid_strftime_tm_year(_Pt) && _Is_valid_strftime_tm_mon(_Pt) && _Is_valid_strftime_tm_mday(_Pt);
case 'g':
case 'G':
return _Is_valid_strftime_tm_year(_Pt) && _Is_valid_strftime_tm_wday(_Pt) && _Is_valid_strftime_tm_yday(_Pt);
case 'r':
case 'X':
case 'T':
return _Is_valid_strftime_tm_hour(_Pt) && _Is_valid_strftime_tm_min(_Pt) && _Is_valid_strftime_tm_sec(_Pt);
case 'c':
return _Is_valid_strftime_tm_wday(_Pt) && _Is_valid_strftime_tm_mon(_Pt) && _Is_valid_strftime_tm_mday(_Pt)
&& _Is_valid_strftime_tm_hour(_Pt) && _Is_valid_strftime_tm_min(_Pt) && _Is_valid_strftime_tm_sec(_Pt)
&& _Is_valid_strftime_tm_year(_Pt);
case 'V': // C23 7.29.3.5 "The strftime function"/3 says that %V depends on tm_year, tm_wday, and tm_yday.
// The UCRT uses them without validating them.
return true;
case 'z': // C23 7.29.3.5 "The strftime function"/3 says that %z and %Z depend on tm_isdst.
case 'Z': // The UCRT treats it as a boolean value, so there's no need for validation.
return true;
case 'n': // newline
case 't': // tab
return true;
default:
// We should have handled %% and called _Is_valid_strftime_specifier() before calling this function.
_STL_INTERNAL_CHECK(false);
return false;
}
}
_EXPORT_STD extern "C++" template <class _Elem, class _OutIt = ostreambuf_iterator<_Elem, char_traits<_Elem>>>
2019-09-05 01:57:56 +03:00
class time_put : public locale::facet { // facet for converting encoded times to text
public:
static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);
2019-09-05 01:57:56 +03:00
using char_type = _Elem;
using iter_type = _OutIt;
using _Ctype = ctype<_Elem>;
_OutIt __CLR_OR_THIS_CALL put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const tm* _Pt, const _Elem* _Fmtfirst,
const _Elem* _Fmtlast) const { // put formatted time from _Pt to _Dest for [_Fmtfirst, _Fmtlast)
const _Ctype& _Ctype_fac = _STD use_facet<_Ctype>(_Iosbase.getloc());
for (; _Fmtfirst != _Fmtlast; ++_Fmtfirst) {
if (_Ctype_fac.narrow(*_Fmtfirst) != '%') {
*_Dest++ = *_Fmtfirst; // copy literal element
} else if (++_Fmtfirst == _Fmtlast) { // treat trailing % as %%
*_Dest++ = _Fmtfirst[-1];
break;
} else { // get specifier after %
char _Specifier = _Ctype_fac.narrow(*_Fmtfirst);
char _Modifier = '\0';
_Elem _Percent = _Fmtfirst[-1];
if (_Specifier == 'E' || _Specifier == 'O' || _Specifier == 'Q' || _Specifier == '#') {
if (++_Fmtfirst == _Fmtlast) { // no specifier, copy %[E0Q#] as literal elements
*_Dest++ = _Percent;
*_Dest++ = _Specifier;
break;
}
// save both qualifier and specifier
_Modifier = _Specifier;
_Specifier = _Ctype_fac.narrow(*_Fmtfirst);
}
if (_Specifier == '%' && _Modifier == '\0') {
// if the specifier is percent and no modifier is set, just append it
*_Dest++ = _Percent;
} else if (!_Is_valid_strftime_specifier(_Specifier)) {
// no valid specifier, directly copy as literal elements
*_Dest++ = _Percent;
if (_Modifier != '\0') {
*_Dest++ = _Modifier;
}
*_Dest++ = _Specifier;
} else {
if (_Is_valid_strftime_tm_data(_Specifier, _Pt)) {
_Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field
} else {
*_Dest++ = _Elem('?');
}
}
2019-09-05 01:57:56 +03:00
}
}
return _Dest;
}
_OutIt __CLR_OR_THIS_CALL put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const tm* _Pt, char _Specifier,
char _Modifier = '\0') const { // put formatted time from _Pt to _Dest for _Specifier/_Modifier
return do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier);
}
__PURE_APPDOMAIN_GLOBAL static locale::id id; // unique facet id
explicit __CLR_OR_THIS_CALL time_put(size_t _Refs = 0) : locale::facet(_Refs) { // construct from current locale
_BEGIN_LOCINFO(_Lobj)
_Init(_Lobj);
_END_LOCINFO()
}
__CLR_OR_THIS_CALL time_put(const _Locinfo& _Lobj, size_t _Refs = 0) : locale::facet(_Refs) {
_Init(_Lobj);
}
static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr, const locale* _Ploc = nullptr) {
// return locale category mask and construct standard facet
if (_Ppf && !*_Ppf) {
*_Ppf = new time_put<_Elem, _OutIt>(_Locinfo(_Ploc->_C_str()));
2019-09-05 01:57:56 +03:00
}
return _X_TIME;
}
protected:
__CLR_OR_THIS_CALL ~time_put() noexcept override {}
2019-09-05 01:57:56 +03:00
void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj) { // initialize from _Lobj
_Tnames = _Lobj._Gettnames();
}
virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest, ios_base& _Iosbase, _Elem, const tm* _Pt, char _Specifier,
2019-09-05 01:57:56 +03:00
char _Modifier = '\0') const { // put formatted time from _Pt to _Dest for [_Fmtfirst, _Fmtlast)
char _Fmt[5] = "!%x\0"; // '!' for nonzero count, null for modifier
size_t _Count;
size_t _Num;
string _Str;
if (_Modifier == '\0') {
_Fmt[2] = _Specifier;
} else { // add both modifier and specifier
_Fmt[2] = _Modifier;
_Fmt[3] = _Specifier;
}
int& _Errno_ref = errno; // Nonzero cost, pay it once
const int _Old_errno = _Errno_ref;
2019-09-05 01:57:56 +03:00
for (_Num = 16;; _Num *= 2) { // convert into ever larger string buffer until success
_Str.append(_Num, '\0');
_Count = _Strftime(&_Str[0], _Str.size(), _Fmt, _Pt, _Tnames._Getptr());
if (0 < _Count) {
2019-09-05 01:57:56 +03:00
break;
} else if (_Errno_ref == EINVAL) {
_Iosbase.setstate(ios_base::badbit);
return _Dest;
2019-09-05 01:57:56 +03:00
}
}
_Errno_ref = _Old_errno;
2019-09-05 01:57:56 +03:00
return _STD copy(&_Str[1], &_Str[_Count], _Dest);
}
private:
_Locinfo::_Timevec _Tnames; // locale-specific stuff for _Strftime
};
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // defined(__clang__)
2019-09-05 01:57:56 +03:00
template <class _Elem, class _OutIt>
__PURE_APPDOMAIN_GLOBAL locale::id time_put<_Elem, _OutIt>::id;
#ifdef __clang__
#pragma clang diagnostic pop
#endif // defined(__clang__)
2019-09-05 01:57:56 +03:00
extern "C++" template <class _OutIt>
class time_put<wchar_t, _OutIt> : public locale::facet { // facet for converting encoded times to wchar_t text
2019-09-05 01:57:56 +03:00
public:
using _Elem = wchar_t;
using char_type = _Elem;
using iter_type = _OutIt;
using _Ctype = ctype<_Elem>;
_OutIt __CLR_OR_THIS_CALL put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const tm* _Pt, const _Elem* _Fmtfirst,
const _Elem* _Fmtlast) const { // put formatted time from _Pt to _Dest for [_Fmtfirst, _Fmtlast)
const _Ctype& _Ctype_fac = _STD use_facet<_Ctype>(_Iosbase.getloc());
for (; _Fmtfirst != _Fmtlast; ++_Fmtfirst) {
if (_Ctype_fac.narrow(*_Fmtfirst) != '%') {
*_Dest++ = *_Fmtfirst; // copy literal element
} else if (++_Fmtfirst == _Fmtlast) { // treat trailing % as %%
*_Dest++ = _Fmtfirst[-1];
break;
} else { // get specifier after %
_Elem _Raw = *_Fmtfirst;
char _Specifier = _Ctype_fac.narrow(_Raw);
char _Modifier = '\0';
_Elem _Percent = _Fmtfirst[-1];
if (_Specifier == 'E' || _Specifier == 'O' || _Specifier == 'Q' || _Specifier == '#') {
if (++_Fmtfirst == _Fmtlast) { // no specifier, copy %[E0Q#] as literal elements
*_Dest++ = _Percent;
*_Dest++ = _Raw;
break;
}
// save both qualifier and specifier
_Modifier = _Specifier;
_Specifier = _Ctype_fac.narrow(*_Fmtfirst);
}
if (_Specifier == '%' && _Modifier == '\0') {
// if the specifier is percent and no modifier is set, just append it
*_Dest++ = _Percent;
} else if (!_Is_valid_strftime_specifier(_Specifier)) {
// no valid specifier, directly copy as literal elements
*_Dest++ = _Percent;
if (_Modifier != '\0') {
*_Dest++ = _Raw;
}
*_Dest++ = *_Fmtfirst;
} else {
if (_Is_valid_strftime_tm_data(_Specifier, _Pt)) {
_Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field
} else {
*_Dest++ = _Elem('?');
}
}
2019-09-05 01:57:56 +03:00
}
}
return _Dest;
}
_OutIt __CLR_OR_THIS_CALL put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const tm* _Pt, char _Specifier,
char _Modifier = '\0') const { // put formatted time from _Pt to _Dest for _Specifier/_Modifier
return do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier);
}
__PURE_APPDOMAIN_GLOBAL static locale::id id; // unique facet id
explicit __CLR_OR_THIS_CALL time_put(size_t _Refs = 0) : locale::facet(_Refs) { // construct from current locale
_BEGIN_LOCINFO(_Lobj)
_Init(_Lobj);
_END_LOCINFO()
}
__CLR_OR_THIS_CALL time_put(const _Locinfo& _Lobj, size_t _Refs = 0) : locale::facet(_Refs) {
_Init(_Lobj);
}
static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr, const locale* _Ploc = nullptr) {
// return locale category mask and construct standard facet
if (_Ppf && !*_Ppf) {
*_Ppf = new time_put<_Elem, _OutIt>(_Locinfo(_Ploc->_C_str()));
2019-09-05 01:57:56 +03:00
}
return _X_TIME;
}
protected:
__CLR_OR_THIS_CALL ~time_put() noexcept override {}
2019-09-05 01:57:56 +03:00
__CLR_OR_THIS_CALL time_put(const char* _Locname, size_t _Refs = 0) : locale::facet(_Refs) {
_BEGIN_LOCINFO(_Lobj(_Locname))
_Init(_Lobj);
_END_LOCINFO()
}
void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj) { // initialize from _Lobj
_Tnames = _Lobj._W_Gettnames();
}
virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest, ios_base& _Iosbase, _Elem, const tm* _Pt, char _Specifier,
2019-09-05 01:57:56 +03:00
char _Modifier = '\0') const { // put formatted time from _Pt to _Dest for [_Fmtfirst, _Fmtlast)
wchar_t _Fmt[5] = L"!%x\0"; // ! for nonzero count, null for modifier
size_t _Count;
size_t _Num;
wstring _Str;
if (_Modifier == '\0') {
_Fmt[2] = static_cast<_Elem>(_Specifier); // conversion rule unspecified
} else { // add both modifier and specifier
_Fmt[2] = static_cast<_Elem>(_Modifier);
_Fmt[3] = static_cast<_Elem>(_Specifier);
}
int& _Errno_ref = errno; // Nonzero cost, pay it once
const int _Old_errno = _Errno_ref;
2019-09-05 01:57:56 +03:00
for (_Num = 16;; _Num *= 2) { // convert into ever larger string buffer until success
_Str.append(_Num, '\0');
_Count = _Wcsftime(&_Str[0], _Str.size(), _Fmt, _Pt, _Tnames._Getptr());
if (0 < _Count) {
2019-09-05 01:57:56 +03:00
break;
} else if (_Errno_ref == EINVAL) {
_Iosbase.setstate(ios_base::badbit);
return _Dest;
2019-09-05 01:57:56 +03:00
}
}
_Errno_ref = _Old_errno;
2019-09-05 01:57:56 +03:00
return _STD copy(&_Str[1], &_Str[_Count], _Dest);
}
private:
_Locinfo::_Timevec _Tnames; // locale-specific stuff for _Wcsftime
};
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // defined(__clang__)
2019-09-05 01:57:56 +03:00
template <class _OutIt>
__PURE_APPDOMAIN_GLOBAL locale::id time_put<wchar_t, _OutIt>::id;
#ifdef __clang__
#pragma clang diagnostic pop
#endif // defined(__clang__)
2019-09-05 01:57:56 +03:00
#if defined(_CRTBLD)
extern "C++" template <class _OutIt>
class time_put<unsigned short, _OutIt>
2019-09-05 01:57:56 +03:00
: public locale::facet { // facet for converting encoded times to unsigned short text
public:
using _Elem = unsigned short;
using char_type = _Elem;
using iter_type = _OutIt;
using _Ctype = ctype<_Elem>;
_OutIt __CLR_OR_THIS_CALL put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const tm* _Pt, const _Elem* _Fmtfirst,
const _Elem* _Fmtlast) const { // put formatted time from _Pt to _Dest for [_Fmtfirst, _Fmtlast)
const _Ctype& _Ctype_fac = _STD use_facet<_Ctype>(_Iosbase.getloc());
for (; _Fmtfirst != _Fmtlast; ++_Fmtfirst) {
if (_Ctype_fac.narrow(*_Fmtfirst) != '%') {
*_Dest++ = *_Fmtfirst; // copy literal element
} else if (++_Fmtfirst == _Fmtlast) { // treat trailing % as %%
*_Dest++ = _Fmtfirst[-1];
break;
} else { // get specifier after %
_Elem _Raw = *_Fmtfirst;
char _Specifier = _Ctype_fac.narrow(_Raw);
2019-09-05 01:57:56 +03:00
char _Modifier = '\0';
_Elem _Percent = _Fmtfirst[-1];
if (_Specifier == 'E' || _Specifier == 'O' || _Specifier == 'Q' || _Specifier == '#') {
if (++_Fmtfirst == _Fmtlast) { // no specifier, copy %[E0Q#] as literal elements
*_Dest++ = _Percent;
*_Dest++ = _Raw;
2019-09-05 01:57:56 +03:00
break;
}
// save both qualifier and specifier
_Modifier = _Specifier;
_Specifier = _Ctype_fac.narrow(*_Fmtfirst);
}
if (_Specifier == '%' && _Modifier == '\0') {
// if the specifier is percent and no modifier is set, just append it
*_Dest++ = _Percent;
} else if (!_Is_valid_strftime_specifier(_Specifier)) {
// no valid specifier, directly copy as literal elements
*_Dest++ = _Percent;
if (_Modifier != '\0') {
*_Dest++ = _Raw;
}
*_Dest++ = *_Fmtfirst;
} else {
if (_Is_valid_strftime_tm_data(_Specifier, _Pt)) {
_Dest = do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier); // convert a single field
} else {
*_Dest++ = _Elem('?');
}
}
2019-09-05 01:57:56 +03:00
}
}
return _Dest;
}
_OutIt __CLR_OR_THIS_CALL put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const tm* _Pt, char _Specifier,
char _Modifier = '\0') const { // put formatted time from _Pt to _Dest for _Specifier/_Modifier
return do_put(_Dest, _Iosbase, _Fill, _Pt, _Specifier, _Modifier);
}
__PURE_APPDOMAIN_GLOBAL static locale::id id; // unique facet id
explicit __CLR_OR_THIS_CALL time_put(size_t _Refs = 0) : locale::facet(_Refs) { // construct from current locale
_BEGIN_LOCINFO(_Lobj)
_Init(_Lobj);
_END_LOCINFO()
}
__CLR_OR_THIS_CALL time_put(const _Locinfo& _Lobj, size_t _Refs = 0) : locale::facet(_Refs) {
_Init(_Lobj);
}
static size_t __CLRCALL_OR_CDECL _Getcat(const locale::facet** _Ppf = nullptr, const locale* _Ploc = nullptr) {
// return locale category mask and construct standard facet
if (_Ppf && !*_Ppf) {
*_Ppf = new time_put<_Elem, _OutIt>(_Locinfo(_Ploc->_C_str()));
2019-09-05 01:57:56 +03:00
}
return _X_TIME;
}
protected:
__CLR_OR_THIS_CALL ~time_put() noexcept override {}
2019-09-05 01:57:56 +03:00
__CLR_OR_THIS_CALL time_put(const char* _Locname, size_t _Refs = 0) : locale::facet(_Refs) {
_BEGIN_LOCINFO(_Lobj(_Locname))
_Init(_Lobj);
_END_LOCINFO()
}
void __CLR_OR_THIS_CALL _Init(const _Locinfo& _Lobj) { // initialize from _Lobj
_Tnames = _Lobj._W_Gettnames();
}
virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest, ios_base& _Iosbase, _Elem, const tm* _Pt, char _Specifier,
2019-09-05 01:57:56 +03:00
char _Modifier = '\0') const { // put formatted time from _Pt to _Dest for [_Fmtfirst, _Fmtlast)
wchar_t _Fmt[5] = L"!%x\0"; // ! for nonzero count, null for modifier
size_t _Count;
size_t _Num;
wstring _Str;
if (_Modifier == '\0') {
_Fmt[2] = static_cast<_Elem>(_Specifier); // conversion rule unspecified
} else { // add both modifier and specifier
_Fmt[2] = static_cast<_Elem>(_Modifier);
_Fmt[3] = static_cast<_Elem>(_Specifier);
}
int& _Errno_ref = errno; // Nonzero cost, pay it once
const int _Old_errno = _Errno_ref;
2019-09-05 01:57:56 +03:00
for (_Num = 16;; _Num *= 2) { // convert into ever larger string buffer until success
_Str.append(_Num, '\0');
_Count = _Wcsftime(&_Str[0], _Str.size(), _Fmt, _Pt, _Tnames._Getptr());
if (0 < _Count) {
2019-09-05 01:57:56 +03:00
break;
} else if (_Errno_ref == EINVAL) {
_Iosbase.setstate(ios_base::badbit);
return _Dest;
2019-09-05 01:57:56 +03:00
}
}
_Errno_ref = _Old_errno;
2019-09-05 01:57:56 +03:00
return _STD copy(&_Str[1], &_Str[_Count], _Dest);
}
private:
_Locinfo::_Timevec _Tnames; // locale-specific stuff for _Wcsftime
};
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdllimport-static-field-def"
#endif // defined(__clang__)
2019-09-05 01:57:56 +03:00
template <class _OutIt>
__PURE_APPDOMAIN_GLOBAL locale::id time_put<unsigned short, _OutIt>::id;
#ifdef __clang__
#pragma clang diagnostic pop
#endif // defined(__clang__)
2019-09-05 01:57:56 +03:00
#endif // defined(_CRTBLD)
_EXPORT_STD template <class _Elem, class _OutIt = ostreambuf_iterator<_Elem, char_traits<_Elem>>>
2019-09-05 01:57:56 +03:00
class time_put_byname : public time_put<_Elem, _OutIt> { // time_put for named locale
public:
static_assert(!_ENFORCE_FACET_SPECIALIZATIONS || _Is_any_of_v<_Elem, char, wchar_t>, _FACET_SPECIALIZATION_MESSAGE);
explicit time_put_byname(const char* _Locname, size_t _Refs = 0)
2020-05-15 01:58:54 +03:00
: time_put<_Elem, _OutIt>(_Locname, _Refs) {} // construct for named locale
2019-09-05 01:57:56 +03:00
explicit time_put_byname(const string& _Str, size_t _Refs = 0)
2020-05-15 01:58:54 +03:00
: time_put<_Elem, _OutIt>(_Str.c_str(), _Refs) {} // construct for named locale
2019-09-05 01:57:56 +03:00
protected:
__CLR_OR_THIS_CALL ~time_put_byname() noexcept override {}
2019-09-05 01:57:56 +03:00
};
#if defined(_DLL_CPPLIB)
#if !defined(_CRTBLD) || defined(__FORCE_INSTANCE)
template class _CRTIMP2_PURE_IMPORT time_get<char, istreambuf_iterator<char, char_traits<char>>>;
template class _CRTIMP2_PURE_IMPORT time_put<char, ostreambuf_iterator<char, char_traits<char>>>;
template _CRTIMP2_PURE void __CLR_OR_THIS_CALL time_get<char, istreambuf_iterator<char, char_traits<char>>>::_Getvals(
wchar_t, const _Locinfo&);
template class _CRTIMP2_PURE_IMPORT time_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t>>>;
template class _CRTIMP2_PURE_IMPORT time_put<wchar_t, ostreambuf_iterator<wchar_t, char_traits<wchar_t>>>;
template _CRTIMP2_PURE void __CLR_OR_THIS_CALL
time_get<wchar_t, istreambuf_iterator<wchar_t, char_traits<wchar_t>>>::_Getvals(wchar_t, const _Locinfo&);
#endif // !defined(_CRTBLD) || defined(__FORCE_INSTANCE)
#ifdef __FORCE_INSTANCE
template class _CRTIMP2_PURE_IMPORT
time_get<unsigned short, istreambuf_iterator<unsigned short, char_traits<unsigned short>>>;
template class _CRTIMP2_PURE_IMPORT
time_put<unsigned short, ostreambuf_iterator<unsigned short, char_traits<unsigned short>>>;
template _CRTIMP2_PURE void __CLR_OR_THIS_CALL
time_get<unsigned short, istreambuf_iterator<unsigned short, char_traits<unsigned short>>>::_Getvals(
wchar_t, const _Locinfo&);
#endif // defined(__FORCE_INSTANCE)
2019-09-05 01:57:56 +03:00
#endif // defined(_DLL_CPPLIB)
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _XLOCTIME_