aboutsummaryrefslogtreecommitdiff
path: root/system/lib/libcxx/locale.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'system/lib/libcxx/locale.cpp')
-rw-r--r--system/lib/libcxx/locale.cpp5838
1 files changed, 5838 insertions, 0 deletions
diff --git a/system/lib/libcxx/locale.cpp b/system/lib/libcxx/locale.cpp
new file mode 100644
index 00000000..388660d2
--- /dev/null
+++ b/system/lib/libcxx/locale.cpp
@@ -0,0 +1,5838 @@
+//===------------------------- locale.cpp ---------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "string"
+#include "locale"
+#include "codecvt"
+#include "vector"
+#include "algorithm"
+#include "algorithm"
+#include "typeinfo"
+#include "type_traits"
+#include "clocale"
+#include "cstring"
+#include "cwctype"
+#include "__sso_allocator"
+#if _WIN32
+#include <locale.h>
+#else // _WIN32
+#include <langinfo.h>
+#endif // _!WIN32
+#include <stdlib.h>
+
+#ifdef _LIBCPP_STABLE_APPLE_ABI
+namespace {
+ decltype(MB_CUR_MAX_L(_VSTD::declval<locale_t>()))
+ inline _LIBCPP_INLINE_VISIBILITY
+ mb_cur_max_l(locale_t loc)
+ {
+ return MB_CUR_MAX_L(loc);
+ }
+}
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#ifndef _LIBCPP_STABLE_APPLE_ABI
+locale_t __cloc() {
+ // In theory this could create a race condition. In practice
+ // the race condition is non-fatal since it will just create
+ // a little resource leak. Better approach would be appreciated.
+#ifdef __APPLE__
+ return 0;
+#else
+ static locale_t result = newlocale(LC_ALL_MASK, "C", 0);
+ return result;
+#endif
+}
+#endif // _LIBCPP_STABLE_APPLE_ABI
+
+namespace {
+
+struct release
+{
+ void operator()(locale::facet* p) {p->__release_shared();}
+};
+
+template <class T, class A0>
+inline
+T&
+make(A0 a0)
+{
+ static typename aligned_storage<sizeof(T)>::type buf;
+ ::new (&buf) T(a0);
+ return *(T*)&buf;
+}
+
+template <class T, class A0, class A1>
+inline
+T&
+make(A0 a0, A1 a1)
+{
+ static typename aligned_storage<sizeof(T)>::type buf;
+ ::new (&buf) T(a0, a1);
+ return *(T*)&buf;
+}
+
+template <class T, class A0, class A1, class A2>
+inline
+T&
+make(A0 a0, A1 a1, A2 a2)
+{
+ static typename aligned_storage<sizeof(T)>::type buf;
+ ::new (&buf) T(a0, a1, a2);
+ return *(T*)&buf;
+}
+
+}
+
+class _LIBCPP_HIDDEN locale::__imp
+ : public facet
+{
+ enum {N = 28};
+ string name_;
+ vector<facet*, __sso_allocator<facet*, N> > facets_;
+public:
+ explicit __imp(size_t refs = 0);
+ explicit __imp(const string& name, size_t refs = 0);
+ __imp(const __imp&);
+ __imp(const __imp&, const string&, locale::category c);
+ __imp(const __imp& other, const __imp& one, locale::category c);
+ __imp(const __imp&, facet* f, long id);
+ ~__imp();
+
+ const string& name() const {return name_;}
+ bool has_facet(long id) const {return id < facets_.size() && facets_[id];}
+ const locale::facet* use_facet(long id) const;
+
+ static const locale& make_classic();
+ static locale& make_global();
+private:
+ void install(facet* f, long id);
+ template <class F> void install(F* f) {install(f, f->id.__get());}
+ template <class F> void install_from(const __imp& other);
+};
+
+locale::__imp::__imp(size_t refs)
+ : facet(refs),
+ name_("C"),
+ facets_(N)
+{
+ facets_.clear();
+ install(&make<_VSTD::collate<char> >(1));
+ install(&make<_VSTD::collate<wchar_t> >(1));
+ install(&make<_VSTD::ctype<char> >((ctype_base::mask*)0, false, 1));
+ install(&make<_VSTD::ctype<wchar_t> >(1));
+ install(&make<codecvt<char, char, mbstate_t> >(1));
+ install(&make<codecvt<wchar_t, char, mbstate_t> >(1));
+ install(&make<codecvt<char16_t, char, mbstate_t> >(1));
+ install(&make<codecvt<char32_t, char, mbstate_t> >(1));
+ install(&make<numpunct<char> >(1));
+ install(&make<numpunct<wchar_t> >(1));
+ install(&make<num_get<char> >(1));
+ install(&make<num_get<wchar_t> >(1));
+ install(&make<num_put<char> >(1));
+ install(&make<num_put<wchar_t> >(1));
+ install(&make<moneypunct<char, false> >(1));
+ install(&make<moneypunct<char, true> >(1));
+ install(&make<moneypunct<wchar_t, false> >(1));
+ install(&make<moneypunct<wchar_t, true> >(1));
+ install(&make<money_get<char> >(1));
+ install(&make<money_get<wchar_t> >(1));
+ install(&make<money_put<char> >(1));
+ install(&make<money_put<wchar_t> >(1));
+ install(&make<time_get<char> >(1));
+ install(&make<time_get<wchar_t> >(1));
+ install(&make<time_put<char> >(1));
+ install(&make<time_put<wchar_t> >(1));
+ install(&make<_VSTD::messages<char> >(1));
+ install(&make<_VSTD::messages<wchar_t> >(1));
+}
+
+locale::__imp::__imp(const string& name, size_t refs)
+ : facet(refs),
+ name_(name),
+ facets_(N)
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ try
+ {
+#endif // _LIBCPP_NO_EXCEPTIONS
+ facets_ = locale::classic().__locale_->facets_;
+ for (unsigned i = 0; i < facets_.size(); ++i)
+ if (facets_[i])
+ facets_[i]->__add_shared();
+ install(new collate_byname<char>(name_));
+ install(new collate_byname<wchar_t>(name_));
+ install(new ctype_byname<char>(name_));
+ install(new ctype_byname<wchar_t>(name_));
+ install(new codecvt_byname<char, char, mbstate_t>(name_));
+ install(new codecvt_byname<wchar_t, char, mbstate_t>(name_));
+ install(new codecvt_byname<char16_t, char, mbstate_t>(name_));
+ install(new codecvt_byname<char32_t, char, mbstate_t>(name_));
+ install(new numpunct_byname<char>(name_));
+ install(new numpunct_byname<wchar_t>(name_));
+ install(new moneypunct_byname<char, false>(name_));
+ install(new moneypunct_byname<char, true>(name_));
+ install(new moneypunct_byname<wchar_t, false>(name_));
+ install(new moneypunct_byname<wchar_t, true>(name_));
+ install(new time_get_byname<char>(name_));
+ install(new time_get_byname<wchar_t>(name_));
+ install(new time_put_byname<char>(name_));
+ install(new time_put_byname<wchar_t>(name_));
+ install(new messages_byname<char>(name_));
+ install(new messages_byname<wchar_t>(name_));
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ }
+ catch (...)
+ {
+ for (unsigned i = 0; i < facets_.size(); ++i)
+ if (facets_[i])
+ facets_[i]->__release_shared();
+ throw;
+ }
+#endif // _LIBCPP_NO_EXCEPTIONS
+}
+
+locale::__imp::__imp(const __imp& other)
+ : name_(other.name_),
+ facets_(max<size_t>(N, other.facets_.size()))
+{
+ facets_ = other.facets_;
+ for (unsigned i = 0; i < facets_.size(); ++i)
+ if (facets_[i])
+ facets_[i]->__add_shared();
+}
+
+locale::__imp::__imp(const __imp& other, const string& name, locale::category c)
+ : name_("*"),
+ facets_(N)
+{
+ facets_ = other.facets_;
+ for (unsigned i = 0; i < facets_.size(); ++i)
+ if (facets_[i])
+ facets_[i]->__add_shared();
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ try
+ {
+#endif // _LIBCPP_NO_EXCEPTIONS
+ if (c & locale::collate)
+ {
+ install(new collate_byname<char>(name));
+ install(new collate_byname<wchar_t>(name));
+ }
+ if (c & locale::ctype)
+ {
+ install(new ctype_byname<char>(name));
+ install(new ctype_byname<wchar_t>(name));
+ install(new codecvt_byname<char, char, mbstate_t>(name));
+ install(new codecvt_byname<wchar_t, char, mbstate_t>(name));
+ install(new codecvt_byname<char16_t, char, mbstate_t>(name));
+ install(new codecvt_byname<char32_t, char, mbstate_t>(name));
+ }
+ if (c & locale::monetary)
+ {
+ install(new moneypunct_byname<char, false>(name));
+ install(new moneypunct_byname<char, true>(name));
+ install(new moneypunct_byname<wchar_t, false>(name));
+ install(new moneypunct_byname<wchar_t, true>(name));
+ }
+ if (c & locale::numeric)
+ {
+ install(new numpunct_byname<char>(name));
+ install(new numpunct_byname<wchar_t>(name));
+ }
+ if (c & locale::time)
+ {
+ install(new time_get_byname<char>(name));
+ install(new time_get_byname<wchar_t>(name));
+ install(new time_put_byname<char>(name));
+ install(new time_put_byname<wchar_t>(name));
+ }
+ if (c & locale::messages)
+ {
+ install(new messages_byname<char>(name));
+ install(new messages_byname<wchar_t>(name));
+ }
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ }
+ catch (...)
+ {
+ for (unsigned i = 0; i < facets_.size(); ++i)
+ if (facets_[i])
+ facets_[i]->__release_shared();
+ throw;
+ }
+#endif // _LIBCPP_NO_EXCEPTIONS
+}
+
+template<class F>
+inline
+void
+locale::__imp::install_from(const locale::__imp& one)
+{
+ long id = F::id.__get();
+ install(const_cast<F*>(static_cast<const F*>(one.use_facet(id))), id);
+}
+
+locale::__imp::__imp(const __imp& other, const __imp& one, locale::category c)
+ : name_("*"),
+ facets_(N)
+{
+ facets_ = other.facets_;
+ for (unsigned i = 0; i < facets_.size(); ++i)
+ if (facets_[i])
+ facets_[i]->__add_shared();
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ try
+ {
+#endif // _LIBCPP_NO_EXCEPTIONS
+ if (c & locale::collate)
+ {
+ install_from<_VSTD::collate<char> >(one);
+ install_from<_VSTD::collate<wchar_t> >(one);
+ }
+ if (c & locale::ctype)
+ {
+ install_from<_VSTD::ctype<char> >(one);
+ install_from<_VSTD::ctype<wchar_t> >(one);
+ install_from<_VSTD::codecvt<char, char, mbstate_t> >(one);
+ install_from<_VSTD::codecvt<char16_t, char, mbstate_t> >(one);
+ install_from<_VSTD::codecvt<char32_t, char, mbstate_t> >(one);
+ install_from<_VSTD::codecvt<wchar_t, char, mbstate_t> >(one);
+ }
+ if (c & locale::monetary)
+ {
+ install_from<moneypunct<char, false> >(one);
+ install_from<moneypunct<char, true> >(one);
+ install_from<moneypunct<wchar_t, false> >(one);
+ install_from<moneypunct<wchar_t, true> >(one);
+ install_from<money_get<char> >(one);
+ install_from<money_get<wchar_t> >(one);
+ install_from<money_put<char> >(one);
+ install_from<money_put<wchar_t> >(one);
+ }
+ if (c & locale::numeric)
+ {
+ install_from<numpunct<char> >(one);
+ install_from<numpunct<wchar_t> >(one);
+ install_from<num_get<char> >(one);
+ install_from<num_get<wchar_t> >(one);
+ install_from<num_put<char> >(one);
+ install_from<num_put<wchar_t> >(one);
+ }
+ if (c & locale::time)
+ {
+ install_from<time_get<char> >(one);
+ install_from<time_get<wchar_t> >(one);
+ install_from<time_put<char> >(one);
+ install_from<time_put<wchar_t> >(one);
+ }
+ if (c & locale::messages)
+ {
+ install_from<_VSTD::messages<char> >(one);
+ install_from<_VSTD::messages<wchar_t> >(one);
+ }
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ }
+ catch (...)
+ {
+ for (unsigned i = 0; i < facets_.size(); ++i)
+ if (facets_[i])
+ facets_[i]->__release_shared();
+ throw;
+ }
+#endif // _LIBCPP_NO_EXCEPTIONS
+}
+
+locale::__imp::__imp(const __imp& other, facet* f, long id)
+ : name_("*"),
+ facets_(max<size_t>(N, other.facets_.size()+1))
+{
+ f->__add_shared();
+ unique_ptr<facet, release> hold(f);
+ facets_ = other.facets_;
+ for (unsigned i = 0; i < other.facets_.size(); ++i)
+ if (facets_[i])
+ facets_[i]->__add_shared();
+ install(hold.get(), id);
+}
+
+locale::__imp::~__imp()
+{
+ for (unsigned i = 0; i < facets_.size(); ++i)
+ if (facets_[i])
+ facets_[i]->__release_shared();
+}
+
+void
+locale::__imp::install(facet* f, long id)
+{
+ f->__add_shared();
+ unique_ptr<facet, release> hold(f);
+ if (id >= facets_.size())
+ facets_.resize(id+1);
+ if (facets_[id])
+ facets_[id]->__release_shared();
+ facets_[id] = hold.release();
+}
+
+const locale::facet*
+locale::__imp::use_facet(long id) const
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ if (!has_facet(id))
+ throw bad_cast();
+#endif // _LIBCPP_NO_EXCEPTIONS
+ return facets_[id];
+}
+
+// locale
+
+const locale&
+locale::__imp::make_classic()
+{
+ // only one thread can get in here and it only gets in once
+ static aligned_storage<sizeof(locale)>::type buf;
+ locale* c = (locale*)&buf;
+ c->__locale_ = &make<__imp>(1);
+ return *c;
+}
+
+const locale&
+locale::classic()
+{
+ static const locale& c = __imp::make_classic();
+ return c;
+}
+
+locale&
+locale::__imp::make_global()
+{
+ // only one thread can get in here and it only gets in once
+ static aligned_storage<sizeof(locale)>::type buf;
+ locale* g = (locale*)&buf;
+ ::new (&buf) locale(locale::classic());
+ return *(locale*)&buf;
+}
+
+locale&
+locale::__global()
+{
+ static locale& g = __imp::make_global();
+ return g;
+}
+
+locale::locale() _NOEXCEPT
+ : __locale_(__global().__locale_)
+{
+ __locale_->__add_shared();
+}
+
+locale::locale(const locale& l) _NOEXCEPT
+ : __locale_(l.__locale_)
+{
+ __locale_->__add_shared();
+}
+
+locale::~locale()
+{
+ __locale_->__release_shared();
+}
+
+const locale&
+locale::operator=(const locale& other) _NOEXCEPT
+{
+ other.__locale_->__add_shared();
+ __locale_->__release_shared();
+ __locale_ = other.__locale_;
+ return *this;
+}
+
+locale::locale(const char* name)
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ : __locale_(name ? new __imp(name)
+ : throw runtime_error("locale constructed with null"))
+#else // _LIBCPP_NO_EXCEPTIONS
+ : __locale_(new __imp(name))
+#endif
+{
+ __locale_->__add_shared();
+}
+
+locale::locale(const string& name)
+ : __locale_(new __imp(name))
+{
+ __locale_->__add_shared();
+}
+
+locale::locale(const locale& other, const char* name, category c)
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ : __locale_(name ? new __imp(*other.__locale_, name, c)
+ : throw runtime_error("locale constructed with null"))
+#else // _LIBCPP_NO_EXCEPTIONS
+ : __locale_(new __imp(*other.__locale_, name, c))
+#endif
+{
+ __locale_->__add_shared();
+}
+
+locale::locale(const locale& other, const string& name, category c)
+ : __locale_(new __imp(*other.__locale_, name, c))
+{
+ __locale_->__add_shared();
+}
+
+locale::locale(const locale& other, const locale& one, category c)
+ : __locale_(new __imp(*other.__locale_, *one.__locale_, c))
+{
+ __locale_->__add_shared();
+}
+
+string
+locale::name() const
+{
+ return __locale_->name();
+}
+
+void
+locale::__install_ctor(const locale& other, facet* f, long id)
+{
+ if (f)
+ __locale_ = new __imp(*other.__locale_, f, id);
+ else
+ __locale_ = other.__locale_;
+ __locale_->__add_shared();
+}
+
+locale
+locale::global(const locale& loc)
+{
+ locale& g = __global();
+ locale r = g;
+ g = loc;
+ if (g.name() != "*")
+ setlocale(LC_ALL, g.name().c_str());
+ return r;
+}
+
+bool
+locale::has_facet(id& x) const
+{
+ return __locale_->has_facet(x.__get());
+}
+
+const locale::facet*
+locale::use_facet(id& x) const
+{
+ return __locale_->use_facet(x.__get());
+}
+
+bool
+locale::operator==(const locale& y) const
+{
+ return (__locale_ == y.__locale_)
+ || (__locale_->name() != "*" && __locale_->name() == y.__locale_->name());
+}
+
+// locale::facet
+
+locale::facet::~facet()
+{
+}
+
+void
+locale::facet::__on_zero_shared() _NOEXCEPT
+{
+ delete this;
+}
+
+// locale::id
+
+int32_t locale::id::__next_id = 0;
+
+namespace
+{
+
+class __fake_bind
+{
+ locale::id* id_;
+ void (locale::id::* pmf_)();
+public:
+ __fake_bind(void (locale::id::* pmf)(), locale::id* id)
+ : id_(id), pmf_(pmf) {}
+
+ void operator()() const
+ {
+ (id_->*pmf_)();
+ }
+};
+
+}
+
+long
+locale::id::__get()
+{
+ call_once(__flag_, __fake_bind(&locale::id::__init, this));
+ return __id_ - 1;
+}
+
+void
+locale::id::__init()
+{
+ __id_ = __sync_add_and_fetch(&__next_id, 1);
+}
+
+// template <> class collate_byname<char>
+
+collate_byname<char>::collate_byname(const char* n, size_t refs)
+ : collate<char>(refs),
+ __l(newlocale(LC_ALL_MASK, n, 0))
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ if (__l == 0)
+ throw runtime_error("collate_byname<char>::collate_byname"
+ " failed to construct for " + string(n));
+#endif // _LIBCPP_NO_EXCEPTIONS
+}
+
+collate_byname<char>::collate_byname(const string& name, size_t refs)
+ : collate<char>(refs),
+ __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ if (__l == 0)
+ throw runtime_error("collate_byname<char>::collate_byname"
+ " failed to construct for " + name);
+#endif // _LIBCPP_NO_EXCEPTIONS
+}
+
+collate_byname<char>::~collate_byname()
+{
+ freelocale(__l);
+}
+
+int
+collate_byname<char>::do_compare(const char_type* __lo1, const char_type* __hi1,
+ const char_type* __lo2, const char_type* __hi2) const
+{
+ string_type lhs(__lo1, __hi1);
+ string_type rhs(__lo2, __hi2);
+ int r = strcoll_l(lhs.c_str(), rhs.c_str(), __l);
+ if (r < 0)
+ return -1;
+ if (r > 0)
+ return 1;
+ return r;
+}
+
+collate_byname<char>::string_type
+collate_byname<char>::do_transform(const char_type* lo, const char_type* hi) const
+{
+ const string_type in(lo, hi);
+ string_type out(strxfrm_l(0, in.c_str(), 0, __l), char());
+ strxfrm_l(const_cast<char*>(out.c_str()), in.c_str(), out.size()+1, __l);
+ return out;
+}
+
+// template <> class collate_byname<wchar_t>
+
+collate_byname<wchar_t>::collate_byname(const char* n, size_t refs)
+ : collate<wchar_t>(refs),
+ __l(newlocale(LC_ALL_MASK, n, 0))
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ if (__l == 0)
+ throw runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)"
+ " failed to construct for " + string(n));
+#endif // _LIBCPP_NO_EXCEPTIONS
+}
+
+collate_byname<wchar_t>::collate_byname(const string& name, size_t refs)
+ : collate<wchar_t>(refs),
+ __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ if (__l == 0)
+ throw runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)"
+ " failed to construct for " + name);
+#endif // _LIBCPP_NO_EXCEPTIONS
+}
+
+collate_byname<wchar_t>::~collate_byname()
+{
+ freelocale(__l);
+}
+
+int
+collate_byname<wchar_t>::do_compare(const char_type* __lo1, const char_type* __hi1,
+ const char_type* __lo2, const char_type* __hi2) const
+{
+ string_type lhs(__lo1, __hi1);
+ string_type rhs(__lo2, __hi2);
+ int r = wcscoll_l(lhs.c_str(), rhs.c_str(), __l);
+ if (r < 0)
+ return -1;
+ if (r > 0)
+ return 1;
+ return r;
+}
+
+collate_byname<wchar_t>::string_type
+collate_byname<wchar_t>::do_transform(const char_type* lo, const char_type* hi) const
+{
+ const string_type in(lo, hi);
+ string_type out(wcsxfrm_l(0, in.c_str(), 0, __l), wchar_t());
+ wcsxfrm_l(const_cast<wchar_t*>(out.c_str()), in.c_str(), out.size()+1, __l);
+ return out;
+}
+
+// template <> class ctype<wchar_t>;
+
+locale::id ctype<wchar_t>::id;
+
+ctype<wchar_t>::~ctype()
+{
+}
+
+bool
+ctype<wchar_t>::do_is(mask m, char_type c) const
+{
+ return isascii(c) ? ctype<char>::classic_table()[c] & m : false;
+}
+
+const wchar_t*
+ctype<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
+{
+ for (; low != high; ++low, ++vec)
+ *vec = static_cast<mask>(isascii(*low) ?
+ ctype<char>::classic_table()[*low] : 0);
+ return low;
+}
+
+const wchar_t*
+ctype<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
+{
+ for (; low != high; ++low)
+ if (isascii(*low) && (ctype<char>::classic_table()[*low] & m))
+ break;
+ return low;
+}
+
+const wchar_t*
+ctype<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
+{
+ for (; low != high; ++low)
+ if (!(isascii(*low) && (ctype<char>::classic_table()[*low] & m)))
+ break;
+ return low;
+}
+
+wchar_t
+ctype<wchar_t>::do_toupper(char_type c) const
+{
+#if !(defined(_LIBCPP_STABLE_APPLE_ABI) || defined(__FreeBSD__))
+ return isascii(c) ? ctype<char>::__classic_upper_table()[c] : c;
+#else
+ return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
+#endif
+}
+
+const wchar_t*
+ctype<wchar_t>::do_toupper(char_type* low, const char_type* high) const
+{
+ for (; low != high; ++low)
+#if !(defined(_LIBCPP_STABLE_APPLE_ABI) || defined(__FreeBSD__))
+ *low = isascii(*low) ? ctype<char>::__classic_upper_table()[*low]
+ : *low;
+#else
+ *low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low;
+#endif
+ return low;
+}
+
+wchar_t
+ctype<wchar_t>::do_tolower(char_type c) const
+{
+#ifndef _LIBCPP_STABLE_APPLE_ABI
+ return isascii(c) ? ctype<char>::__classic_lower_table()[c] : c;
+#else
+ return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
+#endif
+}
+
+const wchar_t*
+ctype<wchar_t>::do_tolower(char_type* low, const char_type* high) const
+{
+ for (; low != high; ++low)
+#ifndef _LIBCPP_STABLE_APPLE_ABI
+ *low = isascii(*low) ? ctype<char>::__classic_lower_table()[*low]
+ : *low;
+#else
+ *low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low;
+#endif
+ return low;
+}
+
+wchar_t
+ctype<wchar_t>::do_widen(char c) const
+{
+ return c;
+}
+
+const char*
+ctype<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const
+{
+ for (; low != high; ++low, ++dest)
+ *dest = *low;
+ return low;
+}
+
+char
+ctype<wchar_t>::do_narrow(char_type c, char dfault) const
+{
+ if (isascii(c))
+ return static_cast<char>(c);
+ return dfault;
+}
+
+const wchar_t*
+ctype<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
+{
+ for (; low != high; ++low, ++dest)
+ if (isascii(*low))
+ *dest = *low;
+ else
+ *dest = dfault;
+ return low;
+}
+
+// template <> class ctype<char>;
+
+locale::id ctype<char>::id;
+
+ctype<char>::ctype(const mask* tab, bool del, size_t refs)
+ : locale::facet(refs),
+ __tab_(tab),
+ __del_(del)
+{
+ if (__tab_ == 0)
+ __tab_ = classic_table();
+}
+
+ctype<char>::~ctype()
+{
+ if (__tab_ && __del_)
+ delete [] __tab_;
+}
+
+char
+ctype<char>::do_toupper(char_type c) const
+{
+#ifndef _LIBCPP_STABLE_APPLE_ABI
+ return isascii(c) ? __classic_upper_table()[c] : c;
+#else
+ return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
+#endif
+}
+
+const char*
+ctype<char>::do_toupper(char_type* low, const char_type* high) const
+{
+ for (; low != high; ++low)
+#ifndef _LIBCPP_STABLE_APPLE_ABI
+ *low = isascii(*low) ? __classic_upper_table()[*low] : *low;
+#else
+ *low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low;
+#endif
+ return low;
+}
+
+char
+ctype<char>::do_tolower(char_type c) const
+{
+#ifndef _LIBCPP_STABLE_APPLE_ABI
+ return isascii(c) ? __classic_lower_table()[c] : c;
+#else
+ return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
+#endif
+}
+
+const char*
+ctype<char>::do_tolower(char_type* low, const char_type* high) const
+{
+ for (; low != high; ++low)
+#ifndef _LIBCPP_STABLE_APPLE_ABI
+ *low = isascii(*low) ? __classic_lower_table()[*low] : *low;
+#else
+ *low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low;
+#endif
+ return low;
+}
+
+char
+ctype<char>::do_widen(char c) const
+{
+ return c;
+}
+
+const char*
+ctype<char>::do_widen(const char* low, const char* high, char_type* dest) const
+{
+ for (; low != high; ++low, ++dest)
+ *dest = *low;
+ return low;
+}
+
+char
+ctype<char>::do_narrow(char_type c, char dfault) const
+{
+ if (isascii(c))
+ return static_cast<char>(c);
+ return dfault;
+}
+
+const char*
+ctype<char>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
+{
+ for (; low != high; ++low, ++dest)
+ if (isascii(*low))
+ *dest = *low;
+ else
+ *dest = dfault;
+ return low;
+}
+
+const ctype<char>::mask*
+ctype<char>::classic_table() _NOEXCEPT
+{
+#if defined(__APPLE__) || defined(__FreeBSD__)
+ return _DefaultRuneLocale.__runetype;
+#elif defined(__GLIBC__)
+ return __cloc()->__ctype_b;
+// This is assumed to be safe, which is a nonsense assumption because we're
+// going to end up dereferencing it later...
+#else
+ return NULL;
+#endif
+}
+
+#ifndef _LIBCPP_STABLE_APPLE_ABI
+const int*
+ctype<char>::__classic_lower_table() _NOEXCEPT
+{
+#if defined(__APPLE__) || defined(__FreeBSD__)
+ return _DefaultRuneLocale.__maplower;
+#elif defined(__GLIBC__)
+ return __cloc()->__ctype_tolower;
+#else
+ return NULL;
+#endif
+}
+
+const int*
+ctype<char>::__classic_upper_table() _NOEXCEPT
+{
+#if defined(__APPLE__) || defined(__FreeBSD__)
+ return _DefaultRuneLocale.__mapupper;
+#elif defined(__GLIBC__)
+ return __cloc()->__ctype_toupper;
+#else
+ return NULL;
+#endif
+}
+#endif // _LIBCPP_STABLE_APPLE_ABI
+
+// template <> class ctype_byname<char>
+
+ctype_byname<char>::ctype_byname(const char* name, size_t refs)
+ : ctype<char>(0, false, refs),
+ __l(newlocale(LC_ALL_MASK, name, 0))
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ if (__l == 0)
+ throw runtime_error("ctype_byname<char>::ctype_byname"
+ " failed to construct for " + string(name));
+#endif // _LIBCPP_NO_EXCEPTIONS
+}
+
+ctype_byname<char>::ctype_byname(const string& name, size_t refs)
+ : ctype<char>(0, false, refs),
+ __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ if (__l == 0)
+ throw runtime_error("ctype_byname<char>::ctype_byname"
+ " failed to construct for " + name);
+#endif // _LIBCPP_NO_EXCEPTIONS
+}
+
+ctype_byname<char>::~ctype_byname()
+{
+ freelocale(__l);
+}
+
+char
+ctype_byname<char>::do_toupper(char_type c) const
+{
+ return toupper_l(c, __l);
+}
+
+const char*
+ctype_byname<char>::do_toupper(char_type* low, const char_type* high) const
+{
+ for (; low != high; ++low)
+ *low = toupper_l(*low, __l);
+ return low;
+}
+
+char
+ctype_byname<char>::do_tolower(char_type c) const
+{
+ return tolower_l(c, __l);
+}
+
+const char*
+ctype_byname<char>::do_tolower(char_type* low, const char_type* high) const
+{
+ for (; low != high; ++low)
+ *low = tolower_l(*low, __l);
+ return low;
+}
+
+// template <> class ctype_byname<wchar_t>
+
+ctype_byname<wchar_t>::ctype_byname(const char* name, size_t refs)
+ : ctype<wchar_t>(refs),
+ __l(newlocale(LC_ALL_MASK, name, 0))
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ if (__l == 0)
+ throw runtime_error("ctype_byname<wchar_t>::ctype_byname"
+ " failed to construct for " + string(name));
+#endif // _LIBCPP_NO_EXCEPTIONS
+}
+
+ctype_byname<wchar_t>::ctype_byname(const string& name, size_t refs)
+ : ctype<wchar_t>(refs),
+ __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+ if (__l == 0)
+ throw runtime_error("ctype_byname<wchar_t>::ctype_byname"
+ " failed to construct for " + name);
+#endif // _LIBCPP_NO_EXCEPTIONS
+}
+
+ctype_byname<wchar_t>::~ctype_byname()
+{
+ freelocale(__l);
+}
+
+bool
+ctype_byname<wchar_t>::do_is(mask m, char_type c) const
+{
+#ifdef _LIBCPP_WCTYPE_IS_MASK
+ return static_cast<bool>(iswctype_l(c, m, __l));
+#else
+ // FIXME: This is broken for things that test more than one flag.
+ if (m & space && !iswspace_l(c, __l)) return false;
+ if (m & print && !iswprint_l(c, __l)) return false;
+ if (m & cntrl && !iswcntrl_l(c, __l)) return false;
+ if (m & upper && !iswupper_l(c, __l)) return false;
+ if (m & lower && !iswlower_l(c, __l)) return false;
+ if (m & alpha && !iswalpha_l(c, __l)) return false;
+ if (m & digit && !iswdigit_l(c, __l)) return false;
+ if (m & punct && !iswpunct_l(c, __l)) return false;
+ if (m & xdigit && !iswxdigit_l(c, __l)) return false;
+ if (m & blank && !iswblank_l(c, __l)) return false;
+ return true;
+#endif
+}
+
+const wchar_t*
+ctype_byname<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
+{
+ for (; low != high; ++low, ++vec)
+ {
+ if (isascii(*low))
+ *vec = static_cast<mask>(ctype<char>::classic_table()[*low]);
+ else
+ {
+ *vec = 0;
+ if (iswspace_l(*low, __l))
+ *vec |= space;
+ if (iswprint_l(*low, __l))
+ *vec |= print;
+ if (iswcntrl_l(*low, __l))
+ *vec |= cntrl;
+ if (iswupper_l(*low, __l))
+ *vec |= upper;
+ if (iswlower_l(*low, __l))
+ *vec |= lower;
+ if (iswalpha_l(*low, __l))
+ *vec |= alpha;
+ if (iswdigit_l(*low, __l))
+ *vec |= digit;
+ if (iswpunct_l(*low, __l))
+ *vec |= punct;
+ if (iswxdigit_l(*low, __l))
+ *vec |= xdigit;
+ }
+ }
+ return low;
+}
+
+const wchar_t*
+ctype_byname<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
+{
+ for (; low != high; ++low)
+ {
+#ifdef _LIBCPP_WCTYPE_IS_MASK
+ if (iswctype_l(*low, m, __l))
+ break;
+#else
+ if (m & space && !iswspace_l(*low, __l)) continue;
+ if (m & print && !iswprint_l(*low, __l)) continue;
+ if (m & cntrl && !iswcntrl_l(*low, __l)) continue;
+ if (m & upper && !iswupper_l(*low, __l)) continue;
+ if (m & lower && !iswlower_l(*low, __l)) continue;
+ if (m & alpha && !iswalpha_l(*low, __l)) continue;
+ if (m & digit && !iswdigit_l(*low, __l)) continue;
+ if (m & punct && !iswpunct_l(*low, __l)) continue;
+ if (m & xdigit && !iswxdigit_l(*low, __l)) continue;
+ if (m & blank && !iswblank_l(*low, __l)) continue;
+ break;
+#endif
+ }
+ return low;
+}
+
+const wchar_t*
+ctype_byname<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
+{
+ for (; low != high; ++low)
+ {
+#ifdef _LIBCPP_WCTYPE_IS_MASK
+ if (!iswctype_l(*low, m, __l))
+ break;
+#else
+ if (m & space && iswspace_l(*low, __l)) continue;
+ if (m & print && iswprint_l(*low, __l)) continue;
+ if (m & cntrl && iswcntrl_l(*low, __l)) continue;
+ if (m & upper && iswupper_l(*low, __l)) continue;
+ if (m & lower && iswlower_l(*low, __l)) continue;
+ if (m & alpha && iswalpha_l(*low, __l)) continue;
+ if (m & digit && iswdi