Home | History | Annotate | Download | only in c_locale_win32
      1 /*
      2  * Copyright (c) 2007 2008
      3  * Francois Dumont
      4  *
      5  * This material is provided "as is", with absolutely no warranty expressed
      6  * or implied. Any use is at your own risk.
      7  *
      8  * Permission to use or copy this software for any purpose is hereby granted
      9  * without fee, provided the above notices are retained on all copies.
     10  * Permission to modify the code and to distribute modified code is granted,
     11  * provided the above notices are retained, and a notice that the code was
     12  * modified is included with the above copyright notice.
     13  *
     14  */
     15 
     16 #if defined (_STLP_USE_SAFE_STRING_FUNCTIONS)
     17 #  define _STLP_WCSNCPY(D, DS, S, C) wcsncpy_s(D, DS, S, C)
     18 #else
     19 #  define _STLP_WCSNCPY(D, DS, S, C) wcsncpy(D, S, C)
     20 #endif
     21 
     22 static const wchar_t* __wtrue_name = L"true";
     23 static const wchar_t* __wfalse_name = L"false";
     24 
     25 typedef struct _Locale_codecvt {
     26   _Locale_lcid_t lc;
     27   UINT cp;
     28   unsigned char cleads[256 / CHAR_BIT];
     29   unsigned char max_char_size;
     30   DWORD mbtowc_flags;
     31   DWORD wctomb_flags;
     32 } _Locale_codecvt_t;
     33 
     34 /* Ctype */
     35 _Locale_mask_t _WLocale_ctype(_Locale_ctype_t* ltype, wint_t c,
     36                               _Locale_mask_t which_bits) {
     37   wchar_t buf[2];
     38   WORD out[2];
     39   buf[0] = c; buf[1] = 0;
     40   GetStringTypeW(CT_CTYPE1, buf, -1, out);
     41   _STLP_MARK_PARAMETER_AS_UNUSED(ltype)
     42   return (_Locale_mask_t)(MapCtypeMask(out[0]) & which_bits);
     43 }
     44 
     45 wint_t _WLocale_tolower(_Locale_ctype_t* ltype, wint_t c) {
     46   wchar_t in_c = c;
     47   wchar_t res;
     48 
     49   LCMapStringW(ltype->lc.id, LCMAP_LOWERCASE, &in_c, 1, &res, 1);
     50   return res;
     51 }
     52 
     53 wint_t _WLocale_toupper(_Locale_ctype_t* ltype, wint_t c) {
     54   wchar_t in_c = c;
     55   wchar_t res;
     56 
     57   LCMapStringW(ltype->lc.id, LCMAP_UPPERCASE, &in_c, 1, &res, 1);
     58   return res;
     59 }
     60 
     61 _Locale_codecvt_t* _Locale_codecvt_create(const char * name, _Locale_lcid_t* lc_hint, int *__err_code) {
     62   char cp_name[MAX_CP_LEN + 1];
     63   unsigned char *ptr;
     64   CPINFO CPInfo;
     65   int i;
     66 
     67   _Locale_codecvt_t *lcodecvt = (_Locale_codecvt_t*)malloc(sizeof(_Locale_codecvt_t));
     68 
     69   if (!lcodecvt) { *__err_code = _STLP_LOC_NO_MEMORY; return lcodecvt; }
     70   memset(lcodecvt, 0, sizeof(_Locale_codecvt_t));
     71 
     72   if (__GetLCIDFromName(name, &lcodecvt->lc.id, cp_name, lc_hint) == -1)
     73   { free(lcodecvt); *__err_code = _STLP_LOC_UNKNOWN_NAME; return NULL; }
     74 
     75   lcodecvt->cp = atoi(cp_name);
     76   if (!GetCPInfo(lcodecvt->cp, &CPInfo)) { free(lcodecvt); return NULL; }
     77 
     78   if (lcodecvt->cp != CP_UTF7 && lcodecvt->cp != CP_UTF8) {
     79     lcodecvt->mbtowc_flags = MB_PRECOMPOSED;
     80     lcodecvt->wctomb_flags = WC_COMPOSITECHECK | WC_SEPCHARS;
     81   }
     82   lcodecvt->max_char_size = CPInfo.MaxCharSize;
     83 
     84   if (CPInfo.MaxCharSize > 1) {
     85     for (ptr = (unsigned char*)CPInfo.LeadByte; *ptr && *(ptr + 1); ptr += 2)
     86       for (i = *ptr; i <= *(ptr + 1); ++i) lcodecvt->cleads[i / CHAR_BIT] |= (0x01 << i % CHAR_BIT);
     87   }
     88 
     89   return lcodecvt;
     90 }
     91 
     92 char const* _Locale_codecvt_name(const _Locale_codecvt_t* lcodecvt, char* buf) {
     93   char cp_buf[MAX_CP_LEN + 1];
     94   my_ltoa(lcodecvt->cp, cp_buf);
     95   return __GetLocaleName(lcodecvt->lc.id, cp_buf, buf);
     96 }
     97 
     98 void _Locale_codecvt_destroy(_Locale_codecvt_t* lcodecvt) {
     99   if (!lcodecvt) return;
    100 
    101   free(lcodecvt);
    102 }
    103 
    104 int _WLocale_mb_cur_max (_Locale_codecvt_t * lcodecvt)
    105 { return lcodecvt->max_char_size; }
    106 
    107 int _WLocale_mb_cur_min (_Locale_codecvt_t *lcodecvt) {
    108   _STLP_MARK_PARAMETER_AS_UNUSED(lcodecvt)
    109   return 1;
    110 }
    111 
    112 int _WLocale_is_stateless (_Locale_codecvt_t * lcodecvt)
    113 { return (lcodecvt->max_char_size == 1) ? 1 : 0; }
    114 
    115 static int __isleadbyte(int i, unsigned char *ctable) {
    116   unsigned char c = (unsigned char)i;
    117   return (ctable[c / CHAR_BIT] & (0x01 << c % CHAR_BIT));
    118 }
    119 
    120 static int __mbtowc(_Locale_codecvt_t *l, wchar_t *dst, const char *from, unsigned int count) {
    121   int result;
    122 
    123   if (l->cp == CP_UTF7 || l->cp == CP_UTF8) {
    124     result = MultiByteToWideChar(l->cp, l->mbtowc_flags, from, count, dst, 1);
    125     if (result == 0) {
    126       switch (GetLastError()) {
    127         case ERROR_NO_UNICODE_TRANSLATION:
    128           return -2;
    129         default:
    130           return -1;
    131       }
    132     }
    133   }
    134   else {
    135     if (count == 1 && __isleadbyte(*from, l->cleads)) return (size_t)-2;
    136     result = MultiByteToWideChar(l->cp, l->mbtowc_flags, from, count, dst, 1);
    137     if (result == 0) return -1;
    138   }
    139 
    140   return result;
    141 }
    142 
    143 size_t _WLocale_mbtowc(_Locale_codecvt_t *lcodecvt, wchar_t *to,
    144                        const char *from, size_t n, mbstate_t *shift_state) {
    145   int result;
    146   _STLP_MARK_PARAMETER_AS_UNUSED(shift_state)
    147   if (lcodecvt->max_char_size == 1) { /* Single byte encoding. */
    148     result = MultiByteToWideChar(lcodecvt->cp, lcodecvt->mbtowc_flags, from, 1, to, 1);
    149     if (result == 0) return (size_t)-1;
    150     return result;
    151   }
    152   else { /* Multi byte encoding. */
    153     int retval;
    154     unsigned int count = 1;
    155     while (n--) {
    156       retval = __mbtowc(lcodecvt, to, from, count);
    157       if (retval == -2)
    158       { if (++count > ((unsigned int)lcodecvt->max_char_size)) return (size_t)-1; }
    159       else if (retval == -1)
    160       { return (size_t)-1; }
    161       else
    162       { return count; }
    163     }
    164     return (size_t)-2;
    165   }
    166 }
    167 
    168 size_t _WLocale_wctomb(_Locale_codecvt_t *lcodecvt, char *to, size_t n,
    169                        const wchar_t c, mbstate_t *shift_state) {
    170   int size = WideCharToMultiByte(lcodecvt->cp, lcodecvt->wctomb_flags, &c, 1, NULL, 0, NULL, NULL);
    171 
    172   if (!size) return (size_t)-1;
    173   if ((size_t)size > n) return (size_t)-2;
    174 
    175   if (n > INT_MAX)
    176     /* Limiting the output buf size to INT_MAX seems like reasonable to transform a single wchar_t. */
    177     n = INT_MAX;
    178 
    179   WideCharToMultiByte(lcodecvt->cp,  lcodecvt->wctomb_flags, &c, 1, to, (int)n, NULL, NULL);
    180 
    181   _STLP_MARK_PARAMETER_AS_UNUSED(shift_state)
    182   return (size_t)size;
    183 }
    184 
    185 size_t _WLocale_unshift(_Locale_codecvt_t *lcodecvt, mbstate_t *st,
    186                         char *buf, size_t n, char **next) {
    187   /* _WLocale_wctomb do not even touch to st, there is nothing to unshift in this localization implementation. */
    188   _STLP_MARK_PARAMETER_AS_UNUSED(lcodecvt)
    189   _STLP_MARK_PARAMETER_AS_UNUSED(st)
    190   _STLP_MARK_PARAMETER_AS_UNUSED(&n)
    191   *next = buf;
    192   return 0;
    193 }
    194 
    195 /* Collate */
    196 /* This function takes care of the potential size_t DWORD different size. */
    197 static int _WLocale_strcmp_aux(_Locale_collate_t* lcol,
    198                                const wchar_t* s1, size_t n1,
    199                                const wchar_t* s2, size_t n2) {
    200   int result = CSTR_EQUAL;
    201   while (n1 > 0 || n2 > 0) {
    202     DWORD size1 = trim_size_t_to_DWORD(n1);
    203     DWORD size2 = trim_size_t_to_DWORD(n2);
    204     result = CompareStringW(lcol->lc.id, 0, s1, size1, s2, size2);
    205     if (result != CSTR_EQUAL)
    206       break;
    207     n1 -= size1;
    208     n2 -= size2;
    209   }
    210   return result;
    211 }
    212 
    213 int _WLocale_strcmp(_Locale_collate_t* lcol,
    214                     const wchar_t* s1, size_t n1,
    215                     const wchar_t* s2, size_t n2) {
    216   int result;
    217   result = _WLocale_strcmp_aux(lcol, s1, n1, s2, n2);
    218   return (result == CSTR_EQUAL) ? 0 : (result == CSTR_LESS_THAN) ? -1 : 1;
    219 }
    220 
    221 size_t _WLocale_strxfrm(_Locale_collate_t* lcol,
    222                         wchar_t* dst, size_t dst_size,
    223                         const wchar_t* src, size_t src_size) {
    224   int result, i;
    225 
    226   /* see _Locale_strxfrm: */
    227   if (src_size > INT_MAX) {
    228     if (dst != 0) {
    229       _STLP_WCSNCPY(dst, dst_size, src, src_size);
    230     }
    231     return src_size;
    232   }
    233   if (dst_size > INT_MAX) {
    234     dst_size = INT_MAX;
    235   }
    236   result = LCMapStringW(lcol->lc.id, LCMAP_SORTKEY, src, (int)src_size, dst, (int)dst_size);
    237   if (result != 0 && dst != 0) {
    238     for (i = result - 1; i >= 0; --i) {
    239       dst[i] = ((unsigned char*)dst)[i];
    240     }
    241   }
    242   return result != 0 ? result - 1 : 0;
    243 }
    244 
    245 /* Numeric */
    246 wchar_t _WLocale_decimal_point(_Locale_numeric_t* lnum) {
    247   wchar_t buf[4];
    248   GetLocaleInfoW(lnum->lc.id, LOCALE_SDECIMAL, buf, 4);
    249   return buf[0];
    250 }
    251 
    252 wchar_t _WLocale_thousands_sep(_Locale_numeric_t* lnum) {
    253   wchar_t buf[4];
    254   GetLocaleInfoW(lnum->lc.id, LOCALE_STHOUSAND, buf, 4);
    255   return buf[0];
    256 }
    257 
    258 const wchar_t * _WLocale_true(_Locale_numeric_t* lnum, wchar_t* buf, size_t bufSize) {
    259   _STLP_MARK_PARAMETER_AS_UNUSED(lnum)
    260   _STLP_MARK_PARAMETER_AS_UNUSED(buf)
    261   _STLP_MARK_PARAMETER_AS_UNUSED(&bufSize)
    262   return __wtrue_name;
    263 }
    264 
    265 const wchar_t * _WLocale_false(_Locale_numeric_t* lnum, wchar_t* buf, size_t bufSize) {
    266   _STLP_MARK_PARAMETER_AS_UNUSED(lnum)
    267   _STLP_MARK_PARAMETER_AS_UNUSED(buf)
    268   _STLP_MARK_PARAMETER_AS_UNUSED(&bufSize)
    269   return __wfalse_name;
    270 }
    271 
    272 /* Monetary */
    273 const wchar_t* _WLocale_int_curr_symbol(_Locale_monetary_t * lmon, wchar_t* buf, size_t bufSize)
    274 { GetLocaleInfoW(lmon->lc.id, LOCALE_SINTLSYMBOL, buf, (int)bufSize); return buf; }
    275 
    276 const wchar_t* _WLocale_currency_symbol(_Locale_monetary_t * lmon, wchar_t* buf, size_t bufSize)
    277 { GetLocaleInfoW(lmon->lc.id, LOCALE_SCURRENCY, buf, (int)bufSize); return buf; }
    278 
    279 wchar_t _WLocale_mon_decimal_point(_Locale_monetary_t * lmon)
    280 { return lmon->decimal_point[0]; }
    281 
    282 wchar_t _WLocale_mon_thousands_sep(_Locale_monetary_t * lmon)
    283 { return lmon->thousands_sep[0]; }
    284 
    285 const wchar_t* _WLocale_positive_sign(_Locale_monetary_t * lmon, wchar_t* buf, size_t bufSize)
    286 { GetLocaleInfoW(lmon->lc.id, LOCALE_SPOSITIVESIGN, buf, (int)bufSize); return buf; }
    287 
    288 const wchar_t* _WLocale_negative_sign(_Locale_monetary_t * lmon, wchar_t* buf, size_t bufSize)
    289 { GetLocaleInfoW(lmon->lc.id, LOCALE_SNEGATIVESIGN, buf, (int)bufSize); return buf; }
    290 
    291 /* Time */
    292 const wchar_t * _WLocale_full_monthname(_Locale_time_t * ltime, int month,
    293                                         wchar_t* buf, size_t bufSize)
    294 { GetLocaleInfoW(ltime->lc.id, LOCALE_SMONTHNAME1 + month, buf, (int)bufSize); return buf; }
    295 
    296 const wchar_t * _WLocale_abbrev_monthname(_Locale_time_t * ltime, int month,
    297                                           wchar_t* buf, size_t bufSize)
    298 { GetLocaleInfoW(ltime->lc.id, LOCALE_SABBREVMONTHNAME1 + month, buf, (int)bufSize); return buf; }
    299 
    300 const wchar_t * _WLocale_full_dayofweek(_Locale_time_t * ltime, int day,
    301                                         wchar_t* buf, size_t bufSize)
    302 { GetLocaleInfoW(ltime->lc.id, LOCALE_SDAYNAME1 + day, buf, (int)bufSize); return buf; }
    303 
    304 const wchar_t * _WLocale_abbrev_dayofweek(_Locale_time_t * ltime, int day,
    305                                           wchar_t* buf, size_t bufSize)
    306 { GetLocaleInfoW(ltime->lc.id, LOCALE_SABBREVDAYNAME1 + day, buf, (int)bufSize); return buf; }
    307 
    308 const wchar_t* _WLocale_am_str(_Locale_time_t* ltime,
    309                                wchar_t* buf, size_t bufSize)
    310 { GetLocaleInfoW(ltime->lc.id, LOCALE_S1159, buf, (int)bufSize); return buf; }
    311 
    312 const wchar_t* _WLocale_pm_str(_Locale_time_t* ltime,
    313                                wchar_t* buf, size_t bufSize)
    314 { GetLocaleInfoW(ltime->lc.id, LOCALE_S2359, buf, (int)bufSize); return buf; }
    315