Index: include/__locale =================================================================== --- include/__locale +++ include/__locale @@ -407,6 +407,32 @@ # define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT # define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA # define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_XDIGIT +#elif defined(__ANDROID__) + # if !defined(_U) + # if !defined(_CTYPE_U) + # error Bionic header ctype.h does not define either _U nor _CTYPE_U + # endif + # define _U _CTYPE_U + # define _L _CTYPE_L + # define _N _CTYPE_N + # define _S _CTYPE_S + # define _P _CTYPE_P + # define _C _CTYPE_C + # define _X _CTYPE_X + # define _B _CTYPE_B + # endif +typedef unsigned short mask; + static const mask space = _S; + static const mask print = _P | _U | _L | _N | _B; + static const mask cntrl = _C; + static const mask upper = _U; + static const mask lower = _L; + static const mask alpha = _U | _L; + static const mask digit = _N; + static const mask punct = _P; + static const mask xdigit = _N | _X; + // See src/support/android/locale_android.cpp for details! + static const mask blank = 0x100; #else typedef unsigned long mask; static const mask space = 1<<0; Index: src/locale.cpp =================================================================== --- src/locale.cpp +++ src/locale.cpp @@ -52,6 +52,10 @@ } #endif // __cloc_defined +inline locale_t __new_cloc() { + return newlocale(LC_ALL_MASK, "C", 0); +} + namespace { struct release @@ -648,8 +652,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) + { +#if !defined(__ANDROID__) throw runtime_error("collate_byname::collate_byname" " failed to construct for " + string(n)); +#else + __l = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -659,8 +669,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) + { +#if !defined(__ANDROID__) throw runtime_error("collate_byname::collate_byname" " failed to construct for " + name); +#else + __l = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -700,8 +716,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) + { +#if !defined(__ANDROID__) throw runtime_error("collate_byname::collate_byname(size_t refs)" " failed to construct for " + string(n)); +#else + __l = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -711,8 +733,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) + { +#if !defined(__ANDROID__) throw runtime_error("collate_byname::collate_byname(size_t refs)" " failed to construct for " + name); +#else + __l = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -806,6 +834,8 @@ #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \ defined(__NetBSD__) return isascii(c) ? ctype::__classic_upper_table()[c] : c; +#elif defined(__ANDROID__) + return isascii(c) ? _toupper_tab_[c + 1] : c; #else return (isascii(c) && iswlower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'a'+L'A' : c; #endif @@ -821,6 +851,8 @@ defined(__NetBSD__) *low = isascii(*low) ? ctype::__classic_upper_table()[*low] : *low; +#elif defined(__ANDROID__) + *low = isascii(*low) ? _toupper_tab_[*low + 1] : *low; #else *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? (*low-L'a'+L'A') : *low; #endif @@ -835,6 +867,8 @@ #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \ defined(__NetBSD__) return isascii(c) ? ctype::__classic_lower_table()[c] : c; +#elif defined(__ANDROID__) + return isascii(c) ? _tolower_tab_[c + 1] : c; #else return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'A'+'a' : c; #endif @@ -850,6 +884,8 @@ defined(__NetBSD__) *low = isascii(*low) ? ctype::__classic_lower_table()[*low] : *low; +#elif defined(__ANDROID__) + *low = isascii(*low) ? _tolower_tab_[*low + 1] : *low; #else *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-L'A'+L'a' : *low; #endif @@ -919,6 +955,8 @@ #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) return isascii(c) ? static_cast(__classic_upper_table()[static_cast(c)]) : c; +#elif defined(__ANDROID__) + return isascii(c) ? _toupper_tab_[c + 1] : c; #else return (isascii(c) && islower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'a'+'A' : c; #endif @@ -936,6 +974,8 @@ #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) *low = isascii(*low) ? static_cast(__classic_upper_table()[static_cast(*low)]) : *low; +#elif defined(__ANDROID__) + *low = isascii(*low) ? _toupper_tab_[*low + 1] : *low; #else *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'a'+'A' : *low; #endif @@ -953,6 +993,8 @@ #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) return isascii(c) ? static_cast(__classic_lower_table()[static_cast(c)]) : c; +#elif defined(__ANDROID__) + return isascii(c) ? _tolower_tab_[c + 1] : c; #else return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'A'+'a' : c; #endif @@ -968,6 +1010,8 @@ *low = static_cast(__classic_lower_table()[static_cast(*low)]); #elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) *low = isascii(*low) ? static_cast(__classic_lower_table()[static_cast(*low)]) : *low; +#elif defined(__ANDROID__) + *low = isascii(*low) ? _tolower_tab_[*low + 1] : *low; #else *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'A'+'a' : *low; #endif @@ -1013,7 +1057,12 @@ extern "C" const int ** __ctype_toupper_loc(); #endif -#ifdef _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE +#if defined(__ANDROID__) +// See src/support/android/android_locale.cpp +extern "C" const unsigned short* const _ctype_android; +#endif + +#if defined(_LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE) const ctype::mask* ctype::classic_table() _NOEXCEPT { @@ -1114,6 +1163,8 @@ #elif defined(_NEWLIB_VERSION) // Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1]. return _ctype_ + 1; +#elif defined(__ANDROID__) + return _ctype_android; #elif defined(_AIX) return (const unsigned int *)__lc_ctype_ptr->obj->mask; #else @@ -1174,8 +1225,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) + { +#if !defined(__ANDROID__) throw runtime_error("ctype_byname::ctype_byname" " failed to construct for " + string(name)); +#else + __l = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -1185,8 +1242,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) + { +#if !defined(__ANDROID__) throw runtime_error("ctype_byname::ctype_byname" " failed to construct for " + name); +#else + __l = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -1231,8 +1294,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) + { +#if !defined(__ANDROID__) throw runtime_error("ctype_byname::ctype_byname" " failed to construct for " + string(name)); +#else + __l = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -1242,8 +1311,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) + { +#if !defined(__ANDROID__) throw runtime_error("ctype_byname::ctype_byname" " failed to construct for " + name); +#else + __l = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -1522,8 +1597,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__l == 0) + { +#if !defined(__ANDROID__) throw runtime_error("codecvt_byname::codecvt_byname" " failed to construct for " + string(nm)); +#else + __l = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -4318,7 +4399,12 @@ { if (strcmp(nm, "C") != 0) { - __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); + locale_t l = newlocale(LC_ALL_MASK, nm, 0); +#if defined(__ANDROID__) + if (l == 0) + l = __new_cloc(); +#endif + __locale_unique_ptr loc(l, freelocale); #ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) throw runtime_error("numpunct_byname::numpunct_byname" @@ -4361,7 +4447,12 @@ { if (strcmp(nm, "C") != 0) { - __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); + locale_t l = newlocale(LC_ALL_MASK, nm, 0); +#if defined(__ANDROID__) + if (l == 0) + l = __new_cloc(); +#endif + __locale_unique_ptr loc(l, freelocale); #ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) throw runtime_error("numpunct_byname::numpunct_byname" @@ -4775,8 +4866,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__loc_ == 0) + { +#if !defined(__ANDROID__) throw runtime_error("time_get_byname" " failed to construct for " + string(nm)); +#else + __loc_ = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -4785,8 +4882,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__loc_ == 0) + { +# if !defined(__ANDROID__) throw runtime_error("time_get_byname" " failed to construct for " + nm); +#else + __loc_ = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -5463,8 +5566,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__loc_ == 0) + { +# if !defined(__ANDROID__) throw runtime_error("time_put_byname" " failed to construct for " + string(nm)); +#else + __loc_ = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -5473,8 +5582,14 @@ { #ifndef _LIBCPP_NO_EXCEPTIONS if (__loc_ == 0) + { +# if !defined(__ANDROID__) throw runtime_error("time_put_byname" " failed to construct for " + nm); +#else + __loc_ = __new_cloc(); +#endif + } #endif // _LIBCPP_NO_EXCEPTIONS } @@ -5893,7 +6008,12 @@ moneypunct_byname::init(const char* nm) { typedef moneypunct base; - __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); + locale_t l = newlocale(LC_ALL_MASK, nm, 0); +#if defined(__ANDROID__) + if (l == 0) + l = __new_cloc(); +#endif + __locale_unique_ptr loc(l, freelocale); #ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) throw runtime_error("moneypunct_byname" @@ -5941,7 +6061,12 @@ moneypunct_byname::init(const char* nm) { typedef moneypunct base; - __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); + locale_t l = newlocale(LC_ALL_MASK, nm, 0); +#if defined(__ANDROID__) + if (l == 0) + l = __new_cloc(); +#endif + __locale_unique_ptr loc(l, freelocale); #ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) throw runtime_error("moneypunct_byname" @@ -6006,7 +6131,12 @@ moneypunct_byname::init(const char* nm) { typedef moneypunct base; - __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); + locale_t l = newlocale(LC_ALL_MASK, nm, 0); +#if defined(__ANDROID__) + if (l == 0) + l = __new_cloc(); +#endif + __locale_unique_ptr loc(l, freelocale); #ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) throw runtime_error("moneypunct_byname" @@ -6089,7 +6219,12 @@ moneypunct_byname::init(const char* nm) { typedef moneypunct base; - __locale_unique_ptr loc(newlocale(LC_ALL_MASK, nm, 0), freelocale); + locale_t l = newlocale(LC_ALL_MASK, nm, 0); +#if defined(__ANDROID__) + if (l == 0) + l = __new_cloc(); +#endif + __locale_unique_ptr loc(l, freelocale); #ifndef _LIBCPP_NO_EXCEPTIONS if (loc == nullptr) throw runtime_error("moneypunct_byname" Index: src/support/android/locale_android.cpp =================================================================== --- /dev/null +++ src/support/android/locale_android.cpp @@ -0,0 +1,101 @@ +// -*- C++ -*- +//===-------------------- support/win32/locale_win32.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 + +// Bionic exports the non-standard _ctype_ array in , +// unfortunately, cannot be used directly for libc++ because it doesn't +// have a proper bit-flag for blank characters. +// +// Note that the header does define a _B flag (as 0x80), but it +// is only set on the space (32) character, and used to implement +// isprint() properly. The implementation of isblank() relies on +// direct comparisons with 9 and 32 instead. +// +// The following is a local copy of the Bionic _ctype_ array that has +// been modified in the following way: +// +// - It stores 16-bit unsigned values, instead of 8-bit char ones. +// +// - Bit flag _BLANK (0x100) is used to indicate blank characters. +// It is only set for indices 9 (TAB) and 32 (SPACE). +// +// - Support signed char properly for indexing. + +// Used to tag blank characters, this doesn't appear in nor +// the original Bionic _ctype_ array. +#define _BLANK 0x100 + +// NOTE: A standalone forward declaration is required to ensure that this +// variable is properly exported with a C name. In other words, this does +// _not_ work: +// +// extern "C" { +// const char* const _ctype_android = ...; +// } +// +extern "C" const unsigned short* const _ctype_android; + +static const unsigned short ctype_android_tab[256+128] = { + /* -128..-1 */ + _C, _C, _C, _C, _C, _C, _C, _C, /* 80 */ + _C, _C, _C, _C, _C, _C, _C, _C, /* 88 */ + _C, _C, _C, _C, _C, _C, _C, _C, /* 90 */ + _C, _C, _C, _C, _C, _C, _C, _C, /* 98 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* A0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* A8 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* B0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* B8 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* C0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* C8 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* D0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* D8 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* E0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* E8 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* F0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* F8 */ + /* 0..127 */ + _C, _C, _C, _C, _C, _C, _C, _C, + _C, _C|_S|_BLANK, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, + _C, _C, _C, _C, _C, _C, _C, _C, + _C, _C, _C, _C, _C, _C, _C, _C, + _S|_B|_BLANK, _P, _P, _P, _P, _P, _P, _P, + _P, _P, _P, _P, _P, _P, _P, _P, + _N, _N, _N, _N, _N, _N, _N, _N, + _N, _N, _P, _P, _P, _P, _P, _P, + _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, + _U, _U, _U, _U, _U, _U, _U, _U, + _U, _U, _U, _U, _U, _U, _U, _U, + _U, _U, _U, _P, _P, _P, _P, _P, + _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, + _L, _L, _L, _L, _L, _L, _L, _L, + _L, _L, _L, _L, _L, _L, _L, _L, + /* determine printability based on the IS0 8859 8-bit standard */ + _L, _L, _L, _P, _P, _P, _P, _C, + /* 128..255, same as -128..127 */ + _C, _C, _C, _C, _C, _C, _C, _C, /* 80 */ + _C, _C, _C, _C, _C, _C, _C, _C, /* 88 */ + _C, _C, _C, _C, _C, _C, _C, _C, /* 90 */ + _C, _C, _C, _C, _C, _C, _C, _C, /* 98 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* A0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* A8 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* B0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* B8 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* C0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* C8 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* D0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* D8 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* E0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* E8 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* F0 */ + _P, _P, _P, _P, _P, _P, _P, _P, /* F8 */ +}; + +const unsigned short* const _ctype_android = ctype_android_tab + 128;