mf/session: Implement support for sinks that provide sample allocators.
[wine.git] / dlls / msvcrt / locale.c
blobfda3d11b86d80a9792f1dafc159ef038bc75bea5
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 = 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 BOOL init_category_name(const char *name, int len,
384 MSVCRT_pthreadlocinfo locinfo, int category)
386 locinfo->lc_category[category].locale = MSVCRT_malloc(len+1);
387 locinfo->lc_category[category].refcount = MSVCRT_malloc(sizeof(int));
388 if(!locinfo->lc_category[category].locale
389 || !locinfo->lc_category[category].refcount) {
390 MSVCRT_free(locinfo->lc_category[category].locale);
391 MSVCRT_free(locinfo->lc_category[category].refcount);
392 locinfo->lc_category[category].locale = NULL;
393 locinfo->lc_category[category].refcount = NULL;
394 return FALSE;
397 memcpy(locinfo->lc_category[category].locale, name, len);
398 locinfo->lc_category[category].locale[len] = 0;
399 *locinfo->lc_category[category].refcount = 1;
400 return TRUE;
403 /* INTERNAL: Set lc_handle, lc_id and lc_category in threadlocinfo struct */
404 static BOOL update_threadlocinfo_category(LCID lcid, unsigned short cp,
405 MSVCRT_pthreadlocinfo locinfo, int category)
407 char buf[256], *p;
409 if(GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_NOUSEROVERRIDE, buf, 256)) {
410 p = buf;
412 locinfo->lc_id[category].wLanguage = 0;
413 while(*p) {
414 locinfo->lc_id[category].wLanguage *= 16;
416 if(*p <= '9')
417 locinfo->lc_id[category].wLanguage += *p-'0';
418 else
419 locinfo->lc_id[category].wLanguage += *p-'a'+10;
421 p++;
424 locinfo->lc_id[category].wCountry =
425 locinfo->lc_id[category].wLanguage;
428 locinfo->lc_id[category].wCodePage = cp;
430 locinfo->lc_handle[category] = lcid;
432 if(!locinfo->lc_category[category].locale) {
433 int len = 0;
435 len += GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE
436 |LOCALE_NOUSEROVERRIDE, buf, 256);
437 buf[len-1] = '_';
438 len += GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY
439 |LOCALE_NOUSEROVERRIDE, &buf[len], 256-len);
440 buf[len-1] = '.';
441 MSVCRT_sprintf(buf+len, "%d", cp);
442 len += strlen(buf+len);
444 return init_category_name(buf, len, locinfo, category);
447 return TRUE;
450 /* INTERNAL: swap pointers values */
451 static inline void swap_pointers(void **p1, void **p2) {
452 void *hlp;
454 hlp = *p1;
455 *p1 = *p2;
456 *p2 = hlp;
459 /* INTERNAL: returns pthreadlocinfo struct */
460 MSVCRT_pthreadlocinfo CDECL get_locinfo(void) {
461 thread_data_t *data = msvcrt_get_thread_data();
463 if(!data || !data->have_locale)
464 return MSVCRT_locale->locinfo;
466 return data->locinfo;
469 /* INTERNAL: returns pthreadlocinfo struct */
470 MSVCRT_pthreadmbcinfo CDECL get_mbcinfo(void) {
471 thread_data_t *data = msvcrt_get_thread_data();
473 if(!data || !data->have_locale)
474 return MSVCRT_locale->mbcinfo;
476 return data->mbcinfo;
479 /* INTERNAL: constructs string returned by setlocale */
480 static inline char* construct_lc_all(MSVCRT_pthreadlocinfo locinfo) {
481 static char current_lc_all[MAX_LOCALE_LENGTH];
483 int i;
485 for(i=MSVCRT_LC_MIN+1; i<MSVCRT_LC_MAX; i++) {
486 if(strcmp(locinfo->lc_category[i].locale,
487 locinfo->lc_category[i+1].locale))
488 break;
491 if(i==MSVCRT_LC_MAX)
492 return locinfo->lc_category[MSVCRT_LC_COLLATE].locale;
494 MSVCRT_sprintf(current_lc_all,
495 "LC_COLLATE=%s;LC_CTYPE=%s;LC_MONETARY=%s;LC_NUMERIC=%s;LC_TIME=%s",
496 locinfo->lc_category[MSVCRT_LC_COLLATE].locale,
497 locinfo->lc_category[MSVCRT_LC_CTYPE].locale,
498 locinfo->lc_category[MSVCRT_LC_MONETARY].locale,
499 locinfo->lc_category[MSVCRT_LC_NUMERIC].locale,
500 locinfo->lc_category[MSVCRT_LC_TIME].locale);
502 return current_lc_all;
506 /*********************************************************************
507 * _Getdays (MSVCRT.@)
509 char* CDECL _Getdays(void)
511 MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr;
512 int i, len, size = 0;
513 char *out;
515 TRACE("\n");
517 for(i=0; i<7; i++) {
518 size += strlen(cur->str.names.short_wday[i]) + 1;
519 size += strlen(cur->str.names.wday[i]) + 1;
521 out = MSVCRT_malloc(size+1);
522 if(!out)
523 return NULL;
525 size = 0;
526 for(i=0; i<7; i++) {
527 out[size++] = ':';
528 len = strlen(cur->str.names.short_wday[i]);
529 memcpy(&out[size], cur->str.names.short_wday[i], len);
530 size += len;
532 out[size++] = ':';
533 len = strlen(cur->str.names.wday[i]);
534 memcpy(&out[size], cur->str.names.wday[i], len);
535 size += len;
537 out[size] = '\0';
539 return out;
542 #if _MSVCR_VER >= 110
543 /*********************************************************************
544 * _W_Getdays (MSVCR110.@)
546 MSVCRT_wchar_t* CDECL _W_Getdays(void)
548 MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr;
549 MSVCRT_wchar_t *out;
550 int i, len, size = 0;
552 TRACE("\n");
554 for(i=0; i<7; i++) {
555 size += MSVCRT_wcslen(cur->wstr.names.short_wday[i]) + 1;
556 size += MSVCRT_wcslen(cur->wstr.names.wday[i]) + 1;
558 out = MSVCRT_malloc((size+1)*sizeof(*out));
559 if(!out)
560 return NULL;
562 size = 0;
563 for(i=0; i<7; i++) {
564 out[size++] = ':';
565 len = MSVCRT_wcslen(cur->wstr.names.short_wday[i]);
566 memcpy(&out[size], cur->wstr.names.short_wday[i], len*sizeof(*out));
567 size += len;
569 out[size++] = ':';
570 len = MSVCRT_wcslen(cur->wstr.names.wday[i]);
571 memcpy(&out[size], cur->wstr.names.wday[i], len*sizeof(*out));
572 size += len;
574 out[size] = '\0';
576 return out;
578 #endif
580 /*********************************************************************
581 * _Getmonths (MSVCRT.@)
583 char* CDECL _Getmonths(void)
585 MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr;
586 int i, len, size = 0;
587 char *out;
589 TRACE("\n");
591 for(i=0; i<12; i++) {
592 size += strlen(cur->str.names.short_mon[i]) + 1;
593 size += strlen(cur->str.names.mon[i]) + 1;
595 out = MSVCRT_malloc(size+1);
596 if(!out)
597 return NULL;
599 size = 0;
600 for(i=0; i<12; i++) {
601 out[size++] = ':';
602 len = strlen(cur->str.names.short_mon[i]);
603 memcpy(&out[size], cur->str.names.short_mon[i], len);
604 size += len;
606 out[size++] = ':';
607 len = strlen(cur->str.names.mon[i]);
608 memcpy(&out[size], cur->str.names.mon[i], len);
609 size += len;
611 out[size] = '\0';
613 return out;
616 #if _MSVCR_VER >= 110
617 /*********************************************************************
618 * _W_Getmonths (MSVCR110.@)
620 MSVCRT_wchar_t* CDECL _W_Getmonths(void)
622 MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr;
623 MSVCRT_wchar_t *out;
624 int i, len, size = 0;
626 TRACE("\n");
628 for(i=0; i<12; i++) {
629 size += MSVCRT_wcslen(cur->wstr.names.short_mon[i]) + 1;
630 size += MSVCRT_wcslen(cur->wstr.names.mon[i]) + 1;
632 out = MSVCRT_malloc((size+1)*sizeof(*out));
633 if(!out)
634 return NULL;
636 size = 0;
637 for(i=0; i<12; i++) {
638 out[size++] = ':';
639 len = MSVCRT_wcslen(cur->wstr.names.short_mon[i]);
640 memcpy(&out[size], cur->wstr.names.short_mon[i], len*sizeof(*out));
641 size += len;
643 out[size++] = ':';
644 len = MSVCRT_wcslen(cur->wstr.names.mon[i]);
645 memcpy(&out[size], cur->wstr.names.mon[i], len*sizeof(*out));
646 size += len;
648 out[size] = '\0';
650 return out;
652 #endif
654 /*********************************************************************
655 * _Gettnames (MSVCRT.@)
657 void* CDECL _Gettnames(void)
659 MSVCRT___lc_time_data *ret, *cur = get_locinfo()->lc_time_curr;
660 unsigned int i, len, size = sizeof(MSVCRT___lc_time_data);
662 TRACE("\n");
664 for(i=0; i<ARRAY_SIZE(cur->str.str); i++)
665 size += strlen(cur->str.str[i])+1;
667 ret = MSVCRT_malloc(size);
668 if(!ret)
669 return NULL;
670 memcpy(ret, cur, sizeof(*ret));
672 size = 0;
673 for(i=0; i<ARRAY_SIZE(cur->str.str); i++) {
674 len = strlen(cur->str.str[i])+1;
675 memcpy(&ret->data[size], cur->str.str[i], len);
676 ret->str.str[i] = &ret->data[size];
677 size += len;
680 return ret;
683 #if _MSVCR_VER >= 110
684 /*********************************************************************
685 * _W_Gettnames (MSVCR110.@)
687 void* CDECL _W_Gettnames(void)
689 return _Gettnames();
691 #endif
693 /*********************************************************************
694 * __crtLCMapStringA (MSVCRT.@)
696 int CDECL __crtLCMapStringA(
697 LCID lcid, DWORD mapflags, const char* src, int srclen, char* dst,
698 int dstlen, unsigned int codepage, int xflag
700 WCHAR buf_in[32], *in = buf_in;
701 WCHAR buf_out[32], *out = buf_out;
702 int in_len, out_len, r;
704 TRACE("(lcid %x, flags %x, %s(%d), %p(%d), %x, %d), partial stub!\n",
705 lcid, mapflags, src, srclen, dst, dstlen, codepage, xflag);
707 in_len = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, src, srclen, NULL, 0);
708 if (!in_len) return 0;
709 if (in_len > ARRAY_SIZE(buf_in))
711 in = malloc(in_len * sizeof(WCHAR));
712 if (!in) return 0;
715 r = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, src, srclen, in, in_len);
716 if (!r) goto done;
718 if (mapflags & LCMAP_SORTKEY)
720 r = LCMapStringW(lcid, mapflags, in, in_len, (WCHAR*)dst, dstlen);
721 goto done;
724 r = LCMapStringW(lcid, mapflags, in, in_len, NULL, 0);
725 if (!r) goto done;
726 out_len = r;
727 if (r > ARRAY_SIZE(buf_out))
729 out = malloc(r * sizeof(WCHAR));
730 if (!out)
732 r = 0;
733 goto done;
737 r = LCMapStringW(lcid, mapflags, in, in_len, out, out_len);
738 if (!r) goto done;
740 r = WideCharToMultiByte(codepage, 0, out, out_len, dst, dstlen, NULL, NULL);
742 done:
743 if (in != buf_in) free(in);
744 if (out != buf_out) free(out);
745 return r;
748 /*********************************************************************
749 * __crtLCMapStringW (MSVCRT.@)
751 int CDECL __crtLCMapStringW(LCID lcid, DWORD mapflags, const MSVCRT_wchar_t *src,
752 int srclen, MSVCRT_wchar_t *dst, int dstlen, unsigned int codepage, int xflag)
754 FIXME("(lcid %x, flags %x, %s(%d), %p(%d), %x, %d), partial stub!\n",
755 lcid, mapflags, debugstr_w(src), srclen, dst, dstlen, codepage, xflag);
757 return LCMapStringW(lcid, mapflags, src, srclen, dst, dstlen);
760 /*********************************************************************
761 * __crtCompareStringA (MSVCRT.@)
763 int CDECL __crtCompareStringA( LCID lcid, DWORD flags, const char *src1, int len1,
764 const char *src2, int len2 )
766 FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n",
767 lcid, flags, debugstr_a(src1), len1, debugstr_a(src2), len2 );
768 /* FIXME: probably not entirely right */
769 return CompareStringA( lcid, flags, src1, len1, src2, len2 );
772 /*********************************************************************
773 * __crtCompareStringW (MSVCRT.@)
775 int CDECL __crtCompareStringW( LCID lcid, DWORD flags, const MSVCRT_wchar_t *src1, int len1,
776 const MSVCRT_wchar_t *src2, int len2 )
778 FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n",
779 lcid, flags, debugstr_w(src1), len1, debugstr_w(src2), len2 );
780 /* FIXME: probably not entirely right */
781 return CompareStringW( lcid, flags, src1, len1, src2, len2 );
784 /*********************************************************************
785 * __crtGetLocaleInfoW (MSVCRT.@)
787 int CDECL __crtGetLocaleInfoW( LCID lcid, LCTYPE type, MSVCRT_wchar_t *buffer, int len )
789 FIXME("(lcid %x, type %x, %p(%d), partial stub\n", lcid, type, buffer, len );
790 /* FIXME: probably not entirely right */
791 return GetLocaleInfoW( lcid, type, buffer, len );
794 #if _MSVCR_VER >= 110
795 /*********************************************************************
796 * __crtGetLocaleInfoEx (MSVC110.@)
798 int CDECL __crtGetLocaleInfoEx( const WCHAR *locale, LCTYPE type, MSVCRT_wchar_t *buffer, int len )
800 TRACE("(%s, %x, %p, %d)\n", debugstr_w(locale), type, buffer, len);
801 return GetLocaleInfoEx(locale, type, buffer, len);
803 #endif
805 /*********************************************************************
806 * btowc(MSVCRT.@)
808 MSVCRT_wint_t CDECL MSVCRT_btowc(int c)
810 unsigned char letter = c;
811 MSVCRT_wchar_t ret;
813 if(c == MSVCRT_EOF)
814 return MSVCRT_WEOF;
815 if(!get_locinfo()->lc_codepage)
816 return c & 255;
817 if(!MultiByteToWideChar(get_locinfo()->lc_codepage,
818 MB_ERR_INVALID_CHARS, (LPCSTR)&letter, 1, &ret, 1))
819 return MSVCRT_WEOF;
821 return ret;
824 /*********************************************************************
825 * __crtGetStringTypeW(MSVCRT.@)
827 * This function was accepting different number of arguments in older
828 * versions of msvcrt.
830 BOOL CDECL __crtGetStringTypeW(DWORD unk, DWORD type,
831 MSVCRT_wchar_t *buffer, int len, WORD *out)
833 FIXME("(unk %x, type %x, wstr %p(%d), %p) partial stub\n",
834 unk, type, buffer, len, out);
836 return GetStringTypeW(type, buffer, len, out);
839 /*********************************************************************
840 * localeconv (MSVCRT.@)
842 struct MSVCRT_lconv * CDECL MSVCRT_localeconv(void)
844 return get_locinfo()->lconv;
847 /*********************************************************************
848 * __lconv_init (MSVCRT.@)
850 int CDECL __lconv_init(void)
852 /* this is used to make chars unsigned */
853 charmax = 255;
854 return 0;
857 /*********************************************************************
858 * ___lc_handle_func (MSVCRT.@)
860 LCID* CDECL ___lc_handle_func(void)
862 return get_locinfo()->lc_handle;
865 #if _MSVCR_VER >= 110
866 /*********************************************************************
867 * ___lc_locale_name_func (MSVCR110.@)
869 MSVCRT_wchar_t** CDECL ___lc_locale_name_func(void)
871 return get_locinfo()->lc_name;
873 #endif
875 /*********************************************************************
876 * ___lc_codepage_func (MSVCRT.@)
878 unsigned int CDECL ___lc_codepage_func(void)
880 return get_locinfo()->lc_codepage;
883 /*********************************************************************
884 * ___lc_collate_cp_func (MSVCRT.@)
886 int CDECL ___lc_collate_cp_func(void)
888 return get_locinfo()->lc_collate_cp;
891 /* INTERNAL: frees MSVCRT_pthreadlocinfo struct */
892 void free_locinfo(MSVCRT_pthreadlocinfo locinfo)
894 int i;
896 if(!locinfo)
897 return;
899 if(InterlockedDecrement(&locinfo->refcount))
900 return;
902 for(i=MSVCRT_LC_MIN+1; i<=MSVCRT_LC_MAX; i++) {
903 MSVCRT_free(locinfo->lc_category[i].locale);
904 MSVCRT_free(locinfo->lc_category[i].refcount);
905 #if _MSVCR_VER >= 110
906 MSVCRT_free(locinfo->lc_name[i]);
907 #endif
910 if(locinfo->lconv) {
911 MSVCRT_free(locinfo->lconv->decimal_point);
912 MSVCRT_free(locinfo->lconv->thousands_sep);
913 MSVCRT_free(locinfo->lconv->grouping);
914 MSVCRT_free(locinfo->lconv->int_curr_symbol);
915 MSVCRT_free(locinfo->lconv->currency_symbol);
916 MSVCRT_free(locinfo->lconv->mon_decimal_point);
917 MSVCRT_free(locinfo->lconv->mon_thousands_sep);
918 MSVCRT_free(locinfo->lconv->mon_grouping);
919 MSVCRT_free(locinfo->lconv->positive_sign);
920 MSVCRT_free(locinfo->lconv->negative_sign);
921 #if _MSVCR_VER >= 100
922 MSVCRT_free(locinfo->lconv->_W_decimal_point);
923 MSVCRT_free(locinfo->lconv->_W_thousands_sep);
924 MSVCRT_free(locinfo->lconv->_W_int_curr_symbol);
925 MSVCRT_free(locinfo->lconv->_W_currency_symbol);
926 MSVCRT_free(locinfo->lconv->_W_mon_decimal_point);
927 MSVCRT_free(locinfo->lconv->_W_mon_thousands_sep);
928 MSVCRT_free(locinfo->lconv->_W_positive_sign);
929 MSVCRT_free(locinfo->lconv->_W_negative_sign);
930 #endif
932 MSVCRT_free(locinfo->lconv_intl_refcount);
933 MSVCRT_free(locinfo->lconv_num_refcount);
934 MSVCRT_free(locinfo->lconv_mon_refcount);
935 MSVCRT_free(locinfo->lconv);
937 MSVCRT_free(locinfo->ctype1_refcount);
938 MSVCRT_free(locinfo->ctype1);
940 MSVCRT_free(locinfo->pclmap);
941 MSVCRT_free(locinfo->pcumap);
943 if(locinfo->lc_time_curr != &cloc_time_data)
944 MSVCRT_free(locinfo->lc_time_curr);
946 MSVCRT_free(locinfo);
949 /* INTERNAL: frees MSVCRT_pthreadmbcinfo struct */
950 void free_mbcinfo(MSVCRT_pthreadmbcinfo mbcinfo)
952 if(!mbcinfo)
953 return;
955 if(InterlockedDecrement(&mbcinfo->refcount))
956 return;
958 MSVCRT_free(mbcinfo);
961 MSVCRT__locale_t CDECL get_current_locale_noalloc(MSVCRT__locale_t locale)
963 thread_data_t *data = msvcrt_get_thread_data();
965 if(!data || !data->have_locale)
967 *locale = *MSVCRT_locale;
969 else
971 locale->locinfo = data->locinfo;
972 locale->mbcinfo = data->mbcinfo;
975 InterlockedIncrement(&locale->locinfo->refcount);
976 InterlockedIncrement(&locale->mbcinfo->refcount);
977 return locale;
980 void CDECL free_locale_noalloc(MSVCRT__locale_t locale)
982 free_locinfo(locale->locinfo);
983 free_mbcinfo(locale->mbcinfo);
986 /*********************************************************************
987 * _get_current_locale (MSVCRT.@)
989 MSVCRT__locale_t CDECL MSVCRT__get_current_locale(void)
991 MSVCRT__locale_t loc = MSVCRT_malloc(sizeof(MSVCRT__locale_tstruct));
992 if(!loc)
993 return NULL;
995 return get_current_locale_noalloc(loc);
998 /*********************************************************************
999 * _free_locale (MSVCRT.@)
1001 void CDECL MSVCRT__free_locale(MSVCRT__locale_t locale)
1003 if (!locale)
1004 return;
1006 free_locale_noalloc(locale);
1007 MSVCRT_free(locale);
1010 #if _MSVCR_VER >= 110
1011 static inline BOOL set_lc_locale_name(MSVCRT_pthreadlocinfo locinfo, int cat)
1013 LCID lcid = locinfo->lc_handle[cat];
1014 WCHAR buf[100];
1015 int len;
1017 len = GetLocaleInfoW(lcid, LOCALE_SISO639LANGNAME
1018 |LOCALE_NOUSEROVERRIDE, buf, 100);
1019 if(!len) return FALSE;
1021 if(LocaleNameToLCID(buf, 0) != lcid)
1022 len = LCIDToLocaleName(lcid, buf, 100, 0);
1024 if(!len || !(locinfo->lc_name[cat] = MSVCRT_malloc(len*sizeof(MSVCRT_wchar_t))))
1025 return FALSE;
1027 memcpy(locinfo->lc_name[cat], buf, len*sizeof(MSVCRT_wchar_t));
1028 return TRUE;
1030 #else
1031 static inline BOOL set_lc_locale_name(MSVCRT_pthreadlocinfo locinfo, int cat)
1033 return TRUE;
1035 #endif
1037 static inline BOOL category_needs_update(int cat, int user_cat,
1038 MSVCRT_pthreadlocinfo locinfo, LCID lcid, unsigned short cp)
1040 if(!locinfo) return TRUE;
1041 if(user_cat!=cat && user_cat!=MSVCRT_LC_ALL) return FALSE;
1042 return lcid!=locinfo->lc_handle[cat] || cp!=locinfo->lc_id[cat].wCodePage;
1045 static MSVCRT___lc_time_data* create_time_data(LCID lcid)
1047 static const DWORD time_data[] = {
1048 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
1049 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
1050 LOCALE_SABBREVDAYNAME6,
1051 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
1052 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6,
1053 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
1054 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
1055 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
1056 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
1057 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
1058 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
1059 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
1060 LOCALE_S1159, LOCALE_S2359,
1061 LOCALE_SSHORTDATE, LOCALE_SLONGDATE,
1062 LOCALE_STIMEFORMAT
1065 MSVCRT___lc_time_data *cur;
1066 int i, ret, size;
1068 size = sizeof(MSVCRT___lc_time_data);
1069 for(i=0; i<ARRAY_SIZE(time_data); i++) {
1070 ret = GetLocaleInfoA(lcid, time_data[i], NULL, 0);
1071 if(!ret)
1072 return NULL;
1073 size += ret;
1075 ret = GetLocaleInfoW(lcid, time_data[i], NULL, 0);
1076 if(!ret)
1077 return NULL;
1078 size += ret*sizeof(MSVCRT_wchar_t);
1080 #if _MSVCR_VER >= 110
1081 size += LCIDToLocaleName(lcid, NULL, 0, 0)*sizeof(MSVCRT_wchar_t);
1082 #endif
1084 cur = MSVCRT_malloc(size);
1085 if(!cur)
1086 return NULL;
1088 ret = 0;
1089 for(i=0; i<ARRAY_SIZE(time_data); i++) {
1090 cur->str.str[i] = &cur->data[ret];
1091 ret += GetLocaleInfoA(lcid, time_data[i], &cur->data[ret], size-ret);
1093 for(i=0; i<ARRAY_SIZE(time_data); i++) {
1094 cur->wstr.wstr[i] = (MSVCRT_wchar_t*)&cur->data[ret];
1095 ret += GetLocaleInfoW(lcid, time_data[i],
1096 (MSVCRT_wchar_t*)&cur->data[ret], size-ret)*sizeof(MSVCRT_wchar_t);
1098 #if _MSVCR_VER >= 110
1099 cur->locname = (MSVCRT_wchar_t*)&cur->data[ret];
1100 LCIDToLocaleName(lcid, (MSVCRT_wchar_t*)&cur->data[ret], (size-ret)/sizeof(MSVCRT_wchar_t), 0);
1101 #else
1102 cur->lcid = lcid;
1103 #endif
1105 return cur;
1108 static MSVCRT_pthreadlocinfo create_locinfo(int category,
1109 const char *locale, MSVCRT_pthreadlocinfo old_locinfo)
1111 static const char collate[] = "COLLATE=";
1112 static const char ctype[] = "CTYPE=";
1113 static const char monetary[] = "MONETARY=";
1114 static const char numeric[] = "NUMERIC=";
1115 static const char time[] = "TIME=";
1117 MSVCRT_pthreadlocinfo locinfo;
1118 LCID lcid[6] = { 0 };
1119 unsigned short cp[6] = { 0 };
1120 const char *locale_name[6] = { 0 };
1121 int locale_len[6] = { 0 };
1122 char buf[256];
1123 BOOL sname;
1124 #if _MSVCR_VER >= 100
1125 MSVCRT_wchar_t wbuf[256];
1126 #endif
1127 int i;
1129 TRACE("(%d %s)\n", category, locale);
1131 if(category<MSVCRT_LC_MIN || category>MSVCRT_LC_MAX || !locale)
1132 return NULL;
1134 if(locale[0]=='C' && !locale[1]) {
1135 lcid[0] = 0;
1136 cp[0] = CP_ACP;
1137 } else if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') {
1138 const char *p;
1140 while(1) {
1141 locale += 3; /* LC_ */
1142 if(!memcmp(locale, collate, sizeof(collate)-1)) {
1143 i = MSVCRT_LC_COLLATE;
1144 locale += sizeof(collate)-1;
1145 } else if(!memcmp(locale, ctype, sizeof(ctype)-1)) {
1146 i = MSVCRT_LC_CTYPE;
1147 locale += sizeof(ctype)-1;
1148 } else if(!memcmp(locale, monetary, sizeof(monetary)-1)) {
1149 i = MSVCRT_LC_MONETARY;
1150 locale += sizeof(monetary)-1;
1151 } else if(!memcmp(locale, numeric, sizeof(numeric)-1)) {
1152 i = MSVCRT_LC_NUMERIC;
1153 locale += sizeof(numeric)-1;
1154 } else if(!memcmp(locale, time, sizeof(time)-1)) {
1155 i = MSVCRT_LC_TIME;
1156 locale += sizeof(time)-1;
1157 } else
1158 return NULL;
1160 p = strchr(locale, ';');
1161 if(locale[0]=='C' && (locale[1]==';' || locale[1]=='\0')) {
1162 lcid[i] = 0;
1163 cp[i] = CP_ACP;
1164 } else if(p) {
1165 memcpy(buf, locale, p-locale);
1166 buf[p-locale] = '\0';
1167 lcid[i] = MSVCRT_locale_to_LCID(buf, &cp[i], &sname);
1168 if(sname) {
1169 locale_name[i] = locale;
1170 locale_len[i] = p-locale;
1172 } else {
1173 lcid[i] = MSVCRT_locale_to_LCID(locale, &cp[i], &sname);
1174 if(sname) {
1175 locale_name[i] = locale;
1176 locale_len[i] = strlen(locale);
1180 if(lcid[i] == -1)
1181 return NULL;
1183 if(!p || *(p+1)!='L' || *(p+2)!='C' || *(p+3)!='_')
1184 break;
1186 locale = p+1;
1188 } else {
1189 lcid[0] = MSVCRT_locale_to_LCID(locale, &cp[0], &sname);
1190 if(lcid[0] == -1)
1191 return NULL;
1192 if(sname) {
1193 locale_name[0] = locale;
1194 locale_len[0] = strlen(locale);
1197 for(i=1; i<6; i++) {
1198 lcid[i] = lcid[0];
1199 cp[i] = cp[0];
1200 locale_name[i] = locale_name[0];
1201 locale_len[i] = locale_len[0];
1205 locinfo = MSVCRT_malloc(sizeof(MSVCRT_threadlocinfo));
1206 if(!locinfo)
1207 return NULL;
1209 memset(locinfo, 0, sizeof(MSVCRT_threadlocinfo));
1210 locinfo->refcount = 1;
1212 locinfo->lconv = MSVCRT_malloc(sizeof(struct MSVCRT_lconv));
1213 if(!locinfo->lconv) {
1214 free_locinfo(locinfo);
1215 return NULL;
1217 memset(locinfo->lconv, 0, sizeof(struct MSVCRT_lconv));
1219 locinfo->pclmap = MSVCRT_malloc(sizeof(char[256]));
1220 locinfo->pcumap = MSVCRT_malloc(sizeof(char[256]));
1221 if(!locinfo->pclmap || !locinfo->pcumap) {
1222 free_locinfo(locinfo);
1223 return NULL;
1226 if(locale_name[MSVCRT_LC_COLLATE] &&
1227 !init_category_name(locale_name[MSVCRT_LC_COLLATE],
1228 locale_len[MSVCRT_LC_COLLATE], locinfo, MSVCRT_LC_COLLATE)) {
1229 free_locinfo(locinfo);
1230 return NULL;
1233 if(!category_needs_update(MSVCRT_LC_COLLATE, category, old_locinfo,
1234 lcid[MSVCRT_LC_COLLATE], cp[MSVCRT_LC_COLLATE])) {
1235 locinfo->lc_handle[MSVCRT_LC_COLLATE] = old_locinfo->lc_handle[MSVCRT_LC_COLLATE];
1236 locinfo->lc_id[MSVCRT_LC_COLLATE].wCodePage = old_locinfo->lc_id[MSVCRT_LC_COLLATE].wCodePage;
1237 } else if(lcid[MSVCRT_LC_COLLATE] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_COLLATE)) {
1238 if(!update_threadlocinfo_category(lcid[MSVCRT_LC_COLLATE],
1239 cp[MSVCRT_LC_COLLATE], locinfo, MSVCRT_LC_COLLATE)) {
1240 free_locinfo(locinfo);
1241 return NULL;
1244 locinfo->lc_collate_cp = locinfo->lc_id[MSVCRT_LC_COLLATE].wCodePage;
1246 if(!set_lc_locale_name(locinfo, MSVCRT_LC_COLLATE)) {
1247 free_locinfo(locinfo);
1248 return NULL;
1250 } else
1251 locinfo->lc_category[MSVCRT_LC_COLLATE].locale = MSVCRT__strdup("C");
1253 if(locale_name[MSVCRT_LC_CTYPE] &&
1254 !init_category_name(locale_name[MSVCRT_LC_CTYPE],
1255 locale_len[MSVCRT_LC_CTYPE], locinfo, MSVCRT_LC_CTYPE)) {
1256 free_locinfo(locinfo);
1257 return NULL;
1260 if(!category_needs_update(MSVCRT_LC_CTYPE, category, old_locinfo,
1261 lcid[MSVCRT_LC_CTYPE], cp[MSVCRT_LC_CTYPE])) {
1262 locinfo->lc_handle[MSVCRT_LC_CTYPE] = old_locinfo->lc_handle[MSVCRT_LC_CTYPE];
1263 locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage = old_locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage;
1264 } else if(lcid[MSVCRT_LC_CTYPE] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_CTYPE)) {
1265 CPINFO cp_info;
1266 int j;
1268 if(!update_threadlocinfo_category(lcid[MSVCRT_LC_CTYPE],
1269 cp[MSVCRT_LC_CTYPE], locinfo, MSVCRT_LC_CTYPE)) {
1270 free_locinfo(locinfo);
1271 return NULL;
1274 locinfo->lc_codepage = locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage;
1275 locinfo->lc_clike = 1;
1276 if(!GetCPInfo(locinfo->lc_codepage, &cp_info)) {
1277 free_locinfo(locinfo);
1278 return NULL;
1280 locinfo->mb_cur_max = cp_info.MaxCharSize;
1282 locinfo->ctype1_refcount = MSVCRT_malloc(sizeof(int));
1283 locinfo->ctype1 = MSVCRT_malloc(sizeof(short[257]));
1284 if(!locinfo->ctype1_refcount || !locinfo->ctype1) {
1285 free_locinfo(locinfo);
1286 return NULL;
1289 *locinfo->ctype1_refcount = 1;
1290 locinfo->ctype1[0] = 0;
1291 locinfo->pctype = locinfo->ctype1+1;
1293 buf[1] = buf[2] = '\0';
1294 for(i=1; i<257; i++) {
1295 buf[0] = i-1;
1297 /* builtin GetStringTypeA doesn't set output to 0 on invalid input */
1298 locinfo->ctype1[i] = 0;
1300 GetStringTypeA(lcid[MSVCRT_LC_CTYPE], CT_CTYPE1, buf,
1301 1, locinfo->ctype1+i);
1304 for(i=0; cp_info.LeadByte[i+1]!=0; i+=2)
1305 for(j=cp_info.LeadByte[i]; j<=cp_info.LeadByte[i+1]; j++)
1306 locinfo->ctype1[j+1] |= MSVCRT__LEADBYTE;
1308 if(!set_lc_locale_name(locinfo, MSVCRT_LC_CTYPE)) {
1309 free_locinfo(locinfo);
1310 return NULL;
1313 for(i=0; i<256; i++) {
1314 if(locinfo->pctype[i] & MSVCRT__LEADBYTE)
1315 buf[i] = ' ';
1316 else
1317 buf[i] = i;
1320 LCMapStringA(lcid[MSVCRT_LC_CTYPE], LCMAP_LOWERCASE, buf, 256,
1321 (char*)locinfo->pclmap, 256);
1322 LCMapStringA(lcid[MSVCRT_LC_CTYPE], LCMAP_UPPERCASE, buf, 256,
1323 (char*)locinfo->pcumap, 256);
1324 } else {
1325 locinfo->lc_clike = 1;
1326 locinfo->mb_cur_max = 1;
1327 locinfo->pctype = MSVCRT__ctype+1;
1328 locinfo->lc_category[MSVCRT_LC_CTYPE].locale = MSVCRT__strdup("C");
1330 for(i=0; i<256; i++) {
1331 if(locinfo->pctype[i] & MSVCRT__LEADBYTE)
1332 buf[i] = ' ';
1333 else
1334 buf[i] = i;
1337 for(i=0; i<256; i++) {
1338 locinfo->pclmap[i] = (i>='A' && i<='Z' ? i-'A'+'a' : i);
1339 locinfo->pcumap[i] = (i>='a' && i<='z' ? i-'a'+'A' : i);
1343 if(locale_name[MSVCRT_LC_MONETARY] &&
1344 !init_category_name(locale_name[MSVCRT_LC_MONETARY],
1345 locale_len[MSVCRT_LC_MONETARY], locinfo, MSVCRT_LC_MONETARY)) {
1346 free_locinfo(locinfo);
1347 return NULL;
1350 if(!category_needs_update(MSVCRT_LC_MONETARY, category, old_locinfo,
1351 lcid[MSVCRT_LC_MONETARY], cp[MSVCRT_LC_MONETARY])) {
1352 locinfo->lc_handle[MSVCRT_LC_MONETARY] = old_locinfo->lc_handle[MSVCRT_LC_MONETARY];
1353 locinfo->lc_id[MSVCRT_LC_MONETARY].wCodePage = old_locinfo->lc_id[MSVCRT_LC_MONETARY].wCodePage;
1354 } else if(lcid[MSVCRT_LC_MONETARY] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_MONETARY)) {
1355 if(!update_threadlocinfo_category(lcid[MSVCRT_LC_MONETARY],
1356 cp[MSVCRT_LC_MONETARY], locinfo, MSVCRT_LC_MONETARY)) {
1357 free_locinfo(locinfo);
1358 return NULL;
1361 locinfo->lconv_intl_refcount = MSVCRT_malloc(sizeof(int));
1362 locinfo->lconv_mon_refcount = MSVCRT_malloc(sizeof(int));
1363 if(!locinfo->lconv_intl_refcount || !locinfo->lconv_mon_refcount) {
1364 free_locinfo(locinfo);
1365 return NULL;
1368 *locinfo->lconv_intl_refcount = 1;
1369 *locinfo->lconv_mon_refcount = 1;
1371 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SINTLSYMBOL
1372 |LOCALE_NOUSEROVERRIDE, buf, 256);
1373 if(i && (locinfo->lconv->int_curr_symbol = MSVCRT_malloc(i)))
1374 memcpy(locinfo->lconv->int_curr_symbol, buf, i);
1375 else {
1376 free_locinfo(locinfo);
1377 return NULL;
1380 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SCURRENCY
1381 |LOCALE_NOUSEROVERRIDE, buf, 256);
1382 if(i && (locinfo->lconv->currency_symbol = MSVCRT_malloc(i)))
1383 memcpy(locinfo->lconv->currency_symbol, buf, i);
1384 else {
1385 free_locinfo(locinfo);
1386 return NULL;
1389 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONDECIMALSEP
1390 |LOCALE_NOUSEROVERRIDE, buf, 256);
1391 if(i && (locinfo->lconv->mon_decimal_point = MSVCRT_malloc(i)))
1392 memcpy(locinfo->lconv->mon_decimal_point, buf, i);
1393 else {
1394 free_locinfo(locinfo);
1395 return NULL;
1398 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONTHOUSANDSEP
1399 |LOCALE_NOUSEROVERRIDE, buf, 256);
1400 if(i && (locinfo->lconv->mon_thousands_sep = MSVCRT_malloc(i)))
1401 memcpy(locinfo->lconv->mon_thousands_sep, buf, i);
1402 else {
1403 free_locinfo(locinfo);
1404 return NULL;
1407 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONGROUPING
1408 |LOCALE_NOUSEROVERRIDE, buf, 256);
1409 if(i>1)
1410 i = i/2 + (buf[i-2]=='0'?0:1);
1411 if(i && (locinfo->lconv->mon_grouping = MSVCRT_malloc(i))) {
1412 for(i=0; buf[i+1]==';'; i+=2)
1413 locinfo->lconv->mon_grouping[i/2] = buf[i]-'0';
1414 locinfo->lconv->mon_grouping[i/2] = buf[i]-'0';
1415 if(buf[i] != '0')
1416 locinfo->lconv->mon_grouping[i/2+1] = 127;
1417 } else {
1418 free_locinfo(locinfo);
1419 return NULL;
1422 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SPOSITIVESIGN
1423 |LOCALE_NOUSEROVERRIDE, buf, 256);
1424 if(i && (locinfo->lconv->positive_sign = MSVCRT_malloc(i)))
1425 memcpy(locinfo->lconv->positive_sign, buf, i);
1426 else {
1427 free_locinfo(locinfo);
1428 return NULL;
1431 i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SNEGATIVESIGN
1432 |LOCALE_NOUSEROVERRIDE, buf, 256);
1433 if(i && (locinfo->lconv->negative_sign = MSVCRT_malloc(i)))
1434 memcpy(locinfo->lconv->negative_sign, buf, i);
1435 else {
1436 free_locinfo(locinfo);
1437 return NULL;
1440 if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IINTLCURRDIGITS
1441 |LOCALE_NOUSEROVERRIDE, buf, 256))
1442 locinfo->lconv->int_frac_digits = atoi(buf);
1443 else {
1444 free_locinfo(locinfo);
1445 return NULL;
1448 if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_ICURRDIGITS
1449 |LOCALE_NOUSEROVERRIDE, buf, 256))
1450 locinfo->lconv->frac_digits = atoi(buf);
1451 else {
1452 free_locinfo(locinfo);
1453 return NULL;
1456 if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSYMPRECEDES
1457 |LOCALE_NOUSEROVERRIDE, buf, 256))
1458 locinfo->lconv->p_cs_precedes = atoi(buf);
1459 else {
1460 free_locinfo(locinfo);
1461 return NULL;
1464 if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSEPBYSPACE
1465 |LOCALE_NOUSEROVERRIDE, buf, 256))
1466 locinfo->lconv->p_sep_by_space = atoi(buf);
1467 else {
1468 free_locinfo(locinfo);
1469 return NULL;
1472 if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSYMPRECEDES
1473 |LOCALE_NOUSEROVERRIDE, buf, 256))
1474 locinfo->lconv->n_cs_precedes = atoi(buf);
1475 else {
1476 free_locinfo(locinfo);
1477 return NULL;
1480 if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSEPBYSPACE
1481 |LOCALE_NOUSEROVERRIDE, buf, 256))
1482 locinfo->lconv->n_sep_by_space = atoi(buf);
1483 else {
1484 free_locinfo(locinfo);
1485 return NULL;
1488 if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSIGNPOSN
1489 |LOCALE_NOUSEROVERRIDE, buf, 256))
1490 locinfo->lconv->p_sign_posn = atoi(buf);
1491 else {
1492 free_locinfo(locinfo);
1493 return NULL;
1496 if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSIGNPOSN
1497 |LOCALE_NOUSEROVERRIDE, buf, 256))
1498 locinfo->lconv->n_sign_posn = atoi(buf);
1499 else {
1500 free_locinfo(locinfo);
1501 return NULL;
1504 #if _MSVCR_VER >= 100
1505 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SINTLSYMBOL
1506 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1507 if(i && (locinfo->lconv->_W_int_curr_symbol = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1508 memcpy(locinfo->lconv->_W_int_curr_symbol, wbuf, i * sizeof(MSVCRT_wchar_t));
1509 else {
1510 free_locinfo(locinfo);
1511 return NULL;
1514 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SCURRENCY
1515 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1516 if(i && (locinfo->lconv->_W_currency_symbol = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1517 memcpy(locinfo->lconv->_W_currency_symbol, wbuf, i * sizeof(MSVCRT_wchar_t));
1518 else {
1519 free_locinfo(locinfo);
1520 return NULL;
1523 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONDECIMALSEP
1524 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1525 if(i && (locinfo->lconv->_W_mon_decimal_point = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1526 memcpy(locinfo->lconv->_W_mon_decimal_point, wbuf, i * sizeof(MSVCRT_wchar_t));
1527 else {
1528 free_locinfo(locinfo);
1529 return NULL;
1532 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONTHOUSANDSEP
1533 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1534 if(i && (locinfo->lconv->_W_mon_thousands_sep = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1535 memcpy(locinfo->lconv->_W_mon_thousands_sep, wbuf, i * sizeof(MSVCRT_wchar_t));
1536 else {
1537 free_locinfo(locinfo);
1538 return NULL;
1541 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SPOSITIVESIGN
1542 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1543 if(i && (locinfo->lconv->_W_positive_sign = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1544 memcpy(locinfo->lconv->_W_positive_sign, wbuf, i * sizeof(MSVCRT_wchar_t));
1545 else {
1546 free_locinfo(locinfo);
1547 return NULL;
1550 i = GetLocaleInfoW(lcid[MSVCRT_LC_MONETARY], LOCALE_SNEGATIVESIGN
1551 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1552 if(i && (locinfo->lconv->_W_negative_sign = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1553 memcpy(locinfo->lconv->_W_negative_sign, wbuf, i * sizeof(MSVCRT_wchar_t));
1554 else {
1555 free_locinfo(locinfo);
1556 return NULL;
1558 #endif
1560 if(!set_lc_locale_name(locinfo, MSVCRT_LC_MONETARY)) {
1561 free_locinfo(locinfo);
1562 return NULL;
1564 } else {
1565 locinfo->lconv->int_curr_symbol = MSVCRT_malloc(sizeof(char));
1566 locinfo->lconv->currency_symbol = MSVCRT_malloc(sizeof(char));
1567 locinfo->lconv->mon_decimal_point = MSVCRT_malloc(sizeof(char));
1568 locinfo->lconv->mon_thousands_sep = MSVCRT_malloc(sizeof(char));
1569 locinfo->lconv->mon_grouping = MSVCRT_malloc(sizeof(char));
1570 locinfo->lconv->positive_sign = MSVCRT_malloc(sizeof(char));
1571 locinfo->lconv->negative_sign = MSVCRT_malloc(sizeof(char));
1573 if(!locinfo->lconv->int_curr_symbol || !locinfo->lconv->currency_symbol
1574 || !locinfo->lconv->mon_decimal_point || !locinfo->lconv->mon_thousands_sep
1575 || !locinfo->lconv->mon_grouping || !locinfo->lconv->positive_sign
1576 || !locinfo->lconv->negative_sign) {
1577 free_locinfo(locinfo);
1578 return NULL;
1581 locinfo->lconv->int_curr_symbol[0] = '\0';
1582 locinfo->lconv->currency_symbol[0] = '\0';
1583 locinfo->lconv->mon_decimal_point[0] = '\0';
1584 locinfo->lconv->mon_thousands_sep[0] = '\0';
1585 locinfo->lconv->mon_grouping[0] = '\0';
1586 locinfo->lconv->positive_sign[0] = '\0';
1587 locinfo->lconv->negative_sign[0] = '\0';
1588 locinfo->lconv->int_frac_digits = charmax;
1589 locinfo->lconv->frac_digits = charmax;
1590 locinfo->lconv->p_cs_precedes = charmax;
1591 locinfo->lconv->p_sep_by_space = charmax;
1592 locinfo->lconv->n_cs_precedes = charmax;
1593 locinfo->lconv->n_sep_by_space = charmax;
1594 locinfo->lconv->p_sign_posn = charmax;
1595 locinfo->lconv->n_sign_posn = charmax;
1597 #if _MSVCR_VER >= 100
1598 locinfo->lconv->_W_int_curr_symbol = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1599 locinfo->lconv->_W_currency_symbol = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1600 locinfo->lconv->_W_mon_decimal_point = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1601 locinfo->lconv->_W_mon_thousands_sep = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1602 locinfo->lconv->_W_positive_sign = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1603 locinfo->lconv->_W_negative_sign = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1605 if(!locinfo->lconv->_W_int_curr_symbol || !locinfo->lconv->_W_currency_symbol
1606 || !locinfo->lconv->_W_mon_decimal_point || !locinfo->lconv->_W_mon_thousands_sep
1607 || !locinfo->lconv->positive_sign || !locinfo->lconv->negative_sign) {
1608 free_locinfo(locinfo);
1609 return NULL;
1612 locinfo->lconv->_W_int_curr_symbol[0] = '\0';
1613 locinfo->lconv->_W_currency_symbol[0] = '\0';
1614 locinfo->lconv->_W_mon_decimal_point[0] = '\0';
1615 locinfo->lconv->_W_mon_thousands_sep[0] = '\0';
1616 locinfo->lconv->_W_positive_sign[0] = '\0';
1617 locinfo->lconv->_W_negative_sign[0] = '\0';
1618 #endif
1620 locinfo->lc_category[MSVCRT_LC_MONETARY].locale = MSVCRT__strdup("C");
1623 if(locale_name[MSVCRT_LC_NUMERIC] &&
1624 !init_category_name(locale_name[MSVCRT_LC_NUMERIC],
1625 locale_len[MSVCRT_LC_NUMERIC], locinfo, MSVCRT_LC_NUMERIC)) {
1626 free_locinfo(locinfo);
1627 return NULL;
1630 if(!category_needs_update(MSVCRT_LC_NUMERIC, category, old_locinfo,
1631 lcid[MSVCRT_LC_NUMERIC], cp[MSVCRT_LC_NUMERIC])) {
1632 locinfo->lc_handle[MSVCRT_LC_NUMERIC] = old_locinfo->lc_handle[MSVCRT_LC_NUMERIC];
1633 locinfo->lc_id[MSVCRT_LC_NUMERIC].wCodePage = old_locinfo->lc_id[MSVCRT_LC_NUMERIC].wCodePage;
1634 } else if(lcid[MSVCRT_LC_NUMERIC] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_NUMERIC)) {
1635 if(!update_threadlocinfo_category(lcid[MSVCRT_LC_NUMERIC],
1636 cp[MSVCRT_LC_NUMERIC], locinfo, MSVCRT_LC_NUMERIC)) {
1637 free_locinfo(locinfo);
1638 return NULL;
1641 if(!locinfo->lconv_intl_refcount)
1642 locinfo->lconv_intl_refcount = MSVCRT_malloc(sizeof(int));
1643 locinfo->lconv_num_refcount = MSVCRT_malloc(sizeof(int));
1644 if(!locinfo->lconv_intl_refcount || !locinfo->lconv_num_refcount) {
1645 free_locinfo(locinfo);
1646 return NULL;
1649 *locinfo->lconv_intl_refcount = 1;
1650 *locinfo->lconv_num_refcount = 1;
1652 i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_SDECIMAL
1653 |LOCALE_NOUSEROVERRIDE, buf, 256);
1654 if(i && (locinfo->lconv->decimal_point = MSVCRT_malloc(i)))
1655 memcpy(locinfo->lconv->decimal_point, buf, i);
1656 else {
1657 free_locinfo(locinfo);
1658 return NULL;
1661 i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_STHOUSAND
1662 |LOCALE_NOUSEROVERRIDE, buf, 256);
1663 if(i && (locinfo->lconv->thousands_sep = MSVCRT_malloc(i)))
1664 memcpy(locinfo->lconv->thousands_sep, buf, i);
1665 else {
1666 free_locinfo(locinfo);
1667 return NULL;
1670 i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_SGROUPING
1671 |LOCALE_NOUSEROVERRIDE, buf, 256);
1672 if(i>1)
1673 i = i/2 + (buf[i-2]=='0'?0:1);
1674 if(i && (locinfo->lconv->grouping = MSVCRT_malloc(i))) {
1675 for(i=0; buf[i+1]==';'; i+=2)
1676 locinfo->lconv->grouping[i/2] = buf[i]-'0';
1677 locinfo->lconv->grouping[i/2] = buf[i]-'0';
1678 if(buf[i] != '0')
1679 locinfo->lconv->grouping[i/2+1] = 127;
1680 } else {
1681 free_locinfo(locinfo);
1682 return NULL;
1685 #if _MSVCR_VER >= 100
1686 i = GetLocaleInfoW(lcid[MSVCRT_LC_NUMERIC], LOCALE_SDECIMAL
1687 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1688 if(i && (locinfo->lconv->_W_decimal_point = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1689 memcpy(locinfo->lconv->_W_decimal_point, wbuf, i * sizeof(MSVCRT_wchar_t));
1690 else {
1691 free_locinfo(locinfo);
1692 return NULL;
1695 i = GetLocaleInfoW(lcid[MSVCRT_LC_NUMERIC], LOCALE_STHOUSAND
1696 |LOCALE_NOUSEROVERRIDE, wbuf, 256);
1697 if(i && (locinfo->lconv->_W_thousands_sep = MSVCRT_malloc(i * sizeof(MSVCRT_wchar_t))))
1698 memcpy(locinfo->lconv->_W_thousands_sep, wbuf, i * sizeof(MSVCRT_wchar_t));
1699 else {
1700 free_locinfo(locinfo);
1701 return NULL;
1703 #endif
1705 if(!set_lc_locale_name(locinfo, MSVCRT_LC_NUMERIC)) {
1706 free_locinfo(locinfo);
1707 return NULL;
1709 } else {
1710 locinfo->lconv->decimal_point = MSVCRT_malloc(sizeof(char[2]));
1711 locinfo->lconv->thousands_sep = MSVCRT_malloc(sizeof(char));
1712 locinfo->lconv->grouping = MSVCRT_malloc(sizeof(char));
1713 if(!locinfo->lconv->decimal_point || !locinfo->lconv->thousands_sep
1714 || !locinfo->lconv->grouping) {
1715 free_locinfo(locinfo);
1716 return NULL;
1719 locinfo->lconv->decimal_point[0] = '.';
1720 locinfo->lconv->decimal_point[1] = '\0';
1721 locinfo->lconv->thousands_sep[0] = '\0';
1722 locinfo->lconv->grouping[0] = '\0';
1724 #if _MSVCR_VER >= 100
1725 locinfo->lconv->_W_decimal_point = MSVCRT_malloc(sizeof(MSVCRT_wchar_t[2]));
1726 locinfo->lconv->_W_thousands_sep = MSVCRT_malloc(sizeof(MSVCRT_wchar_t));
1728 if(!locinfo->lconv->_W_decimal_point || !locinfo->lconv->_W_thousands_sep) {
1729 free_locinfo(locinfo);
1730 return NULL;
1733 locinfo->lconv->_W_decimal_point[0] = '.';
1734 locinfo->lconv->_W_decimal_point[1] = '\0';
1735 locinfo->lconv->_W_thousands_sep[0] = '\0';
1736 #endif
1738 locinfo->lc_category[MSVCRT_LC_NUMERIC].locale = MSVCRT__strdup("C");
1741 if(locale_name[MSVCRT_LC_TIME] &&
1742 !init_category_name(locale_name[MSVCRT_LC_TIME],
1743 locale_len[MSVCRT_LC_TIME], locinfo, MSVCRT_LC_TIME)) {
1744 free_locinfo(locinfo);
1745 return NULL;
1748 if(!category_needs_update(MSVCRT_LC_TIME, category, old_locinfo,
1749 lcid[MSVCRT_LC_TIME], cp[MSVCRT_LC_TIME])) {
1750 locinfo->lc_handle[MSVCRT_LC_TIME] = old_locinfo->lc_handle[MSVCRT_LC_TIME];
1751 locinfo->lc_id[MSVCRT_LC_TIME].wCodePage = old_locinfo->lc_id[MSVCRT_LC_TIME].wCodePage;
1752 } else if(lcid[MSVCRT_LC_TIME] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_TIME)) {
1753 if(!update_threadlocinfo_category(lcid[MSVCRT_LC_TIME],
1754 cp[MSVCRT_LC_TIME], locinfo, MSVCRT_LC_TIME)) {
1755 free_locinfo(locinfo);
1756 return NULL;
1759 if(!set_lc_locale_name(locinfo, MSVCRT_LC_TIME)) {
1760 free_locinfo(locinfo);
1761 return NULL;
1764 locinfo->lc_time_curr = create_time_data(lcid[MSVCRT_LC_TIME]);
1765 if(!locinfo->lc_time_curr) {
1766 free_locinfo(locinfo);
1767 return NULL;
1769 } else {
1770 locinfo->lc_category[MSVCRT_LC_TIME].locale = MSVCRT__strdup("C");
1771 locinfo->lc_time_curr = &cloc_time_data;
1774 return locinfo;
1777 /*********************************************************************
1778 * _lock_locales (UCRTBASE.@)
1780 void CDECL _lock_locales(void)
1782 _mlock(_SETLOCALE_LOCK);
1785 /*********************************************************************
1786 * _unlock_locales (UCRTBASE.@)
1788 void CDECL _unlock_locales(void)
1790 _munlock(_SETLOCALE_LOCK);
1793 /*********************************************************************
1794 * _create_locale (MSVCRT.@)
1796 MSVCRT__locale_t CDECL MSVCRT__create_locale(int category, const char *locale)
1798 MSVCRT__locale_t loc;
1800 loc = MSVCRT_malloc(sizeof(MSVCRT__locale_tstruct));
1801 if(!loc)
1802 return NULL;
1804 loc->locinfo = create_locinfo(category, locale, NULL);
1805 if(!loc->locinfo) {
1806 MSVCRT_free(loc);
1807 return NULL;
1810 loc->mbcinfo = MSVCRT_malloc(sizeof(MSVCRT_threadmbcinfo));
1811 if(!loc->mbcinfo) {
1812 free_locinfo(loc->locinfo);
1813 MSVCRT_free(loc);
1814 return NULL;
1817 loc->mbcinfo->refcount = 1;
1818 _setmbcp_l(loc->locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage,
1819 loc->locinfo->lc_handle[MSVCRT_LC_CTYPE], loc->mbcinfo);
1820 return loc;
1823 #if _MSVCR_VER >= 110
1824 /*********************************************************************
1825 * _wcreate_locale (MSVCR110.@)
1827 MSVCRT__locale_t CDECL MSVCRT__wcreate_locale(int category, const MSVCRT_wchar_t *locale)
1829 MSVCRT__locale_t loc;
1830 MSVCRT_size_t len;
1831 char *str;
1833 if(category<MSVCRT_LC_MIN || category>MSVCRT_LC_MAX || !locale)
1834 return NULL;
1836 len = MSVCRT_wcstombs(NULL, locale, 0);
1837 if(len == -1)
1838 return NULL;
1839 if(!(str = MSVCRT_malloc(++len)))
1840 return NULL;
1841 MSVCRT_wcstombs(str, locale, len);
1843 loc = MSVCRT__create_locale(category, str);
1845 MSVCRT_free(str);
1846 return loc;
1848 #endif
1850 /*********************************************************************
1851 * setlocale (MSVCRT.@)
1853 char* CDECL MSVCRT_setlocale(int category, const char* locale)
1855 MSVCRT_pthreadlocinfo locinfo = get_locinfo();
1856 MSVCRT_pthreadlocinfo newlocinfo;
1858 if(category<MSVCRT_LC_MIN || category>MSVCRT_LC_MAX)
1859 return NULL;
1861 if(!locale) {
1862 if(category == MSVCRT_LC_ALL)
1863 return construct_lc_all(locinfo);
1865 return locinfo->lc_category[category].locale;
1868 newlocinfo = create_locinfo(category, locale, locinfo);
1869 if(!newlocinfo) {
1870 WARN("%d %s failed\n", category, locale);
1871 return NULL;
1874 _lock_locales();
1876 if(locale[0] != 'C' || locale[1] != '\0')
1877 initial_locale = FALSE;
1879 if(locinfo->lc_handle[MSVCRT_LC_COLLATE]!=newlocinfo->lc_handle[MSVCRT_LC_COLLATE]
1880 || locinfo->lc_id[MSVCRT_LC_COLLATE].wCodePage!=newlocinfo->lc_id[MSVCRT_LC_COLLATE].wCodePage) {
1881 locinfo->lc_collate_cp = newlocinfo->lc_collate_cp;
1882 locinfo->lc_handle[MSVCRT_LC_COLLATE] =
1883 newlocinfo->lc_handle[MSVCRT_LC_COLLATE];
1884 locinfo->lc_id[MSVCRT_LC_COLLATE] =
1885 newlocinfo->lc_id[MSVCRT_LC_COLLATE];
1887 #if _MSVCR_VER >= 110
1888 swap_pointers((void**)&locinfo->lc_name[MSVCRT_LC_COLLATE],
1889 (void**)&newlocinfo->lc_name[MSVCRT_LC_COLLATE]);
1890 #endif
1892 if(newlocinfo->lc_category[MSVCRT_LC_COLLATE].locale) {
1893 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_COLLATE].locale,
1894 (void**)&newlocinfo->lc_category[MSVCRT_LC_COLLATE].locale);
1895 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_COLLATE].refcount,
1896 (void**)&newlocinfo->lc_category[MSVCRT_LC_COLLATE].refcount);
1899 if(locinfo->lc_handle[MSVCRT_LC_CTYPE]!=newlocinfo->lc_handle[MSVCRT_LC_CTYPE]
1900 || locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage!=newlocinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage) {
1901 locinfo->lc_handle[MSVCRT_LC_CTYPE] =
1902 newlocinfo->lc_handle[MSVCRT_LC_CTYPE];
1903 locinfo->lc_id[MSVCRT_LC_CTYPE] =
1904 newlocinfo->lc_id[MSVCRT_LC_CTYPE];
1906 locinfo->lc_codepage = newlocinfo->lc_codepage;
1907 locinfo->lc_clike = newlocinfo->lc_clike;
1908 locinfo->mb_cur_max = newlocinfo->mb_cur_max;
1910 swap_pointers((void**)&locinfo->ctype1_refcount,
1911 (void**)&newlocinfo->ctype1_refcount);
1912 swap_pointers((void**)&locinfo->ctype1, (void**)&newlocinfo->ctype1);
1913 swap_pointers((void**)&locinfo->pctype, (void**)&newlocinfo->pctype);
1914 swap_pointers((void**)&locinfo->pclmap, (void**)&newlocinfo->pclmap);
1915 swap_pointers((void**)&locinfo->pcumap, (void**)&newlocinfo->pcumap);
1917 #if _MSVCR_VER >= 110
1918 swap_pointers((void**)&locinfo->lc_name[MSVCRT_LC_CTYPE],
1919 (void**)&newlocinfo->lc_name[MSVCRT_LC_CTYPE]);
1920 #endif
1922 if(newlocinfo->lc_category[MSVCRT_LC_CTYPE].locale) {
1923 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_CTYPE].locale,
1924 (void**)&newlocinfo->lc_category[MSVCRT_LC_CTYPE].locale);
1925 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_CTYPE].refcount,
1926 (void**)&newlocinfo->lc_category[MSVCRT_LC_CTYPE].refcount);
1929 if(locinfo->lc_handle[MSVCRT_LC_MONETARY]!=newlocinfo->lc_handle[MSVCRT_LC_MONETARY]
1930 || locinfo->lc_id[MSVCRT_LC_MONETARY].wCodePage!=newlocinfo->lc_id[MSVCRT_LC_MONETARY].wCodePage) {
1931 locinfo->lc_handle[MSVCRT_LC_MONETARY] =
1932 newlocinfo->lc_handle[MSVCRT_LC_MONETARY];
1933 locinfo->lc_id[MSVCRT_LC_MONETARY] =
1934 newlocinfo->lc_id[MSVCRT_LC_MONETARY];
1936 swap_pointers((void**)&locinfo->lconv->int_curr_symbol,
1937 (void**)&newlocinfo->lconv->int_curr_symbol);
1938 swap_pointers((void**)&locinfo->lconv->currency_symbol,
1939 (void**)&newlocinfo->lconv->currency_symbol);
1940 swap_pointers((void**)&locinfo->lconv->mon_decimal_point,
1941 (void**)&newlocinfo->lconv->mon_decimal_point);
1942 swap_pointers((void**)&locinfo->lconv->mon_thousands_sep,
1943 (void**)&newlocinfo->lconv->mon_thousands_sep);
1944 swap_pointers((void**)&locinfo->lconv->mon_grouping,
1945 (void**)&newlocinfo->lconv->mon_grouping);
1946 swap_pointers((void**)&locinfo->lconv->positive_sign,
1947 (void**)&newlocinfo->lconv->positive_sign);
1948 swap_pointers((void**)&locinfo->lconv->negative_sign,
1949 (void**)&newlocinfo->lconv->negative_sign);
1951 #if _MSVCR_VER >= 100
1952 swap_pointers((void**)&locinfo->lconv->_W_int_curr_symbol,
1953 (void**)&newlocinfo->lconv->_W_int_curr_symbol);
1954 swap_pointers((void**)&locinfo->lconv->_W_currency_symbol,
1955 (void**)&newlocinfo->lconv->_W_currency_symbol);
1956 swap_pointers((void**)&locinfo->lconv->_W_mon_decimal_point,
1957 (void**)&newlocinfo->lconv->_W_mon_decimal_point);
1958 swap_pointers((void**)&locinfo->lconv->_W_mon_thousands_sep,
1959 (void**)&newlocinfo->lconv->_W_mon_thousands_sep);
1960 swap_pointers((void**)&locinfo->lconv->_W_positive_sign,
1961 (void**)&newlocinfo->lconv->_W_positive_sign);
1962 swap_pointers((void**)&locinfo->lconv->_W_negative_sign,
1963 (void**)&newlocinfo->lconv->_W_negative_sign);
1964 #endif
1966 locinfo->lconv->int_frac_digits = newlocinfo->lconv->int_frac_digits;
1967 locinfo->lconv->frac_digits = newlocinfo->lconv->frac_digits;
1968 locinfo->lconv->p_cs_precedes = newlocinfo->lconv->p_cs_precedes;
1969 locinfo->lconv->p_sep_by_space = newlocinfo->lconv->p_sep_by_space;
1970 locinfo->lconv->n_cs_precedes = newlocinfo->lconv->n_cs_precedes;
1971 locinfo->lconv->n_sep_by_space = newlocinfo->lconv->n_sep_by_space;
1972 locinfo->lconv->p_sign_posn = newlocinfo->lconv->p_sign_posn;
1973 locinfo->lconv->n_sign_posn = newlocinfo->lconv->n_sign_posn;
1975 #if _MSVCR_VER >= 110
1976 swap_pointers((void**)&locinfo->lc_name[MSVCRT_LC_MONETARY],
1977 (void**)&newlocinfo->lc_name[MSVCRT_LC_MONETARY]);
1978 #endif
1980 if(newlocinfo->lc_category[MSVCRT_LC_MONETARY].locale) {
1981 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_MONETARY].locale,
1982 (void**)&newlocinfo->lc_category[MSVCRT_LC_MONETARY].locale);
1983 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_MONETARY].refcount,
1984 (void**)&newlocinfo->lc_category[MSVCRT_LC_MONETARY].refcount);
1987 if(locinfo->lc_handle[MSVCRT_LC_NUMERIC]!=newlocinfo->lc_handle[MSVCRT_LC_NUMERIC]
1988 || locinfo->lc_id[MSVCRT_LC_NUMERIC].wCodePage!=newlocinfo->lc_id[MSVCRT_LC_NUMERIC].wCodePage) {
1989 locinfo->lc_handle[MSVCRT_LC_NUMERIC] =
1990 newlocinfo->lc_handle[MSVCRT_LC_NUMERIC];
1991 locinfo->lc_id[MSVCRT_LC_NUMERIC] =
1992 newlocinfo->lc_id[MSVCRT_LC_NUMERIC];
1994 swap_pointers((void**)&locinfo->lconv->decimal_point,
1995 (void**)&newlocinfo->lconv->decimal_point);
1996 swap_pointers((void**)&locinfo->lconv->thousands_sep,
1997 (void**)&newlocinfo->lconv->thousands_sep);
1998 swap_pointers((void**)&locinfo->lconv->grouping,
1999 (void**)&newlocinfo->lconv->grouping);
2001 #if _MSVCR_VER >= 100
2002 swap_pointers((void**)&locinfo->lconv->_W_decimal_point,
2003 (void**)&newlocinfo->lconv->_W_decimal_point);
2004 swap_pointers((void**)&locinfo->lconv->_W_thousands_sep,
2005 (void**)&newlocinfo->lconv->_W_thousands_sep);
2006 #endif
2008 #if _MSVCR_VER >= 110
2009 swap_pointers((void**)&locinfo->lc_name[MSVCRT_LC_NUMERIC],
2010 (void**)&newlocinfo->lc_name[MSVCRT_LC_NUMERIC]);
2011 #endif
2013 if(newlocinfo->lc_category[MSVCRT_LC_NUMERIC].locale) {
2014 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_NUMERIC].locale,
2015 (void**)&newlocinfo->lc_category[MSVCRT_LC_NUMERIC].locale);
2016 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_NUMERIC].refcount,
2017 (void**)&newlocinfo->lc_category[MSVCRT_LC_NUMERIC].refcount);
2020 if(locinfo->lc_handle[MSVCRT_LC_TIME]!=newlocinfo->lc_handle[MSVCRT_LC_TIME]
2021 || locinfo->lc_id[MSVCRT_LC_TIME].wCodePage!=newlocinfo->lc_id[MSVCRT_LC_TIME].wCodePage) {
2022 locinfo->lc_handle[MSVCRT_LC_TIME] =
2023 newlocinfo->lc_handle[MSVCRT_LC_TIME];
2024 locinfo->lc_id[MSVCRT_LC_TIME] =
2025 newlocinfo->lc_id[MSVCRT_LC_TIME];
2026 swap_pointers((void**)&locinfo->lc_time_curr,
2027 (void**)&newlocinfo->lc_time_curr);
2029 #if _MSVCR_VER >= 110
2030 swap_pointers((void**)&locinfo->lc_name[MSVCRT_LC_TIME],
2031 (void**)&newlocinfo->lc_name[MSVCRT_LC_TIME]);
2032 #endif
2034 if(newlocinfo->lc_category[MSVCRT_LC_TIME].locale) {
2035 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_TIME].locale,
2036 (void**)&newlocinfo->lc_category[MSVCRT_LC_TIME].locale);
2037 swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_TIME].refcount,
2038 (void**)&newlocinfo->lc_category[MSVCRT_LC_TIME].refcount);
2041 free_locinfo(newlocinfo);
2042 _unlock_locales();
2044 if(locinfo == MSVCRT_locale->locinfo) {
2045 int i;
2047 MSVCRT___lc_codepage = locinfo->lc_codepage;
2048 MSVCRT___lc_collate_cp = locinfo->lc_collate_cp;
2049 MSVCRT___mb_cur_max = locinfo->mb_cur_max;
2050 MSVCRT__pctype = locinfo->pctype;
2051 for(i=MSVCRT_LC_MIN; i<=MSVCRT_LC_MAX; i++)
2052 MSVCRT___lc_handle[i] = MSVCRT_locale->locinfo->lc_handle[i];
2055 if(category == MSVCRT_LC_ALL)
2056 return construct_lc_all(locinfo);
2058 return locinfo->lc_category[category].locale;
2061 /*********************************************************************
2062 * _wsetlocale (MSVCRT.@)
2064 MSVCRT_wchar_t* CDECL MSVCRT__wsetlocale(int category, const MSVCRT_wchar_t* wlocale)
2066 static MSVCRT_wchar_t current_lc_all[MAX_LOCALE_LENGTH];
2068 char *locale = NULL;
2069 const char *ret;
2070 MSVCRT_size_t len;
2072 if(wlocale) {
2073 len = MSVCRT_wcstombs(NULL, wlocale, 0);
2074 if(len == -1)
2075 return NULL;
2077 locale = MSVCRT_malloc(++len);
2078 if(!locale)
2079 return NULL;
2081 MSVCRT_wcstombs(locale, wlocale, len);
2084 _lock_locales();
2085 ret = MSVCRT_setlocale(category, locale);
2086 MSVCRT_free(locale);
2088 if(ret && MSVCRT_mbstowcs(current_lc_all, ret, MAX_LOCALE_LENGTH)==-1)
2089 ret = NULL;
2091 _unlock_locales();
2092 return ret ? current_lc_all : NULL;
2095 #if _MSVCR_VER >= 80
2096 /*********************************************************************
2097 * _configthreadlocale (MSVCR80.@)
2099 int CDECL _configthreadlocale(int type)
2101 thread_data_t *data = msvcrt_get_thread_data();
2102 MSVCRT__locale_t locale;
2103 int ret;
2105 if(!data)
2106 return -1;
2108 ret = (data->have_locale ? MSVCRT__ENABLE_PER_THREAD_LOCALE : MSVCRT__DISABLE_PER_THREAD_LOCALE);
2110 if(type == MSVCRT__ENABLE_PER_THREAD_LOCALE) {
2111 if(!data->have_locale) {
2112 /* Copy current global locale */
2113 locale = MSVCRT__create_locale(MSVCRT_LC_ALL, MSVCRT_setlocale(MSVCRT_LC_ALL, NULL));
2114 if(!locale)
2115 return -1;
2117 data->locinfo = locale->locinfo;
2118 data->mbcinfo = locale->mbcinfo;
2119 data->have_locale = TRUE;
2120 MSVCRT_free(locale);
2123 return ret;
2126 if(type == MSVCRT__DISABLE_PER_THREAD_LOCALE) {
2127 if(data->have_locale) {
2128 free_locinfo(data->locinfo);
2129 free_mbcinfo(data->mbcinfo);
2130 data->locinfo = MSVCRT_locale->locinfo;
2131 data->mbcinfo = MSVCRT_locale->mbcinfo;
2132 data->have_locale = FALSE;
2135 return ret;
2138 if(!type)
2139 return ret;
2141 return -1;
2143 #endif
2145 BOOL msvcrt_init_locale(void)
2147 int i;
2149 _lock_locales();
2150 MSVCRT_locale = MSVCRT__create_locale(0, "C");
2151 _unlock_locales();
2152 if(!MSVCRT_locale)
2153 return FALSE;
2155 MSVCRT___lc_codepage = MSVCRT_locale->locinfo->lc_codepage;
2156 MSVCRT___lc_collate_cp = MSVCRT_locale->locinfo->lc_collate_cp;
2157 MSVCRT___mb_cur_max = MSVCRT_locale->locinfo->mb_cur_max;
2158 MSVCRT__pctype = MSVCRT_locale->locinfo->pctype;
2159 for(i=MSVCRT_LC_MIN; i<=MSVCRT_LC_MAX; i++)
2160 MSVCRT___lc_handle[i] = MSVCRT_locale->locinfo->lc_handle[i];
2161 _setmbcp(_MB_CP_ANSI);
2162 return TRUE;
2165 #if _MSVCR_VER >= 120
2166 /*********************************************************************
2167 * wctrans (MSVCR120.@)
2169 MSVCRT_wctrans_t CDECL MSVCR120_wctrans(const char *property)
2171 static const char str_tolower[] = "tolower";
2172 static const char str_toupper[] = "toupper";
2174 if(!strcmp(property, str_tolower))
2175 return 2;
2176 if(!strcmp(property, str_toupper))
2177 return 1;
2178 return 0;
2181 /*********************************************************************
2182 * towctrans (MSVCR120.@)
2184 MSVCRT_wint_t CDECL MSVCR120_towctrans(MSVCRT_wint_t c, MSVCRT_wctrans_t category)
2186 if(category == 1)
2187 return MSVCRT__towupper_l(c, NULL);
2188 return MSVCRT__towlower_l(c, NULL);
2190 #endif