xref: /reactos/sdk/lib/crt/locale/locale.c (revision 1de09c47)
1 /*
2  * msvcrt.dll locale functions
3  *
4  * Copyright 2000 Jon Griffiths
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include <precomp.h>
22 #include <locale.h>
23 
24 #include "mbctype.h"
25 #include <internal/wine/msvcrt.h>
26 
27 #define MAX_ELEM_LEN 64 /* Max length of country/language/CP string */
28 #define MAX_LOCALE_LENGTH 256
29 
30 #ifdef _pctype
31 #error _pctype should not be defined
32 #endif
33 
34 #define strcasecmp _stricmp
35 #define strncasecmp _strnicmp
36 unsigned int __lc_codepage = 0;
37 int MSVCRT___lc_collate_cp = 0;
38 LCID MSVCRT___lc_handle[LC_MAX - LC_MIN + 1] = { 0 };
39 int __mb_cur_max = 1;
40 static unsigned char charmax = CHAR_MAX;
41 
42 unsigned char _mbctype[257] = { 0 };
43 
44 /* MT */
45 #define LOCK_LOCALE   _mlock(_SETLOCALE_LOCK);
46 #define UNLOCK_LOCALE _munlock(_SETLOCALE_LOCK);
47 
48 #define MSVCRT_LEADBYTE  0x8000
49 #define MSVCRT_C1_DEFINED 0x200
50 
51 /* Friendly country strings & language names abbreviations. */
52 static const char * const _country_synonyms[] =
53 {
54     "american", "enu",
55     "american english", "enu",
56     "american-english", "enu",
57     "english-american", "enu",
58     "english-us", "enu",
59     "english-usa", "enu",
60     "us", "enu",
61     "usa", "enu",
62     "australian", "ena",
63     "english-aus", "ena",
64     "belgian", "nlb",
65     "french-belgian", "frb",
66     "canadian", "enc",
67     "english-can", "enc",
68     "french-canadian", "frc",
69     "chinese", "chs",
70     "chinese-simplified", "chs",
71     "chinese-traditional", "cht",
72     "dutch-belgian", "nlb",
73     "english-nz", "enz",
74     "uk", "eng",
75     "english-uk", "eng",
76     "french-swiss", "frs",
77     "swiss", "des",
78     "german-swiss", "des",
79     "italian-swiss", "its",
80     "german-austrian", "dea",
81     "portuguese", "ptb",
82     "portuguese-brazil", "ptb",
83     "spanish-mexican", "esm",
84     "norwegian-bokmal", "nor",
85     "norwegian-nynorsk", "non",
86     "spanish-modern", "esn"
87 };
88 
89 /* INTERNAL: Map a synonym to an ISO code */
remap_synonym(char * name)90 static void remap_synonym(char *name)
91 {
92   unsigned int i;
93   for (i = 0; i < sizeof(_country_synonyms)/sizeof(char*); i += 2 )
94   {
95     if (!strcasecmp(_country_synonyms[i],name))
96     {
97       TRACE(":Mapping synonym %s to %s\n",name,_country_synonyms[i+1]);
98       strcpy(name, _country_synonyms[i+1]);
99       return;
100     }
101   }
102 }
103 
104 /* Note: Flags are weighted in order of matching importance */
105 #define FOUND_LANGUAGE         0x4
106 #define FOUND_COUNTRY          0x2
107 #define FOUND_CODEPAGE         0x1
108 
109 typedef struct {
110   char search_language[MAX_ELEM_LEN];
111   char search_country[MAX_ELEM_LEN];
112   char search_codepage[MAX_ELEM_LEN];
113   char found_codepage[MAX_ELEM_LEN];
114   unsigned int match_flags;
115   LANGID found_lang_id;
116 } locale_search_t;
117 
118 #define CONTINUE_LOOKING TRUE
119 #define STOP_LOOKING     FALSE
120 
121 /* INTERNAL: Get and compare locale info with a given string */
compare_info(LCID lcid,DWORD flags,char * buff,const char * cmp,BOOL exact)122 static int compare_info(LCID lcid, DWORD flags, char* buff, const char* cmp, BOOL exact)
123 {
124   int len;
125 
126   if(!cmp[0])
127       return 0;
128 
129   buff[0] = 0;
130   GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN);
131   if (!buff[0])
132     return 0;
133 
134   /* Partial matches are only allowed on language/country names */
135   len = strlen(cmp);
136   if(exact || len<=3)
137     return !strcasecmp(cmp, buff);
138   else
139     return !strncasecmp(cmp, buff, len);
140 }
141 
142 static BOOL CALLBACK
find_best_locale_proc(HMODULE hModule,LPCSTR type,LPCSTR name,WORD LangID,LONG_PTR lParam)143 find_best_locale_proc(HMODULE hModule, LPCSTR type, LPCSTR name, WORD LangID, LONG_PTR lParam)
144 {
145   locale_search_t *res = (locale_search_t *)lParam;
146   const LCID lcid = MAKELCID(LangID, SORT_DEFAULT);
147   char buff[MAX_ELEM_LEN];
148   unsigned int flags = 0;
149 
150   if(PRIMARYLANGID(LangID) == LANG_NEUTRAL)
151     return CONTINUE_LOOKING;
152 
153   /* Check Language */
154   if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language, TRUE) ||
155       compare_info(lcid,LOCALE_SABBREVLANGNAME,buff,res->search_language, TRUE) ||
156       compare_info(lcid,LOCALE_SENGLANGUAGE,buff,res->search_language, FALSE))
157   {
158     TRACE(":Found language: %s->%s\n", res->search_language, buff);
159     flags |= FOUND_LANGUAGE;
160   }
161   else if (res->match_flags & FOUND_LANGUAGE)
162   {
163     return CONTINUE_LOOKING;
164   }
165 
166   /* Check Country */
167   if (compare_info(lcid,LOCALE_SISO3166CTRYNAME,buff,res->search_country, TRUE) ||
168       compare_info(lcid,LOCALE_SABBREVCTRYNAME,buff,res->search_country, TRUE) ||
169       compare_info(lcid,LOCALE_SENGCOUNTRY,buff,res->search_country, FALSE))
170   {
171     TRACE("Found country:%s->%s\n", res->search_country, buff);
172     flags |= FOUND_COUNTRY;
173   }
174   else if (!flags && (res->match_flags & FOUND_COUNTRY))
175   {
176     return CONTINUE_LOOKING;
177   }
178 
179   /* Check codepage */
180   if (compare_info(lcid,LOCALE_IDEFAULTCODEPAGE,buff,res->search_codepage, TRUE) ||
181       (compare_info(lcid,LOCALE_IDEFAULTANSICODEPAGE,buff,res->search_codepage, TRUE)))
182   {
183     TRACE("Found codepage:%s->%s\n", res->search_codepage, buff);
184     flags |= FOUND_CODEPAGE;
185     memcpy(res->found_codepage,res->search_codepage,MAX_ELEM_LEN);
186   }
187   else if (!flags && (res->match_flags & FOUND_CODEPAGE))
188   {
189     return CONTINUE_LOOKING;
190   }
191 
192   if (flags > res->match_flags)
193   {
194     /* Found a better match than previously */
195     res->match_flags = flags;
196     res->found_lang_id = LangID;
197   }
198   if ((flags & (FOUND_LANGUAGE | FOUND_COUNTRY | FOUND_CODEPAGE)) ==
199         (FOUND_LANGUAGE | FOUND_COUNTRY | FOUND_CODEPAGE))
200   {
201     TRACE(":found exact locale match\n");
202     return STOP_LOOKING;
203   }
204   return CONTINUE_LOOKING;
205 }
206 
207 extern int atoi(const char *);
208 
209 /* Internal: Find the LCID for a locale specification */
MSVCRT_locale_to_LCID(const char * locale,unsigned short * codepage)210 LCID MSVCRT_locale_to_LCID(const char *locale, unsigned short *codepage)
211 {
212     LCID lcid;
213     locale_search_t search;
214     const char *cp, *region;
215 
216     memset(&search, 0, sizeof(locale_search_t));
217 
218     cp = strchr(locale, '.');
219     region = strchr(locale, '_');
220 
221     lstrcpynA(search.search_language, locale, MAX_ELEM_LEN);
222     if(region) {
223         lstrcpynA(search.search_country, region+1, MAX_ELEM_LEN);
224         if(region-locale < MAX_ELEM_LEN)
225             search.search_language[region-locale] = '\0';
226     } else
227         search.search_country[0] = '\0';
228 
229     if(cp) {
230         lstrcpynA(search.search_codepage, cp+1, MAX_ELEM_LEN);
231         if(region && cp-region-1<MAX_ELEM_LEN)
232           search.search_country[cp-region-1] = '\0';
233         if(cp-locale < MAX_ELEM_LEN)
234             search.search_language[cp-locale] = '\0';
235     } else
236         search.search_codepage[0] = '\0';
237 
238     if(!search.search_country[0] && !search.search_codepage[0])
239         remap_synonym(search.search_language);
240 
241     EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), (LPSTR)RT_STRING,
242             (LPCSTR)LOCALE_ILANGUAGE,find_best_locale_proc,
243             (LONG_PTR)&search);
244 
245     if (!search.match_flags)
246         return -1;
247 
248     /* If we were given something that didn't match, fail */
249     if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY))
250         return -1;
251 
252     lcid =  MAKELCID(search.found_lang_id, SORT_DEFAULT);
253 
254     /* Populate partial locale, translating LCID to locale string elements */
255     if (!(search.match_flags & FOUND_CODEPAGE)) {
256         /* Even if a codepage is not enumerated for a locale
257          * it can be set if valid */
258         if (search.search_codepage[0]) {
259             if (IsValidCodePage(atoi(search.search_codepage)))
260                 memcpy(search.found_codepage,search.search_codepage,MAX_ELEM_LEN);
261             else {
262                 /* Special codepage values: OEM & ANSI */
263                 if (!strcasecmp(search.search_codepage,"OCP")) {
264                     GetLocaleInfoA(lcid, LOCALE_IDEFAULTCODEPAGE,
265                             search.found_codepage, MAX_ELEM_LEN);
266                 } else if (!strcasecmp(search.search_codepage,"ACP")) {
267                     GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE,
268                             search.found_codepage, MAX_ELEM_LEN);
269                 } else
270                     return -1;
271 
272                 if (!atoi(search.found_codepage))
273                     return -1;
274             }
275         } else {
276             /* Prefer ANSI codepages if present */
277             GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE,
278                     search.found_codepage, MAX_ELEM_LEN);
279             if (!search.found_codepage[0] || !atoi(search.found_codepage))
280                 GetLocaleInfoA(lcid, LOCALE_IDEFAULTCODEPAGE,
281                         search.found_codepage, MAX_ELEM_LEN);
282         }
283     }
284     if (codepage)
285         *codepage = atoi(search.found_codepage);
286 
287     return lcid;
288 }
289 
290 /* INTERNAL: Set lc_handle, lc_id and lc_category in threadlocinfo struct */
update_threadlocinfo_category(LCID lcid,unsigned short cp,MSVCRT__locale_t loc,int category)291 static BOOL update_threadlocinfo_category(LCID lcid, unsigned short cp,
292         MSVCRT__locale_t loc, int category)
293 {
294     char buf[256], *p;
295     int len;
296 
297     if(GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_NOUSEROVERRIDE, buf, 256)) {
298         p = buf;
299 
300         loc->locinfo->lc_id[category].wLanguage = 0;
301         while(*p) {
302             loc->locinfo->lc_id[category].wLanguage *= 16;
303 
304             if(*p <= '9')
305                 loc->locinfo->lc_id[category].wLanguage += *p-'0';
306             else
307                 loc->locinfo->lc_id[category].wLanguage += *p-'a'+10;
308 
309             p++;
310         }
311 
312         loc->locinfo->lc_id[category].wCountry =
313             loc->locinfo->lc_id[category].wLanguage;
314     }
315 
316     loc->locinfo->lc_id[category].wCodePage = cp;
317 
318     loc->locinfo->lc_handle[category] = lcid;
319 
320     len = 0;
321     len += GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE
322             |LOCALE_NOUSEROVERRIDE, buf, 256);
323     buf[len-1] = '_';
324     len += GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY
325             |LOCALE_NOUSEROVERRIDE, &buf[len], 256-len);
326     buf[len-1] = '.';
327     sprintf(buf+len, "%u", cp);
328     len += strlen(buf+len)+1;
329 
330     loc->locinfo->lc_category[category].locale = MSVCRT_malloc(len);
331     loc->locinfo->lc_category[category].refcount = MSVCRT_malloc(sizeof(int));
332     if(!loc->locinfo->lc_category[category].locale
333             || !loc->locinfo->lc_category[category].refcount) {
334         MSVCRT_free(loc->locinfo->lc_category[category].locale);
335         MSVCRT_free(loc->locinfo->lc_category[category].refcount);
336         loc->locinfo->lc_category[category].locale = NULL;
337         loc->locinfo->lc_category[category].refcount = NULL;
338         return TRUE;
339     }
340     memcpy(loc->locinfo->lc_category[category].locale, buf, len);
341     *loc->locinfo->lc_category[category].refcount = 1;
342 
343     return FALSE;
344 }
345 
346 /* INTERNAL: swap pointers values */
swap_pointers(void ** p1,void ** p2)347 static inline void swap_pointers(void **p1, void **p2) {
348     void *hlp;
349 
350     hlp = *p1;
351     *p1 = *p2;
352     *p2 = hlp;
353 }
354 
355 /* INTERNAL: returns pthreadlocinfo struct */
get_locinfo(void)356 MSVCRT_pthreadlocinfo get_locinfo(void) {
357     thread_data_t *data = msvcrt_get_thread_data();
358 
359     if(!data || !data->have_locale)
360         return MSVCRT_locale->locinfo;
361 
362     return data->locinfo;
363 }
364 
365 /* INTERNAL: returns pthreadlocinfo struct */
get_mbcinfo(void)366 MSVCRT_pthreadmbcinfo get_mbcinfo(void) {
367     thread_data_t *data = msvcrt_get_thread_data();
368 
369     if(!data || !data->have_locale)
370         return MSVCRT_locale->mbcinfo;
371 
372     return data->mbcinfo;
373 }
374 
375 /* INTERNAL: constructs string returned by setlocale */
construct_lc_all(MSVCRT_pthreadlocinfo locinfo)376 static inline char* construct_lc_all(MSVCRT_pthreadlocinfo locinfo) {
377     static char current_lc_all[MAX_LOCALE_LENGTH];
378 
379     int i;
380 
381     for(i=MSVCRT_LC_MIN+1; i<MSVCRT_LC_MAX; i++) {
382         if(strcmp(locinfo->lc_category[i].locale,
383                     locinfo->lc_category[i+1].locale))
384             break;
385     }
386 
387     if(i==MSVCRT_LC_MAX)
388         return locinfo->lc_category[MSVCRT_LC_COLLATE].locale;
389 
390     sprintf(current_lc_all,
391             "LC_COLLATE=%s;LC_CTYPE=%s;LC_MONETARY=%s;LC_NUMERIC=%s;LC_TIME=%s",
392             locinfo->lc_category[MSVCRT_LC_COLLATE].locale,
393             locinfo->lc_category[MSVCRT_LC_CTYPE].locale,
394             locinfo->lc_category[MSVCRT_LC_MONETARY].locale,
395             locinfo->lc_category[MSVCRT_LC_NUMERIC].locale,
396             locinfo->lc_category[MSVCRT_LC_TIME].locale);
397 
398     return current_lc_all;
399 }
400 
401 
402 /*********************************************************************
403  *		wsetlocale (MSVCRT.@)
404  */
_wsetlocale(int category,const wchar_t * locale)405 wchar_t* CDECL _wsetlocale(int category, const wchar_t* locale)
406 {
407   static wchar_t fake[] = {
408     'E','n','g','l','i','s','h','_','U','n','i','t','e','d',' ',
409     'S','t','a','t','e','s','.','1','2','5','2',0 };
410 
411   FIXME("%d %s\n", category, debugstr_w(locale));
412 
413   return fake;
414 }
415 
416 /*********************************************************************
417  *		_Getdays (MSVCRT.@)
418  */
_Getdays(void)419 char* CDECL _Getdays(void)
420 {
421     MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr;
422     int i, len, size;
423     char *out;
424 
425     TRACE("\n");
426 
427     size = cur->str.names.short_mon[0]-cur->str.names.short_wday[0];
428     out = MSVCRT_malloc(size+1);
429     if(!out)
430         return NULL;
431 
432     size = 0;
433     for(i=0; i<7; i++) {
434         out[size++] = ':';
435         len = strlen(cur->str.names.short_wday[i]);
436         memcpy(&out[size], cur->str.names.short_wday[i], len);
437         size += len;
438 
439         out[size++] = ':';
440         len = strlen(cur->str.names.wday[i]);
441         memcpy(&out[size], cur->str.names.wday[i], len);
442         size += len;
443     }
444     out[size] = '\0';
445 
446     return out;
447 }
448 
449 /*********************************************************************
450  *		_Getmonths (MSVCRT.@)
451  */
_Getmonths(void)452 char* CDECL _Getmonths(void)
453 {
454     MSVCRT___lc_time_data *cur = get_locinfo()->lc_time_curr;
455     int i, len, size;
456     char *out;
457 
458     TRACE("\n");
459 
460     size = cur->str.names.am-cur->str.names.short_mon[0];
461     out = MSVCRT_malloc(size+1);
462     if(!out)
463         return NULL;
464 
465     size = 0;
466     for(i=0; i<12; i++) {
467         out[size++] = ':';
468         len = strlen(cur->str.names.short_mon[i]);
469         memcpy(&out[size], cur->str.names.short_mon[i], len);
470         size += len;
471 
472         out[size++] = ':';
473         len = strlen(cur->str.names.mon[i]);
474         memcpy(&out[size], cur->str.names.mon[i], len);
475         size += len;
476     }
477     out[size] = '\0';
478 
479     return out;
480 }
481 
482 /*********************************************************************
483  *		_Gettnames (MSVCRT.@)
484  */
_Gettnames(void)485 void* CDECL _Gettnames(void)
486 {
487     MSVCRT___lc_time_data *ret, *cur = get_locinfo()->lc_time_curr;
488     unsigned int i, size = sizeof(MSVCRT___lc_time_data);
489 
490     TRACE("\n");
491 
492     for(i=0; i<sizeof(cur->str.str)/sizeof(cur->str.str[0]); i++)
493         size += strlen(cur->str.str[i])+1;
494 
495     ret = MSVCRT_malloc(size);
496     if(!ret)
497         return NULL;
498     memcpy(ret, cur, size);
499 
500     size = 0;
501     for(i=0; i<sizeof(cur->str.str)/sizeof(cur->str.str[0]); i++) {
502         ret->str.str[i] = &ret->data[size];
503         size += strlen(&ret->data[size])+1;
504     }
505 
506     return ret;
507 }
508 
509 /*********************************************************************
510  *		__crtLCMapStringA (MSVCRT.@)
511  */
__crtLCMapStringA(LCID lcid,DWORD mapflags,const char * src,int srclen,char * dst,int dstlen,unsigned int codepage,int xflag)512 int CDECL __crtLCMapStringA(
513   LCID lcid, DWORD mapflags, const char* src, int srclen, char* dst,
514   int dstlen, unsigned int codepage, int xflag
515 ) {
516   FIXME("(lcid %x, flags %x, %s(%d), %p(%d), %x, %d), partial stub!\n",
517         lcid,mapflags,src,srclen,dst,dstlen,codepage,xflag);
518   /* FIXME: A bit incorrect. But msvcrt itself just converts its
519    * arguments to wide strings and then calls LCMapStringW
520    */
521   return LCMapStringA(lcid,mapflags,src,srclen,dst,dstlen);
522 }
523 
524 /*********************************************************************
525  *              __crtLCMapStringW (MSVCRT.@)
526  */
__crtLCMapStringW(LCID lcid,DWORD mapflags,const wchar_t * src,int srclen,wchar_t * dst,int dstlen,unsigned int codepage,int xflag)527 int CDECL __crtLCMapStringW(LCID lcid, DWORD mapflags, const wchar_t *src,
528         int srclen, wchar_t *dst, int dstlen, unsigned int codepage, int xflag)
529 {
530     FIXME("(lcid %x, flags %x, %s(%d), %p(%d), %x, %d), partial stub!\n",
531             lcid, mapflags, debugstr_w(src), srclen, dst, dstlen, codepage, xflag);
532 
533     return LCMapStringW(lcid, mapflags, src, srclen, dst, dstlen);
534 }
535 
536 /*********************************************************************
537  *		__crtCompareStringA (MSVCRT.@)
538  */
__crtCompareStringA(LCID lcid,DWORD flags,const char * src1,int len1,const char * src2,int len2)539 int CDECL __crtCompareStringA( LCID lcid, DWORD flags, const char *src1, int len1,
540                                const char *src2, int len2 )
541 {
542     FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n",
543           lcid, flags, debugstr_a(src1), len1, debugstr_a(src2), len2 );
544     /* FIXME: probably not entirely right */
545     return CompareStringA( lcid, flags, src1, len1, src2, len2 );
546 }
547 
548 /*********************************************************************
549  *		__crtCompareStringW (MSVCRT.@)
550  */
__crtCompareStringW(LCID lcid,DWORD flags,const wchar_t * src1,int len1,const wchar_t * src2,int len2)551 int CDECL __crtCompareStringW( LCID lcid, DWORD flags, const wchar_t *src1, int len1,
552                                const wchar_t *src2, int len2 )
553 {
554     FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n",
555           lcid, flags, debugstr_w(src1), len1, debugstr_w(src2), len2 );
556     /* FIXME: probably not entirely right */
557     return CompareStringW( lcid, flags, src1, len1, src2, len2 );
558 }
559 
560 /*********************************************************************
561  *		__crtGetLocaleInfoW (MSVCRT.@)
562  */
__crtGetLocaleInfoW(LCID lcid,LCTYPE type,wchar_t * buffer,int len)563 int CDECL __crtGetLocaleInfoW( LCID lcid, LCTYPE type, wchar_t *buffer, int len )
564 {
565     FIXME("(lcid %x, type %x, %p(%d), partial stub\n", lcid, type, buffer, len );
566     /* FIXME: probably not entirely right */
567     return GetLocaleInfoW( lcid, type, buffer, len );
568 }
569 
570 /*********************************************************************
571  *              btowc(MSVCRT.@)
572  */
MSVCRT_btowc(int c)573 wint_t CDECL MSVCRT_btowc(int c)
574 {
575     unsigned char letter = c;
576     wchar_t ret;
577 
578     if(!MultiByteToWideChar(get_locinfo()->lc_handle[LC_CTYPE],
579                 0, (LPCSTR)&letter, 1, &ret, 1))
580         return 0;
581 
582     return ret;
583 }
584 
585 /*********************************************************************
586  *              __crtGetStringTypeW(MSVCRT.@)
587  *
588  * This function was accepting different number of arguments in older
589  * versions of msvcrt.
590  */
__crtGetStringTypeW(DWORD unk,DWORD type,wchar_t * buffer,int len,WORD * out)591 BOOL CDECL __crtGetStringTypeW(DWORD unk, DWORD type,
592         wchar_t *buffer, int len, WORD *out)
593 {
594     FIXME("(unk %x, type %x, wstr %p(%d), %p) partial stub\n",
595             unk, type, buffer, len, out);
596 
597     return GetStringTypeW(type, buffer, len, out);
598 }
599 
600 /*********************************************************************
601  *		localeconv (MSVCRT.@)
602  */
localeconv(void)603 struct lconv * CDECL localeconv(void)
604 {
605     return (struct lconv*)get_locinfo()->lconv;
606 }
607 
608 /*********************************************************************
609  *		__lconv_init (MSVCRT.@)
610  */
__lconv_init(void)611 int CDECL __lconv_init(void)
612 {
613     /* this is used to make chars unsigned */
614     charmax = 255;
615     return 0;
616 }
617 
618 /*********************************************************************
619  *      ___lc_handle_func (MSVCRT.@)
620  */
___lc_handle_func(void)621 LCID* CDECL ___lc_handle_func(void)
622 {
623     return MSVCRT___lc_handle;
624 }
625 
626 /*********************************************************************
627  *      ___lc_codepage_func (MSVCRT.@)
628  */
___lc_codepage_func(void)629 unsigned int CDECL ___lc_codepage_func(void)
630 {
631     return __lc_codepage;
632 }
633 
634 /*********************************************************************
635  *      ___lc_collate_cp_func (MSVCRT.@)
636  */
___lc_collate_cp_func(void)637 unsigned int CDECL ___lc_collate_cp_func(void)
638 {
639     return get_locinfo()->lc_collate_cp;
640 }
641 
642 /* INTERNAL: frees MSVCRT_pthreadlocinfo struct */
free_locinfo(MSVCRT_pthreadlocinfo locinfo)643 void free_locinfo(MSVCRT_pthreadlocinfo locinfo)
644 {
645     int i;
646 
647     if(!locinfo)
648         return;
649 
650     if(InterlockedDecrement(&locinfo->refcount))
651         return;
652 
653     for(i=MSVCRT_LC_MIN+1; i<=MSVCRT_LC_MAX; i++) {
654         MSVCRT_free(locinfo->lc_category[i].locale);
655         MSVCRT_free(locinfo->lc_category[i].refcount);
656     }
657 
658     if(locinfo->lconv) {
659         MSVCRT_free(locinfo->lconv->decimal_point);
660         MSVCRT_free(locinfo->lconv->thousands_sep);
661         MSVCRT_free(locinfo->lconv->grouping);
662         MSVCRT_free(locinfo->lconv->int_curr_symbol);
663         MSVCRT_free(locinfo->lconv->currency_symbol);
664         MSVCRT_free(locinfo->lconv->mon_decimal_point);
665         MSVCRT_free(locinfo->lconv->mon_thousands_sep);
666         MSVCRT_free(locinfo->lconv->mon_grouping);
667         MSVCRT_free(locinfo->lconv->positive_sign);
668         MSVCRT_free(locinfo->lconv->negative_sign);
669     }
670     MSVCRT_free(locinfo->lconv_intl_refcount);
671     MSVCRT_free(locinfo->lconv_num_refcount);
672     MSVCRT_free(locinfo->lconv_mon_refcount);
673     MSVCRT_free(locinfo->lconv);
674 
675     MSVCRT_free(locinfo->ctype1_refcount);
676     MSVCRT_free(locinfo->ctype1);
677 
678     MSVCRT_free(locinfo->pclmap);
679     MSVCRT_free(locinfo->pcumap);
680 
681     MSVCRT_free(locinfo->lc_time_curr);
682 
683     MSVCRT_free(locinfo);
684 }
685 
686 /* INTERNAL: frees MSVCRT_pthreadmbcinfo struct */
free_mbcinfo(MSVCRT_pthreadmbcinfo mbcinfo)687 void free_mbcinfo(MSVCRT_pthreadmbcinfo mbcinfo)
688 {
689     if(!mbcinfo)
690         return;
691 
692     if(InterlockedDecrement(&mbcinfo->refcount))
693         return;
694 
695     MSVCRT_free(mbcinfo);
696 }
697 
698 /* _get_current_locale - not exported in native msvcrt */
MSVCRT__get_current_locale(void)699 MSVCRT__locale_t CDECL MSVCRT__get_current_locale(void)
700 {
701     MSVCRT__locale_t loc = MSVCRT_malloc(sizeof(MSVCRT__locale_tstruct));
702     if(!loc)
703         return NULL;
704 
705     loc->locinfo = get_locinfo();
706     loc->mbcinfo = get_mbcinfo();
707     InterlockedIncrement(&loc->locinfo->refcount);
708     InterlockedIncrement(&loc->mbcinfo->refcount);
709     return loc;
710 }
711 
712 /* _free_locale - not exported in native msvcrt */
MSVCRT__free_locale(MSVCRT__locale_t locale)713 void CDECL MSVCRT__free_locale(MSVCRT__locale_t locale)
714 {
715     if (!locale)
716         return;
717 
718     free_locinfo(locale->locinfo);
719     free_mbcinfo(locale->mbcinfo);
720     MSVCRT_free(locale);
721 }
722 
723 /* _create_locale - not exported in native msvcrt */
MSVCRT__create_locale(int category,const char * locale)724 MSVCRT__locale_t CDECL MSVCRT__create_locale(int category, const char *locale)
725 {
726     static const DWORD time_data[] = {
727         LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
728         LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
729         LOCALE_SABBREVDAYNAME6,
730         LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
731         LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6,
732         LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
733         LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
734         LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
735         LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
736         LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
737         LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
738         LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
739         LOCALE_S1159, LOCALE_S2359,
740         LOCALE_SSHORTDATE, LOCALE_SLONGDATE,
741         LOCALE_STIMEFORMAT
742     };
743     static const char collate[] = "COLLATE=";
744     static const char ctype[] = "CTYPE=";
745     static const char monetary[] = "MONETARY=";
746     static const char numeric[] = "NUMERIC=";
747     static const char time[] = "TIME=";
748     static const char cloc_short_date[] = "MM/dd/yy";
749     static const wchar_t cloc_short_dateW[] = {'M','M','/','d','d','/','y','y',0};
750     static const char cloc_long_date[] = "dddd, MMMM dd, yyyy";
751     static const wchar_t cloc_long_dateW[] = {'d','d','d','d',',',' ','M','M','M','M',' ','d','d',',',' ','y','y','y','y',0};
752     static const char cloc_time[] = "HH:mm:ss";
753     static const wchar_t cloc_timeW[] = {'H','H',':','m','m',':','s','s',0};
754 
755     MSVCRT__locale_t loc;
756     LCID lcid[6] = { 0 }, lcid_tmp;
757     unsigned short cp[6] = { 0 };
758     char buf[256];
759     int i, ret, size;
760 
761     TRACE("(%d %s)\n", category, locale);
762 
763     if(category<MSVCRT_LC_MIN || category>MSVCRT_LC_MAX || !locale)
764         return NULL;
765 
766     if(locale[0]=='C' && !locale[1]) {
767         lcid[0] = 0;
768         cp[0] = CP_ACP;
769     } else if(!locale[0]) {
770         lcid[0] = GetSystemDefaultLCID();
771         GetLocaleInfoA(lcid[0], LOCALE_IDEFAULTANSICODEPAGE
772                 |LOCALE_NOUSEROVERRIDE, buf, sizeof(buf));
773         cp[0] = atoi(buf);
774 
775         for(i=1; i<6; i++) {
776             lcid[i] = lcid[0];
777             cp[i] = cp[0];
778         }
779     } else if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') {
780         const char *p;
781 
782         while(1) {
783             locale += 3; /* LC_ */
784             if(!memcmp(locale, collate, sizeof(collate)-1)) {
785                 i = MSVCRT_LC_COLLATE;
786                 locale += sizeof(collate)-1;
787             } else if(!memcmp(locale, ctype, sizeof(ctype)-1)) {
788                 i = MSVCRT_LC_CTYPE;
789                 locale += sizeof(ctype)-1;
790             } else if(!memcmp(locale, monetary, sizeof(monetary)-1)) {
791                 i = MSVCRT_LC_MONETARY;
792                 locale += sizeof(monetary)-1;
793             } else if(!memcmp(locale, numeric, sizeof(numeric)-1)) {
794                 i = MSVCRT_LC_NUMERIC;
795                 locale += sizeof(numeric)-1;
796             } else if(!memcmp(locale, time, sizeof(time)-1)) {
797                 i = MSVCRT_LC_TIME;
798                 locale += sizeof(time)-1;
799             } else
800                 return NULL;
801 
802             p = strchr(locale, ';');
803             if(locale[0]=='C' && (locale[1]==';' || locale[1]=='\0')) {
804                 lcid[i] = 0;
805                 cp[i] = CP_ACP;
806             } else if(p) {
807                 memcpy(buf, locale, p-locale);
808                 buf[p-locale] = '\0';
809                 lcid[i] = MSVCRT_locale_to_LCID(buf, &cp[i]);
810             } else
811                 lcid[i] = MSVCRT_locale_to_LCID(locale, &cp[i]);
812 
813             if(lcid[i] == -1)
814                 return NULL;
815 
816             if(!p || *(p+1)!='L' || *(p+2)!='C' || *(p+3)!='_')
817                 break;
818 
819             locale = p+1;
820         }
821     } else {
822         lcid[0] = MSVCRT_locale_to_LCID(locale, &cp[0]);
823         if(lcid[0] == -1)
824             return NULL;
825 
826         for(i=1; i<6; i++) {
827             lcid[i] = lcid[0];
828             cp[i] = cp[0];
829         }
830     }
831 
832     loc = MSVCRT_malloc(sizeof(MSVCRT__locale_tstruct));
833     if(!loc)
834         return NULL;
835 
836     loc->locinfo = MSVCRT_malloc(sizeof(MSVCRT_threadlocinfo));
837     if(!loc->locinfo) {
838         MSVCRT_free(loc);
839         return NULL;
840     }
841 
842     loc->mbcinfo = MSVCRT_malloc(sizeof(MSVCRT_threadmbcinfo));
843     if(!loc->mbcinfo) {
844         MSVCRT_free(loc->locinfo);
845         MSVCRT_free(loc);
846         return NULL;
847     }
848 
849     memset(loc->locinfo, 0, sizeof(MSVCRT_threadlocinfo));
850     loc->locinfo->refcount = 1;
851     loc->mbcinfo->refcount = 1;
852 
853     loc->locinfo->lconv = MSVCRT_malloc(sizeof(struct MSVCRT_lconv));
854     if(!loc->locinfo->lconv) {
855         MSVCRT__free_locale(loc);
856         return NULL;
857     }
858     memset(loc->locinfo->lconv, 0, sizeof(struct MSVCRT_lconv));
859 
860     loc->locinfo->pclmap = MSVCRT_malloc(sizeof(char[256]));
861     loc->locinfo->pcumap = MSVCRT_malloc(sizeof(char[256]));
862     if(!loc->locinfo->pclmap || !loc->locinfo->pcumap) {
863         MSVCRT__free_locale(loc);
864         return NULL;
865     }
866 
867     if(lcid[MSVCRT_LC_COLLATE] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_COLLATE)) {
868         if(update_threadlocinfo_category(lcid[MSVCRT_LC_COLLATE], cp[MSVCRT_LC_COLLATE], loc, MSVCRT_LC_COLLATE)) {
869             MSVCRT__free_locale(loc);
870             return NULL;
871         }
872 
873         loc->locinfo->lc_collate_cp = loc->locinfo->lc_id[MSVCRT_LC_COLLATE].wCodePage;
874     } else
875         loc->locinfo->lc_category[LC_COLLATE].locale = _strdup("C");
876 
877     if(lcid[MSVCRT_LC_CTYPE] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_CTYPE)) {
878         CPINFO cp_info;
879         int j;
880 
881         if(update_threadlocinfo_category(lcid[MSVCRT_LC_CTYPE], cp[MSVCRT_LC_CTYPE], loc, MSVCRT_LC_CTYPE)) {
882             MSVCRT__free_locale(loc);
883             return NULL;
884         }
885 
886         loc->locinfo->lc_codepage = loc->locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage;
887         loc->locinfo->lc_clike = 1;
888         if(!GetCPInfo(loc->locinfo->lc_codepage, &cp_info)) {
889             MSVCRT__free_locale(loc);
890             return NULL;
891         }
892         loc->locinfo->mb_cur_max = cp_info.MaxCharSize;
893 
894         loc->locinfo->ctype1_refcount = MSVCRT_malloc(sizeof(int));
895         loc->locinfo->ctype1 = MSVCRT_malloc(sizeof(short[257]));
896         if(!loc->locinfo->ctype1_refcount || !loc->locinfo->ctype1) {
897             MSVCRT__free_locale(loc);
898             return NULL;
899         }
900 
901         *loc->locinfo->ctype1_refcount = 1;
902         loc->locinfo->ctype1[0] = 0;
903         loc->locinfo->pctype = loc->locinfo->ctype1+1;
904 
905         buf[1] = buf[2] = '\0';
906         for(i=1; i<257; i++) {
907             buf[0] = i-1;
908 
909             /* builtin GetStringTypeA doesn't set output to 0 on invalid input */
910             loc->locinfo->ctype1[i] = 0;
911 
912             GetStringTypeA(lcid[MSVCRT_LC_CTYPE], CT_CTYPE1, buf,
913                     1, loc->locinfo->ctype1+i);
914         }
915 
916         for(i=0; cp_info.LeadByte[i+1]!=0; i+=2)
917             for(j=cp_info.LeadByte[i]; j<=cp_info.LeadByte[i+1]; j++)
918                 loc->locinfo->ctype1[j+1] |= _LEADBYTE;
919     } else {
920         loc->locinfo->lc_clike = 1;
921         loc->locinfo->mb_cur_max = 1;
922         loc->locinfo->pctype = _ctype+1;
923         loc->locinfo->lc_category[LC_CTYPE].locale = _strdup("C");
924     }
925 
926     for(i=0; i<256; i++) {
927         if(loc->locinfo->pctype[i] & _LEADBYTE)
928             buf[i] = ' ';
929         else
930             buf[i] = i;
931 
932     }
933 
934     if(lcid[MSVCRT_LC_CTYPE]) {
935         LCMapStringA(lcid[MSVCRT_LC_CTYPE], LCMAP_LOWERCASE, buf, 256,
936                 (char*)loc->locinfo->pclmap, 256);
937         LCMapStringA(lcid[MSVCRT_LC_CTYPE], LCMAP_UPPERCASE, buf, 256,
938                 (char*)loc->locinfo->pcumap, 256);
939     } else {
940         for(i=0; i<256; i++) {
941             loc->locinfo->pclmap[i] = (i>='A' && i<='Z' ? i-'A'+'a' : i);
942             loc->locinfo->pcumap[i] = (i>='a' && i<='z' ? i-'a'+'A' : i);
943         }
944     }
945 
946     _setmbcp_l(loc->locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage, lcid[MSVCRT_LC_CTYPE], loc->mbcinfo);
947 
948     if(lcid[MSVCRT_LC_MONETARY] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_MONETARY)) {
949         if(update_threadlocinfo_category(lcid[MSVCRT_LC_MONETARY], cp[MSVCRT_LC_MONETARY], loc, MSVCRT_LC_MONETARY)) {
950             MSVCRT__free_locale(loc);
951             return NULL;
952         }
953 
954         loc->locinfo->lconv_intl_refcount = MSVCRT_malloc(sizeof(int));
955         loc->locinfo->lconv_mon_refcount = MSVCRT_malloc(sizeof(int));
956         if(!loc->locinfo->lconv_intl_refcount || !loc->locinfo->lconv_mon_refcount) {
957             MSVCRT__free_locale(loc);
958             return NULL;
959         }
960 
961         *loc->locinfo->lconv_intl_refcount = 1;
962         *loc->locinfo->lconv_mon_refcount = 1;
963 
964         i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SINTLSYMBOL
965                 |LOCALE_NOUSEROVERRIDE, buf, 256);
966         if(i && (loc->locinfo->lconv->int_curr_symbol = MSVCRT_malloc(i)))
967             memcpy(loc->locinfo->lconv->int_curr_symbol, buf, i);
968         else {
969             MSVCRT__free_locale(loc);
970             return NULL;
971         }
972 
973         i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SCURRENCY
974                 |LOCALE_NOUSEROVERRIDE, buf, 256);
975         if(i && (loc->locinfo->lconv->currency_symbol = MSVCRT_malloc(i)))
976             memcpy(loc->locinfo->lconv->currency_symbol, buf, i);
977         else {
978             MSVCRT__free_locale(loc);
979             return NULL;
980         }
981 
982         i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONDECIMALSEP
983                 |LOCALE_NOUSEROVERRIDE, buf, 256);
984         if(i && (loc->locinfo->lconv->mon_decimal_point = MSVCRT_malloc(i)))
985             memcpy(loc->locinfo->lconv->mon_decimal_point, buf, i);
986         else {
987             MSVCRT__free_locale(loc);
988             return NULL;
989         }
990 
991         i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONTHOUSANDSEP
992                 |LOCALE_NOUSEROVERRIDE, buf, 256);
993         if(i && (loc->locinfo->lconv->mon_thousands_sep = MSVCRT_malloc(i)))
994             memcpy(loc->locinfo->lconv->mon_thousands_sep, buf, i);
995         else {
996             MSVCRT__free_locale(loc);
997             return NULL;
998         }
999 
1000         i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SMONGROUPING
1001                 |LOCALE_NOUSEROVERRIDE, buf, 256);
1002         if(i>1)
1003             i = i/2 + (buf[i-2]=='0'?0:1);
1004         if(i && (loc->locinfo->lconv->mon_grouping = MSVCRT_malloc(i))) {
1005             for(i=0; buf[i+1]==';'; i+=2)
1006                 loc->locinfo->lconv->mon_grouping[i/2] = buf[i]-'0';
1007             loc->locinfo->lconv->mon_grouping[i/2] = buf[i]-'0';
1008             if(buf[i] != '0')
1009                 loc->locinfo->lconv->mon_grouping[i/2+1] = 127;
1010         } else {
1011             MSVCRT__free_locale(loc);
1012             return NULL;
1013         }
1014 
1015         i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SPOSITIVESIGN
1016                 |LOCALE_NOUSEROVERRIDE, buf, 256);
1017         if(i && (loc->locinfo->lconv->positive_sign = MSVCRT_malloc(i)))
1018             memcpy(loc->locinfo->lconv->positive_sign, buf, i);
1019         else {
1020             MSVCRT__free_locale(loc);
1021             return NULL;
1022         }
1023 
1024         i = GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_SNEGATIVESIGN
1025                 |LOCALE_NOUSEROVERRIDE, buf, 256);
1026         if(i && (loc->locinfo->lconv->negative_sign = MSVCRT_malloc(i)))
1027             memcpy(loc->locinfo->lconv->negative_sign, buf, i);
1028         else {
1029             MSVCRT__free_locale(loc);
1030             return NULL;
1031         }
1032 
1033         if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IINTLCURRDIGITS
1034                     |LOCALE_NOUSEROVERRIDE, buf, 256))
1035             loc->locinfo->lconv->int_frac_digits = atoi(buf);
1036         else {
1037             MSVCRT__free_locale(loc);
1038             return NULL;
1039         }
1040 
1041         if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_ICURRDIGITS
1042                     |LOCALE_NOUSEROVERRIDE, buf, 256))
1043             loc->locinfo->lconv->frac_digits = atoi(buf);
1044         else {
1045             MSVCRT__free_locale(loc);
1046             return NULL;
1047         }
1048 
1049         if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSYMPRECEDES
1050                     |LOCALE_NOUSEROVERRIDE, buf, 256))
1051             loc->locinfo->lconv->p_cs_precedes = atoi(buf);
1052         else {
1053             MSVCRT__free_locale(loc);
1054             return NULL;
1055         }
1056 
1057         if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSEPBYSPACE
1058                     |LOCALE_NOUSEROVERRIDE, buf, 256))
1059             loc->locinfo->lconv->p_sep_by_space = atoi(buf);
1060         else {
1061             MSVCRT__free_locale(loc);
1062             return NULL;
1063         }
1064 
1065         if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSYMPRECEDES
1066                     |LOCALE_NOUSEROVERRIDE, buf, 256))
1067             loc->locinfo->lconv->n_cs_precedes = atoi(buf);
1068         else {
1069             MSVCRT__free_locale(loc);
1070             return NULL;
1071         }
1072 
1073         if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSEPBYSPACE
1074                     |LOCALE_NOUSEROVERRIDE, buf, 256))
1075             loc->locinfo->lconv->n_sep_by_space = atoi(buf);
1076         else {
1077             MSVCRT__free_locale(loc);
1078             return NULL;
1079         }
1080 
1081         if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_IPOSSIGNPOSN
1082                     |LOCALE_NOUSEROVERRIDE, buf, 256))
1083             loc->locinfo->lconv->p_sign_posn = atoi(buf);
1084         else {
1085             MSVCRT__free_locale(loc);
1086             return NULL;
1087         }
1088 
1089         if(GetLocaleInfoA(lcid[MSVCRT_LC_MONETARY], LOCALE_INEGSIGNPOSN
1090                     |LOCALE_NOUSEROVERRIDE, buf, 256))
1091             loc->locinfo->lconv->n_sign_posn = atoi(buf);
1092         else {
1093             MSVCRT__free_locale(loc);
1094             return NULL;
1095         }
1096     } else {
1097         loc->locinfo->lconv->int_curr_symbol = MSVCRT_malloc(sizeof(char));
1098         loc->locinfo->lconv->currency_symbol = MSVCRT_malloc(sizeof(char));
1099         loc->locinfo->lconv->mon_decimal_point = MSVCRT_malloc(sizeof(char));
1100         loc->locinfo->lconv->mon_thousands_sep = MSVCRT_malloc(sizeof(char));
1101         loc->locinfo->lconv->mon_grouping = MSVCRT_malloc(sizeof(char));
1102         loc->locinfo->lconv->positive_sign = MSVCRT_malloc(sizeof(char));
1103         loc->locinfo->lconv->negative_sign = MSVCRT_malloc(sizeof(char));
1104 
1105         if(!loc->locinfo->lconv->int_curr_symbol || !loc->locinfo->lconv->currency_symbol
1106                 || !loc->locinfo->lconv->mon_decimal_point || !loc->locinfo->lconv->mon_thousands_sep
1107                 || !loc->locinfo->lconv->mon_grouping || !loc->locinfo->lconv->positive_sign
1108                 || !loc->locinfo->lconv->negative_sign) {
1109             MSVCRT__free_locale(loc);
1110             return NULL;
1111         }
1112 
1113         loc->locinfo->lconv->int_curr_symbol[0] = '\0';
1114         loc->locinfo->lconv->currency_symbol[0] = '\0';
1115         loc->locinfo->lconv->mon_decimal_point[0] = '\0';
1116         loc->locinfo->lconv->mon_thousands_sep[0] = '\0';
1117         loc->locinfo->lconv->mon_grouping[0] = '\0';
1118         loc->locinfo->lconv->positive_sign[0] = '\0';
1119         loc->locinfo->lconv->negative_sign[0] = '\0';
1120         loc->locinfo->lconv->int_frac_digits = 127;
1121         loc->locinfo->lconv->frac_digits = 127;
1122         loc->locinfo->lconv->p_cs_precedes = 127;
1123         loc->locinfo->lconv->p_sep_by_space = 127;
1124         loc->locinfo->lconv->n_cs_precedes = 127;
1125         loc->locinfo->lconv->n_sep_by_space = 127;
1126         loc->locinfo->lconv->p_sign_posn = 127;
1127         loc->locinfo->lconv->n_sign_posn = 127;
1128 
1129         loc->locinfo->lc_category[LC_MONETARY].locale = _strdup("C");
1130     }
1131 
1132     if(lcid[MSVCRT_LC_NUMERIC] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_NUMERIC)) {
1133         if(update_threadlocinfo_category(lcid[MSVCRT_LC_NUMERIC], cp[MSVCRT_LC_NUMERIC], loc, MSVCRT_LC_NUMERIC)) {
1134             MSVCRT__free_locale(loc);
1135             return NULL;
1136         }
1137 
1138         if(!loc->locinfo->lconv_intl_refcount)
1139             loc->locinfo->lconv_intl_refcount = MSVCRT_malloc(sizeof(int));
1140         loc->locinfo->lconv_num_refcount = MSVCRT_malloc(sizeof(int));
1141         if(!loc->locinfo->lconv_intl_refcount || !loc->locinfo->lconv_num_refcount) {
1142             MSVCRT__free_locale(loc);
1143             return NULL;
1144         }
1145 
1146         *loc->locinfo->lconv_intl_refcount = 1;
1147         *loc->locinfo->lconv_num_refcount = 1;
1148 
1149         i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_SDECIMAL
1150                 |LOCALE_NOUSEROVERRIDE, buf, 256);
1151         if(i && (loc->locinfo->lconv->decimal_point = MSVCRT_malloc(i)))
1152             memcpy(loc->locinfo->lconv->decimal_point, buf, i);
1153         else {
1154             MSVCRT__free_locale(loc);
1155             return NULL;
1156         }
1157 
1158         i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_STHOUSAND
1159                 |LOCALE_NOUSEROVERRIDE, buf, 256);
1160         if(i && (loc->locinfo->lconv->thousands_sep = MSVCRT_malloc(i)))
1161             memcpy(loc->locinfo->lconv->thousands_sep, buf, i);
1162         else {
1163             MSVCRT__free_locale(loc);
1164             return NULL;
1165         }
1166 
1167         i = GetLocaleInfoA(lcid[MSVCRT_LC_NUMERIC], LOCALE_SGROUPING
1168                 |LOCALE_NOUSEROVERRIDE, buf, 256);
1169         if(i>1)
1170             i = i/2 + (buf[i-2]=='0'?0:1);
1171         if(i && (loc->locinfo->lconv->grouping = MSVCRT_malloc(i))) {
1172             for(i=0; buf[i+1]==';'; i+=2)
1173                 loc->locinfo->lconv->grouping[i/2] = buf[i]-'0';
1174             loc->locinfo->lconv->grouping[i/2] = buf[i]-'0';
1175             if(buf[i] != '0')
1176                 loc->locinfo->lconv->grouping[i/2+1] = 127;
1177         } else {
1178             MSVCRT__free_locale(loc);
1179             return NULL;
1180         }
1181     } else {
1182         loc->locinfo->lconv->decimal_point = MSVCRT_malloc(sizeof(char[2]));
1183         loc->locinfo->lconv->thousands_sep = MSVCRT_malloc(sizeof(char));
1184         loc->locinfo->lconv->grouping = MSVCRT_malloc(sizeof(char));
1185         if(!loc->locinfo->lconv->decimal_point || !loc->locinfo->lconv->thousands_sep
1186                 || !loc->locinfo->lconv->grouping) {
1187             MSVCRT__free_locale(loc);
1188             return NULL;
1189         }
1190 
1191         loc->locinfo->lconv->decimal_point[0] = '.';
1192         loc->locinfo->lconv->decimal_point[1] = '\0';
1193         loc->locinfo->lconv->thousands_sep[0] = '\0';
1194         loc->locinfo->lconv->grouping[0] = '\0';
1195 
1196         loc->locinfo->lc_category[LC_NUMERIC].locale = _strdup("C");
1197     }
1198 
1199     if(lcid[MSVCRT_LC_TIME] && (category==MSVCRT_LC_ALL || category==MSVCRT_LC_TIME)) {
1200         if(update_threadlocinfo_category(lcid[MSVCRT_LC_TIME], cp[MSVCRT_LC_TIME], loc, MSVCRT_LC_TIME)) {
1201             MSVCRT__free_locale(loc);
1202             return NULL;
1203         }
1204     } else
1205         loc->locinfo->lc_category[LC_TIME].locale = _strdup("C");
1206 
1207     size = sizeof(MSVCRT___lc_time_data);
1208     lcid_tmp = lcid[MSVCRT_LC_TIME] ? lcid[MSVCRT_LC_TIME] : MAKELCID(LANG_ENGLISH, SORT_DEFAULT);
1209     for(i=0; i<sizeof(time_data)/sizeof(time_data[0]); i++) {
1210         if(time_data[i]==LOCALE_SSHORTDATE && !lcid[MSVCRT_LC_TIME]) {
1211             size += sizeof(cloc_short_date) + sizeof(cloc_short_dateW);
1212         }else if(time_data[i]==LOCALE_SLONGDATE && !lcid[MSVCRT_LC_TIME]) {
1213             size += sizeof(cloc_long_date) + sizeof(cloc_long_dateW);
1214         }else {
1215             ret = GetLocaleInfoA(lcid_tmp, time_data[i]
1216                     |LOCALE_NOUSEROVERRIDE, NULL, 0);
1217             if(!ret) {
1218                 MSVCRT__free_locale(loc);
1219                 return NULL;
1220             }
1221             size += ret;
1222 
1223             ret = GetLocaleInfoW(lcid_tmp, time_data[i]
1224                     |LOCALE_NOUSEROVERRIDE, NULL, 0);
1225             if(!ret) {
1226                 MSVCRT__free_locale(loc);
1227                 return NULL;
1228             }
1229             size += ret*sizeof(wchar_t);
1230         }
1231     }
1232 
1233     loc->locinfo->lc_time_curr = MSVCRT_malloc(size);
1234     if(!loc->locinfo->lc_time_curr) {
1235         MSVCRT__free_locale(loc);
1236         return NULL;
1237     }
1238 
1239     ret = 0;
1240     for(i=0; i<sizeof(time_data)/sizeof(time_data[0]); i++) {
1241         loc->locinfo->lc_time_curr->str.str[i] = &loc->locinfo->lc_time_curr->data[ret];
1242         if(time_data[i]==LOCALE_SSHORTDATE && !lcid[MSVCRT_LC_TIME]) {
1243             memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_short_date, sizeof(cloc_short_date));
1244             ret += sizeof(cloc_short_date);
1245         }else if(time_data[i]==LOCALE_SLONGDATE && !lcid[MSVCRT_LC_TIME]) {
1246             memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_long_date, sizeof(cloc_long_date));
1247             ret += sizeof(cloc_long_date);
1248         }else if(time_data[i]==LOCALE_STIMEFORMAT && !lcid[MSVCRT_LC_TIME]) {
1249             memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_time, sizeof(cloc_time));
1250             ret += sizeof(cloc_time);
1251         }else {
1252             ret += GetLocaleInfoA(lcid_tmp, time_data[i]|LOCALE_NOUSEROVERRIDE,
1253                     &loc->locinfo->lc_time_curr->data[ret], size-ret);
1254         }
1255     }
1256     for(i=0; i<sizeof(time_data)/sizeof(time_data[0]); i++) {
1257         loc->locinfo->lc_time_curr->wstr[i] = (wchar_t*)&loc->locinfo->lc_time_curr->data[ret];
1258         if(time_data[i]==LOCALE_SSHORTDATE && !lcid[MSVCRT_LC_TIME]) {
1259             memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_short_dateW, sizeof(cloc_short_dateW));
1260             ret += sizeof(cloc_short_dateW);
1261         }else if(time_data[i]==LOCALE_SLONGDATE && !lcid[MSVCRT_LC_TIME]) {
1262             memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_long_dateW, sizeof(cloc_long_dateW));
1263             ret += sizeof(cloc_long_dateW);
1264         }else if(time_data[i]==LOCALE_STIMEFORMAT && !lcid[MSVCRT_LC_TIME]) {            memcpy(&loc->locinfo->lc_time_curr->data[ret], cloc_timeW, sizeof(cloc_timeW));
1265             ret += sizeof(cloc_timeW);
1266         }else {
1267             ret += GetLocaleInfoW(lcid_tmp, time_data[i]|LOCALE_NOUSEROVERRIDE,
1268                     (wchar_t*)&loc->locinfo->lc_time_curr->data[ret], size-ret)*sizeof(wchar_t);
1269         }
1270     }
1271     loc->locinfo->lc_time_curr->lcid = lcid[MSVCRT_LC_TIME];
1272 
1273     return loc;
1274 }
1275 
1276 /*********************************************************************
1277  *             setlocale (MSVCRT.@)
1278  */
setlocale(int category,const char * locale)1279 char* CDECL setlocale(int category, const char* locale)
1280 {
1281     MSVCRT__locale_t loc;
1282     MSVCRT_pthreadlocinfo locinfo = get_locinfo();
1283 
1284     if(category<MSVCRT_LC_MIN || category>MSVCRT_LC_MAX)
1285         return NULL;
1286 
1287     if(!locale) {
1288         if(category == MSVCRT_LC_ALL)
1289             return construct_lc_all(locinfo);
1290 
1291         return locinfo->lc_category[category].locale;
1292     }
1293 
1294     loc = MSVCRT__create_locale(category, locale);
1295     if(!loc) {
1296         WARN("%d %s failed\n", category, locale);
1297         return NULL;
1298     }
1299 
1300     LOCK_LOCALE;
1301 
1302     switch(category) {
1303         case MSVCRT_LC_ALL:
1304         case MSVCRT_LC_COLLATE:
1305             locinfo->lc_collate_cp = loc->locinfo->lc_collate_cp;
1306             locinfo->lc_handle[MSVCRT_LC_COLLATE] =
1307                 loc->locinfo->lc_handle[MSVCRT_LC_COLLATE];
1308             swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_COLLATE].locale,
1309                     (void**)&loc->locinfo->lc_category[MSVCRT_LC_COLLATE].locale);
1310             swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_COLLATE].refcount,
1311                     (void**)&loc->locinfo->lc_category[MSVCRT_LC_COLLATE].refcount);
1312 
1313             if(category != MSVCRT_LC_ALL)
1314                 break;
1315             /* fall through */
1316         case MSVCRT_LC_CTYPE:
1317             locinfo->lc_handle[MSVCRT_LC_CTYPE] =
1318                 loc->locinfo->lc_handle[MSVCRT_LC_CTYPE];
1319             swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_CTYPE].locale,
1320                     (void**)&loc->locinfo->lc_category[MSVCRT_LC_CTYPE].locale);
1321             swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_CTYPE].refcount,
1322                     (void**)&loc->locinfo->lc_category[MSVCRT_LC_CTYPE].refcount);
1323 
1324             locinfo->lc_codepage = loc->locinfo->lc_codepage;
1325             locinfo->lc_clike = loc->locinfo->lc_clike;
1326             locinfo->mb_cur_max = loc->locinfo->mb_cur_max;
1327 
1328             swap_pointers((void**)&locinfo->ctype1_refcount,
1329                     (void**)&loc->locinfo->ctype1_refcount);
1330             swap_pointers((void**)&locinfo->ctype1, (void**)&loc->locinfo->ctype1);
1331             swap_pointers((void**)&locinfo->pctype, (void**)&loc->locinfo->pctype);
1332             swap_pointers((void**)&locinfo->pclmap, (void**)&loc->locinfo->pclmap);
1333             swap_pointers((void**)&locinfo->pcumap, (void**)&loc->locinfo->pcumap);
1334 
1335             if(category != MSVCRT_LC_ALL)
1336                 break;
1337             /* fall through */
1338         case MSVCRT_LC_MONETARY:
1339             locinfo->lc_handle[MSVCRT_LC_MONETARY] =
1340                 loc->locinfo->lc_handle[MSVCRT_LC_MONETARY];
1341             swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_MONETARY].locale,
1342                     (void**)&loc->locinfo->lc_category[MSVCRT_LC_MONETARY].locale);
1343             swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_MONETARY].refcount,
1344                     (void**)&loc->locinfo->lc_category[MSVCRT_LC_MONETARY].refcount);
1345 
1346             swap_pointers((void**)&locinfo->lconv->int_curr_symbol,
1347                     (void**)&loc->locinfo->lconv->int_curr_symbol);
1348             swap_pointers((void**)&locinfo->lconv->currency_symbol,
1349                     (void**)&loc->locinfo->lconv->currency_symbol);
1350             swap_pointers((void**)&locinfo->lconv->mon_decimal_point,
1351                     (void**)&loc->locinfo->lconv->mon_decimal_point);
1352             swap_pointers((void**)&locinfo->lconv->mon_thousands_sep,
1353                     (void**)&loc->locinfo->lconv->mon_thousands_sep);
1354             swap_pointers((void**)&locinfo->lconv->mon_grouping,
1355                     (void**)&loc->locinfo->lconv->mon_grouping);
1356             swap_pointers((void**)&locinfo->lconv->positive_sign,
1357                     (void**)&loc->locinfo->lconv->positive_sign);
1358             swap_pointers((void**)&locinfo->lconv->negative_sign,
1359                     (void**)&loc->locinfo->lconv->negative_sign);
1360             locinfo->lconv->int_frac_digits = loc->locinfo->lconv->int_frac_digits;
1361             locinfo->lconv->frac_digits = loc->locinfo->lconv->frac_digits;
1362             locinfo->lconv->p_cs_precedes = loc->locinfo->lconv->p_cs_precedes;
1363             locinfo->lconv->p_sep_by_space = loc->locinfo->lconv->p_sep_by_space;
1364             locinfo->lconv->n_cs_precedes = loc->locinfo->lconv->n_cs_precedes;
1365             locinfo->lconv->n_sep_by_space = loc->locinfo->lconv->n_sep_by_space;
1366             locinfo->lconv->p_sign_posn = loc->locinfo->lconv->p_sign_posn;
1367             locinfo->lconv->n_sign_posn = loc->locinfo->lconv->n_sign_posn;
1368 
1369             if(category != MSVCRT_LC_ALL)
1370                 break;
1371             /* fall through */
1372         case MSVCRT_LC_NUMERIC:
1373             locinfo->lc_handle[MSVCRT_LC_NUMERIC] =
1374                 loc->locinfo->lc_handle[MSVCRT_LC_NUMERIC];
1375             swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_NUMERIC].locale,
1376                     (void**)&loc->locinfo->lc_category[MSVCRT_LC_NUMERIC].locale);
1377             swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_NUMERIC].refcount,
1378                     (void**)&loc->locinfo->lc_category[MSVCRT_LC_NUMERIC].refcount);
1379 
1380             swap_pointers((void**)&locinfo->lconv->decimal_point,
1381                     (void**)&loc->locinfo->lconv->decimal_point);
1382             swap_pointers((void**)&locinfo->lconv->thousands_sep,
1383                     (void**)&loc->locinfo->lconv->thousands_sep);
1384             swap_pointers((void**)&locinfo->lconv->grouping,
1385                     (void**)&loc->locinfo->lconv->grouping);
1386 
1387             if(category != MSVCRT_LC_ALL)
1388                 break;
1389             /* fall through */
1390         case MSVCRT_LC_TIME:
1391             locinfo->lc_handle[MSVCRT_LC_TIME] =
1392                 loc->locinfo->lc_handle[MSVCRT_LC_TIME];
1393             swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_TIME].locale,
1394                     (void**)&loc->locinfo->lc_category[MSVCRT_LC_TIME].locale);
1395             swap_pointers((void**)&locinfo->lc_category[MSVCRT_LC_TIME].refcount,
1396                     (void**)&loc->locinfo->lc_category[MSVCRT_LC_TIME].refcount);
1397             swap_pointers((void**)&locinfo->lc_time_curr,
1398                     (void**)&loc->locinfo->lc_time_curr);
1399 
1400             if(category != MSVCRT_LC_ALL)
1401                 break;
1402     }
1403 
1404     MSVCRT__free_locale(loc);
1405     UNLOCK_LOCALE;
1406 
1407     if(locinfo == MSVCRT_locale->locinfo) {
1408         int i;
1409 
1410         __lc_codepage = locinfo->lc_codepage;
1411         MSVCRT___lc_collate_cp = locinfo->lc_collate_cp;
1412         __mb_cur_max = locinfo->mb_cur_max;
1413         _pctype = locinfo->pctype;
1414         for(i=LC_MIN; i<=LC_MAX; i++)
1415             MSVCRT___lc_handle[i] = MSVCRT_locale->locinfo->lc_handle[i];
1416     }
1417 
1418     if(category == MSVCRT_LC_ALL)
1419         return construct_lc_all(locinfo);
1420 
1421     _Analysis_assume_(category <= 5);
1422     return locinfo->lc_category[category].locale;
1423 }
1424 
1425 /* _configthreadlocale - not exported in native msvcrt */
_configthreadlocale(int type)1426 int CDECL _configthreadlocale(int type)
1427 {
1428     thread_data_t *data = msvcrt_get_thread_data();
1429     MSVCRT__locale_t locale;
1430     int ret;
1431 
1432     if(!data)
1433         return -1;
1434 
1435     ret = (data->have_locale ? _ENABLE_PER_THREAD_LOCALE : _DISABLE_PER_THREAD_LOCALE);
1436 
1437     if(type == _ENABLE_PER_THREAD_LOCALE) {
1438         if(!data->have_locale) {
1439             /* Copy current global locale */
1440             locale = MSVCRT__create_locale(LC_ALL, setlocale(LC_ALL, NULL));
1441             if(!locale)
1442                 return -1;
1443 
1444             data->locinfo = locale->locinfo;
1445             data->mbcinfo = locale->mbcinfo;
1446             data->have_locale = TRUE;
1447             MSVCRT_free(locale);
1448         }
1449 
1450         return ret;
1451     }
1452 
1453     if(type == _DISABLE_PER_THREAD_LOCALE) {
1454         if(data->have_locale) {
1455             free_locinfo(data->locinfo);
1456             free_mbcinfo(data->mbcinfo);
1457             data->locinfo = MSVCRT_locale->locinfo;
1458             data->mbcinfo = MSVCRT_locale->mbcinfo;
1459             data->have_locale = FALSE;
1460         }
1461 
1462         return ret;
1463     }
1464 
1465     if(!type)
1466         return ret;
1467 
1468     return -1;
1469 }
1470 
1471 /*********************************************************************
1472  *         _getmbcp (MSVCRT.@)
1473  */
_getmbcp(void)1474 int CDECL _getmbcp(void)
1475 {
1476   return get_mbcinfo()->mbcodepage;
1477 }
1478 
1479 extern unsigned int __setlc_active;
1480 /*********************************************************************
1481  *         ___setlc_active_func (MSVCRT.@)
1482  */
___setlc_active_func(void)1483 unsigned int CDECL ___setlc_active_func(void)
1484 {
1485   return __setlc_active;
1486 }
1487 
1488 extern unsigned int __unguarded_readlc_active;
1489 /*********************************************************************
1490  *         ___unguarded_readlc_active_add_func (MSVCRT.@)
1491  */
___unguarded_readlc_active_add_func(void)1492 unsigned int * CDECL ___unguarded_readlc_active_add_func(void)
1493 {
1494   return &__unguarded_readlc_active;
1495 }
1496 
1497 MSVCRT__locale_t global_locale = NULL;
__init_global_locale()1498 void __init_global_locale()
1499 {
1500     unsigned i;
1501 
1502     LOCK_LOCALE;
1503     /* Someone created it before us */
1504     if(global_locale)
1505         return;
1506     global_locale = MSVCRT__create_locale(0, "C");
1507 
1508     __lc_codepage = MSVCRT_locale->locinfo->lc_codepage;
1509     MSVCRT___lc_collate_cp = MSVCRT_locale->locinfo->lc_collate_cp;
1510     __mb_cur_max = MSVCRT_locale->locinfo->mb_cur_max;
1511     for(i=LC_MIN; i<=LC_MAX; i++)
1512         MSVCRT___lc_handle[i] = MSVCRT_locale->locinfo->lc_handle[i];
1513     _setmbcp(_MB_CP_ANSI);
1514     UNLOCK_LOCALE;
1515 }
1516 
1517 /*
1518  * @implemented
1519  */
__p__pctype(void)1520 const unsigned short **__p__pctype(void)
1521 {
1522    return &get_locinfo()->pctype;
1523 }
1524 
__pctype_func(void)1525 const unsigned short* __cdecl __pctype_func(void)
1526 {
1527    return get_locinfo()->pctype;
1528 }
1529 
1530