msvcrt: Share locale names between threadlocinfo instances.
[wine.git] / dlls / msvcrt / locale.c
blobb6c36ac4cf1cda1d08fc5b95bdaec45c63416e31
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <limits.h>
25 #include <locale.h>
26 #include <stdarg.h>
27 #include <stdio.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "winnls.h"
34 #include "msvcrt.h"
35 #include "mtdll.h"
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 MSVCRT__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[MSVCRT_LC_MAX - MSVCRT_LC_MIN + 1] = { 0 };
48 int MSVCRT___mb_cur_max = 1;
49 static unsigned char charmax = CHAR_MAX;
50 BOOL initial_locale = TRUE;
52 #define MSVCRT_LEADBYTE 0x8000
53 #define MSVCRT_C1_DEFINED 0x200
55 static const MSVCRT_wchar_t sun[] = {'S','u','n',0};
56 static const MSVCRT_wchar_t mon[] = {'M','o','n',0};
57 static const MSVCRT_wchar_t tue[] = {'T','u','e',0};
58 static const MSVCRT_wchar_t wed[] = {'W','e','d',0};
59 static const MSVCRT_wchar_t thu[] = {'T','h','u',0};
60 static const MSVCRT_wchar_t fri[] = {'F','r','i',0};
61 static const MSVCRT_wchar_t sat[] = {'S','a','t',0};
62 static const MSVCRT_wchar_t sunday[] = {'S','u','n','d','a','y',0};
63 static const MSVCRT_wchar_t monday[] = {'M','o','n','d','a','y',0};
64 static const MSVCRT_wchar_t tuesday[] = {'T','u','e','s','d','a','y',0};
65 static const MSVCRT_wchar_t wednesday[] = {'W','e','d','n','e','s','d','a','y',0};
66 static const MSVCRT_wchar_t thursday[] = {'T','h','u','r','s','d','a','y',0};
67 static const MSVCRT_wchar_t friday[] = {'F','r','i','d','a','y',0};
68 static const MSVCRT_wchar_t saturday[] = {'S','a','t','u','r','d','a','y',0};
69 static const MSVCRT_wchar_t jan[] = {'J','a','n',0};
70 static const MSVCRT_wchar_t feb[] = {'F','e','b',0};
71 static const MSVCRT_wchar_t mar[] = {'M','a','r',0};
72 static const MSVCRT_wchar_t apr[] = {'A','p','r',0};
73 static const MSVCRT_wchar_t may[] = {'M','a','y',0};
74 static const MSVCRT_wchar_t jun[] = {'J','u','n',0};
75 static const MSVCRT_wchar_t jul[] = {'J','u','l',0};
76 static const MSVCRT_wchar_t aug[] = {'A','u','g',0};
77 static const MSVCRT_wchar_t sep[] = {'S','e','p',0};
78 static const MSVCRT_wchar_t oct[] = {'O','c','t',0};
79 static const MSVCRT_wchar_t nov[] = {'N','o','v',0};
80 static const MSVCRT_wchar_t dec[] = {'D','e','c',0};
81 static const MSVCRT_wchar_t january[] = {'J','a','n','u','a','r','y',0};
82 static const MSVCRT_wchar_t february[] = {'F','e','b','r','u','a','r','y',0};
83 static const MSVCRT_wchar_t march[] = {'M','a','r','c','h',0};
84 static const MSVCRT_wchar_t april[] = {'A','p','r','i','l',0};
85 static const MSVCRT_wchar_t june[] = {'J','u','n','e',0};
86 static const MSVCRT_wchar_t july[] = {'J','u','l','y',0};
87 static const MSVCRT_wchar_t august[] = {'A','u','g','u','s','t',0};
88 static const MSVCRT_wchar_t september[] = {'S','e','p','t','e','m','b','e','r',0};
89 static const MSVCRT_wchar_t october[] = {'O','c','t','o','b','e','r',0};
90 static const MSVCRT_wchar_t november[] = {'N','o','v','e','m','b','e','r',0};
91 static const MSVCRT_wchar_t december[] = {'D','e','c','e','m','b','e','r',0};
92 static const MSVCRT_wchar_t am[] = {'A','M',0};
93 static const MSVCRT_wchar_t pm[] = {'P','M',0};
94 static const MSVCRT_wchar_t cloc_short_date[] = {'M','M','/','d','d','/','y','y',0};
95 static const MSVCRT_wchar_t cloc_date[] = {'d','d','d','d',',',' ','M','M','M','M',' ','d','d',',',' ','y','y','y','y',0};
96 static const MSVCRT_wchar_t cloc_time[] = {'H','H',':','m','m',':','s','s',0};
98 #if _MSVCR_VER >= 110
99 static const MSVCRT_wchar_t en_us[] = {'e','n','-','U','S',0};
100 #endif
102 MSVCRT___lc_time_data cloc_time_data =
104 {{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
105 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday",
106 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
107 "January", "February", "March", "April", "May", "June", "July",
108 "August", "September", "October", "November", "December",
109 "AM", "PM", "MM/dd/yy", "dddd, MMMM dd, yyyy", "HH:mm:ss"}},
110 #if _MSVCR_VER < 110
111 MAKELCID(LANG_ENGLISH, SORT_DEFAULT),
112 #endif
113 {1, 0},
114 {{sun, mon, tue, wed, thu, fri, sat,
115 sunday, monday, tuesday, wednesday, thursday, friday, saturday,
116 jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec,
117 january, february, march, april, may, june, july,
118 august, september, october, november, december,
119 am, pm, cloc_short_date, cloc_date, cloc_time}},
120 #if _MSVCR_VER >= 110
121 en_us,
122 #endif
125 /* Friendly country strings & language names abbreviations. */
126 static const char * const _country_synonyms[] =
128 "american", "enu",
129 "american english", "enu",
130 "american-english", "enu",
131 "english-american", "enu",
132 "english-us", "enu",
133 "english-usa", "enu",
134 "us", "enu",
135 "usa", "enu",
136 "australian", "ena",
137 "english-aus", "ena",
138 "belgian", "nlb",
139 "french-belgian", "frb",
140 "canadian", "enc",
141 "english-can", "enc",
142 "french-canadian", "frc",
143 "chinese", "chs",
144 "chinese-simplified", "chs",
145 "chinese-traditional", "cht",
146 "dutch-belgian", "nlb",
147 "english-nz", "enz",
148 "uk", "eng",
149 "english-uk", "eng",
150 "french-swiss", "frs",
151 "swiss", "des",
152 "german-swiss", "des",
153 "italian-swiss", "its",
154 "german-austrian", "dea",
155 "portuguese", "ptb",
156 "portuguese-brazil", "ptb",
157 "spanish-mexican", "esm",
158 "norwegian-bokmal", "nor",
159 "norwegian-nynorsk", "non",
160 "spanish-modern", "esn"
163 /* INTERNAL: Map a synonym to an ISO code */
164 static void remap_synonym(char *name)
166 unsigned int i;
167 for (i = 0; i < ARRAY_SIZE(_country_synonyms); i += 2)
169 if (!MSVCRT__stricmp(_country_synonyms[i],name))
171 TRACE(":Mapping synonym %s to %s\n",name,_country_synonyms[i+1]);
172 strcpy(name, _country_synonyms[i+1]);
173 return;
178 /* Note: Flags are weighted in order of matching importance */
179 #define FOUND_SNAME 0x4
180 #define FOUND_LANGUAGE 0x2
181 #define FOUND_COUNTRY 0x1
183 typedef struct {
184 char search_language[MAX_ELEM_LEN];
185 char search_country[MAX_ELEM_LEN];
186 DWORD found_codepage;
187 unsigned int match_flags;
188 LANGID found_lang_id;
189 BOOL allow_sname;
190 } locale_search_t;
192 #define CONTINUE_LOOKING TRUE
193 #define STOP_LOOKING FALSE
195 /* INTERNAL: Get and compare locale info with a given string */
196 static int compare_info(LCID lcid, DWORD flags, char* buff, const char* cmp, BOOL exact)
198 int len;
200 if(!cmp[0])
201 return 0;
203 buff[0] = 0;
204 GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN);
205 if (!buff[0])
206 return 0;
208 /* Partial matches are only allowed on language/country names */
209 len = strlen(cmp);
210 if(exact || len<=3)
211 return !MSVCRT__stricmp(cmp, buff);
212 else
213 return !MSVCRT__strnicmp(cmp, buff, len);
216 static BOOL CALLBACK
217 find_best_locale_proc(HMODULE hModule, LPCSTR type, LPCSTR name, WORD LangID, LONG_PTR lParam)
219 locale_search_t *res = (locale_search_t *)lParam;
220 const LCID lcid = MAKELCID(LangID, SORT_DEFAULT);
221 char buff[MAX_ELEM_LEN];
222 unsigned int flags = 0;
224 if(PRIMARYLANGID(LangID) == LANG_NEUTRAL)
225 return CONTINUE_LOOKING;
227 #if _MSVCR_VER >= 110
228 if (res->allow_sname && compare_info(lcid,LOCALE_SNAME,buff,res->search_language, TRUE))
230 TRACE(":Found locale: %s->%s\n", res->search_language, buff);
231 res->match_flags = FOUND_SNAME;
232 res->found_lang_id = LangID;
233 return STOP_LOOKING;
235 #endif
237 /* Check Language */
238 if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language, TRUE) ||
239 compare_info(lcid,LOCALE_SABBREVLANGNAME,buff,res->search_language, TRUE) ||
240 compare_info(lcid,LOCALE_SENGLANGUAGE,buff,res->search_language, FALSE))
242 TRACE(":Found language: %s->%s\n", res->search_language, buff);
243 flags |= FOUND_LANGUAGE;
245 else if (res->match_flags & FOUND_LANGUAGE)
247 return CONTINUE_LOOKING;
250 /* Check Country */
251 if (compare_info(lcid,LOCALE_SISO3166CTRYNAME,buff,res->search_country, TRUE) ||
252 compare_info(lcid,LOCALE_SABBREVCTRYNAME,buff,res->search_country, TRUE) ||
253 compare_info(lcid,LOCALE_SENGCOUNTRY,buff,res->search_country, FALSE))
255 TRACE("Found country:%s->%s\n", res->search_country, buff);
256 flags |= FOUND_COUNTRY;
258 else if (!flags && (res->match_flags & FOUND_COUNTRY))
260 return CONTINUE_LOOKING;
263 if (flags > res->match_flags)
265 /* Found a better match than previously */
266 res->match_flags = flags;
267 res->found_lang_id = LangID;
269 if ((flags & (FOUND_LANGUAGE | FOUND_COUNTRY)) ==
270 (FOUND_LANGUAGE | FOUND_COUNTRY))
272 TRACE(":found exact locale match\n");
273 return STOP_LOOKING;
275 return CONTINUE_LOOKING;
278 /* Internal: Find the LCID for a locale specification */
279 LCID MSVCRT_locale_to_LCID(const char *locale, unsigned short *codepage, BOOL *sname)
281 thread_data_t *data = msvcrt_get_thread_data();
282 const char *cp, *region;
283 BOOL is_sname = FALSE;
284 DWORD locale_cp;
285 LCID lcid;
287 if (!strcmp(locale, data->cached_locale)) {
288 if (codepage)
289 *codepage = data->cached_cp;
290 if (sname)
291 *sname = data->cached_sname;
292 return data->cached_lcid;
295 cp = strchr(locale, '.');
296 region = strchr(locale, '_');
298 if(!locale[0] || (cp == locale && !region)) {
299 lcid = GetUserDefaultLCID();
300 } else {
301 locale_search_t search;
303 memset(&search, 0, sizeof(locale_search_t));
304 lstrcpynA(search.search_language, locale, MAX_ELEM_LEN);
305 if(region) {
306 lstrcpynA(search.search_country, region+1, MAX_ELEM_LEN);
307 if(region-locale < MAX_ELEM_LEN)
308 search.search_language[region-locale] = '\0';
309 } else
310 search.search_country[0] = '\0';
312 if(cp) {
313 if(region && cp-region-1<MAX_ELEM_LEN)
314 search.search_country[cp-region-1] = '\0';
315 if(cp-locale < MAX_ELEM_LEN)
316 search.search_language[cp-locale] = '\0';
319 if(!cp && !region)
321 remap_synonym(search.search_language);
322 search.allow_sname = TRUE;
325 if(!MSVCRT__stricmp(search.search_country, "China"))
326 strcpy(search.search_country, "People's Republic of China");
328 EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), (LPSTR)RT_STRING,
329 (LPCSTR)LOCALE_ILANGUAGE,find_best_locale_proc,
330 (LONG_PTR)&search);
332 if (!search.match_flags)
333 return -1;
335 /* If we were given something that didn't match, fail */
336 if (search.search_language[0] && !(search.match_flags & (FOUND_SNAME | FOUND_LANGUAGE)))
337 return -1;
338 if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY))
339 return -1;
341 lcid = MAKELCID(search.found_lang_id, SORT_DEFAULT);
342 is_sname = (search.match_flags & FOUND_SNAME) != 0;
345 /* Obtain code page */
346 if (!cp || !cp[1] || !MSVCRT__strnicmp(cp, ".ACP", 4)) {
347 GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
348 (WCHAR *)&locale_cp, sizeof(DWORD)/sizeof(WCHAR));
349 if (!locale_cp)
350 locale_cp = GetACP();
351 } else if (!MSVCRT__strnicmp(cp, ".OCP", 4)) {
352 GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
353 (WCHAR *)&locale_cp, sizeof(DWORD)/sizeof(WCHAR));
354 #if _MSVCR_VER >= 140
355 } else if (!MSVCRT__strnicmp(cp, ".UTF-8", 6)
356 || !MSVCRT__strnicmp(cp, ".UTF8", 5)) {
357 locale_cp = CP_UTF8;
358 #endif
359 } else {
360 locale_cp = MSVCRT_atoi(cp + 1);
362 if (!IsValidCodePage(locale_cp))
363 return -1;
365 if (!locale_cp)
366 return -1;
368 if (codepage)
369 *codepage = locale_cp;
370 if (sname)
371 *sname = is_sname;
373 if (strlen(locale) < sizeof(data->cached_locale)) {
374 strcpy(data->cached_locale, locale);
375 data->cached_lcid = lcid;
376 data->cached_cp = locale_cp;
377 data->cached_sname = is_sname;
380 return lcid;
383 static void copy_threadlocinfo_category(MSVCRT_pthreadlocinfo locinfo,
384 const MSVCRT_threadlocinfo *old_locinfo, int category)
386 locinfo->lc_handle[category] = old_locinfo->lc_handle[category];
387 locinfo->lc_id[category] = old_locinfo->lc_id[category];
388 if(!locinfo->lc_category[category].locale) {
389 locinfo->lc_category[category].locale = old_locinfo->lc_category[category].locale;
390 locinfo->lc_category[category].refcount = old_locinfo->lc_category[category].refcount;
391 InterlockedIncrement(locinfo->lc_category[category].refcount);
393 #if _MSVCR_VER >= 110
394 locinfo->lc_name[category] = old_locinfo->lc_name[category];
395 locinfo->lc_category[category].wrefcount = old_locinfo->lc_category[category].wrefcount;
396 if(locinfo->lc_category[category].wrefcount)
397 InterlockedIncrement(locinfo->lc_category[category].wrefcount);
398 #endif
401 static BOOL init_category_name(const char *name, int len,
402 MSVCRT_pthreadlocinfo locinfo, int category)
404 locinfo->lc_category[category].locale = MSVCRT_malloc(len+1);
405 locinfo->lc_category[category].refcount = MSVCRT_malloc(sizeof(int));
406 if(!locinfo->lc_category[category].locale
407 || !locinfo->lc_category[category].refcount) {
408 MSVCRT_free(locinfo->lc_category[category].locale);
409 MSVCRT_free(locinfo->lc_category[category].refcount);
410 locinfo->lc_category[category].locale = NULL;
411 locinfo->lc_category[category].refcount = NULL;
412 return FALSE;
415 memcpy(locinfo->lc_category[category].locale, name, len);
416 locinfo->lc_category[category].locale[len] = 0;
417 *locinfo->lc_category[category].refcount = 1;
418 return TRUE;
421 #if _MSVCR_VER >= 110
422 static inline BOOL set_lc_locale_name(MSVCRT_pthreadlocinfo locinfo, int cat)
424 LCID lcid = locinfo->lc_handle[cat];
425 WCHAR buf[100];
426 int len;
428 locinfo->lc_category[cat].wrefcount = MSVCRT_malloc(sizeof(int));
429 if(!locinfo->lc_category[cat].wrefcount)
430 return FALSE;
431 *locinfo->lc_category[cat].wrefcount = 1;
433 len = GetLocaleInfoW(lcid, LOCALE_SISO639LANGNAME
434 |LOCALE_NOUSEROVERRIDE, buf, 100);
435 if(!len) return FALSE;
437 if(LocaleNameToLCID(buf, 0) != lcid)
438 len = LCIDToLocaleName(lcid, buf, 100, 0);
440 if(!len || !(locinfo->lc_name[cat] = MSVCRT_malloc(len*sizeof(MSVCRT_wchar_t))))
441 return FALSE;
443 memcpy(locinfo->lc_name[cat], buf, len*sizeof(MSVCRT_wchar_t));
444 return TRUE;
446 #else
447 static inline BOOL set_lc_locale_name(MSVCRT_pthreadlocinfo locinfo, int cat)
449 return TRUE;
451 #endif
453 /* INTERNAL: Set lc_handle, lc_id and lc_category in threadlocinfo struct */
454 static BOOL update_threadlocinfo_category(LCID lcid, unsigned short cp,
455 MSVCRT_pthreadlocinfo locinfo, int category)
457 char buf[256], *p;
459 if(GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_NOUSEROVERRIDE, buf, 256)) {
460 p = buf;
462 locinfo->lc_id[category].wLanguage = 0;
463 while(*p) {
464 locinfo->lc_id[category].wLanguage *= 16;
466 if(*p <= '9')
467 locinfo->lc_id[category].wLanguage += *p-'0';
468 else
469 locinfo->lc_id[category].wLanguage += *p-'a'+10;
471 p++;
474 locinfo->lc_id[category].wCountry =
475 locinfo->lc_id[category].wLanguage;
478 locinfo->lc_id[category].wCodePage = cp;
480 locinfo->lc_handle[category] = lcid;
482 set_lc_locale_name(locinfo, category);
484 if(!locinfo->lc_category[category].locale) {
485 int len = 0;
487 len += GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE
488 |LOCALE_NOUSEROVERRIDE, buf, 256);
489 buf[len-1] = '_';
490 len += GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY
491 |LOCALE_NOUSEROVERRIDE, &buf[len], 256-len);
492 buf[len-1] = '.';
493 MSVCRT_sprintf(buf+len, "%d", cp);
494 len += strlen(buf+len);
496 return init_category_name(buf, len, locinfo, category);
499 return TRUE;
502 /* INTERNAL: swap pointers values */
503 static inline void swap_pointers(void **p1, void **p2) {
504 void *hlp;
506 hlp = *p1;
507 *p1 = *p2;
508 *p2 = hlp;
511 /* INTERNAL: returns pthreadlocinfo struct */
512 MSVCRT_pthreadlocinfo CDECL get_locinfo(void) {
513 thread_data_t *data = msvcrt_get_thread_data();
515 if(!data || !data->have_locale)
516 return MSVCRT_locale->locinfo;
518 return data->locinfo;
521 /* INTERNAL: returns pthreadlocinfo struct */
522 MSVCRT_pthreadmbcinfo CDECL get_mbcinfo(void) {
523 thread_data_t *data = msvcrt_get_thread_data();
525 if(!data || !data->have_locale)
526 return MSVCRT_locale->mbcinfo;
528 return data->mbcinfo;
531 /* INTERNAL: constructs string returned by setlocale */
532 static inline char* construct_lc_all(MSVCRT_pthreadlocinfo locinfo) {
533 static char current_lc_all[MAX_LOCALE_LENGTH];
535 int i;
537 for(i=MSVCRT_LC_MIN+1; i<MSVCRT_LC_MAX; i++) {
538 if(strcmp(locinfo->lc_category[i].locale,
539 locinfo->lc_category[i+1].locale))
540 break;
543 if(i==MSVCRT_LC_MAX)
544 return locinfo->lc_category[MSVCRT_LC_COLLATE].locale;
546 MSVCRT_sprintf(current_lc_all,
547 "LC_COLLATE=%s;LC_CTYPE=%s;LC_MONETARY=%s;LC_NUMERIC=%s;LC_TIME=%s",
548 locinfo->lc_category[MSVCRT_LC_COLLATE].locale,
549 locinfo->lc_category[MSVCRT_LC_CTYPE].locale,
550 locinfo->lc_category[MSVCRT_LC_MONETARY].locale,
551 locinfo->lc_category[MSVCRT_LC_NUMERIC].locale,
552 locinfo->lc_category[MSVCRT_LC_TIME].locale);
554 return current_lc_all;
558 /*********************************************************************
559 * _Getdays (MSVCRT.@)
561 char* CDECL _Getdays(void)
563 MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr;
564 int i, len, size = 0;
565 char *out;
567 TRACE("\n");
569 for(i=0; i<7; i++) {
570 size += strlen(cur->str.names.short_wday[i]) + 1;
571 size += strlen(cur->str.names.wday[i]) + 1;
573 out = MSVCRT_malloc(size+1);
574 if(!out)
575 return NULL;
577 size = 0;
578 for(i=0; i<7; i++) {
579 out[size++] = ':';
580 len = strlen(cur->str.names.short_wday[i]);
581 memcpy(&out[size], cur->str.names.short_wday[i], len);
582 size += len;
584 out[size++] = ':';
585 len = strlen(cur->str.names.wday[i]);
586 memcpy(&out[size], cur->str.names.wday[i], len);
587 size += len;
589 out[size] = '\0';
591 return out;
594 #if _MSVCR_VER >= 110
595 /*********************************************************************
596 * _W_Getdays (MSVCR110.@)
598 MSVCRT_wchar_t* CDECL _W_Getdays(void)
600 MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr;
601 MSVCRT_wchar_t *out;
602 int i, len, size = 0;
604 TRACE("\n");
606 for(i=0; i<7; i++) {
607 size += MSVCRT_wcslen(cur->wstr.names.short_wday[i]) + 1;
608 size += MSVCRT_wcslen(cur->wstr.names.wday[i]) + 1;
610 out = MSVCRT_malloc((size+1)*sizeof(*out));
611 if(!out)
612 return NULL;
614 size = 0;
615 for(i=0; i<7; i++) {
616 out[size++] = ':';
617 len = MSVCRT_wcslen(cur->wstr.names.short_wday[i]);
618 memcpy(&out[size], cur->wstr.names.short_wday[i], len*sizeof(*out));
619 size += len;
621 out[size++] = ':';
622 len = MSVCRT_wcslen(cur->wstr.names.wday[i]);
623 memcpy(&out[size], cur->wstr.names.wday[i], len*sizeof(*out));
624 size += len;
626 out[size] = '\0';
628 return out;
630 #endif
632 /*********************************************************************
633 * _Getmonths (MSVCRT.@)
635 char* CDECL _Getmonths(void)
637 MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr;
638 int i, len, size = 0;
639 char *out;
641 TRACE("\n");
643 for(i=0; i<12; i++) {
644 size += strlen(cur->str.names.short_mon[i]) + 1;
645 size += strlen(cur->str.names.mon[i]) + 1;
647 out = MSVCRT_malloc(size+1);
648 if(!out)
649 return NULL;
651 size = 0;
652 for(i=0; i<12; i++) {
653 out[size++] = ':';
654 len = strlen(cur->str.names.short_mon[i]);
655 memcpy(&out[size], cur->str.names.short_mon[i], len);
656 size += len;
658 out[size++] = ':';
659 len = strlen(cur->str.names.mon[i]);
660 memcpy(&out[size], cur->str.names.mon[i], len);
661 size += len;
663 out[size] = '\0';
665 return out;
668 #if _MSVCR_VER >= 110
669 /*********************************************************************
670 * _W_Getmonths (MSVCR110.@)
672 MSVCRT_wchar_t* CDECL _W_Getmonths(void)
674 MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr;
675 MSVCRT_wchar_t *out;
676 int i, len, size = 0;
678 TRACE("\n");
680 for(i=0; i<12; i++) {
681 size += MSVCRT_wcslen(cur->wstr.names.short_mon[i]) + 1;
682 size += MSVCRT_wcslen(cur->wstr.names.mon[i]) + 1;
684 out = MSVCRT_malloc((size+1)*sizeof(*out));
685 if(!out)
686 return NULL;
688 size = 0;
689 for(i=0; i<12; i++) {
690 out[size++] = ':';
691 len = MSVCRT_wcslen(cur->wstr.names.short_mon[i]);
692 memcpy(&out[size], cur->wstr.names.short_mon[i], len*sizeof(*out));
693 size += len;
695 out[size++] = ':';
696 len = MSVCRT_wcslen(cur->wstr.names.mon[i]);
697 memcpy(&out[size], cur->wstr.names.mon[i], len*sizeof(*out));
698 size += len;
700 out[size] = '\0';
702 return out;
704 #endif
706 /*********************************************************************
707 * _Gettnames (MSVCRT.@)
709 void* CDECL _Gettnames(void)
711 MSVCRT___lc_time_data *ret, *cur = get_locinfo()->lc_time_curr;
712 unsigned int i, len, size = sizeof(MSVCRT___lc_time_data);
714 TRACE("\n");
716 for(i=0; i<ARRAY_SIZE(cur->str.str); i++)
717 size += strlen(cur->str.str[i])+1;
719 ret = MSVCRT_malloc(size);
720 if(!ret)
721 return NULL;
722 memcpy(ret, cur, sizeof(*ret));
724 size = 0;
725 for(i=0; i<ARRAY_SIZE(cur->str.str); i++) {
726 len = strlen(cur->str.str[i])+1;
727 memcpy(&ret->data[size], cur->str.str[i], len);
728 ret->str.str[i] = &ret->data[size];
729 size += len;
732 return ret;
735 #if _MSVCR_VER >= 110
736 /*********************************************************************
737 * _W_Gettnames (MSVCR110.@)
739 void* CDECL _W_Gettnames(void)
741 return _Gettnames();
743 #endif
745 /*********************************************************************
746 * __crtLCMapStringA (MSVCRT.@)
748 int CDECL __crtLCMapStringA(
749 LCID lcid, DWORD mapflags, const char* src, int srclen, char* dst,
750 int dstlen, unsigned int codepage, int xflag
752 WCHAR buf_in[32], *in = buf_in;
753 WCHAR buf_out[32], *out = buf_out;
754 int in_len, out_len, r;
756 TRACE("(lcid %x, flags %x, %s(%d), %p(%d), %x, %d), partial stub!\n",
757 lcid, mapflags, src, srclen, dst, dstlen, codepage, xflag);
759 in_len = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, src, srclen, NULL, 0);
760 if (!in_len) return 0;
761 if (in_len > ARRAY_SIZE(buf_in))
763 in = MSVCRT_malloc(in_len * sizeof(WCHAR));
764 if (!in) return 0;
767 r = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, src, srclen, in, in_len);
768 if (!r) goto done;
770 if (mapflags & LCMAP_SORTKEY)
772 r = LCMapStringW(lcid, mapflags, in, in_len, (WCHAR*)dst, dstlen);
773 goto done;
776 r = LCMapStringW(lcid, mapflags, in, in_len, NULL, 0);
777 if (!r) goto done;
778 out_len = r;
779 if (r > ARRAY_SIZE(buf_out))
781 out = MSVCRT_malloc(r * sizeof(WCHAR));
782 if (!out)
784 r = 0;
785 goto done;
789 r = LCMapStringW(lcid, mapflags, in, in_len, out, out_len);
790 if (!r) goto done;
792 r = WideCharToMultiByte(codepage, 0, out, out_len, dst, dstlen, NULL, NULL);
794 done:
795 if (in != buf_in) MSVCRT_free(in);
796 if (out != buf_out) MSVCRT_free(out);
797 return r;
800 /*********************************************************************
801 * __crtLCMapStringW (MSVCRT.@)
803 int CDECL __crtLCMapStringW(LCID lcid, DWORD mapflags, const MSVCRT_wchar_t *src,
804 int srclen, MSVCRT_wchar_t *dst, int dstlen, unsigned int codepage, int xflag)
806 FIXME("(lcid %x, flags %x, %s(%d), %p(%d), %x, %d), partial stub!\n",
807 lcid, mapflags, debugstr_w(src), srclen, dst, dstlen, codepage, xflag);
809 return LCMapStringW(lcid, mapflags, src, srclen, dst, dstlen);
812 /*********************************************************************
813 * __crtCompareStringA (MSVCRT.@)
815 int CDECL __crtCompareStringA( LCID lcid, DWORD flags, const char *src1, int len1,
816 const char *src2, int len2 )
818 FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n",
819 lcid, flags, debugstr_a(src1), len1, debugstr_a(src2), len2 );
820 /* FIXME: probably not entirely right */
821 return CompareStringA( lcid, flags, src1, len1, src2, len2 );
824 /*********************************************************************
825 * __crtCompareStringW (MSVCRT.@)
827 int CDECL __crtCompareStringW( LCID lcid, DWORD flags, const MSVCRT_wchar_t *src1, int len1,
828 const MSVCRT_wchar_t *src2, int len2 )
830 FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n",
831 lcid, flags, debugstr_w(src1), len1, debugstr_w(src2), len2 );
832 /* FIXME: probably not entirely right */
833 return CompareStringW( lcid, flags, src1, len1, src2, len2 );
836 /*********************************************************************
837 * __crtGetLocaleInfoW (MSVCRT.@)
839 int CDECL __crtGetLocaleInfoW( LCID lcid, LCTYPE type, MSVCRT_wchar_t *buffer, int len )
841 FIXME("(lcid %x, type %x, %p(%d), partial stub\n", lcid, type, buffer, len );
842 /* FIXME: probably not entirely right */
843 return GetLocaleInfoW( lcid, type, buffer, len );
846 #if _MSVCR_VER >= 110
847 /*********************************************************************
848 * __crtGetLocaleInfoEx (MSVC110.@)
850 int CDECL __crtGetLocaleInfoEx( const WCHAR *locale, LCTYPE type, MSVCRT_wchar_t *buffer, int len )
852 TRACE("(%s, %x, %p, %d)\n", debugstr_w(locale), type, buffer, len);
853 return GetLocaleInfoEx(locale, type, buffer, len);
855 #endif
857 /*********************************************************************
858 * btowc(MSVCRT.@)
860 MSVCRT_wint_t CDECL MSVCRT_btowc(int c)
862 unsigned char letter = c;
863 MSVCRT_wchar_t ret;
865 if(c == MSVCRT_EOF)
866 return MSVCRT_WEOF;
867 if(!get_locinfo()->lc_codepage)
868 return c & 255;
869 if(!MultiByteToWideChar(get_locinfo()->lc_codepage,
870 MB_ERR_INVALID_CHARS, (LPCSTR)&letter, 1, &ret, 1))
871 return MSVCRT_WEOF;
873 return ret;
876 /*********************************************************************
877 * __crtGetStringTypeW(MSVCRT.@)
879 * This function was accepting different number of arguments in older
880 * versions of msvcrt.
882 BOOL CDECL __crtGetStringTypeW(DWORD unk, DWORD type,
883 MSVCRT_wchar_t *buffer, int len, WORD *out)
885 FIXME("(unk %x, type %x, wstr %p(%d), %p) partial stub\n",
886 unk, type, buffer, len, out);
888 return GetStringTypeW(type, buffer, len, out);
891 /*********************************************************************
892 * localeconv (MSVCRT.@)
894 struct MSVCRT_lconv * CDECL MSVCRT_localeconv(void)
896 return get_locinfo()->lconv;
899 /*********************************************************************
900 * __lconv_init (MSVCRT.@)
902 int CDECL __lconv_init(void)
904 /* this is used to make chars unsigned */
905 charmax = 255;
906 return 0;
909 /*********************************************************************
910 * ___lc_handle_func (MSVCRT.@)
912 LCID* CDECL ___lc_handle_func(void)
914 return get_locinfo()->lc_handle;
917 #if _MSVCR_VER >= 110
918 /*********************************************************************
919 * ___lc_locale_name_func (MSVCR110.@)
921 MSVCRT_wchar_t** CDECL ___lc_locale_name_func(void)
923 return get_locinfo()->lc_name;
925 #endif
927 /*********************************************************************
928 * ___lc_codepage_func (MSVCRT.@)
930 unsigned int CDECL ___lc_codepage_func(void)
932 return get_locinfo()->lc_codepage;
935 /*********************************************************************
936 * ___lc_collate_cp_func (MSVCRT.@)
938 int CDECL ___lc_collate_cp_func(void)
940 return get_locinfo()->lc_collate_cp;
943 /* INTERNAL: frees MSVCRT_pthreadlocinfo struct */
944 void free_locinfo(MSVCRT_pthreadlocinfo locinfo)
946 int i;
948 if(!locinfo)
949 return;
951 if(InterlockedDecrement(&locinfo->refcount))
952 return;
954 for(i=MSVCRT_LC_MIN+1; i<=MSVCRT_LC_MAX; i++) {
955 if(!locinfo->lc_category[i].refcount
956 || !InterlockedDecrement(locinfo->lc_category[i].refcount)) {
957 MSVCRT_free(locinfo->lc_category[i].locale);
958 MSVCRT_free(locinfo->lc_category[i].refcount);
960 if(!locinfo->lc_category[i].wrefcount
961 || !InterlockedDecrement(locinfo->lc_category[i].wrefcount)) {
962 #if _MSVCR_VER >= 110
963 MSVCRT_free(locinfo->lc_name[i]);
964 #endif
965 MSVCRT_free(locinfo->lc_category[i].wrefcount);
969 if(locinfo->lconv) {
970 MSVCRT_free(locinfo->lconv->decimal_point);
971 MSVCRT_free(locinfo->lconv->thousands_sep);
972 MSVCRT_free(locinfo->lconv->grouping);
973 MSVCRT_free(locinfo->lconv->int_curr_symbol);
974 MSVCRT_free(locinfo->lconv->currency_symbol);
975 MSVCRT_free(locinfo->lconv->mon_decimal_point);
976 MSVCRT_free(locinfo->lconv->mon_thousands_sep);
977 MSVCRT_free(locinfo->lconv->mon_grouping);
978 MSVCRT_free(locinfo->lconv->positive_sign);
979 MSVCRT_free(locinfo->lconv->negative_sign);
980 #if _MSVCR_VER >= 100
981 MSVCRT_free(locinfo->lconv->_W_decimal_point);
982 MSVCRT_free(locinfo->lconv->_W_thousands_sep);
983 MSVCRT_free(locinfo->lconv->_W_int_curr_symbol);
984 MSVCRT_free(locinfo->lconv->_W_currency_symbol);
985 MSVCRT_free(locinfo->lconv->_W_mon_decimal_point);
986 MSVCRT_free(locinfo->lconv->_W_mon_thousands_sep);
987 MSVCRT_free(locinfo->lconv->_W_positive_sign);
988 MSVCRT_free(locinfo->lconv->_W_negative_sign);
989 #endif
991 MSVCRT_free(locinfo->lconv_intl_refcount);
992 MSVCRT_free(locinfo->lconv_num_refcount);
993 MSVCRT_free(locinfo->lconv_mon_refcount);
994 MSVCRT_free(locinfo->lconv);
996 MSVCRT_free(locinfo->ctype1_refcount);
997 MSVCRT_free(locinfo->ctype1);
999 MSVCRT_free(locinfo->pclmap);
1000 MSVCRT_free(locinfo->pcumap);
1002 if(locinfo->lc_time_curr != &cloc_time_data)
1003 MSVCRT_free(locinfo->lc_time_curr);
1005 MSVCRT_free(locinfo);
1008 /* INTERNAL: frees MSVCRT_pthreadmbcinfo struct */
1009 void free_mbcinfo(MSVCRT_pthreadmbcinfo mbcinfo)
1011 if(!mbcinfo)
1012 return;
1014 if(InterlockedDecrement(&mbcinfo->refcount))
1015 return;
1017 MSVCRT_free(mbcinfo);
1020 MSVCRT__locale_t CDECL get_current_locale_noalloc(MSVCRT__locale_t locale)
1022 thread_data_t *data = msvcrt_get_thread_data();
1024 if(!data || !data->have_locale)
1026 *locale = *MSVCRT_locale;
1028 else
1030 locale->locinfo = data->locinfo;
1031 locale->mbcinfo = data->mbcinfo;
1034 InterlockedIncrement(&locale->locinfo->refcount);
1035 InterlockedIncrement(&locale->mbcinfo->refcount);
1036 return locale;
1039 void CDECL free_locale_noalloc(MSVCRT__locale_t locale)
1041 free_locinfo(locale->locinfo);
1042 free_mbcinfo(locale->mbcinfo);
1045 /*********************************************************************
1046 * _get_current_locale (MSVCRT.@)
1048 MSVCRT__locale_t CDECL MSVCRT__get_current_locale(void)
1050 MSVCRT__locale_t loc = MSVCRT_malloc(sizeof(MSVCRT__locale_tstruct));
1051 if(!loc)
1052 return NULL;
1054 return get_current_locale_noalloc(loc);
1057 /*********************************************************************
1058 * _free_locale (MSVCRT.@)
1060 void CDECL MSVCRT__free_locale(MSVCRT__locale_t locale)
1062 if (!locale)
1063 return;
1065 free_locale_noalloc(locale);
1066 MSVCRT_free(locale);
1069 static inline BOOL category_needs_update(int cat, int user_cat,
1070 const MSVCRT_threadlocinfo *locinfo, LCID lcid, unsigned short cp)
1072 if(!locinfo) return TRUE;
1073 if(user_cat!=cat && user_cat!=MSVCRT_LC_ALL) return FALSE;
1074 return lcid!=locinfo->lc_handle[cat] || cp!=locinfo->lc_id[cat].wCodePage;
1077 static MSVCRT___lc_time_data* create_time_data(LCID lcid)
1079 static const DWORD time_data[] = {
1080 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
1081 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
1082 LOCALE_SABBREVDAYNAME6,
1083 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
1084 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6,
1085 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
1086 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
1087 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
1088 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
1089 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
1090 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
1091 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
1092 LOCALE_S1159, LOCALE_S2359,
1093 LOCALE_SSHORTDATE, LOCALE_SLONGDATE,
1094 LOCALE_STIMEFORMAT
1097 MSVCRT___lc_time_data *cur;
1098 int i, ret, size;
1100 size = sizeof(MSVCRT___lc_time_data);
1101 for(i=0; i<ARRAY_SIZE(time_data); i++) {
1102 ret = GetLocaleInfoA(lcid, time_data[i], NULL, 0);
1103 if(!ret)
1104 return NULL;
1105 size += ret;
1107 ret = GetLocaleInfoW(lcid, time_data[i], NULL, 0);
1108 if(!ret)
1109 return NULL;
1110 size += ret*sizeof(MSVCRT_wchar_t);
1112 #if _MSVCR_VER >= 110
1113 size += LCIDToLocaleName(lcid, NULL, 0, 0)*sizeof(MSVCRT_wchar_t);
1114 #endif
1116 cur = MSVCRT_malloc(size);
1117 if(!cur)
1118 return NULL;
1120 ret = 0;
1121 for(i=0; i<ARRAY_SIZE(time_data); i++) {
1122 cur->str.str[i] = &cur->data[ret];
1123 ret += GetLocaleInfoA(lcid, time_data[i], &cur->data[ret], size-ret);
1125 for(i=0; i<ARRAY_SIZE(time_data); i++) {
1126 cur->wstr.wstr[i] = (MSVCRT_wchar_t*)&cur->data[ret];
1127 ret += GetLocaleInfoW(lcid, time_data[i],
1128 (MSVCRT_wchar_t*)&cur->data[ret], size-ret)*sizeof(MSVCRT_wchar_t);
1130 #if _MSVCR_VER >= 110
1131 cur->locname = (MSVCRT_wchar_t*)&cur->data[ret];
1132 LCIDToLocaleName(lcid, (MSVCRT_wchar_t*)&cur->data[ret], (size-ret)/sizeof(MSVCRT_wchar_t), 0);
1133 #else
1134 cur->lcid = lcid;
1135 #endif
1137 return cur;
1140 static MSVCRT_pthreadlocinfo create_locinfo(int category,
1141 const char *locale, const MSVCRT_threadlocinfo *old_locinfo)
1143 static const char collate[] = "COLLATE=";
1144 static const char ctype[] = "CTYPE=";
1145 static const char monetary[] = "MONETARY=";
1146 static const char numeric[] = "NUMERIC=";
1147 static const char time[] = "TIME=";
1149 MSVCRT_pthreadlocinfo locinfo;
1150 LCID lcid[6] = { 0 };
1151 unsigned short cp[6] = { 0 };
1152 const char *locale_name[6] = { 0 };
1153 int val, locale_len[6] = { 0 };
1154 char buf[256];
1155 BOOL sname;
1156 #if _MSVCR_VER >= 100
1157 MSVCRT_wchar_t wbuf[256];
1158 #endif
1159 int i;
1161 TRACE("(%d %s)\n", category, locale);
1163 if(category<MSVCRT_LC_MIN || category>MSVCRT_LC_MAX || !locale)
1164 return NULL;
1166 if(locale[0]=='C' && !locale[1]) {
1167 lcid[0] = 0;
1168 cp[0] = CP_ACP;
1169 } else if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') {
1170 const char *p;
1172 while(1) {
1173 locale += 3; /* LC_ */
1174 if(!memcmp(locale, collate, sizeof(collate)-1)) {
1175 i = MSVCRT_LC_COLLATE;
1176 locale += sizeof(collate)-1;
1177 } else if(!memcmp(locale, ctype, sizeof(ctype)-1)) {
1178 i = MSVCRT_LC_CTYPE;
1179 locale += sizeof(ctype)-1;
1180 } else if(!memcmp(locale, monetary, sizeof(monetary)-1)) {
1181 i = MSVCRT_LC_MONETARY;
1182 locale += sizeof(monetary)-1;
1183 } else if(!memcmp(locale, numeric, sizeof(numeric)-1)) {
1184 i = MSVCRT_LC_NUMERIC;
1185 locale += sizeof(numeric)-1;
1186 } else if(!memcmp(locale, time, sizeof(time)-1)) {
1187 i = MSVCRT_LC_TIME;
1188 locale += sizeof(time)-1;
1189 } else
1190 return NULL;
1192 p = strchr(locale, ';');
1193 if(locale[0]=='C' && (locale[1]==';' || locale[1]=='\0')) {
1194 lcid[i] = 0;
1195 cp[i] = CP_ACP;
1196 } else if(p) {
1197 memcpy(buf, locale, p-locale);
1198 buf[p-locale] = '\0';
1199 lcid[i] = MSVCRT_locale_to_LCID(buf, &cp[i], &sname);
1200 if(sname) {
1201 locale_name[i] = locale;
1202 locale_len[i] = p-locale;
1204 } else {
1205 lcid[i] = MSVCRT_locale_to_LCID(locale, &cp[i], &sname);
1206 if(sname) {
1207 locale_name[i] = locale;
1208 locale_len[i] = strlen(locale);
1212 if(lcid[i] == -1)
1213 return NULL;
1215 if(!p || *(p+1)!='L' || *(p+2)!='C' || *(p+3)!='_')
1216 break;
1218 locale = p+1;
1220 } else {
1221 lcid[0] = MSVCRT_locale_to_LCID(locale, &cp[0], &sname);
1222 if(lcid[0] == -1)
1223 return NULL;
1224 if(sname) {
1225 locale_name[0] = locale;
1226 locale_len[0] = strlen(locale);
1229 for(i=1; i<6; i++) {
1230 lcid[i] = lcid[0];
1231 cp[i] = cp[0];
1232 locale_name[i] = locale_name[0];
1233 locale_len[i] = locale_len[0];
1237 locinfo = MSVCRT_malloc(sizeof(MSVCRT_threadlocinfo));
1238 if(!locinfo)
1239 return NULL;
1241 memset(locinfo, 0, sizeof(MSVCRT_threadlocinfo));
1242 locinfo->refcount = 1;
1244 locinfo->lconv = MSVCRT_malloc(sizeof(struct MSVCRT_lconv));
1245 if(!locinfo->lconv) {
1246 free_locinfo(locinfo);
1247 return NULL;
1249 memset(locinfo->lconv, 0, sizeof(struct MSVCRT_lconv));
1251 locinfo->pclmap = MSVCRT_malloc(sizeof(char[256]));
1252 locinfo->pcumap = MSVCRT_malloc(sizeof(char[256]));
1253 if(!locinfo->pclmap || !locinfo->pcumap) {
1254 free_locinfo(locinfo);
1255 return NULL;
1258 if(locale_name[MSVCRT_LC_COLLATE] &&
1259 !init_category_name(locale_name[MSVCRT_LC_COLLATE],
1260 locale_len[MSVCRT_LC_COLLATE], locinfo, MSVCRT_LC_COLLATE)) {
1261 free_locinfo(locinfo);
1262 return NULL;
1265 if(!category_needs_update(MSVCRT_LC_COLLATE, category, old_locinfo,
1266 lcid[MSVCRT_LC_COLLATE], cp[MSVCRT_LC_COLLATE])) {
1267 copy_threadlocinfo_category(locinfo, old_locinfo, MSVCRT_LC_COLLATE);
1268 } else if(lcid[MSVCRT_LC_COLLATE] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_COLLATE)) {
1269 if(!update_threadlocinfo_category(lcid[MSVCRT_LC_COLLATE],
1270 cp[MSVCRT_LC_COLLATE], locinfo, MSVCRT_LC_COLLATE)) {
1271 free_locinfo(locinfo);
1272 return NULL;
1275 locinfo->lc_collate_cp = locinfo->lc_id[MSVCRT_LC_COLLATE].wCodePage;
1276 } else {
1277 if(!init_category_name("C", 1, locinfo, MSVCRT_LC_COLLATE)) {
1278 free_locinfo(locinfo);
1279 return NULL;
1283 if(locale_name[MSVCRT_LC_CTYPE] &&
1284 !init_category_name(locale_name[MSVCRT_LC_CTYPE],
1285 locale_len[MSVCRT_LC_CTYPE], locinfo, MSVCRT_LC_CTYPE)) {
1286 free_locinfo(locinfo);
1287 return NULL;
1290 if(!category_needs_update(MSVCRT_LC_CTYPE, category, old_locinfo,
1291 lcid[MSVCRT_LC_CTYPE], cp[MSVCRT_LC_CTYPE])) {
1292 copy_threadlocinfo_category(locinfo, old_locinfo, MSVCRT_LC_CTYPE);
1293 } else if(lcid[MSVCRT_LC_CTYPE] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_CTYPE)) {
1294 CPINFO cp_info;
1295 int j;
1297 if(!update_threadlocinfo_category(lcid[MSVCRT_LC_CTYPE],
1298 cp[MSVCRT_LC_CTYPE], locinfo, MSVCRT_LC_CTYPE)) {
1299 free_locinfo(locinfo);
1300 return NULL;
1303 locinfo->lc_codepage = locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage;
1304 locinfo->lc_clike = 1;
1305 if(!GetCPInfo(locinfo->lc_codepage, &cp_info)) {
1306 free_locinfo(locinfo);
1307 return NULL;
1309 locinfo->mb_cur_max = cp_info.MaxCharSize;
1311 locinfo->ctype1_refcount = MSVCRT_malloc(sizeof(int));
1312 locinfo->ctype1 = MSVCRT_malloc(sizeof(short[257]));
1313 if(!locinfo->ctype1_refcount || !locinfo->ctype1) {
1314 free_locinfo(locinfo);
1315 return NULL;
1318 *locinfo->ctype1_refcount = 1;
1319 locinfo->ctype1[0] = 0;
1320 locinfo->pctype = locinfo->ctype1+1;
1322 buf[1] = buf[2] = '\0';
1323 for(i=1; i<257; i++) {
1324 buf[0] = i-1;
1326 /* builtin GetStringTypeA doesn't set output to 0 on invalid input */
1327 locinfo->ctype1[i] = 0;
1329 GetStringTypeA(lcid[MSVCRT_LC_CTYPE], CT_CTYPE1, buf,
1330 1, locinfo->ctype1+i);
1333 for(i=0; cp_info.LeadByte[i+1]!=0; i+=2)
1334 for(j=cp_info.LeadByte[i]; j<=cp_info.LeadByte[i+1]; j++)
1335 locinfo->ctype1[j+1] |= MSVCRT__LEADBYTE;
1337 for(i=0; i<256; i++) {
1338 if(locinfo->pctype[i] & MSVCRT__LEADBYTE)
1339 buf[i] = ' ';
1340 else
1341 buf[i] = i;
1344 LCMapStringA(lcid[MSVCRT_LC_CTYPE], LCMAP_LOWERCASE, buf, 256,
1345 (char*)locinfo->pclmap, 256);
1346 LCMapStringA(lcid[MSVCRT_LC_CTYPE], LCMAP_UPPERCASE, buf, 256,
1347 (char*)locinfo->pcumap, 256);
1348 } else {
1349 locinfo->lc_clike = 1;
1350 locinfo->mb_cur_max = 1;
1351 locinfo->pctype = MSVCRT__ctype+1;
1352 if(!init_category_name("C", 1, locinfo, MSVCRT_LC_CTYPE)) {
1353 free_locinfo(locinfo);
1354 return NULL;
1357 for(i=0; i<256; i++) {
1358 if(locinfo->pctype[i] & MSVCRT__LEADBYTE)
1359 buf[i] = ' ';
1360 else
1361 buf[i] = i;
1364 for(i=0; i<256; i++) {
1365 locinfo->pclmap[i] = (i>='A' && i<='Z' ? i-'A'+'a' : i);
1366 locinfo->pcumap[i] = (i>='a' && i<='z' ? i-'a'+'A' : i);
1370 if(locale_name[MSVCRT_LC_MONETARY] &&
1371 !init_category_name(locale_name[MSVCRT_LC_MONETARY],
1372 locale_len[MSVCRT_LC_MONETARY], locinfo, MSVCRT_LC_MONETARY)) {
1373 free_locinfo(locinfo);
1374 return NULL;
1377 if(!category_needs_update(MSVCRT_LC_MONETARY, category, old_locinfo,
1378 lcid[MSVCRT_LC_MONETARY], cp[MSVCRT_LC_MONETARY])) {
1379 copy_threadlocinfo_category(locinfo, old_locinfo, MSVCRT_LC_MONETARY);
1380 } else if(lcid[MSVCRT_LC_MONETARY] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_MONETARY)) {
1381 if(!update_threadlocinfo_category(lcid[MSVCRT_LC_MONETARY],
1382 cp[MSVCRT_LC_MONETARY], locinfo, MSVCRT_LC_MONETARY)) {
1383 free_locinfo(locinfo);
1384 return NULL;
1387 locinfo->lconv_intl_refcount = MSVCRT_malloc(sizeof(int));
1388 locinfo->lconv_mon_refcount = MSVCRT_malloc(sizeof(int));
1389 if(!locinfo->lconv_intl_refcount || !locinfo->lconv_mon_refcount) {
1390 free_locinfo(locinfo);
1391 return NULL;
1394 *locinfo->lconv_intl_refcount = 1;
1395 *locinfo->lconv_mon_refcount = 1;
1397 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SINTLSYMBOL
1398 |LOCALE_NOUSEROVERRIDE, buf, 256);
1399 if(i && (locinfo->lconv->int_curr_symbol = MSVCRT_malloc(i)))
1400 memcpy(locinfo->lconv->int_curr_symbol, buf, i);
1401 else {
1402 free_locinfo(locinfo);
1403 return NULL;
1406 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SCURRENCY
1407 |LOCALE_NOUSEROVERRIDE, buf, 256);
1408 if(i && (locinfo->lconv->currency_symbol = MSVCRT_malloc(i)))
1409 memcpy(locinfo->lconv->currency_symbol, buf, i);
1410 else {
1411 free_locinfo(locinfo);
1412 return NULL;
1415 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONDECIMALSEP
1416 |LOCALE_NOUSEROVERRIDE, buf, 256);
1417 if(i && (locinfo->lconv->mon_decimal_point = MSVCRT_malloc(i)))
1418 memcpy(locinfo->lconv->mon_decimal_point, buf, i);
1419 else {
1420 free_locinfo(locinfo);
1421 return NULL;
1424 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONTHOUSANDSEP
1425 |LOCALE_NOUSEROVERRIDE, buf, 256);
1426 if(i && (locinfo->lconv->mon_thousands_sep = MSVCRT_malloc(i)))
1427 memcpy(locinfo->lconv->mon_thousands_sep, buf, i);
1428 else {
1429 free_locinfo(locinfo);
1430 return NULL;
1433 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONGROUPING
1434 |LOCALE_NOUSEROVERRIDE, buf, 256);
1435 if(i>1)
1436 i = i/2 + (buf[i-2]=='0'?0:1);
1437 if(i && (locinfo->lconv->mon_grouping = MSVCRT_malloc(i))) {
1438 for(i=0; buf[i+1]==';'; i+=2)
1439 locinfo->lconv->mon_grouping[i/2] = buf[i]-'0';
1440 locinfo->lconv->mon_grouping[i/2] = buf[i]-'0';
1441 if(buf[i] != '0')
1442 locinfo->lconv->mon_grouping[i/2+1] = 127;
1443 } else {
1444 free_locinfo(locinfo);
1445 return NULL;
1448 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SPOSITIVESIGN
1449 |LOCALE_NOUSEROVERRIDE, buf, 256);
1450 if(i && (locinfo->lconv->positive_sign = MSVCRT_malloc(i)))
1451 memcpy(locinfo->lconv->positive_sign, buf, i);
1452 else {
1453 free_locinfo(locinfo);
1454 return NULL;
1457 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SNEGATIVESIGN
1458 |LOCALE_NOUSEROVERRIDE, buf, 256);
1459 if(i && (locinfo->lconv->negative_sign = MSVCRT_malloc(i)))
1460 memcpy(locinfo->lconv->negative_sign, buf, i);
1461 else {
1462 free_locinfo(locinfo);
1463 return NULL;
1466 if(GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_IINTLCURRDIGITS
1467 |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2))
1468 locinfo->lconv->int_frac_digits = val;
1469 else {
1470 free_locinfo(locinfo);
1471 return NULL;
1474 if(GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_ICURRDIGITS
1475 |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2))
1476 locinfo->lconv->frac_digits = val;
1477 else {
1478 free_locinfo(locinfo);
1479 return NULL;
1482 if(GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSYMPRECEDES
1483 |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2))
1484 locinfo->lconv->p_cs_precedes = val;
1485 else {
1486 free_locinfo(locinfo);
1487 return NULL;
1490 if(GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSEPBYSPACE
1491 |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2))
1492 locinfo->lconv->p_sep_by_space = val;
1493 else {
1494 free_locinfo(locinfo);
1495 return NULL;
1498 if(GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSYMPRECEDES
1499 |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2))
1500 locinfo->lconv->n_cs_precedes = val;
1501 else {
1502 free_locinfo(locinfo);
1503 return NULL;
1506 if(GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSEPBYSPACE
1507 |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2))
1508 locinfo->lconv->n_sep_by_space = val;
1509 else {
1510 free_locinfo(locinfo);
1511 return NULL;
1514 if(GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSIGNPOSN
1515 |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2))
1516 locinfo->lconv->p_sign_posn = val;
1517 else {
1518 free_locinfo(locinfo);
1519 return NULL;
1522 if(GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSIGNPOSN
1523 |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2))
1524 locinfo->lconv->n_sign_posn = val;
1525 else {
1526 free_locinfo(locinfo);
1527 return NULL;
1530 #if _MSVCR_VER >= 100
1531 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SINTLSYMBOL
1532 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1533 if(i && (locinfo->lconv->_W_int_curr_symbol = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1534 memcpy(locinfo->lconv->_W_int_curr_symbol, wbuf, i * sizeof(MSVCRT_wchar_t));
1535 else {
1536 free_locinfo(locinfo);
1537 return NULL;
1540 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SCURRENCY
1541 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1542 if(i && (locinfo->lconv->_W_currency_symbol = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1543 memcpy(locinfo->lconv->_W_currency_symbol, wbuf, i * sizeof(MSVCRT_wchar_t));
1544 else {
1545 free_locinfo(locinfo);
1546 return NULL;
1549 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONDECIMALSEP
1550 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1551 if(i && (locinfo->lconv->_W_mon_decimal_point = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1552 memcpy(locinfo->lconv->_W_mon_decimal_point, wbuf, i * sizeof(MSVCRT_wchar_t));
1553 else {
1554 free_locinfo(locinfo);
1555 return NULL;
1558 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONTHOUSANDSEP
1559 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1560 if(i && (locinfo->lconv->_W_mon_thousands_sep = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1561 memcpy(locinfo->lconv->_W_mon_thousands_sep, wbuf, i * sizeof(MSVCRT_wchar_t));
1562 else {
1563 free_locinfo(locinfo);
1564 return NULL;
1567 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SPOSITIVESIGN
1568 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1569 if(i && (locinfo->lconv->_W_positive_sign = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1570 memcpy(locinfo->lconv->_W_positive_sign, wbuf, i * sizeof(MSVCRT_wchar_t));
1571 else {
1572 free_locinfo(locinfo);
1573 return NULL;
1576 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SNEGATIVESIGN
1577 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1578 if(i && (locinfo->lconv->_W_negative_sign = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1579 memcpy(locinfo->lconv->_W_negative_sign, wbuf, i * sizeof(MSVCRT_wchar_t));
1580 else {
1581 free_locinfo(locinfo);
1582 return NULL;
1584 #endif
1585 } else {
1586 locinfo->lconv->int_curr_symbol = MSVCRT_malloc(sizeof(char));
1587 locinfo->lconv->currency_symbol = MSVCRT_malloc(sizeof(char));
1588 locinfo->lconv->mon_decimal_point = MSVCRT_malloc(sizeof(char));
1589 locinfo->lconv->mon_thousands_sep = MSVCRT_malloc(sizeof(char));
1590 locinfo->lconv->mon_grouping = MSVCRT_malloc(sizeof(char));
1591 locinfo->lconv->positive_sign = MSVCRT_malloc(sizeof(char));
1592 locinfo->lconv->negative_sign = MSVCRT_malloc(sizeof(char));
1594 if(!locinfo->lconv->int_curr_symbol || !locinfo->lconv->currency_symbol
1595 || !locinfo->lconv->mon_decimal_point || !locinfo->lconv->mon_thousands_sep
1596 || !locinfo->lconv->mon_grouping || !locinfo->lconv->positive_sign
1597 || !locinfo->lconv->negative_sign) {
1598 free_locinfo(locinfo);
1599 return NULL;
1602 locinfo->lconv->int_curr_symbol[0] = '\0';
1603 locinfo->lconv->currency_symbol[0] = '\0';
1604 locinfo->lconv->mon_decimal_point[0] = '\0';
1605 locinfo->lconv->mon_thousands_sep[0] = '\0';
1606 locinfo->lconv->mon_grouping[0] = '\0';
1607 locinfo->lconv->positive_sign[0] = '\0';
1608 locinfo->lconv->negative_sign[0] = '\0';
1609 locinfo->lconv->int_frac_digits = charmax;
1610 locinfo->lconv->frac_digits = charmax;
1611 locinfo->lconv->p_cs_precedes = charmax;
1612 locinfo->lconv->p_sep_by_space = charmax;
1613 locinfo->lconv->n_cs_precedes = charmax;
1614 locinfo->lconv->n_sep_by_space = charmax;
1615 locinfo->lconv->p_sign_posn = charmax;
1616 locinfo->lconv->n_sign_posn = charmax;
1618 #if _MSVCR_VER >= 100
1619 locinfo->lconv->_W_int_curr_symbol = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1620 locinfo->lconv->_W_currency_symbol = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1621 locinfo->lconv->_W_mon_decimal_point = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1622 locinfo->lconv->_W_mon_thousands_sep = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1623 locinfo->lconv->_W_positive_sign = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1624 locinfo->lconv->_W_negative_sign = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1626 if(!locinfo->lconv->_W_int_curr_symbol || !locinfo->lconv->_W_currency_symbol
1627 || !locinfo->lconv->_W_mon_decimal_point || !locinfo->lconv->_W_mon_thousands_sep
1628 || !locinfo->lconv->positive_sign || !locinfo->lconv->negative_sign) {
1629 free_locinfo(locinfo);
1630 return NULL;
1633 locinfo->lconv->_W_int_curr_symbol[0] = '\0';
1634 locinfo->lconv->_W_currency_symbol[0] = '\0';
1635 locinfo->lconv->_W_mon_decimal_point[0] = '\0';
1636 locinfo->lconv->_W_mon_thousands_sep[0] = '\0';
1637 locinfo->lconv->_W_positive_sign[0] = '\0';
1638 locinfo->lconv->_W_negative_sign[0] = '\0';
1639 #endif
1641 if(!init_category_name("C", 1, locinfo, MSVCRT_LC_MONETARY)) {
1642 free_locinfo(locinfo);
1643 return NULL;
1647 if(locale_name[MSVCRT_LC_NUMERIC] &&
1648 !init_category_name(locale_name[MSVCRT_LC_NUMERIC],
1649 locale_len[MSVCRT_LC_NUMERIC], locinfo, MSVCRT_LC_NUMERIC)) {
1650 free_locinfo(locinfo);
1651 return NULL;
1654 if(!category_needs_update(MSVCRT_LC_NUMERIC, category, old_locinfo,
1655 lcid[MSVCRT_LC_NUMERIC], cp[MSVCRT_LC_NUMERIC])) {
1656 copy_threadlocinfo_category(locinfo, old_locinfo, MSVCRT_LC_NUMERIC);
1657 } else if(lcid[MSVCRT_LC_NUMERIC] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_NUMERIC)) {
1658 if(!update_threadlocinfo_category(lcid[MSVCRT_LC_NUMERIC],
1659 cp[MSVCRT_LC_NUMERIC], locinfo, MSVCRT_LC_NUMERIC)) {
1660 free_locinfo(locinfo);
1661 return NULL;
1664 if(!locinfo->lconv_intl_refcount)
1665 locinfo->lconv_intl_refcount = MSVCRT_malloc(sizeof(int));
1666 locinfo->lconv_num_refcount = MSVCRT_malloc(sizeof(int));
1667 if(!locinfo->lconv_intl_refcount || !locinfo->lconv_num_refcount) {
1668 free_locinfo(locinfo);
1669 return NULL;
1672 *locinfo->lconv_intl_refcount = 1;
1673 *locinfo->lconv_num_refcount = 1;
1675 i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_SDECIMAL
1676 |LOCALE_NOUSEROVERRIDE, buf, 256);
1677 if(i && (locinfo->lconv->decimal_point = MSVCRT_malloc(i)))
1678 memcpy(locinfo->lconv->decimal_point, buf, i);
1679 else {
1680 free_locinfo(locinfo);
1681 return NULL;
1684 i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_STHOUSAND
1685 |LOCALE_NOUSEROVERRIDE, buf, 256);
1686 if(i && (locinfo->lconv->thousands_sep = MSVCRT_malloc(i)))
1687 memcpy(locinfo->lconv->thousands_sep, buf, i);
1688 else {
1689 free_locinfo(locinfo);
1690 return NULL;
1693 i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_SGROUPING
1694 |LOCALE_NOUSEROVERRIDE, buf, 256);
1695 if(i>1)
1696 i = i/2 + (buf[i-2]=='0'?0:1);
1697 if(i && (locinfo->lconv->grouping = MSVCRT_malloc(i))) {
1698 for(i=0; buf[i+1]==';'; i+=2)
1699 locinfo->lconv->grouping[i/2] = buf[i]-'0';
1700 locinfo->lconv->grouping[i/2] = buf[i]-'0';
1701 if(buf[i] != '0')
1702 locinfo->lconv->grouping[i/2+1] = 127;
1703 } else {
1704 free_locinfo(locinfo);
1705 return NULL;
1708 #if _MSVCR_VER >= 100
1709 i = GetLocaleInfoW(lcid[MSVCRT_LC_NUMERIC], LOCALE_SDECIMAL
1710 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1711 if(i && (locinfo->lconv->_W_decimal_point = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1712 memcpy(locinfo->lconv->_W_decimal_point, wbuf, i * sizeof(MSVCRT_wchar_t));
1713 else {
1714 free_locinfo(locinfo);
1715 return NULL;
1718 i = GetLocaleInfoW(lcid[MSVCRT_LC_NUMERIC], LOCALE_STHOUSAND
1719 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1720 if(i && (locinfo->lconv->_W_thousands_sep = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1721 memcpy(locinfo->lconv->_W_thousands_sep, wbuf, i * sizeof(MSVCRT_wchar_t));
1722 else {
1723 free_locinfo(locinfo);
1724 return NULL;
1726 #endif
1727 } else {
1728 locinfo->lconv->decimal_point = MSVCRT_malloc(sizeof(char[2]));
1729 locinfo->lconv->thousands_sep = MSVCRT_malloc(sizeof(char));
1730 locinfo->lconv->grouping = MSVCRT_malloc(sizeof(char));
1731 if(!locinfo->lconv->decimal_point || !locinfo->lconv->thousands_sep
1732 || !locinfo->lconv->grouping) {
1733 free_locinfo(locinfo);
1734 return NULL;
1737 locinfo->lconv->decimal_point[0] = '.';
1738 locinfo->lconv->decimal_point[1] = '\0';
1739 locinfo->lconv->thousands_sep[0] = '\0';
1740 locinfo->lconv->grouping[0] = '\0';
1742 #if _MSVCR_VER >= 100
1743 locinfo->lconv->_W_decimal_point = MSVCRT_malloc(sizeof(MSVCRT_wchar_t[2]));
1744 locinfo->lconv->_W_thousands_sep = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1746 if(!locinfo->lconv->_W_decimal_point || !locinfo->lconv->_W_thousands_sep) {
1747 free_locinfo(locinfo);
1748 return NULL;
1751 locinfo->lconv->_W_decimal_point[0] = '.';
1752 locinfo->lconv->_W_decimal_point[1] = '\0';
1753 locinfo->lconv->_W_thousands_sep[0] = '\0';
1754 #endif
1756 if (!init_category_name("C", 1, locinfo, MSVCRT_LC_NUMERIC)) {
1757 free_locinfo(locinfo);
1758 return NULL;
1762 if(locale_name[MSVCRT_LC_TIME] &&
1763 !init_category_name(locale_name[MSVCRT_LC_TIME],
1764 locale_len[MSVCRT_LC_TIME], locinfo, MSVCRT_LC_TIME)) {
1765 free_locinfo(locinfo);
1766 return NULL;
1769 if(!category_needs_update(MSVCRT_LC_TIME, category, old_locinfo,
1770 lcid[MSVCRT_LC_TIME], cp[MSVCRT_LC_TIME])) {
1771 copy_threadlocinfo_category(locinfo, old_locinfo, MSVCRT_LC_TIME);
1772 } else if(lcid[MSVCRT_LC_TIME] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_TIME)) {
1773 if(!update_threadlocinfo_category(lcid[MSVCRT_LC_TIME],
1774 cp[MSVCRT_LC_TIME], locinfo, MSVCRT_LC_TIME)) {
1775 free_locinfo(locinfo);
1776 return NULL;
1779 locinfo->lc_time_curr = create_time_data(lcid[MSVCRT_LC_TIME]);
1780 if(!locinfo->lc_time_curr) {
1781 free_locinfo(locinfo);
1782 return NULL;
1784 } else {
1785 if(!init_category_name("C", 1, locinfo, MSVCRT_LC_TIME)) {
1786 free_locinfo(locinfo);
1787 return NULL;
1789 locinfo->lc_time_curr = &cloc_time_data;
1792 return locinfo;
1795 /*********************************************************************
1796 * _lock_locales (UCRTBASE.@)
1798 void CDECL _lock_locales(void)
1800 _mlock(_SETLOCALE_LOCK);
1803 /*********************************************************************
1804 * _unlock_locales (UCRTBASE.@)
1806 void CDECL _unlock_locales(void)
1808 _munlock(_SETLOCALE_LOCK);
1811 /*********************************************************************
1812 * _create_locale (MSVCRT.@)
1814 MSVCRT__locale_t CDECL MSVCRT__create_locale(int category, const char *locale)
1816 MSVCRT__locale_t loc;
1818 loc = MSVCRT_malloc(sizeof(MSVCRT__locale_tstruct));
1819 if(!loc)
1820 return NULL;
1822 loc->locinfo = create_locinfo(category, locale, NULL);
1823 if(!loc->locinfo) {
1824 MSVCRT_free(loc);
1825 return NULL;
1828 loc->mbcinfo = MSVCRT_malloc(sizeof(MSVCRT_threadmbcinfo));
1829 if(!loc->mbcinfo) {
1830 free_locinfo(loc->locinfo);
1831 MSVCRT_free(loc);
1832 return NULL;
1835 loc->mbcinfo->refcount = 1;
1836 _setmbcp_l(loc->locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage,
1837 loc->locinfo->lc_handle[MSVCRT_LC_CTYPE], loc->mbcinfo);
1838 return loc;
1841 #if _MSVCR_VER >= 110
1842 /*********************************************************************
1843 * _wcreate_locale (MSVCR110.@)
1845 MSVCRT__locale_t CDECL MSVCRT__wcreate_locale(int category, const MSVCRT_wchar_t *locale)
1847 MSVCRT__locale_t loc;
1848 MSVCRT_size_t len;
1849 char *str;
1851 if(category<MSVCRT_LC_MIN || category>MSVCRT_LC_MAX || !locale)
1852 return NULL;
1854 len = MSVCRT_wcstombs(NULL, locale, 0);
1855 if(len == -1)
1856 return NULL;
1857 if(!(str = MSVCRT_malloc(++len)))
1858 return NULL;
1859 MSVCRT_wcstombs(str, locale, len);
1861 loc = MSVCRT__create_locale(category, str);
1863 MSVCRT_free(str);
1864 return loc;
1866 #endif
1868 /*********************************************************************
1869 * setlocale (MSVCRT.@)
1871 char* CDECL MSVCRT_setlocale(int category, const char* locale)
1873 MSVCRT_pthreadlocinfo locinfo = get_locinfo();
1874 MSVCRT_pthreadlocinfo newlocinfo;
1876 if(category<MSVCRT_LC_MIN || category>MSVCRT_LC_MAX)
1877 return NULL;
1879 if(!locale) {
1880 if(category == MSVCRT_LC_ALL)
1881 return construct_lc_all(locinfo);
1883 return locinfo->lc_category[category].locale;
1886 newlocinfo = create_locinfo(category, locale, locinfo);
1887 if(!newlocinfo) {
1888 WARN("%d %s failed\n", category, locale);
1889 return NULL;
1892 _lock_locales();
1894 if(locale[0] != 'C' || locale[1] != '\0')
1895 initial_locale = FALSE;
1897 if(locinfo->lc_handle[MSVCRT_LC_COLLATE]!=newlocinfo->lc_handle[MSVCRT_LC_COLLATE]
1898 || locinfo->lc_id[MSVCRT_LC_COLLATE].wCodePage!=newlocinfo->lc_id[MSVCRT_LC_COLLATE].wCodePage) {
1899 locinfo->lc_collate_cp = newlocinfo->lc_collate_cp;
1900 locinfo->lc_handle[MSVCRT_LC_COLLATE] =
1901 newlocinfo->lc_handle[MSVCRT_LC_COLLATE];
1902 locinfo->lc_id[MSVCRT_LC_COLLATE] =
1903 newlocinfo->lc_id[MSVCRT_LC_COLLATE];
1905 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_COLLATE].wrefcount,
1906 (void**)&newlocinfo->lc_category[MSVCRT_LC_COLLATE].wrefcount);
1907 #if _MSVCR_VER >= 110
1908 swap_pointers((void**)&locinfo->lc_name[MSVCRT_LC_COLLATE],
1909 (void**)&newlocinfo->lc_name[MSVCRT_LC_COLLATE]);
1910 #endif
1912 if(newlocinfo->lc_category[MSVCRT_LC_COLLATE].locale) {
1913 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_COLLATE].locale,
1914 (void**)&newlocinfo->lc_category[MSVCRT_LC_COLLATE].locale);
1915 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_COLLATE].refcount,
1916 (void**)&newlocinfo->lc_category[MSVCRT_LC_COLLATE].refcount);
1919 if(locinfo->lc_handle[MSVCRT_LC_CTYPE]!=newlocinfo->lc_handle[MSVCRT_LC_CTYPE]
1920 || locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage!=newlocinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage) {
1921 locinfo->lc_handle[MSVCRT_LC_CTYPE] =
1922 newlocinfo->lc_handle[MSVCRT_LC_CTYPE];
1923 locinfo->lc_id[MSVCRT_LC_CTYPE] =
1924 newlocinfo->lc_id[MSVCRT_LC_CTYPE];
1926 locinfo->lc_codepage = newlocinfo->lc_codepage;
1927 locinfo->lc_clike = newlocinfo->lc_clike;
1928 locinfo->mb_cur_max = newlocinfo->mb_cur_max;
1930 swap_pointers((void**)&locinfo->ctype1_refcount,
1931 (void**)&newlocinfo->ctype1_refcount);
1932 swap_pointers((void**)&locinfo->ctype1, (void**)&newlocinfo->ctype1);
1933 swap_pointers((void**)&locinfo->pctype, (void**)&newlocinfo->pctype);
1934 swap_pointers((void**)&locinfo->pclmap, (void**)&newlocinfo->pclmap);
1935 swap_pointers((void**)&locinfo->pcumap, (void**)&newlocinfo->pcumap);
1937 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_CTYPE].wrefcount,
1938 (void**)&newlocinfo->lc_category[MSVCRT_LC_CTYPE].wrefcount);
1939 #if _MSVCR_VER >= 110
1940 swap_pointers((void**)&locinfo->lc_name[MSVCRT_LC_CTYPE],
1941 (void**)&newlocinfo->lc_name[MSVCRT_LC_CTYPE]);
1942 #endif
1944 if(newlocinfo->lc_category[MSVCRT_LC_CTYPE].locale) {
1945 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_CTYPE].locale,
1946 (void**)&newlocinfo->lc_category[MSVCRT_LC_CTYPE].locale);
1947 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_CTYPE].refcount,
1948 (void**)&newlocinfo->lc_category[MSVCRT_LC_CTYPE].refcount);
1951 if(locinfo->lc_handle[MSVCRT_LC_MONETARY]!=newlocinfo->lc_handle[MSVCRT_LC_MONETARY]
1952 || locinfo->lc_id[MSVCRT_LC_MONETARY].wCodePage!=newlocinfo->lc_id[MSVCRT_LC_MONETARY].wCodePage) {
1953 locinfo->lc_handle[MSVCRT_LC_MONETARY] =
1954 newlocinfo->lc_handle[MSVCRT_LC_MONETARY];
1955 locinfo->lc_id[MSVCRT_LC_MONETARY] =
1956 newlocinfo->lc_id[MSVCRT_LC_MONETARY];
1958 swap_pointers((void**)&locinfo->lconv->int_curr_symbol,
1959 (void**)&newlocinfo->lconv->int_curr_symbol);
1960 swap_pointers((void**)&locinfo->lconv->currency_symbol,
1961 (void**)&newlocinfo->lconv->currency_symbol);
1962 swap_pointers((void**)&locinfo->lconv->mon_decimal_point,
1963 (void**)&newlocinfo->lconv->mon_decimal_point);
1964 swap_pointers((void**)&locinfo->lconv->mon_thousands_sep,
1965 (void**)&newlocinfo->lconv->mon_thousands_sep);
1966 swap_pointers((void**)&locinfo->lconv->mon_grouping,
1967 (void**)&newlocinfo->lconv->mon_grouping);
1968 swap_pointers((void**)&locinfo->lconv->positive_sign,
1969 (void**)&newlocinfo->lconv->positive_sign);
1970 swap_pointers((void**)&locinfo->lconv->negative_sign,
1971 (void**)&newlocinfo->lconv->negative_sign);
1973 #if _MSVCR_VER >= 100
1974 swap_pointers((void**)&locinfo->lconv->_W_int_curr_symbol,
1975 (void**)&newlocinfo->lconv->_W_int_curr_symbol);
1976 swap_pointers((void**)&locinfo->lconv->_W_currency_symbol,
1977 (void**)&newlocinfo->lconv->_W_currency_symbol);
1978 swap_pointers((void**)&locinfo->lconv->_W_mon_decimal_point,
1979 (void**)&newlocinfo->lconv->_W_mon_decimal_point);
1980 swap_pointers((void**)&locinfo->lconv->_W_mon_thousands_sep,
1981 (void**)&newlocinfo->lconv->_W_mon_thousands_sep);
1982 swap_pointers((void**)&locinfo->lconv->_W_positive_sign,
1983 (void**)&newlocinfo->lconv->_W_positive_sign);
1984 swap_pointers((void**)&locinfo->lconv->_W_negative_sign,
1985 (void**)&newlocinfo->lconv->_W_negative_sign);
1986 #endif
1988 locinfo->lconv->int_frac_digits = newlocinfo->lconv->int_frac_digits;
1989 locinfo->lconv->frac_digits = newlocinfo->lconv->frac_digits;
1990 locinfo->lconv->p_cs_precedes = newlocinfo->lconv->p_cs_precedes;
1991 locinfo->lconv->p_sep_by_space = newlocinfo->lconv->p_sep_by_space;
1992 locinfo->lconv->n_cs_precedes = newlocinfo->lconv->n_cs_precedes;
1993 locinfo->lconv->n_sep_by_space = newlocinfo->lconv->n_sep_by_space;
1994 locinfo->lconv->p_sign_posn = newlocinfo->lconv->p_sign_posn;
1995 locinfo->lconv->n_sign_posn = newlocinfo->lconv->n_sign_posn;
1997 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_MONETARY].wrefcount,
1998 (void**)&newlocinfo->lc_category[MSVCRT_LC_MONETARY].wrefcount);
1999 #if _MSVCR_VER >= 110
2000 swap_pointers((void**)&locinfo->lc_name[MSVCRT_LC_MONETARY],
2001 (void**)&newlocinfo->lc_name[MSVCRT_LC_MONETARY]);
2002 #endif
2004 if(newlocinfo->lc_category[MSVCRT_LC_MONETARY].locale) {
2005 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_MONETARY].locale,
2006 (void**)&newlocinfo->lc_category[MSVCRT_LC_MONETARY].locale);
2007 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_MONETARY].refcount,
2008 (void**)&newlocinfo->lc_category[MSVCRT_LC_MONETARY].refcount);
2011 if(locinfo->lc_handle[MSVCRT_LC_NUMERIC]!=newlocinfo->lc_handle[MSVCRT_LC_NUMERIC]
2012 || locinfo->lc_id[MSVCRT_LC_NUMERIC].wCodePage!=newlocinfo->lc_id[MSVCRT_LC_NUMERIC].wCodePage) {
2013 locinfo->lc_handle[MSVCRT_LC_NUMERIC] =
2014 newlocinfo->lc_handle[MSVCRT_LC_NUMERIC];
2015 locinfo->lc_id[MSVCRT_LC_NUMERIC] =
2016 newlocinfo->lc_id[MSVCRT_LC_NUMERIC];
2018 swap_pointers((void**)&locinfo->lconv->decimal_point,
2019 (void**)&newlocinfo->lconv->decimal_point);
2020 swap_pointers((void**)&locinfo->lconv->thousands_sep,
2021 (void**)&newlocinfo->lconv->thousands_sep);
2022 swap_pointers((void**)&locinfo->lconv->grouping,
2023 (void**)&newlocinfo->lconv->grouping);
2025 #if _MSVCR_VER >= 100
2026 swap_pointers((void**)&locinfo->lconv->_W_decimal_point,
2027 (void**)&newlocinfo->lconv->_W_decimal_point);
2028 swap_pointers((void**)&locinfo->lconv->_W_thousands_sep,
2029 (void**)&newlocinfo->lconv->_W_thousands_sep);
2030 #endif
2032 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_NUMERIC].wrefcount,
2033 (void**)&newlocinfo->lc_category[MSVCRT_LC_NUMERIC].wrefcount);
2034 #if _MSVCR_VER >= 110
2035 swap_pointers((void**)&locinfo->lc_name[MSVCRT_LC_NUMERIC],
2036 (void**)&newlocinfo->lc_name[MSVCRT_LC_NUMERIC]);
2037 #endif
2039 if(newlocinfo->lc_category[MSVCRT_LC_NUMERIC].locale) {
2040 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_NUMERIC].locale,
2041 (void**)&newlocinfo->lc_category[MSVCRT_LC_NUMERIC].locale);
2042 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_NUMERIC].refcount,
2043 (void**)&newlocinfo->lc_category[MSVCRT_LC_NUMERIC].refcount);
2046 if(locinfo->lc_handle[MSVCRT_LC_TIME]!=newlocinfo->lc_handle[MSVCRT_LC_TIME]
2047 || locinfo->lc_id[MSVCRT_LC_TIME].wCodePage!=newlocinfo->lc_id[MSVCRT_LC_TIME].wCodePage) {
2048 locinfo->lc_handle[MSVCRT_LC_TIME] =
2049 newlocinfo->lc_handle[MSVCRT_LC_TIME];
2050 locinfo->lc_id[MSVCRT_LC_TIME] =
2051 newlocinfo->lc_id[MSVCRT_LC_TIME];
2052 swap_pointers((void**)&locinfo->lc_time_curr,
2053 (void**)&newlocinfo->lc_time_curr);
2055 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_TIME].wrefcount,
2056 (void**)&newlocinfo->lc_category[MSVCRT_LC_TIME].wrefcount);
2057 #if _MSVCR_VER >= 110
2058 swap_pointers((void**)&locinfo->lc_name[MSVCRT_LC_TIME],
2059 (void**)&newlocinfo->lc_name[MSVCRT_LC_TIME]);
2060 #endif
2062 if(newlocinfo->lc_category[MSVCRT_LC_TIME].locale) {
2063 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_TIME].locale,
2064 (void**)&newlocinfo->lc_category[MSVCRT_LC_TIME].locale);
2065 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_TIME].refcount,
2066 (void**)&newlocinfo->lc_category[MSVCRT_LC_TIME].refcount);
2069 free_locinfo(newlocinfo);
2070 _unlock_locales();
2072 if(locinfo == MSVCRT_locale->locinfo) {
2073 int i;
2075 MSVCRT___lc_codepage = locinfo->lc_codepage;
2076 MSVCRT___lc_collate_cp = locinfo->lc_collate_cp;
2077 MSVCRT___mb_cur_max = locinfo->mb_cur_max;
2078 MSVCRT__pctype = locinfo->pctype;
2079 for(i=MSVCRT_LC_MIN; i<=MSVCRT_LC_MAX; i++)
2080 MSVCRT___lc_handle[i] = MSVCRT_locale->locinfo->lc_handle[i];
2083 if(category == MSVCRT_LC_ALL)
2084 return construct_lc_all(locinfo);
2086 return locinfo->lc_category[category].locale;
2089 /*********************************************************************
2090 * _wsetlocale (MSVCRT.@)
2092 MSVCRT_wchar_t* CDECL MSVCRT__wsetlocale(int category, const MSVCRT_wchar_t* wlocale)
2094 static MSVCRT_wchar_t current_lc_all[MAX_LOCALE_LENGTH];
2096 char *locale = NULL;
2097 const char *ret;
2098 MSVCRT_size_t len;
2100 if(wlocale) {
2101 len = MSVCRT_wcstombs(NULL, wlocale, 0);
2102 if(len == -1)
2103 return NULL;
2105 locale = MSVCRT_malloc(++len);
2106 if(!locale)
2107 return NULL;
2109 MSVCRT_wcstombs(locale, wlocale, len);
2112 _lock_locales();
2113 ret = MSVCRT_setlocale(category, locale);
2114 MSVCRT_free(locale);
2116 if(ret && MSVCRT_mbstowcs(current_lc_all, ret, MAX_LOCALE_LENGTH)==-1)
2117 ret = NULL;
2119 _unlock_locales();
2120 return ret ? current_lc_all : NULL;
2123 #if _MSVCR_VER >= 80
2124 /*********************************************************************
2125 * _configthreadlocale (MSVCR80.@)
2127 int CDECL _configthreadlocale(int type)
2129 thread_data_t *data = msvcrt_get_thread_data();
2130 MSVCRT__locale_t locale;
2131 int ret;
2133 if(!data)
2134 return -1;
2136 ret = (data->have_locale ? MSVCRT__ENABLE_PER_THREAD_LOCALE : MSVCRT__DISABLE_PER_THREAD_LOCALE);
2138 if(type == MSVCRT__ENABLE_PER_THREAD_LOCALE) {
2139 if(!data->have_locale) {
2140 /* Copy current global locale */
2141 locale = MSVCRT__create_locale(MSVCRT_LC_ALL, MSVCRT_setlocale(MSVCRT_LC_ALL, NULL));
2142 if(!locale)
2143 return -1;
2145 data->locinfo = locale->locinfo;
2146 data->mbcinfo = locale->mbcinfo;
2147 data->have_locale = TRUE;
2148 MSVCRT_free(locale);
2151 return ret;
2154 if(type == MSVCRT__DISABLE_PER_THREAD_LOCALE) {
2155 if(data->have_locale) {
2156 free_locinfo(data->locinfo);
2157 free_mbcinfo(data->mbcinfo);
2158 data->locinfo = MSVCRT_locale->locinfo;
2159 data->mbcinfo = MSVCRT_locale->mbcinfo;
2160 data->have_locale = FALSE;
2163 return ret;
2166 if(!type)
2167 return ret;
2169 return -1;
2171 #endif
2173 BOOL msvcrt_init_locale(void)
2175 int i;
2177 _lock_locales();
2178 MSVCRT_locale = MSVCRT__create_locale(0, "C");
2179 _unlock_locales();
2180 if(!MSVCRT_locale)
2181 return FALSE;
2183 MSVCRT___lc_codepage = MSVCRT_locale->locinfo->lc_codepage;
2184 MSVCRT___lc_collate_cp = MSVCRT_locale->locinfo->lc_collate_cp;
2185 MSVCRT___mb_cur_max = MSVCRT_locale->locinfo->mb_cur_max;
2186 MSVCRT__pctype = MSVCRT_locale->locinfo->pctype;
2187 for(i=MSVCRT_LC_MIN; i<=MSVCRT_LC_MAX; i++)
2188 MSVCRT___lc_handle[i] = MSVCRT_locale->locinfo->lc_handle[i];
2189 _setmbcp(_MB_CP_ANSI);
2190 return TRUE;
2193 #if _MSVCR_VER >= 120
2194 /*********************************************************************
2195 * wctrans (MSVCR120.@)
2197 MSVCRT_wctrans_t CDECL MSVCR120_wctrans(const char *property)
2199 static const char str_tolower[] = "tolower";
2200 static const char str_toupper[] = "toupper";
2202 if(!strcmp(property, str_tolower))
2203 return 2;
2204 if(!strcmp(property, str_toupper))
2205 return 1;
2206 return 0;
2209 /*********************************************************************
2210 * towctrans (MSVCR120.@)
2212 MSVCRT_wint_t CDECL MSVCR120_towctrans(MSVCRT_wint_t c, MSVCRT_wctrans_t category)
2214 if(category == 1)
2215 return MSVCRT__towupper_l(c, NULL);
2216 return MSVCRT__towlower_l(c, NULL);
2218 #endif