// 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::__weeks() const { static const string* weeks = init_weeks(); return weeks; } template <> const wstring* __time_get_c_storage::__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::__months() const { static const string* months = init_months(); return months; } template <> const wstring* __time_get_c_storage::__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::__am_pm() const { static const string* am_pm = init_am_pm(); return am_pm; } template <> const wstring* __time_get_c_storage::__am_pm() const { static const wstring* am_pm = init_wam_pm(); return am_pm; } template <> const string& __time_get_c_storage::__x() const { static string s("%m/%d/%y"); return s; } template <> const wstring& __time_get_c_storage::__x() const { static wstring s(L"%m/%d/%y"); return s; } template <> const string& __time_get_c_storage::__X() const { static string s("%H:%M:%S"); return s; } template <> const wstring& __time_get_c_storage::__X() const { static wstring s(L"%H:%M:%S"); return s; } template <> const string& __time_get_c_storage::__c() const { static string s("%a %b %d %H:%M:%S %Y"); return s; } template <> const wstring& __time_get_c_storage::__c() const { static wstring s(L"%a %b %d %H:%M:%S %Y"); return s; } template <> const string& __time_get_c_storage::__r() const { static string s("%I:%M:%S %p"); return s; } template <> const wstring& __time_get_c_storage::__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::__analyze(char fmt, const ctype& 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::__analyze(char fmt, const ctype& 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::init(const ctype& 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::init(const ctype& 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 struct _LIBCPP_HIDDEN __time_get_temp : public ctype_byname { explicit __time_get_temp(const char* nm) : ctype_byname(nm, 1) {} explicit __time_get_temp(const string& nm) : ctype_byname(nm, 1) {} }; template <> __time_get_storage::__time_get_storage(const char* __nm) : __time_get(__nm) { const __time_get_temp ct(__nm); init(ct); } template <> __time_get_storage::__time_get_storage(const string& __nm) : __time_get(__nm) { const __time_get_temp ct(__nm); init(ct); } template <> __time_get_storage::__time_get_storage(const char* __nm) : __time_get(__nm) { const __time_get_temp ct(__nm); init(ct); } template <> __time_get_storage::__time_get_storage(const string& __nm) : __time_get(__nm) { const __time_get_temp ct(__nm); init(ct); } template <> time_base::dateorder __time_get_storage::__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::__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; template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get; template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname; template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_get_byname; template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put; template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put; template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname; template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS time_put_byname; _LIBCPP_END_NAMESPACE_STD