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