Home | History | Annotate | Download | only in android
      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