mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
1010 lines
25 KiB
C++
1010 lines
25 KiB
C++
// clang-format off
|
|
//===------------------------- locale.cpp ---------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "third_party/libcxx/string"
|
|
#include "third_party/libcxx/locale"
|
|
#include "third_party/libcxx/codecvt"
|
|
#include "third_party/libcxx/vector"
|
|
#include "third_party/libcxx/algorithm"
|
|
#include "third_party/libcxx/typeinfo"
|
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
|
#include "third_party/libcxx/type_traits"
|
|
#endif
|
|
#include "third_party/libcxx/clocale"
|
|
#include "third_party/libcxx/cstring"
|
|
#include "third_party/libcxx/cwctype"
|
|
#include "third_party/libcxx/__sso_allocator"
|
|
#include "third_party/libcxx/include/atomic_support.hh"
|
|
#include "libc/str/locale.h"
|
|
#include "third_party/libcxx/countof.internal.hh"
|
|
#include "third_party/libcxx/__undef_macros"
|
|
|
|
// On Linux, wint_t and wchar_t have different signed-ness, and this causes
|
|
// lots of noise in the build log, but no bugs that I know of.
|
|
#if defined(__clang__)
|
|
#pragma clang diagnostic ignored "-Wsign-conversion"
|
|
#endif
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
namespace {
|
|
|
|
_LIBCPP_NORETURN static void __throw_runtime_error(const string &msg)
|
|
{
|
|
#ifndef _LIBCPP_NO_EXCEPTIONS
|
|
throw runtime_error(msg);
|
|
#else
|
|
(void)msg;
|
|
_VSTD::abort();
|
|
#endif
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// time_get
|
|
|
|
static
|
|
string*
|
|
init_weeks()
|
|
{
|
|
static string weeks[14];
|
|
weeks[0] = "Sunday";
|
|
weeks[1] = "Monday";
|
|
weeks[2] = "Tuesday";
|
|
weeks[3] = "Wednesday";
|
|
weeks[4] = "Thursday";
|
|
weeks[5] = "Friday";
|
|
weeks[6] = "Saturday";
|
|
weeks[7] = "Sun";
|
|
weeks[8] = "Mon";
|
|
weeks[9] = "Tue";
|
|
weeks[10] = "Wed";
|
|
weeks[11] = "Thu";
|
|
weeks[12] = "Fri";
|
|
weeks[13] = "Sat";
|
|
return weeks;
|
|
}
|
|
|
|
static
|
|
wstring*
|
|
init_wweeks()
|
|
{
|
|
static wstring weeks[14];
|
|
weeks[0] = L"Sunday";
|
|
weeks[1] = L"Monday";
|
|
weeks[2] = L"Tuesday";
|
|
weeks[3] = L"Wednesday";
|
|
weeks[4] = L"Thursday";
|
|
weeks[5] = L"Friday";
|
|
weeks[6] = L"Saturday";
|
|
weeks[7] = L"Sun";
|
|
weeks[8] = L"Mon";
|
|
weeks[9] = L"Tue";
|
|
weeks[10] = L"Wed";
|
|
weeks[11] = L"Thu";
|
|
weeks[12] = L"Fri";
|
|
weeks[13] = L"Sat";
|
|
return weeks;
|
|
}
|
|
|
|
template <>
|
|
const string*
|
|
__time_get_c_storage<char>::__weeks() const
|
|
{
|
|
static const string* weeks = init_weeks();
|
|
return weeks;
|
|
}
|
|
|
|
template <>
|
|
const wstring*
|
|
__time_get_c_storage<wchar_t>::__weeks() const
|
|
{
|
|
static const wstring* weeks = init_wweeks();
|
|
return weeks;
|
|
}
|
|
|
|
static
|
|
string*
|
|
init_months()
|
|
{
|
|
static string months[24];
|
|
months[0] = "January";
|
|
months[1] = "February";
|
|
months[2] = "March";
|
|
months[3] = "April";
|
|
months[4] = "May";
|
|
months[5] = "June";
|
|
months[6] = "July";
|
|
months[7] = "August";
|
|
months[8] = "September";
|
|
months[9] = "October";
|
|
months[10] = "November";
|
|
months[11] = "December";
|
|
months[12] = "Jan";
|
|
months[13] = "Feb";
|
|
months[14] = "Mar";
|
|
months[15] = "Apr";
|
|
months[16] = "May";
|
|
months[17] = "Jun";
|
|
months[18] = "Jul";
|
|
months[19] = "Aug";
|
|
months[20] = "Sep";
|
|
months[21] = "Oct";
|
|
months[22] = "Nov";
|
|
months[23] = "Dec";
|
|
return months;
|
|
}
|
|
|
|
static
|
|
wstring*
|
|
init_wmonths()
|
|
{
|
|
static wstring months[24];
|
|
months[0] = L"January";
|
|
months[1] = L"February";
|
|
months[2] = L"March";
|
|
months[3] = L"April";
|
|
months[4] = L"May";
|
|
months[5] = L"June";
|
|
months[6] = L"July";
|
|
months[7] = L"August";
|
|
months[8] = L"September";
|
|
months[9] = L"October";
|
|
months[10] = L"November";
|
|
months[11] = L"December";
|
|
months[12] = L"Jan";
|
|
months[13] = L"Feb";
|
|
months[14] = L"Mar";
|
|
months[15] = L"Apr";
|
|
months[16] = L"May";
|
|
months[17] = L"Jun";
|
|
months[18] = L"Jul";
|
|
months[19] = L"Aug";
|
|
months[20] = L"Sep";
|
|
months[21] = L"Oct";
|
|
months[22] = L"Nov";
|
|
months[23] = L"Dec";
|
|
return months;
|
|
}
|
|
|
|
template <>
|
|
const string*
|
|
__time_get_c_storage<char>::__months() const
|
|
{
|
|
static const string* months = init_months();
|
|
return months;
|
|
}
|
|
|
|
template <>
|
|
const wstring*
|
|
__time_get_c_storage<wchar_t>::__months() const
|
|
{
|
|
static const wstring* months = init_wmonths();
|
|
return months;
|
|
}
|
|
|
|
static
|
|
string*
|
|
init_am_pm()
|
|
{
|
|
static string am_pm[2];
|
|
am_pm[0] = "AM";
|
|
am_pm[1] = "PM";
|
|
return am_pm;
|
|
}
|
|
|
|
static
|
|
wstring*
|
|
init_wam_pm()
|
|
{
|
|
static wstring am_pm[2];
|
|
am_pm[0] = L"AM";
|
|
am_pm[1] = L"PM";
|
|
return am_pm;
|
|
}
|
|
|
|
template <>
|
|
const string*
|
|
__time_get_c_storage<char>::__am_pm() const
|
|
{
|
|
static const string* am_pm = init_am_pm();
|
|
return am_pm;
|
|
}
|
|
|
|
template <>
|
|
const wstring*
|
|
__time_get_c_storage<wchar_t>::__am_pm() const
|
|
{
|
|
static const wstring* am_pm = init_wam_pm();
|
|
return am_pm;
|
|
}
|
|
|
|
template <>
|
|
const string&
|
|
__time_get_c_storage<char>::__x() const
|
|
{
|
|
static string s("%m/%d/%y");
|
|
return s;
|
|
}
|
|
|
|
template <>
|
|
const wstring&
|
|
__time_get_c_storage<wchar_t>::__x() const
|
|
{
|
|
static wstring s(L"%m/%d/%y");
|
|
return s;
|
|
}
|
|
|
|
template <>
|
|
const string&
|
|
__time_get_c_storage<char>::__X() const
|
|
{
|
|
static string s("%H:%M:%S");
|
|
return s;
|
|
}
|
|
|
|
template <>
|
|
const wstring&
|
|
__time_get_c_storage<wchar_t>::__X() const
|
|
{
|
|
static wstring s(L"%H:%M:%S");
|
|
return s;
|
|
}
|
|
|
|
template <>
|
|
const string&
|
|
__time_get_c_storage<char>::__c() const
|
|
{
|
|
static string s("%a %b %d %H:%M:%S %Y");
|
|
return s;
|
|
}
|
|
|
|
template <>
|
|
const wstring&
|
|
__time_get_c_storage<wchar_t>::__c() const
|
|
{
|
|
static wstring s(L"%a %b %d %H:%M:%S %Y");
|
|
return s;
|
|
}
|
|
|
|
template <>
|
|
const string&
|
|
__time_get_c_storage<char>::__r() const
|
|
{
|
|
static string s("%I:%M:%S %p");
|
|
return s;
|
|
}
|
|
|
|
template <>
|
|
const wstring&
|
|
__time_get_c_storage<wchar_t>::__r() const
|
|
{
|
|
static wstring s(L"%I:%M:%S %p");
|
|
return s;
|
|
}
|
|
|
|
// time_get_byname
|
|
|
|
__time_get::__time_get(const char* nm)
|
|
: __loc_(newlocale(LC_ALL_MASK, nm, 0))
|
|
{
|
|
if (__loc_ == 0)
|
|
__throw_runtime_error("time_get_byname"
|
|
" failed to construct for " + string(nm));
|
|
}
|
|
|
|
__time_get::__time_get(const string& nm)
|
|
: __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0))
|
|
{
|
|
if (__loc_ == 0)
|
|
__throw_runtime_error("time_get_byname"
|
|
" failed to construct for " + nm);
|
|
}
|
|
|
|
__time_get::~__time_get()
|
|
{
|
|
freelocale(__loc_);
|
|
}
|
|
#if defined(__clang__)
|
|
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
|
|
#endif
|
|
#if defined(__GNUG__)
|
|
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
|
#endif
|
|
|
|
template <>
|
|
string
|
|
__time_get_storage<char>::__analyze(char fmt, const ctype<char>& ct)
|
|
{
|
|
tm t = {0};
|
|
t.tm_sec = 59;
|
|
t.tm_min = 55;
|
|
t.tm_hour = 23;
|
|
t.tm_mday = 31;
|
|
t.tm_mon = 11;
|
|
t.tm_year = 161;
|
|
t.tm_wday = 6;
|
|
t.tm_yday = 364;
|
|
t.tm_isdst = -1;
|
|
char buf[100];
|
|
char f[3] = {0};
|
|
f[0] = '%';
|
|
f[1] = fmt;
|
|
size_t n = strftime_l(buf, countof(buf), f, &t, __loc_);
|
|
char* bb = buf;
|
|
char* be = buf + n;
|
|
string result;
|
|
while (bb != be)
|
|
{
|
|
if (ct.is(ctype_base::space, *bb))
|
|
{
|
|
result.push_back(' ');
|
|
for (++bb; bb != be && ct.is(ctype_base::space, *bb); ++bb)
|
|
;
|
|
continue;
|
|
}
|
|
char* w = bb;
|
|
ios_base::iostate err = ios_base::goodbit;
|
|
ptrdiff_t i = __scan_keyword(w, be, this->__weeks_, this->__weeks_+14,
|
|
ct, err, false)
|
|
- this->__weeks_;
|
|
if (i < 14)
|
|
{
|
|
result.push_back('%');
|
|
if (i < 7)
|
|
result.push_back('A');
|
|
else
|
|
result.push_back('a');
|
|
bb = w;
|
|
continue;
|
|
}
|
|
w = bb;
|
|
i = __scan_keyword(w, be, this->__months_, this->__months_+24,
|
|
ct, err, false)
|
|
- this->__months_;
|
|
if (i < 24)
|
|
{
|
|
result.push_back('%');
|
|
if (i < 12)
|
|
result.push_back('B');
|
|
else
|
|
result.push_back('b');
|
|
if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
|
|
result.back() = 'm';
|
|
bb = w;
|
|
continue;
|
|
}
|
|
if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0)
|
|
{
|
|
w = bb;
|
|
i = __scan_keyword(w, be, this->__am_pm_, this->__am_pm_+2,
|
|
ct, err, false) - this->__am_pm_;
|
|
if (i < 2)
|
|
{
|
|
result.push_back('%');
|
|
result.push_back('p');
|
|
bb = w;
|
|
continue;
|
|
}
|
|
}
|
|
w = bb;
|
|
if (ct.is(ctype_base::digit, *bb))
|
|
{
|
|
switch(__get_up_to_n_digits(bb, be, err, ct, 4))
|
|
{
|
|
case 6:
|
|
result.push_back('%');
|
|
result.push_back('w');
|
|
break;
|
|
case 7:
|
|
result.push_back('%');
|
|
result.push_back('u');
|
|
break;
|
|
case 11:
|
|
result.push_back('%');
|
|
result.push_back('I');
|
|
break;
|
|
case 12:
|
|
result.push_back('%');
|
|
result.push_back('m');
|
|
break;
|
|
case 23:
|
|
result.push_back('%');
|
|
result.push_back('H');
|
|
break;
|
|
case 31:
|
|
result.push_back('%');
|
|
result.push_back('d');
|
|
break;
|
|
case 55:
|
|
result.push_back('%');
|
|
result.push_back('M');
|
|
break;
|
|
case 59:
|
|
result.push_back('%');
|
|
result.push_back('S');
|
|
break;
|
|
case 61:
|
|
result.push_back('%');
|
|
result.push_back('y');
|
|
break;
|
|
case 364:
|
|
result.push_back('%');
|
|
result.push_back('j');
|
|
break;
|
|
case 2061:
|
|
result.push_back('%');
|
|
result.push_back('Y');
|
|
break;
|
|
default:
|
|
for (; w != bb; ++w)
|
|
result.push_back(*w);
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
if (*bb == '%')
|
|
{
|
|
result.push_back('%');
|
|
result.push_back('%');
|
|
++bb;
|
|
continue;
|
|
}
|
|
result.push_back(*bb);
|
|
++bb;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#if defined(__clang__)
|
|
#pragma clang diagnostic ignored "-Wmissing-braces"
|
|
#endif
|
|
|
|
template <>
|
|
wstring
|
|
__time_get_storage<wchar_t>::__analyze(char fmt, const ctype<wchar_t>& ct)
|
|
{
|
|
tm t = {0};
|
|
t.tm_sec = 59;
|
|
t.tm_min = 55;
|
|
t.tm_hour = 23;
|
|
t.tm_mday = 31;
|
|
t.tm_mon = 11;
|
|
t.tm_year = 161;
|
|
t.tm_wday = 6;
|
|
t.tm_yday = 364;
|
|
t.tm_isdst = -1;
|
|
char buf[100];
|
|
char f[3] = {0};
|
|
f[0] = '%';
|
|
f[1] = fmt;
|
|
strftime_l(buf, countof(buf), f, &t, __loc_);
|
|
wchar_t wbuf[100];
|
|
wchar_t* wbb = wbuf;
|
|
mbstate_t mb = {0};
|
|
const char* bb = buf;
|
|
size_t j = __libcpp_mbsrtowcs_l( wbb, &bb, countof(wbuf), &mb, __loc_);
|
|
if (j == size_t(-1))
|
|
__throw_runtime_error("locale not supported");
|
|
wchar_t* wbe = wbb + j;
|
|
wstring result;
|
|
while (wbb != wbe)
|
|
{
|
|
if (ct.is(ctype_base::space, *wbb))
|
|
{
|
|
result.push_back(L' ');
|
|
for (++wbb; wbb != wbe && ct.is(ctype_base::space, *wbb); ++wbb)
|
|
;
|
|
continue;
|
|
}
|
|
wchar_t* w = wbb;
|
|
ios_base::iostate err = ios_base::goodbit;
|
|
ptrdiff_t i = __scan_keyword(w, wbe, this->__weeks_, this->__weeks_+14,
|
|
ct, err, false)
|
|
- this->__weeks_;
|
|
if (i < 14)
|
|
{
|
|
result.push_back(L'%');
|
|
if (i < 7)
|
|
result.push_back(L'A');
|
|
else
|
|
result.push_back(L'a');
|
|
wbb = w;
|
|
continue;
|
|
}
|
|
w = wbb;
|
|
i = __scan_keyword(w, wbe, this->__months_, this->__months_+24,
|
|
ct, err, false)
|
|
- this->__months_;
|
|
if (i < 24)
|
|
{
|
|
result.push_back(L'%');
|
|
if (i < 12)
|
|
result.push_back(L'B');
|
|
else
|
|
result.push_back(L'b');
|
|
if (fmt == 'x' && ct.is(ctype_base::digit, this->__months_[i][0]))
|
|
result.back() = L'm';
|
|
wbb = w;
|
|
continue;
|
|
}
|
|
if (this->__am_pm_[0].size() + this->__am_pm_[1].size() > 0)
|
|
{
|
|
w = wbb;
|
|
i = __scan_keyword(w, wbe, this->__am_pm_, this->__am_pm_+2,
|
|
ct, err, false) - this->__am_pm_;
|
|
if (i < 2)
|
|
{
|
|
result.push_back(L'%');
|
|
result.push_back(L'p');
|
|
wbb = w;
|
|
continue;
|
|
}
|
|
}
|
|
w = wbb;
|
|
if (ct.is(ctype_base::digit, *wbb))
|
|
{
|
|
switch(__get_up_to_n_digits(wbb, wbe, err, ct, 4))
|
|
{
|
|
case 6:
|
|
result.push_back(L'%');
|
|
result.push_back(L'w');
|
|
break;
|
|
case 7:
|
|
result.push_back(L'%');
|
|
result.push_back(L'u');
|
|
break;
|
|
case 11:
|
|
result.push_back(L'%');
|
|
result.push_back(L'I');
|
|
break;
|
|
case 12:
|
|
result.push_back(L'%');
|
|
result.push_back(L'm');
|
|
break;
|
|
case 23:
|
|
result.push_back(L'%');
|
|
result.push_back(L'H');
|
|
break;
|
|
case 31:
|
|
result.push_back(L'%');
|
|
result.push_back(L'd');
|
|
break;
|
|
case 55:
|
|
result.push_back(L'%');
|
|
result.push_back(L'M');
|
|
break;
|
|
case 59:
|
|
result.push_back(L'%');
|
|
result.push_back(L'S');
|
|
break;
|
|
case 61:
|
|
result.push_back(L'%');
|
|
result.push_back(L'y');
|
|
break;
|
|
case 364:
|
|
result.push_back(L'%');
|
|
result.push_back(L'j');
|
|
break;
|
|
case 2061:
|
|
result.push_back(L'%');
|
|
result.push_back(L'Y');
|
|
break;
|
|
default:
|
|
for (; w != wbb; ++w)
|
|
result.push_back(*w);
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
if (ct.narrow(*wbb, 0) == '%')
|
|
{
|
|
result.push_back(L'%');
|
|
result.push_back(L'%');
|
|
++wbb;
|
|
continue;
|
|
}
|
|
result.push_back(*wbb);
|
|
++wbb;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template <>
|
|
void
|
|
__time_get_storage<char>::init(const ctype<char>& ct)
|
|
{
|
|
tm t = {0};
|
|
char buf[100];
|
|
// __weeks_
|
|
for (int i = 0; i < 7; ++i)
|
|
{
|
|
t.tm_wday = i;
|
|
strftime_l(buf, countof(buf), "%A", &t, __loc_);
|
|
__weeks_[i] = buf;
|
|
strftime_l(buf, countof(buf), "%a", &t, __loc_);
|
|
__weeks_[i+7] = buf;
|
|
}
|
|
// __months_
|
|
for (int i = 0; i < 12; ++i)
|
|
{
|
|
t.tm_mon = i;
|
|
strftime_l(buf, countof(buf), "%B", &t, __loc_);
|
|
__months_[i] = buf;
|
|
strftime_l(buf, countof(buf), "%b", &t, __loc_);
|
|
__months_[i+12] = buf;
|
|
}
|
|
// __am_pm_
|
|
t.tm_hour = 1;
|
|
strftime_l(buf, countof(buf), "%p", &t, __loc_);
|
|
__am_pm_[0] = buf;
|
|
t.tm_hour = 13;
|
|
strftime_l(buf, countof(buf), "%p", &t, __loc_);
|
|
__am_pm_[1] = buf;
|
|
__c_ = __analyze('c', ct);
|
|
__r_ = __analyze('r', ct);
|
|
__x_ = __analyze('x', ct);
|
|
__X_ = __analyze('X', ct);
|
|
}
|
|
|
|
template <>
|
|
void
|
|
__time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct)
|
|
{
|
|
tm t = {0};
|
|
char buf[100];
|
|
wchar_t wbuf[100];
|
|
wchar_t* wbe;
|
|
mbstate_t mb = {0};
|
|
// __weeks_
|
|
for (int i = 0; i < 7; ++i)
|
|
{
|
|
t.tm_wday = i;
|
|
strftime_l(buf, countof(buf), "%A", &t, __loc_);
|
|
mb = mbstate_t();
|
|
const char* bb = buf;
|
|
size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
|
|
if (j == size_t(-1))
|
|
__throw_runtime_error("locale not supported");
|
|
wbe = wbuf + j;
|
|
__weeks_[i].assign(wbuf, wbe);
|
|
strftime_l(buf, countof(buf), "%a", &t, __loc_);
|
|
mb = mbstate_t();
|
|
bb = buf;
|
|
j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
|
|
if (j == size_t(-1))
|
|
__throw_runtime_error("locale not supported");
|
|
wbe = wbuf + j;
|
|
__weeks_[i+7].assign(wbuf, wbe);
|
|
}
|
|
// __months_
|
|
for (int i = 0; i < 12; ++i)
|
|
{
|
|
t.tm_mon = i;
|
|
strftime_l(buf, countof(buf), "%B", &t, __loc_);
|
|
mb = mbstate_t();
|
|
const char* bb = buf;
|
|
size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
|
|
if (j == size_t(-1))
|
|
__throw_runtime_error("locale not supported");
|
|
wbe = wbuf + j;
|
|
__months_[i].assign(wbuf, wbe);
|
|
strftime_l(buf, countof(buf), "%b", &t, __loc_);
|
|
mb = mbstate_t();
|
|
bb = buf;
|
|
j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
|
|
if (j == size_t(-1))
|
|
__throw_runtime_error("locale not supported");
|
|
wbe = wbuf + j;
|
|
__months_[i+12].assign(wbuf, wbe);
|
|
}
|
|
// __am_pm_
|
|
t.tm_hour = 1;
|
|
strftime_l(buf, countof(buf), "%p", &t, __loc_);
|
|
mb = mbstate_t();
|
|
const char* bb = buf;
|
|
size_t j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
|
|
if (j == size_t(-1))
|
|
__throw_runtime_error("locale not supported");
|
|
wbe = wbuf + j;
|
|
__am_pm_[0].assign(wbuf, wbe);
|
|
t.tm_hour = 13;
|
|
strftime_l(buf, countof(buf), "%p", &t, __loc_);
|
|
mb = mbstate_t();
|
|
bb = buf;
|
|
j = __libcpp_mbsrtowcs_l(wbuf, &bb, countof(wbuf), &mb, __loc_);
|
|
if (j == size_t(-1))
|
|
__throw_runtime_error("locale not supported");
|
|
wbe = wbuf + j;
|
|
__am_pm_[1].assign(wbuf, wbe);
|
|
__c_ = __analyze('c', ct);
|
|
__r_ = __analyze('r', ct);
|
|
__x_ = __analyze('x', ct);
|
|
__X_ = __analyze('X', ct);
|
|
}
|
|
|
|
template <class CharT>
|
|
struct _LIBCPP_HIDDEN __time_get_temp
|
|
: public ctype_byname<CharT>
|
|
{
|
|
explicit __time_get_temp(const char* nm)
|
|
: ctype_byname<CharT>(nm, 1) {}
|
|
explicit __time_get_temp(const string& nm)
|
|
: ctype_byname<CharT>(nm, 1) {}
|
|
};
|
|
|
|
template <>
|
|
__time_get_storage<char>::__time_get_storage(const char* __nm)
|
|
: __time_get(__nm)
|
|
{
|
|
const __time_get_temp<char> ct(__nm);
|
|
init(ct);
|
|
}
|
|
|
|
template <>
|
|
__time_get_storage<char>::__time_get_storage(const string& __nm)
|
|
: __time_get(__nm)
|
|
{
|
|
const __time_get_temp<char> ct(__nm);
|
|
init(ct);
|
|
}
|
|
|
|
template <>
|
|
__time_get_storage<wchar_t>::__time_get_storage(const char* __nm)
|
|
: __time_get(__nm)
|
|
{
|
|
const __time_get_temp<wchar_t> ct(__nm);
|
|
init(ct);
|
|
}
|
|
|
|
template <>
|
|
__time_get_storage<wchar_t>::__time_get_storage(const string& __nm)
|
|
: __time_get(__nm)
|
|
{
|
|
const __time_get_temp<wchar_t> ct(__nm);
|
|
init(ct);
|
|
}
|
|
|
|
template <>
|
|
time_base::dateorder
|
|
__time_get_storage<char>::__do_date_order() const
|
|
{
|
|
unsigned i;
|
|
for (i = 0; i < __x_.size(); ++i)
|
|
if (__x_[i] == '%')
|
|
break;
|
|
++i;
|
|
switch (__x_[i])
|
|
{
|
|
case 'y':
|
|
case 'Y':
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == '%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
switch (__x_[i])
|
|
{
|
|
case 'm':
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == '%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == 'd')
|
|
return time_base::ymd;
|
|
break;
|
|
case 'd':
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == '%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == 'm')
|
|
return time_base::ydm;
|
|
break;
|
|
}
|
|
break;
|
|
case 'm':
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == '%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == 'd')
|
|
{
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == '%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == 'y' || __x_[i] == 'Y')
|
|
return time_base::mdy;
|
|
break;
|
|
}
|
|
break;
|
|
case 'd':
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == '%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == 'm')
|
|
{
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == '%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == 'y' || __x_[i] == 'Y')
|
|
return time_base::dmy;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return time_base::no_order;
|
|
}
|
|
|
|
template <>
|
|
time_base::dateorder
|
|
__time_get_storage<wchar_t>::__do_date_order() const
|
|
{
|
|
unsigned i;
|
|
for (i = 0; i < __x_.size(); ++i)
|
|
if (__x_[i] == L'%')
|
|
break;
|
|
++i;
|
|
switch (__x_[i])
|
|
{
|
|
case L'y':
|
|
case L'Y':
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == L'%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
switch (__x_[i])
|
|
{
|
|
case L'm':
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == L'%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == L'd')
|
|
return time_base::ymd;
|
|
break;
|
|
case L'd':
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == L'%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == L'm')
|
|
return time_base::ydm;
|
|
break;
|
|
}
|
|
break;
|
|
case L'm':
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == L'%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == L'd')
|
|
{
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == L'%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == L'y' || __x_[i] == L'Y')
|
|
return time_base::mdy;
|
|
break;
|
|
}
|
|
break;
|
|
case L'd':
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == L'%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == L'm')
|
|
{
|
|
for (++i; i < __x_.size(); ++i)
|
|
if (__x_[i] == L'%')
|
|
break;
|
|
if (i == __x_.size())
|
|
break;
|
|
++i;
|
|
if (__x_[i] == L'y' || __x_[i] == L'Y')
|
|
return time_base::dmy;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return time_base::no_order;
|
|
}
|
|
|
|
// time_put
|
|
|
|
__time_put::__time_put(const char* nm)
|
|
: __loc_(newlocale(LC_ALL_MASK, nm, 0))
|
|
{
|
|
if (__loc_ == 0)
|
|
__throw_runtime_error("time_put_byname"
|
|
" failed to construct for " + string(nm));
|
|
}
|
|
|
|
__time_put::__time_put(const string& nm)
|
|
: __loc_(newlocale(LC_ALL_MASK, nm.c_str(), 0))
|
|
{
|
|
if (__loc_ == 0)
|
|
__throw_runtime_error("time_put_byname"
|
|
" failed to construct for " + nm);
|
|
}
|
|
|
|
__time_put::~__time_put()
|
|
{
|
|
if (__loc_ != _LIBCPP_GET_C_LOCALE)
|
|
freelocale(__loc_);
|
|
}
|
|
|
|
void
|
|
__time_put::__do_put(char* __nb, char*& __ne, const tm* __tm,
|
|
char __fmt, char __mod) const
|
|
{
|
|
char fmt[] = {'%', __fmt, __mod, 0};
|
|
if (__mod != 0)
|
|
swap(fmt[1], fmt[2]);
|
|
size_t n = strftime_l(__nb, countof(__nb, __ne), fmt, __tm, __loc_);
|
|
__ne = __nb + n;
|
|
}
|
|
|
|
void
|
|
__time_put::__do_put(wchar_t* __wb, wchar_t*& __we, const tm* __tm,
|
|
char __fmt, char __mod) const
|
|
{
|
|
char __nar[100];
|
|
char* __ne = __nar + 100;
|
|
__do_put(__nar, __ne, __tm, __fmt, __mod);
|
|
mbstate_t mb = {0};
|
|
const char* __nb = __nar;
|
|
size_t j = __libcpp_mbsrtowcs_l(__wb, &__nb, countof(__wb, __we), &mb, __loc_);
|
|
if (j == size_t(-1))
|
|
__throw_runtime_error("locale not supported");
|
|
__we = __wb + j;
|
|
}
|
|
|
|
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<char>;
|
|
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get<wchar_t>;
|
|
|
|
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<char>;
|
|
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname<wchar_t>;
|
|
|
|
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<char>;
|
|
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put<wchar_t>;
|
|
|
|
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<char>;
|
|
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname<wchar_t>;
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|