1 // -*- C++ -*- 2 //===-------------------- support/android/locale_support.c ------------------===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is dual licensed under the MIT and the University of Illinois Open 7 // Source Licenses. See LICENSE.TXT for details. 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include <ctype.h> 12 #include <errno.h> 13 #include <limits.h> 14 #include <locale.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <time.h> 18 #include <wctype.h> 19 20 // Contains an implementation of all locale-specific functions (those 21 // ending in _l, like strcoll_l()), as simple wrapper to the non-locale 22 // specific ones for now. 23 // 24 // That's because Android's C library doesn't support locales. Or more 25 // specifically, only supports the "C" one. 26 // 27 // TODO(digit): Write a more complete implementation that uses JNI to 28 // invoke the platform APIs to implement proper handling. 29 // 30 31 /////////////////////////////////////////////////////////////////////// 32 // ctype.h declarations 33 34 # define define_char_wrapper_l(name) \ 35 int name ## _l (int ch, locale_t loc) { \ 36 return name (ch); \ 37 } 38 39 define_char_wrapper_l (isalnum); 40 define_char_wrapper_l (isalpha); 41 define_char_wrapper_l (iscntrl); 42 define_char_wrapper_l (isdigit); 43 define_char_wrapper_l (islower); 44 define_char_wrapper_l (isgraph); 45 define_char_wrapper_l (isprint); 46 define_char_wrapper_l (ispunct); 47 define_char_wrapper_l (isspace); 48 define_char_wrapper_l (isupper); 49 define_char_wrapper_l (isxdigit); 50 define_char_wrapper_l (isblank); 51 define_char_wrapper_l (tolower) 52 define_char_wrapper_l (toupper) 53 54 // TODO(ajwong): This table is copied from bionic's ctype implementation. 55 // It doesn't support signed chars and will index out of bounds. The best way 56 // to fix is to patch bionic's ctype array to support both signed and 57 // unsigned char and then just directly reference it. 58 static char const real_ctype_c_mask_table[256] = { 59 0, 60 _C, _C, _C, _C, _C, _C, _C, _C, 61 _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, 62 _C, _C, _C, _C, _C, _C, _C, _C, 63 _C, _C, _C, _C, _C, _C, _C, _C, 64 _S|(char)_B, _P, _P, _P, _P, _P, _P, _P, 65 _P, _P, _P, _P, _P, _P, _P, _P, 66 _N, _N, _N, _N, _N, _N, _N, _N, 67 _N, _N, _P, _P, _P, _P, _P, _P, 68 _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, 69 _U, _U, _U, _U, _U, _U, _U, _U, 70 _U, _U, _U, _U, _U, _U, _U, _U, 71 _U, _U, _U, _P, _P, _P, _P, _P, 72 _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, 73 _L, _L, _L, _L, _L, _L, _L, _L, 74 _L, _L, _L, _L, _L, _L, _L, _L, 75 /* determine printability based on the IS0 8859 8-bit standard */ 76 _L, _L, _L, _P, _P, _P, _P, _C, 77 78 _C, _C, _C, _C, _C, _C, _C, _C, /* 80 */ 79 _C, _C, _C, _C, _C, _C, _C, _C, /* 88 */ 80 _C, _C, _C, _C, _C, _C, _C, _C, /* 90 */ 81 _C, _C, _C, _C, _C, _C, _C, _C, /* 98 */ 82 _P, _P, _P, _P, _P, _P, _P, _P, /* A0 */ 83 _P, _P, _P, _P, _P, _P, _P, _P, /* A8 */ 84 _P, _P, _P, _P, _P, _P, _P, _P, /* B0 */ 85 _P, _P, _P, _P, _P, _P, _P, _P, /* B8 */ 86 _P, _P, _P, _P, _P, _P, _P, _P, /* C0 */ 87 _P, _P, _P, _P, _P, _P, _P, _P, /* C8 */ 88 _P, _P, _P, _P, _P, _P, _P, _P, /* D0 */ 89 _P, _P, _P, _P, _P, _P, _P, _P, /* D8 */ 90 _P, _P, _P, _P, _P, _P, _P, _P, /* E0 */ 91 _P, _P, _P, _P, _P, _P, _P, _P, /* E8 */ 92 _P, _P, _P, _P, _P, _P, _P, _P, /* F0 */ 93 _P, _P, _P, _P, _P, _P, _P, _P /* F8 */ 94 }; 95 char const* const __ctype_c_mask_table = &real_ctype_c_mask_table[0]; 96 97 /////////////////////////////////////////////////////////////////////// 98 // stdio.h declarations 99 100 int vasprintf_l(char** strp, locale_t l, const char* fmt, va_list args) { 101 // Ignore locale. 102 return vasprintf(strp, fmt, args); 103 } 104 105 int asprintf_l(char** strp, locale_t locale, const char* fmt, ...) { 106 va_list args; 107 va_start(args, fmt); 108 int result = vasprintf_l(strp, locale, fmt, args); 109 va_end(args); 110 return result; 111 } 112 113 int vsprintf_l(char* str, locale_t l, const char* fmt, va_list args) { 114 // Ignore locale. 115 return vsprintf(str, fmt, args); 116 } 117 118 int sprintf_l(char* str, locale_t l, const char* fmt, ...) { 119 va_list args; 120 va_start(args, fmt); 121 int result = vsprintf_l(str, l, fmt, args); 122 va_end(args); 123 return result; 124 } 125 126 int vsnprintf_l(char* str, size_t size, locale_t l, const char* fmt, va_list args) { 127 return vsnprintf(str, size, fmt, args); 128 } 129 130 int snprintf_l(char* str, size_t size, locale_t l, const char* fmt, ...) { 131 va_list args; 132 va_start(args, fmt); 133 int result = vsnprintf_l(str, size, l, fmt, args); 134 va_end(args); 135 return result; 136 } 137 138 int vsscanf_l(const char* str, locale_t l, const char* fmt, va_list args) { 139 return vsscanf(str, fmt, args); 140 } 141 142 int sscanf_l(const char* str, locale_t l, const char* fmt, ...) { 143 va_list args; 144 va_start(args, fmt); 145 int result = vsscanf_l(str, l, fmt, args); 146 va_end(args); 147 return result; 148 } 149 150 /////////////////////////////////////////////////////////////////////// 151 // stdlib.h declarations 152 153 long strtol_l(const char *nptr, char **endptr, int base, locale_t loc) { 154 return strtol(nptr, endptr, base); 155 } 156 157 long long strtoll_l(const char *nptr, char **endptr, int base, locale_t loc) { 158 return strtoll(nptr, endptr, base); 159 } 160 161 unsigned long strtoul_l(const char *nptr, char **endptr, int base, locale_t loc) { 162 return strtoul(nptr, endptr, base); 163 } 164 165 unsigned long long strtoull_l(const char *nptr, char **endptr, int base, locale_t loc) { 166 return strtoull(nptr, endptr, base); 167 } 168 169 long double strtold_l (const char *nptr, char **endptr, locale_t loc) { 170 return strtold(nptr, endptr); 171 } 172 173 /////////////////////////////////////////////////////////////////////// 174 // string.h declarations 175 176 int strcoll_l(const char* s1, const char* s2, locale_t loc) { 177 return strcoll(s1, s2); 178 } 179 180 int strxfrm_l(char* dst, const char* src, size_t n, locale_t loc) { 181 return strxfrm(dst, src, n); 182 } 183 184 /////////////////////////////////////////////////////////////////////// 185 // time.h declarations 186 187 size_t strftime_l(char *s, size_t maxsize, const char *format, 188 const struct tm * timeptr, locale_t loc) { 189 return strftime(s, maxsize, format, timeptr); 190 } 191 192 /////////////////////////////////////////////////////////////////////// 193 // wchar.h declarations 194 195 int wcscoll_l(const wchar_t* s1, const wchar_t* s2, locale_t loc) { 196 return wcscoll(s1, s2); 197 } 198 199 int wcsxfrm_l(wchar_t* dst, const wchar_t* src, size_t n, locale_t loc) { 200 return wcsxfrm(dst, src, n); 201 } 202 203 /////////////////////////////////////////////////////////////////////// 204 // wctype.h declarations 205 206 #define define_wchar_wrapper(name) \ 207 int name ## _l (wint_t c, locale_t loc) { \ 208 return name (c); \ 209 } 210 211 define_wchar_wrapper(iswspace) 212 define_wchar_wrapper(iswprint) 213 define_wchar_wrapper(iswcntrl) 214 define_wchar_wrapper(iswupper) 215 define_wchar_wrapper(iswlower) 216 define_wchar_wrapper(iswalpha) 217 define_wchar_wrapper(iswdigit) 218 define_wchar_wrapper(iswpunct) 219 define_wchar_wrapper(iswxdigit) 220 define_wchar_wrapper(iswblank) 221 222 wint_t towlower_l(wint_t c, locale_t loc) { 223 return towlower(c); 224 } 225 226 wint_t towupper_l(wint_t c, locale_t loc) { 227 return towupper(c); 228 } 229 230 /////////////////////////////////////////////////////////////////////// 231 // locale.h declarations 232 233 #define LC_NULL_LOCALE ((locale_t)0) 234 235 locale_t newlocale(int category_mask, const char* locale, locale_t base) { 236 if (base != LC_NULL_LOCALE) 237 return base; 238 239 locale_t loc = calloc(1, sizeof(*loc)); 240 return loc; 241 } 242 243 locale_t duplocale(locale_t loc) { 244 if (loc == LC_GLOBAL_LOCALE) 245 return loc; 246 if (loc == LC_NULL_LOCALE) { 247 errno = EINVAL; 248 return LC_NULL_LOCALE; 249 } 250 locale_t copy = calloc(1, sizeof(*loc)); 251 copy[0] = loc[0]; 252 return copy; 253 } 254 255 // Static mutable variable because setlocale() is supposed to return 256 // a pointer to a writable C string. 257 static char g_C_LOCALE_SETTING[] = "C"; 258 259 char *setlocale(int category, const char *locale) { 260 // Sanity check. 261 if (!locale) { 262 errno = EINVAL; 263 return NULL; 264 } 265 // Only accept "", "C" or "POSIX", all equivalent on Android. 266 if (strcmp(locale, "") && strcmp(locale, "C") && strcmp(locale, "POSIX")) { 267 errno = EINVAL; 268 return NULL; 269 } 270 return g_C_LOCALE_SETTING; 271 } 272 273 locale_t uselocale(locale_t loc) { 274 // If 'loc' is LC_GLOBAL_LOCALE, should return the global locale set 275 // through setlocale(). Since the implementation above doesn't modify 276 // anything, just return LC_GLOBAL_LOCALE too. 277 278 // If 'loc' is (locale_t)0, should return either LC_GLOBAL_LOCALE or 279 // or the global locale if setlocale() has been called at least once. 280 281 // Should return the previous value from a previous call, of 282 // LC_GLOBAL_LOCALE. 283 284 // So, in all cases, return LC_GLOBAL_LOCALE 285 return LC_GLOBAL_LOCALE; 286 } 287 288 void freelocale(locale_t loc) { 289 if (loc != LC_NULL_LOCALE && loc != LC_GLOBAL_LOCALE) 290 free(loc); 291 } 292 293 static struct lconv g_C_LCONV[1] = { { 294 .decimal_point = ".", 295 .thousands_sep = "", 296 .grouping = "", 297 .int_curr_symbol = "", 298 .currency_symbol = "", 299 .mon_decimal_point = "", 300 .mon_thousands_sep = "", 301 .mon_grouping = "", 302 .positive_sign = "", 303 .negative_sign = "", 304 .int_frac_digits = CHAR_MAX, 305 .frac_digits = CHAR_MAX, 306 .p_cs_precedes = CHAR_MAX, 307 .p_sep_by_space = CHAR_MAX, 308 .n_cs_precedes = CHAR_MAX, 309 .n_sep_by_space = CHAR_MAX, 310 .p_sign_posn = CHAR_MAX, 311 .n_sign_posn = CHAR_MAX, 312 .int_p_cs_precedes = CHAR_MAX, 313 .int_p_sep_by_space = CHAR_MAX, 314 .int_n_cs_precedes = CHAR_MAX, 315 .int_n_sep_by_space = CHAR_MAX, 316 .int_p_sign_posn = CHAR_MAX, 317 .int_n_sign_posn = CHAR_MAX, 318 } }; 319 320 struct lconv* localeconv(void) { 321 return g_C_LCONV; 322 } 323