|
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; } |