diff --git a/include/__locale b/include/__locale index 61034094..521da049 100644 --- a/include/__locale +++ b/include/__locale @@ -302,7 +302,11 @@ locale::operator()(const basic_string<_CharT, _Traits, _Allocator>& __x, class _LIBCPP_VISIBLE ctype_base { public: +#ifdef __GLIBC__ + typedef unsigned short mask; +#else typedef __uint32_t mask; +#endif #if __APPLE__ static const mask space = _CTYPE_S; @@ -537,6 +541,8 @@ public: #endif _LIBCPP_ALWAYS_INLINE const mask* table() const _NOEXCEPT {return __tab_;} static const mask* classic_table() _NOEXCEPT; + static const int* __classic_upper_table() _NOEXCEPT; + static const int* __classic_lower_table() _NOEXCEPT; protected: ~ctype(); diff --git a/include/locale b/include/locale index f85e63c3..4a65eb6b 100644 --- a/include/locale +++ b/include/locale @@ -192,6 +192,9 @@ template class messages_byname; _LIBCPP_BEGIN_NAMESPACE_STD +// Get the C locale object +locale_t __cloc(); + // OSX has nice foo_l() functions that let you turn off use of the global // locale. Linux, not so much. The following functions avoid the locale when // that's possible and otherwise do the wrong thing. FIXME. diff --git a/src/locale.cpp b/src/locale.cpp index 5d1d607f..eafd7639 100644 --- a/src/locale.cpp +++ b/src/locale.cpp @@ -116,6 +116,18 @@ namespace with_locale { namespace { _LIBCPP_BEGIN_NAMESPACE_STD +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 +} + namespace { struct release @@ -767,93 +779,64 @@ ctype::~ctype() bool ctype::do_is(mask m, char_type c) const { -#ifdef __APPLE__ - return isascii(c) ? _DefaultRuneLocale.__runetype[c] & m : false; -#else - return false; -#endif + return isascii(c) ? ctype::classic_table()[c] & m : false; } const wchar_t* ctype::do_is(const char_type* low, const char_type* high, mask* vec) const { -#ifdef __APPLE__ for (; low != high; ++low, ++vec) - *vec = static_cast(isascii(*low) ? _DefaultRuneLocale.__runetype[*low] : 0); + *vec = static_cast(isascii(*low) ? + ctype::classic_table()[*low] : 0); return low; -#else - return NULL; -#endif } const wchar_t* ctype::do_scan_is(mask m, const char_type* low, const char_type* high) const { -#ifdef __APPLE__ for (; low != high; ++low) - if (isascii(*low) && (_DefaultRuneLocale.__runetype[*low] & m)) + if (isascii(*low) && (ctype::classic_table()[*low] & m)) break; return low; -#else - return NULL; -#endif } const wchar_t* ctype::do_scan_not(mask m, const char_type* low, const char_type* high) const { -#ifdef __APPLE__ for (; low != high; ++low) - if (!(isascii(*low) && (_DefaultRuneLocale.__runetype[*low] & m))) + if (!(isascii(*low) && (ctype::classic_table()[*low] & m))) break; return low; -#else - return NULL; -#endif } wchar_t ctype::do_toupper(char_type c) const { -#ifdef __APPLE__ - return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c; -#else - return 0; -#endif + return isascii(c) ? ctype::__classic_upper_table()[c] : c; } const wchar_t* ctype::do_toupper(char_type* low, const char_type* high) const { -#ifdef __APPLE__ for (; low != high; ++low) - *low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low; + *low = isascii(*low) ? ctype::__classic_upper_table()[*low] + : *low; return low; -#else - return NULL; -#endif } wchar_t ctype::do_tolower(char_type c) const { -#ifdef __APPLE__ - return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c; -#else - return 0; -#endif + return isascii(c) ? ctype::__classic_lower_table()[c] : c; } const wchar_t* ctype::do_tolower(char_type* low, const char_type* high) const { -#ifdef __APPLE__ for (; low != high; ++low) - *low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low; + *low = isascii(*low) ? ctype::__classic_lower_table()[*low] + : *low; return low; -#else - return NULL; -#endif } wchar_t @@ -898,10 +881,8 @@ ctype::ctype(const mask* tab, bool del, size_t refs) __tab_(tab), __del_(del) { -#ifdef __APPLE__ - if (__tab_ == 0) - __tab_ = _DefaultRuneLocale.__runetype; -#endif + if (__tab_ == 0) + __tab_ = classic_table(); } ctype::~ctype() @@ -913,45 +894,29 @@ ctype::~ctype() char ctype::do_toupper(char_type c) const { -#ifdef __APPLE__ - return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c; -#else - return 0; -#endif + return isascii(c) ? __classic_upper_table()[c] : c; } const char* ctype::do_toupper(char_type* low, const char_type* high) const { -#ifdef __APPLE__ for (; low != high; ++low) - *low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low; + *low = isascii(*low) ? __classic_upper_table()[*low] : *low; return low; -#else - return NULL; -#endif } char ctype::do_tolower(char_type c) const { -#ifdef __APPLE__ - return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c; -#else - return 0; -#endif + return isascii(c) ? __classic_lower_table()[c] : c; } const char* ctype::do_tolower(char_type* low, const char_type* high) const { -#ifdef __APPLE__ for (; low != high; ++low) - *low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low; + *low = isascii(*low) ? __classic_lower_table()[*low] : *low; return low; -#else - return NULL; -#endif } char @@ -992,6 +957,33 @@ ctype::classic_table() _NOEXCEPT { #ifdef __APPLE__ return _DefaultRuneLocale.__runetype; +#elif defined(__GLIBC__) + return __cloc()->__ctype_b; +// This is assumed to be safe. +#else + return NULL; +#endif +} + +const int* +ctype::__classic_lower_table() _NOEXCEPT +{ +#ifdef __APPLE__ + return _DefaultRuneLocale.__maplower; +#elif defined(__GLIBC__) + return __cloc()->__ctype_tolower; +#else + return NULL; +#endif +} + +const int* +ctype::__classic_upper_table() _NOEXCEPT +{ +#ifdef __APPLE__ + return _DefaultRuneLocale.__mapupper; +#elif defined(__GLIBC__) + return __cloc()->__ctype_toupper; #else return NULL; #endif @@ -1092,11 +1084,10 @@ ctype_byname::do_is(mask m, char_type c) const const wchar_t* ctype_byname::do_is(const char_type* low, const char_type* high, mask* vec) const { -#ifdef __APPLE__ for (; low != high; ++low, ++vec) { if (isascii(*low)) - *vec = static_cast(_DefaultRuneLocale.__runetype[*low]); + *vec = static_cast(ctype::classic_table()[*low]); else { *vec = 0; @@ -1121,9 +1112,6 @@ ctype_byname::do_is(const char_type* low, const char_type* high, mask* } } return low; -#else - return NULL; -#endif } const wchar_t*