2 * msvcrt.dll locale functions
4 * Copyright 2000 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
41 #define MAX_ELEM_LEN 64 /* Max length of country/language/CP string */
42 #define MAX_LOCALE_LENGTH 256
43 _locale_t MSVCRT_locale
= NULL
;
44 unsigned short *MSVCRT__pctype
= NULL
;
45 unsigned int MSVCRT___lc_codepage
= 0;
46 int MSVCRT___lc_collate_cp
= 0;
47 LCID MSVCRT___lc_handle
[LC_MAX
- LC_MIN
+ 1] = { 0 };
48 int MSVCRT___mb_cur_max
= 1;
49 BOOL initial_locale
= TRUE
;
51 #define MSVCRT_LEADBYTE 0x8000
52 #define MSVCRT_C1_DEFINED 0x200
54 __lc_time_data cloc_time_data
=
56 {{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
57 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday",
58 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
59 "January", "February", "March", "April", "May", "June", "July",
60 "August", "September", "October", "November", "December",
61 "AM", "PM", "MM/dd/yy", "dddd, MMMM dd, yyyy", "HH:mm:ss"}},
63 MAKELCID(LANG_ENGLISH
, SORT_DEFAULT
),
66 #if _MSVCR_VER == 0 || _MSVCR_VER >= 100
67 {{L
"Sun", L
"Mon", L
"Tue", L
"Wed", L
"Thu", L
"Fri", L
"Sat",
68 L
"Sunday", L
"Monday", L
"Tuesday", L
"Wednesday", L
"Thursday", L
"Friday", L
"Saturday",
69 L
"Jan", L
"Feb", L
"Mar", L
"Apr", L
"May", L
"Jun", L
"Jul", L
"Aug", L
"Sep", L
"Oct", L
"Nov", L
"Dec",
70 L
"January", L
"February", L
"March", L
"April", L
"May", L
"June", L
"July",
71 L
"August", L
"September", L
"October", L
"November", L
"December",
72 L
"AM", L
"PM", L
"MM/dd/yy", L
"dddd, MMMM dd, yyyy", L
"HH:mm:ss"}},
79 static const unsigned char cloc_clmap
[256] =
81 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
82 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
83 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
84 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
85 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
86 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
87 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
88 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
89 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
90 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
91 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
92 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
93 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
94 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
95 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
96 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
97 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
98 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
99 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
100 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
101 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
102 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
103 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
104 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
105 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
106 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
107 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
108 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
109 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
110 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
111 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
112 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
115 static const unsigned char cloc_cumap
[256] =
117 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
118 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
119 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
120 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
121 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
122 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
123 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
124 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
125 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
126 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
127 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
128 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
129 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
130 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
131 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
132 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
133 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
134 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
135 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
136 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
137 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
138 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
139 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
140 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
141 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
142 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
143 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
144 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
145 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
146 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
147 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
148 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
151 static char empty
[] = "";
152 static char cloc_dec_point
[] = ".";
153 #if _MSVCR_VER >= 100
154 static wchar_t emptyW
[] = L
"";
155 static wchar_t cloc_dec_pointW
[] = L
".";
157 static struct lconv cloc_lconv
=
159 cloc_dec_point
, empty
, empty
, empty
, empty
, empty
, empty
, empty
, empty
, empty
,
160 CHAR_MAX
, CHAR_MAX
, CHAR_MAX
, CHAR_MAX
, CHAR_MAX
, CHAR_MAX
, CHAR_MAX
, CHAR_MAX
,
161 #if _MSVCR_VER >= 100
162 cloc_dec_pointW
, emptyW
, emptyW
, emptyW
, emptyW
, emptyW
, emptyW
, emptyW
166 /* Friendly country strings & language names abbreviations. */
167 static const char * const _country_synonyms
[] =
170 "american english", "enu",
171 "american-english", "enu",
172 "english-american", "enu",
174 "english-usa", "enu",
178 "english-aus", "ena",
180 "french-belgian", "frb",
182 "english-can", "enc",
183 "french-canadian", "frc",
185 "chinese-simplified", "chs",
186 "chinese-traditional", "cht",
187 "dutch-belgian", "nlb",
191 "french-swiss", "frs",
193 "german-swiss", "des",
194 "italian-swiss", "its",
195 "german-austrian", "dea",
197 "portuguese-brazil", "ptb",
198 "spanish-mexican", "esm",
199 "norwegian-bokmal", "nor",
200 "norwegian-nynorsk", "non",
201 "spanish-modern", "esn"
204 /* INTERNAL: Map a synonym to an ISO code */
205 static void remap_synonym(char *name
)
208 for (i
= 0; i
< ARRAY_SIZE(_country_synonyms
); i
+= 2)
210 if (!_stricmp(_country_synonyms
[i
],name
))
212 TRACE(":Mapping synonym %s to %s\n",name
,_country_synonyms
[i
+1]);
213 strcpy(name
, _country_synonyms
[i
+1]);
219 /* Note: Flags are weighted in order of matching importance */
220 #define FOUND_SNAME 0x4
221 #define FOUND_LANGUAGE 0x2
222 #define FOUND_COUNTRY 0x1
225 char search_language
[MAX_ELEM_LEN
];
226 char search_country
[MAX_ELEM_LEN
];
227 DWORD found_codepage
;
228 unsigned int match_flags
;
229 LANGID found_lang_id
;
233 #define CONTINUE_LOOKING TRUE
234 #define STOP_LOOKING FALSE
236 /* INTERNAL: Get and compare locale info with a given string */
237 static int compare_info(LCID lcid
, DWORD flags
, char* buff
, const char* cmp
, BOOL exact
)
245 GetLocaleInfoA(lcid
, flags
|LOCALE_NOUSEROVERRIDE
, buff
, MAX_ELEM_LEN
);
249 /* Partial matches are only allowed on language/country names */
252 return !_stricmp(cmp
, buff
);
254 return !_strnicmp(cmp
, buff
, len
);
258 find_best_locale_proc(HMODULE hModule
, LPCSTR type
, LPCSTR name
, WORD LangID
, LONG_PTR lParam
)
260 locale_search_t
*res
= (locale_search_t
*)lParam
;
261 const LCID lcid
= MAKELCID(LangID
, SORT_DEFAULT
);
262 char buff
[MAX_ELEM_LEN
];
263 unsigned int flags
= 0;
265 if(PRIMARYLANGID(LangID
) == LANG_NEUTRAL
)
266 return CONTINUE_LOOKING
;
268 #if _MSVCR_VER >= 110
269 if (res
->allow_sname
&& compare_info(lcid
,LOCALE_SNAME
,buff
,res
->search_language
, TRUE
))
271 TRACE(":Found locale: %s->%s\n", res
->search_language
, buff
);
272 res
->match_flags
= FOUND_SNAME
;
273 res
->found_lang_id
= LangID
;
279 if (compare_info(lcid
,LOCALE_SISO639LANGNAME
,buff
,res
->search_language
, TRUE
) ||
280 compare_info(lcid
,LOCALE_SABBREVLANGNAME
,buff
,res
->search_language
, TRUE
) ||
281 compare_info(lcid
,LOCALE_SENGLANGUAGE
,buff
,res
->search_language
, FALSE
))
283 TRACE(":Found language: %s->%s\n", res
->search_language
, buff
);
284 flags
|= FOUND_LANGUAGE
;
286 else if (res
->match_flags
& FOUND_LANGUAGE
)
288 return CONTINUE_LOOKING
;
292 if (compare_info(lcid
,LOCALE_SISO3166CTRYNAME
,buff
,res
->search_country
, TRUE
) ||
293 compare_info(lcid
,LOCALE_SABBREVCTRYNAME
,buff
,res
->search_country
, TRUE
) ||
294 compare_info(lcid
,LOCALE_SENGCOUNTRY
,buff
,res
->search_country
, FALSE
))
296 TRACE("Found country:%s->%s\n", res
->search_country
, buff
);
297 flags
|= FOUND_COUNTRY
;
299 else if (!flags
&& (res
->match_flags
& FOUND_COUNTRY
))
301 return CONTINUE_LOOKING
;
304 if (flags
> res
->match_flags
)
306 /* Found a better match than previously */
307 res
->match_flags
= flags
;
308 res
->found_lang_id
= LangID
;
310 if ((flags
& (FOUND_LANGUAGE
| FOUND_COUNTRY
)) ==
311 (FOUND_LANGUAGE
| FOUND_COUNTRY
))
313 TRACE(":found exact locale match\n");
316 return CONTINUE_LOOKING
;
319 /* Internal: Find the LCID for a locale specification */
320 LCID
locale_to_LCID(const char *locale
, unsigned short *codepage
, BOOL
*sname
)
322 thread_data_t
*data
= msvcrt_get_thread_data();
323 const char *cp
, *region
;
324 BOOL is_sname
= FALSE
;
328 if (!strcmp(locale
, data
->cached_locale
)) {
330 *codepage
= data
->cached_cp
;
332 *sname
= data
->cached_sname
;
333 return data
->cached_lcid
;
336 cp
= strchr(locale
, '.');
337 region
= strchr(locale
, '_');
339 if(!locale
[0] || (cp
== locale
&& !region
)) {
340 lcid
= GetUserDefaultLCID();
342 locale_search_t search
;
344 memset(&search
, 0, sizeof(locale_search_t
));
345 lstrcpynA(search
.search_language
, locale
, MAX_ELEM_LEN
);
347 lstrcpynA(search
.search_country
, region
+1, MAX_ELEM_LEN
);
348 if(region
-locale
< MAX_ELEM_LEN
)
349 search
.search_language
[region
-locale
] = '\0';
351 search
.search_country
[0] = '\0';
354 if(region
&& cp
-region
-1<MAX_ELEM_LEN
)
355 search
.search_country
[cp
-region
-1] = '\0';
356 if(cp
-locale
< MAX_ELEM_LEN
)
357 search
.search_language
[cp
-locale
] = '\0';
362 remap_synonym(search
.search_language
);
363 search
.allow_sname
= TRUE
;
366 if(!_stricmp(search
.search_country
, "China"))
367 strcpy(search
.search_country
, "People's Republic of China");
369 EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), (LPSTR
)RT_STRING
,
370 (LPCSTR
)LOCALE_ILANGUAGE
,find_best_locale_proc
,
373 if (!search
.match_flags
)
376 /* If we were given something that didn't match, fail */
377 if (search
.search_language
[0] && !(search
.match_flags
& (FOUND_SNAME
| FOUND_LANGUAGE
)))
379 if (search
.search_country
[0] && !(search
.match_flags
& FOUND_COUNTRY
))
382 lcid
= MAKELCID(search
.found_lang_id
, SORT_DEFAULT
);
383 is_sname
= (search
.match_flags
& FOUND_SNAME
) != 0;
386 /* Obtain code page */
387 if (!cp
|| !cp
[1] || !_strnicmp(cp
, ".ACP", 4)) {
388 GetLocaleInfoW(lcid
, LOCALE_IDEFAULTANSICODEPAGE
| LOCALE_RETURN_NUMBER
,
389 (WCHAR
*)&locale_cp
, sizeof(DWORD
)/sizeof(WCHAR
));
391 locale_cp
= GetACP();
392 } else if (!_strnicmp(cp
, ".OCP", 4)) {
393 GetLocaleInfoW(lcid
, LOCALE_IDEFAULTCODEPAGE
| LOCALE_RETURN_NUMBER
,
394 (WCHAR
*)&locale_cp
, sizeof(DWORD
)/sizeof(WCHAR
));
395 #if _MSVCR_VER >= 140
396 } else if (!_strnicmp(cp
, ".UTF-8", 6)
397 || !_strnicmp(cp
, ".UTF8", 5)) {
401 locale_cp
= atoi(cp
+ 1);
403 if (!IsValidCodePage(locale_cp
))
410 *codepage
= locale_cp
;
414 if (strlen(locale
) < sizeof(data
->cached_locale
)) {
415 strcpy(data
->cached_locale
, locale
);
416 data
->cached_lcid
= lcid
;
417 data
->cached_cp
= locale_cp
;
418 data
->cached_sname
= is_sname
;
424 static void copy_threadlocinfo_category(pthreadlocinfo locinfo
,
425 const threadlocinfo
*old_locinfo
, int category
)
427 locinfo
->lc_handle
[category
] = old_locinfo
->lc_handle
[category
];
428 locinfo
->lc_id
[category
] = old_locinfo
->lc_id
[category
];
429 if(!locinfo
->lc_category
[category
].locale
) {
430 locinfo
->lc_category
[category
].locale
= old_locinfo
->lc_category
[category
].locale
;
431 locinfo
->lc_category
[category
].refcount
= old_locinfo
->lc_category
[category
].refcount
;
432 InterlockedIncrement(locinfo
->lc_category
[category
].refcount
);
434 #if _MSVCR_VER >= 110
435 locinfo
->lc_name
[category
] = old_locinfo
->lc_name
[category
];
436 locinfo
->lc_category
[category
].wrefcount
= old_locinfo
->lc_category
[category
].wrefcount
;
437 if(locinfo
->lc_category
[category
].wrefcount
)
438 InterlockedIncrement(locinfo
->lc_category
[category
].wrefcount
);
442 static BOOL
init_category_name(const char *name
, int len
,
443 pthreadlocinfo locinfo
, int category
)
445 locinfo
->lc_category
[category
].locale
= malloc(len
+1);
446 locinfo
->lc_category
[category
].refcount
= malloc(sizeof(int));
447 if(!locinfo
->lc_category
[category
].locale
448 || !locinfo
->lc_category
[category
].refcount
) {
449 free(locinfo
->lc_category
[category
].locale
);
450 free(locinfo
->lc_category
[category
].refcount
);
451 locinfo
->lc_category
[category
].locale
= NULL
;
452 locinfo
->lc_category
[category
].refcount
= NULL
;
456 memcpy(locinfo
->lc_category
[category
].locale
, name
, len
);
457 locinfo
->lc_category
[category
].locale
[len
] = 0;
458 *locinfo
->lc_category
[category
].refcount
= 1;
462 #if _MSVCR_VER >= 110
463 static inline BOOL
set_lc_locale_name(pthreadlocinfo locinfo
, int cat
)
465 LCID lcid
= locinfo
->lc_handle
[cat
];
469 locinfo
->lc_category
[cat
].wrefcount
= malloc(sizeof(int));
470 if(!locinfo
->lc_category
[cat
].wrefcount
)
472 *locinfo
->lc_category
[cat
].wrefcount
= 1;
474 len
= GetLocaleInfoW(lcid
, LOCALE_SISO639LANGNAME
475 |LOCALE_NOUSEROVERRIDE
, buf
, 100);
476 if(!len
) return FALSE
;
478 if(LocaleNameToLCID(buf
, 0) != lcid
)
479 len
= LCIDToLocaleName(lcid
, buf
, 100, 0);
481 if(!len
|| !(locinfo
->lc_name
[cat
] = malloc(len
*sizeof(wchar_t))))
484 memcpy(locinfo
->lc_name
[cat
], buf
, len
*sizeof(wchar_t));
488 static inline BOOL
set_lc_locale_name(pthreadlocinfo locinfo
, int cat
)
494 /* INTERNAL: Set lc_handle, lc_id and lc_category in threadlocinfo struct */
495 static BOOL
update_threadlocinfo_category(LCID lcid
, unsigned short cp
,
496 pthreadlocinfo locinfo
, int category
)
500 if(GetLocaleInfoA(lcid
, LOCALE_ILANGUAGE
|LOCALE_NOUSEROVERRIDE
, buf
, 256)) {
503 locinfo
->lc_id
[category
].wLanguage
= 0;
505 locinfo
->lc_id
[category
].wLanguage
*= 16;
508 locinfo
->lc_id
[category
].wLanguage
+= *p
-'0';
510 locinfo
->lc_id
[category
].wLanguage
+= *p
-'a'+10;
515 locinfo
->lc_id
[category
].wCountry
=
516 locinfo
->lc_id
[category
].wLanguage
;
519 locinfo
->lc_id
[category
].wCodePage
= cp
;
521 locinfo
->lc_handle
[category
] = lcid
;
523 set_lc_locale_name(locinfo
, category
);
525 if(!locinfo
->lc_category
[category
].locale
) {
528 len
+= GetLocaleInfoA(lcid
, LOCALE_SENGLANGUAGE
529 |LOCALE_NOUSEROVERRIDE
, buf
, 256);
531 len
+= GetLocaleInfoA(lcid
, LOCALE_SENGCOUNTRY
532 |LOCALE_NOUSEROVERRIDE
, &buf
[len
], 256-len
);
534 sprintf(buf
+len
, "%d", cp
);
535 len
+= strlen(buf
+len
);
537 return init_category_name(buf
, len
, locinfo
, category
);
543 /*********************************************************************
544 * _lock_locales (UCRTBASE.@)
546 void CDECL
_lock_locales(void)
548 _lock(_SETLOCALE_LOCK
);
551 /*********************************************************************
552 * _unlock_locales (UCRTBASE.@)
554 void CDECL
_unlock_locales(void)
556 _unlock(_SETLOCALE_LOCK
);
559 static void CDECL
grab_locinfo(pthreadlocinfo locinfo
)
563 InterlockedIncrement(&locinfo
->refcount
);
564 for(i
=LC_MIN
+1; i
<=LC_MAX
; i
++)
566 InterlockedIncrement(locinfo
->lc_category
[i
].refcount
);
567 if(locinfo
->lc_category
[i
].wrefcount
)
568 InterlockedIncrement(locinfo
->lc_category
[i
].wrefcount
);
570 if(locinfo
->lconv_intl_refcount
)
571 InterlockedIncrement(locinfo
->lconv_intl_refcount
);
572 if(locinfo
->lconv_num_refcount
)
573 InterlockedIncrement(locinfo
->lconv_num_refcount
);
574 if(locinfo
->lconv_mon_refcount
)
575 InterlockedIncrement(locinfo
->lconv_mon_refcount
);
576 if(locinfo
->ctype1_refcount
)
577 InterlockedIncrement(locinfo
->ctype1_refcount
);
578 InterlockedIncrement(&locinfo
->lc_time_curr
->refcount
);
581 static void CDECL
update_thread_locale(thread_data_t
*data
)
583 if((data
->locale_flags
& LOCALE_FREE
) && ((data
->locale_flags
& LOCALE_THREAD
) ||
584 (data
->locinfo
== MSVCRT_locale
->locinfo
&& data
->mbcinfo
== MSVCRT_locale
->mbcinfo
)))
587 if(data
->locale_flags
& LOCALE_FREE
)
589 free_locinfo(data
->locinfo
);
590 free_mbcinfo(data
->mbcinfo
);
594 data
->locinfo
= MSVCRT_locale
->locinfo
;
595 grab_locinfo(data
->locinfo
);
599 data
->mbcinfo
= MSVCRT_locale
->mbcinfo
;
600 InterlockedIncrement(&data
->mbcinfo
->refcount
);
601 _unlock(_MB_CP_LOCK
);
603 data
->locale_flags
|= LOCALE_FREE
;
606 /* INTERNAL: returns threadlocinfo struct */
607 pthreadlocinfo CDECL
get_locinfo(void) {
608 thread_data_t
*data
= msvcrt_get_thread_data();
609 update_thread_locale(data
);
610 return data
->locinfo
;
613 /* INTERNAL: returns pthreadmbcinfo struct */
614 pthreadmbcinfo CDECL
get_mbcinfo(void) {
615 thread_data_t
*data
= msvcrt_get_thread_data();
616 update_thread_locale(data
);
617 return data
->mbcinfo
;
620 /* INTERNAL: constructs string returned by setlocale */
621 static inline char* construct_lc_all(pthreadlocinfo locinfo
) {
622 static char current_lc_all
[MAX_LOCALE_LENGTH
];
626 for(i
=LC_MIN
+1; i
<LC_MAX
; i
++) {
627 if(strcmp(locinfo
->lc_category
[i
].locale
,
628 locinfo
->lc_category
[i
+1].locale
))
633 return locinfo
->lc_category
[LC_COLLATE
].locale
;
635 sprintf(current_lc_all
,
636 "LC_COLLATE=%s;LC_CTYPE=%s;LC_MONETARY=%s;LC_NUMERIC=%s;LC_TIME=%s",
637 locinfo
->lc_category
[LC_COLLATE
].locale
,
638 locinfo
->lc_category
[LC_CTYPE
].locale
,
639 locinfo
->lc_category
[LC_MONETARY
].locale
,
640 locinfo
->lc_category
[LC_NUMERIC
].locale
,
641 locinfo
->lc_category
[LC_TIME
].locale
);
643 return current_lc_all
;
647 /*********************************************************************
648 * _Getdays (MSVCRT.@)
650 char* CDECL
_Getdays(void)
652 __lc_time_data
*cur
= get_locinfo()->lc_time_curr
;
653 int i
, len
, size
= 0;
659 size
+= strlen(cur
->str
.names
.short_wday
[i
]) + 1;
660 size
+= strlen(cur
->str
.names
.wday
[i
]) + 1;
662 out
= malloc(size
+1);
669 len
= strlen(cur
->str
.names
.short_wday
[i
]);
670 memcpy(&out
[size
], cur
->str
.names
.short_wday
[i
], len
);
674 len
= strlen(cur
->str
.names
.wday
[i
]);
675 memcpy(&out
[size
], cur
->str
.names
.wday
[i
], len
);
683 #if _MSVCR_VER >= 110
684 /*********************************************************************
685 * _W_Getdays (MSVCR110.@)
687 wchar_t* CDECL
_W_Getdays(void)
689 __lc_time_data
*cur
= get_locinfo()->lc_time_curr
;
691 int i
, len
, size
= 0;
696 size
+= wcslen(cur
->wstr
.names
.short_wday
[i
]) + 1;
697 size
+= wcslen(cur
->wstr
.names
.wday
[i
]) + 1;
699 out
= malloc((size
+1)*sizeof(*out
));
706 len
= wcslen(cur
->wstr
.names
.short_wday
[i
]);
707 memcpy(&out
[size
], cur
->wstr
.names
.short_wday
[i
], len
*sizeof(*out
));
711 len
= wcslen(cur
->wstr
.names
.wday
[i
]);
712 memcpy(&out
[size
], cur
->wstr
.names
.wday
[i
], len
*sizeof(*out
));
721 /*********************************************************************
722 * _Getmonths (MSVCRT.@)
724 char* CDECL
_Getmonths(void)
726 __lc_time_data
*cur
= get_locinfo()->lc_time_curr
;
727 int i
, len
, size
= 0;
732 for(i
=0; i
<12; i
++) {
733 size
+= strlen(cur
->str
.names
.short_mon
[i
]) + 1;
734 size
+= strlen(cur
->str
.names
.mon
[i
]) + 1;
736 out
= malloc(size
+1);
741 for(i
=0; i
<12; i
++) {
743 len
= strlen(cur
->str
.names
.short_mon
[i
]);
744 memcpy(&out
[size
], cur
->str
.names
.short_mon
[i
], len
);
748 len
= strlen(cur
->str
.names
.mon
[i
]);
749 memcpy(&out
[size
], cur
->str
.names
.mon
[i
], len
);
757 #if _MSVCR_VER >= 110
758 /*********************************************************************
759 * _W_Getmonths (MSVCR110.@)
761 wchar_t* CDECL
_W_Getmonths(void)
763 __lc_time_data
*cur
= get_locinfo()->lc_time_curr
;
765 int i
, len
, size
= 0;
769 for(i
=0; i
<12; i
++) {
770 size
+= wcslen(cur
->wstr
.names
.short_mon
[i
]) + 1;
771 size
+= wcslen(cur
->wstr
.names
.mon
[i
]) + 1;
773 out
= malloc((size
+1)*sizeof(*out
));
778 for(i
=0; i
<12; i
++) {
780 len
= wcslen(cur
->wstr
.names
.short_mon
[i
]);
781 memcpy(&out
[size
], cur
->wstr
.names
.short_mon
[i
], len
*sizeof(*out
));
785 len
= wcslen(cur
->wstr
.names
.mon
[i
]);
786 memcpy(&out
[size
], cur
->wstr
.names
.mon
[i
], len
*sizeof(*out
));
795 /*********************************************************************
796 * _Gettnames (MSVCRT.@)
798 void* CDECL
_Gettnames(void)
800 __lc_time_data
*ret
, *cur
= get_locinfo()->lc_time_curr
;
801 unsigned int i
, len
, size
= sizeof(__lc_time_data
);
805 for(i
=0; i
<ARRAY_SIZE(cur
->str
.str
); i
++)
806 size
+= strlen(cur
->str
.str
[i
])+1;
807 #if _MSVCR_VER >= 110
808 for(i
=0; i
<ARRAY_SIZE(cur
->wstr
.wstr
); i
++)
809 size
+= (wcslen(cur
->wstr
.wstr
[i
]) + 1) * sizeof(wchar_t);
815 memcpy(ret
, cur
, sizeof(*ret
));
818 for(i
=0; i
<ARRAY_SIZE(cur
->str
.str
); i
++) {
819 len
= strlen(cur
->str
.str
[i
])+1;
820 memcpy(&ret
->data
[size
], cur
->str
.str
[i
], len
);
821 ret
->str
.str
[i
] = &ret
->data
[size
];
824 #if _MSVCR_VER >= 110
825 for(i
=0; i
<ARRAY_SIZE(cur
->wstr
.wstr
); i
++) {
826 len
= (wcslen(cur
->wstr
.wstr
[i
]) + 1) * sizeof(wchar_t);
827 memcpy(&ret
->data
[size
], cur
->wstr
.wstr
[i
], len
);
828 ret
->wstr
.wstr
[i
] = (wchar_t*)&ret
->data
[size
];
836 #if _MSVCR_VER >= 110
837 /*********************************************************************
838 * _W_Gettnames (MSVCR110.@)
840 void* CDECL
_W_Gettnames(void)
846 /*********************************************************************
847 * __crtLCMapStringA (MSVCRT.@)
849 int CDECL
__crtLCMapStringA(
850 LCID lcid
, DWORD mapflags
, const char* src
, int srclen
, char* dst
,
851 int dstlen
, unsigned int codepage
, int xflag
853 WCHAR buf_in
[32], *in
= buf_in
;
854 WCHAR buf_out
[32], *out
= buf_out
;
855 int in_len
, out_len
, r
;
857 TRACE("(lcid %x, flags %x, %s(%d), %p(%d), %x, %d), partial stub!\n",
858 lcid
, mapflags
, src
, srclen
, dst
, dstlen
, codepage
, xflag
);
860 in_len
= MultiByteToWideChar(codepage
, MB_ERR_INVALID_CHARS
, src
, srclen
, NULL
, 0);
861 if (!in_len
) return 0;
862 if (in_len
> ARRAY_SIZE(buf_in
))
864 in
= malloc(in_len
* sizeof(WCHAR
));
868 r
= MultiByteToWideChar(codepage
, MB_ERR_INVALID_CHARS
, src
, srclen
, in
, in_len
);
871 if (mapflags
& LCMAP_SORTKEY
)
873 r
= LCMapStringW(lcid
, mapflags
, in
, in_len
, (WCHAR
*)dst
, dstlen
);
877 r
= LCMapStringW(lcid
, mapflags
, in
, in_len
, NULL
, 0);
880 if (r
> ARRAY_SIZE(buf_out
))
882 out
= malloc(r
* sizeof(WCHAR
));
890 r
= LCMapStringW(lcid
, mapflags
, in
, in_len
, out
, out_len
);
893 r
= WideCharToMultiByte(codepage
, 0, out
, out_len
, dst
, dstlen
, NULL
, NULL
);
896 if (in
!= buf_in
) free(in
);
897 if (out
!= buf_out
) free(out
);
901 /*********************************************************************
902 * __crtLCMapStringW (MSVCRT.@)
904 int CDECL
__crtLCMapStringW(LCID lcid
, DWORD mapflags
, const wchar_t *src
,
905 int srclen
, wchar_t *dst
, int dstlen
, unsigned int codepage
, int xflag
)
907 FIXME("(lcid %x, flags %x, %s(%d), %p(%d), %x, %d), partial stub!\n",
908 lcid
, mapflags
, debugstr_w(src
), srclen
, dst
, dstlen
, codepage
, xflag
);
910 return LCMapStringW(lcid
, mapflags
, src
, srclen
, dst
, dstlen
);
913 /*********************************************************************
914 * __crtCompareStringA (MSVCRT.@)
916 int CDECL
__crtCompareStringA( LCID lcid
, DWORD flags
, const char *src1
, int len1
,
917 const char *src2
, int len2
)
919 FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n",
920 lcid
, flags
, debugstr_a(src1
), len1
, debugstr_a(src2
), len2
);
921 /* FIXME: probably not entirely right */
922 return CompareStringA( lcid
, flags
, src1
, len1
, src2
, len2
);
925 /*********************************************************************
926 * __crtCompareStringW (MSVCRT.@)
928 int CDECL
__crtCompareStringW( LCID lcid
, DWORD flags
, const wchar_t *src1
, int len1
,
929 const wchar_t *src2
, int len2
)
931 FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n",
932 lcid
, flags
, debugstr_w(src1
), len1
, debugstr_w(src2
), len2
);
933 /* FIXME: probably not entirely right */
934 return CompareStringW( lcid
, flags
, src1
, len1
, src2
, len2
);
937 /*********************************************************************
938 * __crtGetLocaleInfoW (MSVCRT.@)
940 int CDECL
__crtGetLocaleInfoW( LCID lcid
, LCTYPE type
, wchar_t *buffer
, int len
)
942 FIXME("(lcid %x, type %x, %p(%d), partial stub\n", lcid
, type
, buffer
, len
);
943 /* FIXME: probably not entirely right */
944 return GetLocaleInfoW( lcid
, type
, buffer
, len
);
947 #if _MSVCR_VER >= 110
948 /*********************************************************************
949 * __crtGetLocaleInfoEx (MSVC110.@)
951 int CDECL
__crtGetLocaleInfoEx( const WCHAR
*locale
, LCTYPE type
, wchar_t *buffer
, int len
)
953 TRACE("(%s, %x, %p, %d)\n", debugstr_w(locale
), type
, buffer
, len
);
954 return GetLocaleInfoEx(locale
, type
, buffer
, len
);
958 /*********************************************************************
959 * __crtGetStringTypeW(MSVCRT.@)
961 * This function was accepting different number of arguments in older
962 * versions of msvcrt.
964 BOOL CDECL
__crtGetStringTypeW(DWORD unk
, DWORD type
,
965 wchar_t *buffer
, int len
, WORD
*out
)
967 FIXME("(unk %x, type %x, wstr %p(%d), %p) partial stub\n",
968 unk
, type
, buffer
, len
, out
);
970 return GetStringTypeW(type
, buffer
, len
, out
);
973 /*********************************************************************
974 * localeconv (MSVCRT.@)
976 struct lconv
* CDECL
localeconv(void)
978 return get_locinfo()->lconv
;
981 /*********************************************************************
982 * __lconv_init (MSVCRT.@)
984 int CDECL
__lconv_init(void)
986 /* this is used to make chars unsigned */
987 cloc_lconv
.int_frac_digits
= (char)UCHAR_MAX
;
988 cloc_lconv
.frac_digits
= (char)UCHAR_MAX
;
989 cloc_lconv
.p_cs_precedes
= (char)UCHAR_MAX
;
990 cloc_lconv
.p_sep_by_space
= (char)UCHAR_MAX
;
991 cloc_lconv
.n_cs_precedes
= (char)UCHAR_MAX
;
992 cloc_lconv
.n_sep_by_space
= (char)UCHAR_MAX
;
993 cloc_lconv
.p_sign_posn
= (char)UCHAR_MAX
;
994 cloc_lconv
.n_sign_posn
= (char)UCHAR_MAX
;
998 /*********************************************************************
999 * ___lc_handle_func (MSVCRT.@)
1001 LCID
* CDECL
___lc_handle_func(void)
1003 return (LCID
*)get_locinfo()->lc_handle
;
1006 #if _MSVCR_VER >= 110
1007 /*********************************************************************
1008 * ___lc_locale_name_func (MSVCR110.@)
1010 wchar_t** CDECL
___lc_locale_name_func(void)
1012 return get_locinfo()->lc_name
;
1016 /*********************************************************************
1017 * ___lc_codepage_func (MSVCRT.@)
1019 unsigned int CDECL
___lc_codepage_func(void)
1021 return get_locinfo()->lc_codepage
;
1024 /*********************************************************************
1025 * ___lc_collate_cp_func (MSVCRT.@)
1027 int CDECL
___lc_collate_cp_func(void)
1029 return get_locinfo()->lc_collate_cp
;
1032 /* INTERNAL: frees pthreadlocinfo struct */
1033 void free_locinfo(pthreadlocinfo locinfo
)
1040 for(i
=LC_MIN
+1; i
<=LC_MAX
; i
++) {
1041 if(!locinfo
->lc_category
[i
].refcount
1042 || !InterlockedDecrement(locinfo
->lc_category
[i
].refcount
)) {
1043 free(locinfo
->lc_category
[i
].locale
);
1044 free(locinfo
->lc_category
[i
].refcount
);
1046 if(!locinfo
->lc_category
[i
].wrefcount
1047 || !InterlockedDecrement(locinfo
->lc_category
[i
].wrefcount
)) {
1048 #if _MSVCR_VER >= 110
1049 free(locinfo
->lc_name
[i
]);
1051 free(locinfo
->lc_category
[i
].wrefcount
);
1055 if(locinfo
->lconv_num_refcount
1056 && !InterlockedDecrement(locinfo
->lconv_num_refcount
)) {
1057 free(locinfo
->lconv
->decimal_point
);
1058 free(locinfo
->lconv
->thousands_sep
);
1059 free(locinfo
->lconv
->grouping
);
1060 #if _MSVCR_VER >= 100
1061 free(locinfo
->lconv
->_W_decimal_point
);
1062 free(locinfo
->lconv
->_W_thousands_sep
);
1064 free(locinfo
->lconv_num_refcount
);
1066 if(locinfo
->lconv_mon_refcount
1067 && !InterlockedDecrement(locinfo
->lconv_mon_refcount
)) {
1068 free(locinfo
->lconv
->int_curr_symbol
);
1069 free(locinfo
->lconv
->currency_symbol
);
1070 free(locinfo
->lconv
->mon_decimal_point
);
1071 free(locinfo
->lconv
->mon_thousands_sep
);
1072 free(locinfo
->lconv
->mon_grouping
);
1073 free(locinfo
->lconv
->positive_sign
);
1074 free(locinfo
->lconv
->negative_sign
);
1075 #if _MSVCR_VER >= 100
1076 free(locinfo
->lconv
->_W_int_curr_symbol
);
1077 free(locinfo
->lconv
->_W_currency_symbol
);
1078 free(locinfo
->lconv
->_W_mon_decimal_point
);
1079 free(locinfo
->lconv
->_W_mon_thousands_sep
);
1080 free(locinfo
->lconv
->_W_positive_sign
);
1081 free(locinfo
->lconv
->_W_negative_sign
);
1083 free(locinfo
->lconv_mon_refcount
);
1085 if(locinfo
->lconv_intl_refcount
1086 && !InterlockedDecrement(locinfo
->lconv_intl_refcount
)) {
1087 free(locinfo
->lconv_intl_refcount
);
1088 free(locinfo
->lconv
);
1091 if(locinfo
->ctype1_refcount
1092 && !InterlockedDecrement(locinfo
->ctype1_refcount
)) {
1093 free(locinfo
->ctype1_refcount
);
1094 free(locinfo
->ctype1
);
1095 free((void*)locinfo
->pclmap
);
1096 free((void*)locinfo
->pcumap
);
1099 if(locinfo
->lc_time_curr
&& !InterlockedDecrement(&locinfo
->lc_time_curr
->refcount
)
1100 && locinfo
->lc_time_curr
!= &cloc_time_data
)
1101 free(locinfo
->lc_time_curr
);
1103 if(InterlockedDecrement(&locinfo
->refcount
))
1109 /* INTERNAL: frees pthreadmbcinfo struct */
1110 void free_mbcinfo(pthreadmbcinfo mbcinfo
)
1115 if(InterlockedDecrement(&mbcinfo
->refcount
))
1121 _locale_t CDECL
get_current_locale_noalloc(_locale_t locale
)
1123 thread_data_t
*data
= msvcrt_get_thread_data();
1125 update_thread_locale(data
);
1126 locale
->locinfo
= data
->locinfo
;
1127 locale
->mbcinfo
= data
->mbcinfo
;
1129 grab_locinfo(locale
->locinfo
);
1130 InterlockedIncrement(&locale
->mbcinfo
->refcount
);
1134 void CDECL
free_locale_noalloc(_locale_t locale
)
1136 free_locinfo(locale
->locinfo
);
1137 free_mbcinfo(locale
->mbcinfo
);
1140 /*********************************************************************
1141 * _get_current_locale (MSVCRT.@)
1143 _locale_t CDECL
_get_current_locale(void)
1145 _locale_t loc
= malloc(sizeof(_locale_tstruct
));
1149 return get_current_locale_noalloc(loc
);
1152 /*********************************************************************
1153 * _free_locale (MSVCRT.@)
1155 void CDECL
_free_locale(_locale_t locale
)
1160 free_locale_noalloc(locale
);
1164 static inline BOOL
category_needs_update(int cat
,
1165 const threadlocinfo
*locinfo
, LCID lcid
, unsigned short cp
)
1167 if(!locinfo
) return TRUE
;
1168 return lcid
!=locinfo
->lc_handle
[cat
] || cp
!=locinfo
->lc_id
[cat
].wCodePage
;
1171 static __lc_time_data
* create_time_data(LCID lcid
)
1173 static const DWORD time_data
[] = {
1174 LOCALE_SABBREVDAYNAME7
, LOCALE_SABBREVDAYNAME1
, LOCALE_SABBREVDAYNAME2
,
1175 LOCALE_SABBREVDAYNAME3
, LOCALE_SABBREVDAYNAME4
, LOCALE_SABBREVDAYNAME5
,
1176 LOCALE_SABBREVDAYNAME6
,
1177 LOCALE_SDAYNAME7
, LOCALE_SDAYNAME1
, LOCALE_SDAYNAME2
, LOCALE_SDAYNAME3
,
1178 LOCALE_SDAYNAME4
, LOCALE_SDAYNAME5
, LOCALE_SDAYNAME6
,
1179 LOCALE_SABBREVMONTHNAME1
, LOCALE_SABBREVMONTHNAME2
, LOCALE_SABBREVMONTHNAME3
,
1180 LOCALE_SABBREVMONTHNAME4
, LOCALE_SABBREVMONTHNAME5
, LOCALE_SABBREVMONTHNAME6
,
1181 LOCALE_SABBREVMONTHNAME7
, LOCALE_SABBREVMONTHNAME8
, LOCALE_SABBREVMONTHNAME9
,
1182 LOCALE_SABBREVMONTHNAME10
, LOCALE_SABBREVMONTHNAME11
, LOCALE_SABBREVMONTHNAME12
,
1183 LOCALE_SMONTHNAME1
, LOCALE_SMONTHNAME2
, LOCALE_SMONTHNAME3
, LOCALE_SMONTHNAME4
,
1184 LOCALE_SMONTHNAME5
, LOCALE_SMONTHNAME6
, LOCALE_SMONTHNAME7
, LOCALE_SMONTHNAME8
,
1185 LOCALE_SMONTHNAME9
, LOCALE_SMONTHNAME10
, LOCALE_SMONTHNAME11
, LOCALE_SMONTHNAME12
,
1186 LOCALE_S1159
, LOCALE_S2359
,
1187 LOCALE_SSHORTDATE
, LOCALE_SLONGDATE
,
1191 __lc_time_data
*cur
;
1194 size
= sizeof(__lc_time_data
);
1195 for(i
=0; i
<ARRAY_SIZE(time_data
); i
++) {
1196 ret
= GetLocaleInfoA(lcid
, time_data
[i
], NULL
, 0);
1201 #if _MSVCR_VER == 0 || _MSVCR_VER >= 100
1202 ret
= GetLocaleInfoW(lcid
, time_data
[i
], NULL
, 0);
1205 size
+= ret
*sizeof(wchar_t);
1208 #if _MSVCR_VER >= 110
1209 size
+= LCIDToLocaleName(lcid
, NULL
, 0, 0)*sizeof(wchar_t);
1217 for(i
=0; i
<ARRAY_SIZE(time_data
); i
++) {
1218 cur
->str
.str
[i
] = &cur
->data
[ret
];
1219 ret
+= GetLocaleInfoA(lcid
, time_data
[i
], &cur
->data
[ret
], size
-ret
);
1221 #if _MSVCR_VER == 0 || _MSVCR_VER >= 100
1222 for(i
=0; i
<ARRAY_SIZE(time_data
); i
++) {
1223 cur
->wstr
.wstr
[i
] = (wchar_t*)&cur
->data
[ret
];
1224 ret
+= GetLocaleInfoW(lcid
, time_data
[i
],
1225 (wchar_t*)&cur
->data
[ret
], size
-ret
)*sizeof(wchar_t);
1228 #if _MSVCR_VER >= 110
1229 cur
->locname
= (wchar_t*)&cur
->data
[ret
];
1230 LCIDToLocaleName(lcid
, (wchar_t*)&cur
->data
[ret
], (size
-ret
)/sizeof(wchar_t), 0);
1240 static pthreadlocinfo
create_locinfo(int category
,
1241 const char *locale
, const threadlocinfo
*old_locinfo
)
1243 static const char collate
[] = "COLLATE=";
1244 static const char ctype
[] = "CTYPE=";
1245 static const char monetary
[] = "MONETARY=";
1246 static const char numeric
[] = "NUMERIC=";
1247 static const char time
[] = "TIME=";
1249 pthreadlocinfo locinfo
;
1250 LCID lcid
[6] = { 0 };
1251 unsigned short cp
[6] = { 0 };
1252 const char *locale_name
[6] = { 0 };
1253 int val
, locale_len
[6] = { 0 };
1256 #if _MSVCR_VER >= 100
1261 TRACE("(%d %s)\n", category
, locale
);
1263 if(category
<LC_MIN
|| category
>LC_MAX
|| !locale
)
1266 if(locale
[0]=='C' && !locale
[1]) {
1269 } else if (locale
[0] == 'L' && locale
[1] == 'C' && locale
[2] == '_') {
1273 locale
+= 3; /* LC_ */
1274 if(!memcmp(locale
, collate
, sizeof(collate
)-1)) {
1276 locale
+= sizeof(collate
)-1;
1277 } else if(!memcmp(locale
, ctype
, sizeof(ctype
)-1)) {
1279 locale
+= sizeof(ctype
)-1;
1280 } else if(!memcmp(locale
, monetary
, sizeof(monetary
)-1)) {
1282 locale
+= sizeof(monetary
)-1;
1283 } else if(!memcmp(locale
, numeric
, sizeof(numeric
)-1)) {
1285 locale
+= sizeof(numeric
)-1;
1286 } else if(!memcmp(locale
, time
, sizeof(time
)-1)) {
1288 locale
+= sizeof(time
)-1;
1292 p
= strchr(locale
, ';');
1293 if(locale
[0]=='C' && (locale
[1]==';' || locale
[1]=='\0')) {
1297 memcpy(buf
, locale
, p
-locale
);
1298 buf
[p
-locale
] = '\0';
1299 lcid
[i
] = locale_to_LCID(buf
, &cp
[i
], &sname
);
1301 locale_name
[i
] = locale
;
1302 locale_len
[i
] = p
-locale
;
1305 lcid
[i
] = locale_to_LCID(locale
, &cp
[i
], &sname
);
1307 locale_name
[i
] = locale
;
1308 locale_len
[i
] = strlen(locale
);
1315 if(!p
|| *(p
+1)!='L' || *(p
+2)!='C' || *(p
+3)!='_')
1321 lcid
[0] = locale_to_LCID(locale
, &cp
[0], &sname
);
1325 locale_name
[0] = locale
;
1326 locale_len
[0] = strlen(locale
);
1329 for(i
=1; i
<6; i
++) {
1332 locale_name
[i
] = locale_name
[0];
1333 locale_len
[i
] = locale_len
[0];
1337 for(i
=1; i
<6; i
++) {
1338 if(category
!=LC_ALL
&& category
!=i
) {
1340 lcid
[i
] = old_locinfo
->lc_handle
[i
];
1341 cp
[i
] = old_locinfo
->lc_id
[i
].wCodePage
;
1349 locinfo
= malloc(sizeof(threadlocinfo
));
1353 memset(locinfo
, 0, sizeof(threadlocinfo
));
1354 locinfo
->refcount
= 1;
1356 if(locale_name
[LC_COLLATE
] &&
1357 !init_category_name(locale_name
[LC_COLLATE
],
1358 locale_len
[LC_COLLATE
], locinfo
, LC_COLLATE
)) {
1359 free_locinfo(locinfo
);
1363 if(!category_needs_update(LC_COLLATE
, old_locinfo
,
1364 lcid
[LC_COLLATE
], cp
[LC_COLLATE
])) {
1365 copy_threadlocinfo_category(locinfo
, old_locinfo
, LC_COLLATE
);
1366 locinfo
->lc_collate_cp
= old_locinfo
->lc_collate_cp
;
1367 } else if(lcid
[LC_COLLATE
]) {
1368 if(!update_threadlocinfo_category(lcid
[LC_COLLATE
],
1369 cp
[LC_COLLATE
], locinfo
, LC_COLLATE
)) {
1370 free_locinfo(locinfo
);
1374 locinfo
->lc_collate_cp
= locinfo
->lc_id
[LC_COLLATE
].wCodePage
;
1376 if(!init_category_name("C", 1, locinfo
, LC_COLLATE
)) {
1377 free_locinfo(locinfo
);
1382 if(locale_name
[LC_CTYPE
] &&
1383 !init_category_name(locale_name
[LC_CTYPE
],
1384 locale_len
[LC_CTYPE
], locinfo
, LC_CTYPE
)) {
1385 free_locinfo(locinfo
);
1389 if(!category_needs_update(LC_CTYPE
, old_locinfo
,
1390 lcid
[LC_CTYPE
], cp
[LC_CTYPE
])) {
1391 copy_threadlocinfo_category(locinfo
, old_locinfo
, LC_CTYPE
);
1392 locinfo
->lc_codepage
= old_locinfo
->lc_codepage
;
1393 locinfo
->lc_clike
= old_locinfo
->lc_clike
;
1394 locinfo
->mb_cur_max
= old_locinfo
->mb_cur_max
;
1395 locinfo
->ctype1
= old_locinfo
->ctype1
;
1396 locinfo
->ctype1_refcount
= old_locinfo
->ctype1_refcount
;
1397 locinfo
->pctype
= old_locinfo
->pctype
;
1398 locinfo
->pclmap
= old_locinfo
->pclmap
;
1399 locinfo
->pcumap
= old_locinfo
->pcumap
;
1400 if(locinfo
->ctype1_refcount
)
1401 InterlockedIncrement(locinfo
->ctype1_refcount
);
1402 } else if(lcid
[LC_CTYPE
]) {
1406 if(!update_threadlocinfo_category(lcid
[LC_CTYPE
],
1407 cp
[LC_CTYPE
], locinfo
, LC_CTYPE
)) {
1408 free_locinfo(locinfo
);
1412 locinfo
->lc_codepage
= locinfo
->lc_id
[LC_CTYPE
].wCodePage
;
1413 locinfo
->lc_clike
= 1;
1414 if(!GetCPInfo(locinfo
->lc_codepage
, &cp_info
)) {
1415 free_locinfo(locinfo
);
1418 locinfo
->mb_cur_max
= cp_info
.MaxCharSize
;
1420 locinfo
->ctype1_refcount
= malloc(sizeof(int));
1421 if(!locinfo
->ctype1_refcount
) {
1422 free_locinfo(locinfo
);
1425 *locinfo
->ctype1_refcount
= 1;
1427 locinfo
->ctype1
= malloc(sizeof(short[257]));
1428 locinfo
->pclmap
= malloc(sizeof(char[256]));
1429 locinfo
->pcumap
= malloc(sizeof(char[256]));
1430 if(!locinfo
->ctype1
|| !locinfo
->pclmap
|| !locinfo
->pcumap
) {
1431 free_locinfo(locinfo
);
1435 locinfo
->ctype1
[0] = 0;
1436 locinfo
->pctype
= locinfo
->ctype1
+1;
1438 buf
[1] = buf
[2] = '\0';
1439 for(i
=1; i
<257; i
++) {
1442 /* builtin GetStringTypeA doesn't set output to 0 on invalid input */
1443 locinfo
->ctype1
[i
] = 0;
1445 GetStringTypeA(lcid
[LC_CTYPE
], CT_CTYPE1
, buf
,
1446 1, locinfo
->ctype1
+i
);
1449 for(i
=0; cp_info
.LeadByte
[i
+1]!=0; i
+=2)
1450 for(j
=cp_info
.LeadByte
[i
]; j
<=cp_info
.LeadByte
[i
+1]; j
++)
1451 locinfo
->ctype1
[j
+1] |= _LEADBYTE
;
1453 for(i
=0; i
<256; i
++) {
1454 if(locinfo
->pctype
[i
] & _LEADBYTE
)
1460 LCMapStringA(lcid
[LC_CTYPE
], LCMAP_LOWERCASE
, buf
, 256,
1461 (char*)locinfo
->pclmap
, 256);
1462 LCMapStringA(lcid
[LC_CTYPE
], LCMAP_UPPERCASE
, buf
, 256,
1463 (char*)locinfo
->pcumap
, 256);
1465 locinfo
->lc_clike
= 1;
1466 locinfo
->mb_cur_max
= 1;
1467 locinfo
->pctype
= MSVCRT__ctype
+1;
1468 locinfo
->pclmap
= cloc_clmap
;
1469 locinfo
->pcumap
= cloc_cumap
;
1470 if(!init_category_name("C", 1, locinfo
, LC_CTYPE
)) {
1471 free_locinfo(locinfo
);
1476 if(!category_needs_update(LC_MONETARY
, old_locinfo
,
1477 lcid
[LC_MONETARY
], cp
[LC_MONETARY
]) &&
1478 !category_needs_update(LC_NUMERIC
, old_locinfo
,
1479 lcid
[LC_NUMERIC
], cp
[LC_NUMERIC
])) {
1480 locinfo
->lconv
= old_locinfo
->lconv
;
1481 locinfo
->lconv_intl_refcount
= old_locinfo
->lconv_intl_refcount
;
1482 if(locinfo
->lconv_intl_refcount
)
1483 InterlockedIncrement(locinfo
->lconv_intl_refcount
);
1484 } else if(lcid
[LC_MONETARY
] || lcid
[LC_NUMERIC
]) {
1485 locinfo
->lconv
= malloc(sizeof(struct lconv
));
1486 locinfo
->lconv_intl_refcount
= malloc(sizeof(int));
1487 if(!locinfo
->lconv
|| !locinfo
->lconv_intl_refcount
) {
1488 free(locinfo
->lconv
);
1489 free(locinfo
->lconv_intl_refcount
);
1490 locinfo
->lconv
= NULL
;
1491 locinfo
->lconv_intl_refcount
= NULL
;
1492 free_locinfo(locinfo
);
1495 memset(locinfo
->lconv
, 0, sizeof(struct lconv
));
1496 *locinfo
->lconv_intl_refcount
= 1;
1498 locinfo
->lconv
= &cloc_lconv
;
1501 if(locale_name
[LC_MONETARY
] &&
1502 !init_category_name(locale_name
[LC_MONETARY
],
1503 locale_len
[LC_MONETARY
], locinfo
, LC_MONETARY
)) {
1504 free_locinfo(locinfo
);
1508 if(!category_needs_update(LC_MONETARY
, old_locinfo
,
1509 lcid
[LC_MONETARY
], cp
[LC_MONETARY
])) {
1510 copy_threadlocinfo_category(locinfo
, old_locinfo
, LC_MONETARY
);
1511 locinfo
->lconv_mon_refcount
= old_locinfo
->lconv_mon_refcount
;
1512 if(locinfo
->lconv_mon_refcount
)
1513 InterlockedIncrement(locinfo
->lconv_mon_refcount
);
1514 if(locinfo
->lconv
!= &cloc_lconv
&& locinfo
->lconv
!= old_locinfo
->lconv
) {
1515 locinfo
->lconv
->int_curr_symbol
= old_locinfo
->lconv
->int_curr_symbol
;
1516 locinfo
->lconv
->currency_symbol
= old_locinfo
->lconv
->currency_symbol
;
1517 locinfo
->lconv
->mon_decimal_point
= old_locinfo
->lconv
->mon_decimal_point
;
1518 locinfo
->lconv
->mon_thousands_sep
= old_locinfo
->lconv
->mon_thousands_sep
;
1519 locinfo
->lconv
->mon_grouping
= old_locinfo
->lconv
->mon_grouping
;
1520 locinfo
->lconv
->positive_sign
= old_locinfo
->lconv
->positive_sign
;
1521 locinfo
->lconv
->negative_sign
= old_locinfo
->lconv
->negative_sign
;
1522 locinfo
->lconv
->int_frac_digits
= old_locinfo
->lconv
->int_frac_digits
;
1523 locinfo
->lconv
->frac_digits
= old_locinfo
->lconv
->frac_digits
;
1524 locinfo
->lconv
->p_cs_precedes
= old_locinfo
->lconv
->p_cs_precedes
;
1525 locinfo
->lconv
->p_sep_by_space
= old_locinfo
->lconv
->p_sep_by_space
;
1526 locinfo
->lconv
->n_cs_precedes
= old_locinfo
->lconv
->n_cs_precedes
;
1527 locinfo
->lconv
->n_sep_by_space
= old_locinfo
->lconv
->n_sep_by_space
;
1528 locinfo
->lconv
->p_sign_posn
= old_locinfo
->lconv
->p_sign_posn
;
1529 locinfo
->lconv
->n_sign_posn
= old_locinfo
->lconv
->n_sign_posn
;
1530 #if _MSVCR_VER >= 100
1531 locinfo
->lconv
->_W_int_curr_symbol
= old_locinfo
->lconv
->_W_int_curr_symbol
;
1532 locinfo
->lconv
->_W_currency_symbol
= old_locinfo
->lconv
->_W_currency_symbol
;
1533 locinfo
->lconv
->_W_mon_decimal_point
= old_locinfo
->lconv
->_W_mon_decimal_point
;
1534 locinfo
->lconv
->_W_mon_thousands_sep
= old_locinfo
->lconv
->_W_mon_thousands_sep
;
1535 locinfo
->lconv
->_W_positive_sign
= old_locinfo
->lconv
->_W_positive_sign
;
1536 locinfo
->lconv
->_W_negative_sign
= old_locinfo
->lconv
->_W_negative_sign
;
1539 } else if(lcid
[LC_MONETARY
]) {
1540 if(!update_threadlocinfo_category(lcid
[LC_MONETARY
],
1541 cp
[LC_MONETARY
], locinfo
, LC_MONETARY
)) {
1542 free_locinfo(locinfo
);
1546 locinfo
->lconv_mon_refcount
= malloc(sizeof(int));
1547 if(!locinfo
->lconv_mon_refcount
) {
1548 free_locinfo(locinfo
);
1552 *locinfo
->lconv_mon_refcount
= 1;
1554 i
= GetLocaleInfoA(lcid
[LC_MONETARY
], LOCALE_SINTLSYMBOL
1555 |LOCALE_NOUSEROVERRIDE
, buf
, 256);
1556 if(i
&& (locinfo
->lconv
->int_curr_symbol
= malloc(i
)))
1557 memcpy(locinfo
->lconv
->int_curr_symbol
, buf
, i
);
1559 free_locinfo(locinfo
);
1563 i
= GetLocaleInfoA(lcid
[LC_MONETARY
], LOCALE_SCURRENCY
1564 |LOCALE_NOUSEROVERRIDE
, buf
, 256);
1565 if(i
&& (locinfo
->lconv
->currency_symbol
= malloc(i
)))
1566 memcpy(locinfo
->lconv
->currency_symbol
, buf
, i
);
1568 free_locinfo(locinfo
);
1572 i
= GetLocaleInfoA(lcid
[LC_MONETARY
], LOCALE_SMONDECIMALSEP
1573 |LOCALE_NOUSEROVERRIDE
, buf
, 256);
1574 if(i
&& (locinfo
->lconv
->mon_decimal_point
= malloc(i
)))
1575 memcpy(locinfo
->lconv
->mon_decimal_point
, buf
, i
);
1577 free_locinfo(locinfo
);
1581 i
= GetLocaleInfoA(lcid
[LC_MONETARY
], LOCALE_SMONTHOUSANDSEP
1582 |LOCALE_NOUSEROVERRIDE
, buf
, 256);
1583 if(i
&& (locinfo
->lconv
->mon_thousands_sep
= malloc(i
)))
1584 memcpy(locinfo
->lconv
->mon_thousands_sep
, buf
, i
);
1586 free_locinfo(locinfo
);
1590 i
= GetLocaleInfoA(lcid
[LC_MONETARY
], LOCALE_SMONGROUPING
1591 |LOCALE_NOUSEROVERRIDE
, buf
, 256);
1593 i
= i
/2 + (buf
[i
-2]=='0'?0:1);
1594 if(i
&& (locinfo
->lconv
->mon_grouping
= malloc(i
))) {
1595 for(i
=0; buf
[i
+1]==';'; i
+=2)
1596 locinfo
->lconv
->mon_grouping
[i
/2] = buf
[i
]-'0';
1597 locinfo
->lconv
->mon_grouping
[i
/2] = buf
[i
]-'0';
1599 locinfo
->lconv
->mon_grouping
[i
/2+1] = 127;
1601 free_locinfo(locinfo
);
1605 i
= GetLocaleInfoA(lcid
[LC_MONETARY
], LOCALE_SPOSITIVESIGN
1606 |LOCALE_NOUSEROVERRIDE
, buf
, 256);
1607 if(i
&& (locinfo
->lconv
->positive_sign
= malloc(i
)))
1608 memcpy(locinfo
->lconv
->positive_sign
, buf
, i
);
1610 free_locinfo(locinfo
);
1614 i
= GetLocaleInfoA(lcid
[LC_MONETARY
], LOCALE_SNEGATIVESIGN
1615 |LOCALE_NOUSEROVERRIDE
, buf
, 256);
1616 if(i
&& (locinfo
->lconv
->negative_sign
= malloc(i
)))
1617 memcpy(locinfo
->lconv
->negative_sign
, buf
, i
);
1619 free_locinfo(locinfo
);
1623 if(GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_IINTLCURRDIGITS
1624 |LOCALE_NOUSEROVERRIDE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&val
, 2))
1625 locinfo
->lconv
->int_frac_digits
= val
;
1627 free_locinfo(locinfo
);
1631 if(GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_ICURRDIGITS
1632 |LOCALE_NOUSEROVERRIDE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&val
, 2))
1633 locinfo
->lconv
->frac_digits
= val
;
1635 free_locinfo(locinfo
);
1639 if(GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_IPOSSYMPRECEDES
1640 |LOCALE_NOUSEROVERRIDE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&val
, 2))
1641 locinfo
->lconv
->p_cs_precedes
= val
;
1643 free_locinfo(locinfo
);
1647 if(GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_IPOSSEPBYSPACE
1648 |LOCALE_NOUSEROVERRIDE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&val
, 2))
1649 locinfo
->lconv
->p_sep_by_space
= val
;
1651 free_locinfo(locinfo
);
1655 if(GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_INEGSYMPRECEDES
1656 |LOCALE_NOUSEROVERRIDE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&val
, 2))
1657 locinfo
->lconv
->n_cs_precedes
= val
;
1659 free_locinfo(locinfo
);
1663 if(GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_INEGSEPBYSPACE
1664 |LOCALE_NOUSEROVERRIDE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&val
, 2))
1665 locinfo
->lconv
->n_sep_by_space
= val
;
1667 free_locinfo(locinfo
);
1671 if(GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_IPOSSIGNPOSN
1672 |LOCALE_NOUSEROVERRIDE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&val
, 2))
1673 locinfo
->lconv
->p_sign_posn
= val
;
1675 free_locinfo(locinfo
);
1679 if(GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_INEGSIGNPOSN
1680 |LOCALE_NOUSEROVERRIDE
|LOCALE_RETURN_NUMBER
, (WCHAR
*)&val
, 2))
1681 locinfo
->lconv
->n_sign_posn
= val
;
1683 free_locinfo(locinfo
);
1687 #if _MSVCR_VER >= 100
1688 i
= GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_SINTLSYMBOL
1689 |LOCALE_NOUSEROVERRIDE
, wbuf
, 256);
1690 if(i
&& (locinfo
->lconv
->_W_int_curr_symbol
= malloc(i
* sizeof(wchar_t))))
1691 memcpy(locinfo
->lconv
->_W_int_curr_symbol
, wbuf
, i
* sizeof(wchar_t));
1693 free_locinfo(locinfo
);
1697 i
= GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_SCURRENCY
1698 |LOCALE_NOUSEROVERRIDE
, wbuf
, 256);
1699 if(i
&& (locinfo
->lconv
->_W_currency_symbol
= malloc(i
* sizeof(wchar_t))))
1700 memcpy(locinfo
->lconv
->_W_currency_symbol
, wbuf
, i
* sizeof(wchar_t));
1702 free_locinfo(locinfo
);
1706 i
= GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_SMONDECIMALSEP
1707 |LOCALE_NOUSEROVERRIDE
, wbuf
, 256);
1708 if(i
&& (locinfo
->lconv
->_W_mon_decimal_point
= malloc(i
* sizeof(wchar_t))))
1709 memcpy(locinfo
->lconv
->_W_mon_decimal_point
, wbuf
, i
* sizeof(wchar_t));
1711 free_locinfo(locinfo
);
1715 i
= GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_SMONTHOUSANDSEP
1716 |LOCALE_NOUSEROVERRIDE
, wbuf
, 256);
1717 if(i
&& (locinfo
->lconv
->_W_mon_thousands_sep
= malloc(i
* sizeof(wchar_t))))
1718 memcpy(locinfo
->lconv
->_W_mon_thousands_sep
, wbuf
, i
* sizeof(wchar_t));
1720 free_locinfo(locinfo
);
1724 i
= GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_SPOSITIVESIGN
1725 |LOCALE_NOUSEROVERRIDE
, wbuf
, 256);
1726 if(i
&& (locinfo
->lconv
->_W_positive_sign
= malloc(i
* sizeof(wchar_t))))
1727 memcpy(locinfo
->lconv
->_W_positive_sign
, wbuf
, i
* sizeof(wchar_t));
1729 free_locinfo(locinfo
);
1733 i
= GetLocaleInfoW(lcid
[LC_MONETARY
], LOCALE_SNEGATIVESIGN
1734 |LOCALE_NOUSEROVERRIDE
, wbuf
, 256);
1735 if(i
&& (locinfo
->lconv
->_W_negative_sign
= malloc(i
* sizeof(wchar_t))))
1736 memcpy(locinfo
->lconv
->_W_negative_sign
, wbuf
, i
* sizeof(wchar_t));
1738 free_locinfo(locinfo
);
1743 if (locinfo
->lconv
!= &cloc_lconv
) {
1744 locinfo
->lconv
->int_curr_symbol
= cloc_lconv
.int_curr_symbol
;
1745 locinfo
->lconv
->currency_symbol
= cloc_lconv
.currency_symbol
;
1746 locinfo
->lconv
->mon_decimal_point
= cloc_lconv
.mon_decimal_point
;
1747 locinfo
->lconv
->mon_thousands_sep
= cloc_lconv
.mon_thousands_sep
;
1748 locinfo
->lconv
->mon_grouping
= cloc_lconv
.mon_grouping
;
1749 locinfo
->lconv
->positive_sign
= cloc_lconv
.positive_sign
;
1750 locinfo
->lconv
->negative_sign
= cloc_lconv
.negative_sign
;
1751 locinfo
->lconv
->int_frac_digits
= cloc_lconv
.int_frac_digits
;
1752 locinfo
->lconv
->frac_digits
= cloc_lconv
.frac_digits
;
1753 locinfo
->lconv
->p_cs_precedes
= cloc_lconv
.p_cs_precedes
;
1754 locinfo
->lconv
->p_sep_by_space
= cloc_lconv
.p_sep_by_space
;
1755 locinfo
->lconv
->n_cs_precedes
= cloc_lconv
.n_cs_precedes
;
1756 locinfo
->lconv
->n_sep_by_space
= cloc_lconv
.n_sep_by_space
;
1757 locinfo
->lconv
->p_sign_posn
= cloc_lconv
.p_sign_posn
;
1758 locinfo
->lconv
->n_sign_posn
= cloc_lconv
.n_sign_posn
;
1760 #if _MSVCR_VER >= 100
1761 locinfo
->lconv
->_W_int_curr_symbol
= cloc_lconv
._W_int_curr_symbol
;
1762 locinfo
->lconv
->_W_currency_symbol
= cloc_lconv
._W_currency_symbol
;
1763 locinfo
->lconv
->_W_mon_decimal_point
= cloc_lconv
._W_mon_decimal_point
;
1764 locinfo
->lconv
->_W_mon_thousands_sep
= cloc_lconv
._W_mon_thousands_sep
;
1765 locinfo
->lconv
->_W_positive_sign
= cloc_lconv
._W_positive_sign
;
1766 locinfo
->lconv
->_W_negative_sign
= cloc_lconv
._W_negative_sign
;
1770 if(!init_category_name("C", 1, locinfo
, LC_MONETARY
)) {
1771 free_locinfo(locinfo
);
1776 if(locale_name
[LC_NUMERIC
] &&
1777 !init_category_name(locale_name
[LC_NUMERIC
],
1778 locale_len
[LC_NUMERIC
], locinfo
, LC_NUMERIC
)) {
1779 free_locinfo(locinfo
);
1783 if(!category_needs_update(LC_NUMERIC
, old_locinfo
,
1784 lcid
[LC_NUMERIC
], cp
[LC_NUMERIC
])) {
1785 copy_threadlocinfo_category(locinfo
, old_locinfo
, LC_NUMERIC
);
1786 locinfo
->lconv_num_refcount
= old_locinfo
->lconv_num_refcount
;
1787 if(locinfo
->lconv_num_refcount
)
1788 InterlockedIncrement(locinfo
->lconv_num_refcount
);
1789 if(locinfo
->lconv
!= &cloc_lconv
&& locinfo
->lconv
!= old_locinfo
->lconv
) {
1790 locinfo
->lconv
->decimal_point
= old_locinfo
->lconv
->decimal_point
;
1791 locinfo
->lconv
->thousands_sep
= old_locinfo
->lconv
->thousands_sep
;
1792 locinfo
->lconv
->grouping
= old_locinfo
->lconv
->grouping
;
1793 #if _MSVCR_VER >= 100
1794 locinfo
->lconv
->_W_decimal_point
= old_locinfo
->lconv
->_W_decimal_point
;
1795 locinfo
->lconv
->_W_thousands_sep
= old_locinfo
->lconv
->_W_thousands_sep
;
1798 } else if(lcid
[LC_NUMERIC
]) {
1799 if(!update_threadlocinfo_category(lcid
[LC_NUMERIC
],
1800 cp
[LC_NUMERIC
], locinfo
, LC_NUMERIC
)) {
1801 free_locinfo(locinfo
);
1805 locinfo
->lconv_num_refcount
= malloc(sizeof(int));
1806 if(!locinfo
->lconv_num_refcount
) {
1807 free_locinfo(locinfo
);
1811 *locinfo
->lconv_num_refcount
= 1;
1813 i
= GetLocaleInfoA(lcid
[LC_NUMERIC
], LOCALE_SDECIMAL
1814 |LOCALE_NOUSEROVERRIDE
, buf
, 256);
1815 if(i
&& (locinfo
->lconv
->decimal_point
= malloc(i
)))
1816 memcpy(locinfo
->lconv
->decimal_point
, buf
, i
);
1818 free_locinfo(locinfo
);
1822 i
= GetLocaleInfoA(lcid
[LC_NUMERIC
], LOCALE_STHOUSAND
1823 |LOCALE_NOUSEROVERRIDE
, buf
, 256);
1824 if(i
&& (locinfo
->lconv
->thousands_sep
= malloc(i
)))
1825 memcpy(locinfo
->lconv
->thousands_sep
, buf
, i
);
1827 free_locinfo(locinfo
);
1831 i
= GetLocaleInfoA(lcid
[LC_NUMERIC
], LOCALE_SGROUPING
1832 |LOCALE_NOUSEROVERRIDE
, buf
, 256);
1834 i
= i
/2 + (buf
[i
-2]=='0'?0:1);
1835 if(i
&& (locinfo
->lconv
->grouping
= malloc(i
))) {
1836 for(i
=0; buf
[i
+1]==';'; i
+=2)
1837 locinfo
->lconv
->grouping
[i
/2] = buf
[i
]-'0';
1838 locinfo
->lconv
->grouping
[i
/2] = buf
[i
]-'0';
1840 locinfo
->lconv
->grouping
[i
/2+1] = 127;
1842 free_locinfo(locinfo
);
1846 #if _MSVCR_VER >= 100
1847 i
= GetLocaleInfoW(lcid
[LC_NUMERIC
], LOCALE_SDECIMAL
1848 |LOCALE_NOUSEROVERRIDE
, wbuf
, 256);
1849 if(i
&& (locinfo
->lconv
->_W_decimal_point
= malloc(i
* sizeof(wchar_t))))
1850 memcpy(locinfo
->lconv
->_W_decimal_point
, wbuf
, i
* sizeof(wchar_t));
1852 free_locinfo(locinfo
);
1856 i
= GetLocaleInfoW(lcid
[LC_NUMERIC
], LOCALE_STHOUSAND
1857 |LOCALE_NOUSEROVERRIDE
, wbuf
, 256);
1858 if(i
&& (locinfo
->lconv
->_W_thousands_sep
= malloc(i
* sizeof(wchar_t))))
1859 memcpy(locinfo
->lconv
->_W_thousands_sep
, wbuf
, i
* sizeof(wchar_t));
1861 free_locinfo(locinfo
);
1866 if (locinfo
->lconv
!= &cloc_lconv
) {
1867 locinfo
->lconv
->decimal_point
= cloc_lconv
.decimal_point
;
1868 locinfo
->lconv
->thousands_sep
= cloc_lconv
.thousands_sep
;
1869 locinfo
->lconv
->grouping
= cloc_lconv
.grouping
;
1871 #if _MSVCR_VER >= 100
1872 locinfo
->lconv
->_W_decimal_point
= cloc_lconv
._W_decimal_point
;
1873 locinfo
->lconv
->_W_thousands_sep
= cloc_lconv
._W_thousands_sep
;
1877 if (!init_category_name("C", 1, locinfo
, LC_NUMERIC
)) {
1878 free_locinfo(locinfo
);
1883 if(locale_name
[LC_TIME
] &&
1884 !init_category_name(locale_name
[LC_TIME
],
1885 locale_len
[LC_TIME
], locinfo
, LC_TIME
)) {
1886 free_locinfo(locinfo
);
1890 if(!category_needs_update(LC_TIME
, old_locinfo
,
1891 lcid
[LC_TIME
], cp
[LC_TIME
])) {
1892 copy_threadlocinfo_category(locinfo
, old_locinfo
, LC_TIME
);
1893 locinfo
->lc_time_curr
= old_locinfo
->lc_time_curr
;
1894 InterlockedIncrement(&locinfo
->lc_time_curr
->refcount
);
1895 } else if(lcid
[LC_TIME
]) {
1896 if(!update_threadlocinfo_category(lcid
[LC_TIME
],
1897 cp
[LC_TIME
], locinfo
, LC_TIME
)) {
1898 free_locinfo(locinfo
);
1902 locinfo
->lc_time_curr
= create_time_data(lcid
[LC_TIME
]);
1903 if(!locinfo
->lc_time_curr
) {
1904 free_locinfo(locinfo
);
1908 if(!init_category_name("C", 1, locinfo
, LC_TIME
)) {
1909 free_locinfo(locinfo
);
1912 locinfo
->lc_time_curr
= &cloc_time_data
;
1913 InterlockedIncrement(&locinfo
->lc_time_curr
->refcount
);
1919 /*********************************************************************
1920 * _create_locale (MSVCRT.@)
1922 _locale_t CDECL
_create_locale(int category
, const char *locale
)
1926 loc
= malloc(sizeof(_locale_tstruct
));
1930 loc
->locinfo
= create_locinfo(category
, locale
, NULL
);
1936 loc
->mbcinfo
= create_mbcinfo(loc
->locinfo
->lc_id
[LC_CTYPE
].wCodePage
,
1937 loc
->locinfo
->lc_handle
[LC_CTYPE
], NULL
);
1939 free_locinfo(loc
->locinfo
);
1946 #if _MSVCR_VER >= 110
1947 /*********************************************************************
1948 * _wcreate_locale (MSVCR110.@)
1950 _locale_t CDECL
_wcreate_locale(int category
, const wchar_t *locale
)
1956 if(category
<LC_MIN
|| category
>LC_MAX
|| !locale
)
1959 len
= wcstombs(NULL
, locale
, 0);
1962 if(!(str
= malloc(++len
)))
1964 wcstombs(str
, locale
, len
);
1966 loc
= _create_locale(category
, str
);
1973 /*********************************************************************
1974 * setlocale (MSVCRT.@)
1976 char* CDECL
setlocale(int category
, const char* locale
)
1978 thread_data_t
*data
= msvcrt_get_thread_data();
1979 pthreadlocinfo locinfo
= get_locinfo(), newlocinfo
;
1981 if(category
<LC_MIN
|| category
>LC_MAX
)
1985 if(category
== LC_ALL
)
1986 return construct_lc_all(locinfo
);
1988 return locinfo
->lc_category
[category
].locale
;
1991 newlocinfo
= create_locinfo(category
, locale
, locinfo
);
1993 WARN("%d %s failed\n", category
, locale
);
1997 if(locale
[0] != 'C' || locale
[1] != '\0')
1998 initial_locale
= FALSE
;
2000 if(data
->locale_flags
& LOCALE_THREAD
)
2002 if(data
->locale_flags
& LOCALE_FREE
)
2003 free_locinfo(data
->locinfo
);
2004 data
->locinfo
= newlocinfo
;
2011 free_locinfo(MSVCRT_locale
->locinfo
);
2012 MSVCRT_locale
->locinfo
= newlocinfo
;
2014 MSVCRT___lc_codepage
= newlocinfo
->lc_codepage
;
2015 MSVCRT___lc_collate_cp
= newlocinfo
->lc_collate_cp
;
2016 MSVCRT___mb_cur_max
= newlocinfo
->mb_cur_max
;
2017 MSVCRT__pctype
= newlocinfo
->pctype
;
2018 for(i
=LC_MIN
; i
<=LC_MAX
; i
++)
2019 MSVCRT___lc_handle
[i
] = MSVCRT_locale
->locinfo
->lc_handle
[i
];
2021 update_thread_locale(data
);
2024 if(category
== LC_ALL
)
2025 return construct_lc_all(data
->locinfo
);
2027 return data
->locinfo
->lc_category
[category
].locale
;
2030 /*********************************************************************
2031 * _wsetlocale (MSVCRT.@)
2033 wchar_t* CDECL
_wsetlocale(int category
, const wchar_t* wlocale
)
2035 static wchar_t current_lc_all
[MAX_LOCALE_LENGTH
];
2037 char *locale
= NULL
;
2042 len
= wcstombs(NULL
, wlocale
, 0);
2046 locale
= malloc(++len
);
2050 wcstombs(locale
, wlocale
, len
);
2054 ret
= setlocale(category
, locale
);
2057 if(ret
&& mbstowcs(current_lc_all
, ret
, MAX_LOCALE_LENGTH
)==-1)
2061 return ret
? current_lc_all
: NULL
;
2064 #if _MSVCR_VER >= 80
2065 /*********************************************************************
2066 * _configthreadlocale (MSVCR80.@)
2068 int CDECL
_configthreadlocale(int type
)
2070 thread_data_t
*data
= msvcrt_get_thread_data();
2073 ret
= (data
->locale_flags
& LOCALE_THREAD
? _ENABLE_PER_THREAD_LOCALE
:
2074 _DISABLE_PER_THREAD_LOCALE
);
2076 if(type
== _ENABLE_PER_THREAD_LOCALE
)
2077 data
->locale_flags
|= LOCALE_THREAD
;
2078 else if(type
== _DISABLE_PER_THREAD_LOCALE
)
2079 data
->locale_flags
&= ~LOCALE_THREAD
;
2087 BOOL
msvcrt_init_locale(void)
2092 MSVCRT_locale
= _create_locale(0, "C");
2097 MSVCRT___lc_codepage
= MSVCRT_locale
->locinfo
->lc_codepage
;
2098 MSVCRT___lc_collate_cp
= MSVCRT_locale
->locinfo
->lc_collate_cp
;
2099 MSVCRT___mb_cur_max
= MSVCRT_locale
->locinfo
->mb_cur_max
;
2100 MSVCRT__pctype
= MSVCRT_locale
->locinfo
->pctype
;
2101 for(i
=LC_MIN
; i
<=LC_MAX
; i
++)
2102 MSVCRT___lc_handle
[i
] = MSVCRT_locale
->locinfo
->lc_handle
[i
];
2103 _setmbcp(_MB_CP_ANSI
);
2107 #if _MSVCR_VER >= 120
2108 /*********************************************************************
2109 * wctrans (MSVCR120.@)
2111 wctrans_t CDECL
wctrans(const char *property
)
2113 static const char str_tolower
[] = "tolower";
2114 static const char str_toupper
[] = "toupper";
2116 if(!strcmp(property
, str_tolower
))
2118 if(!strcmp(property
, str_toupper
))