2 * msvcrt.dll locale functions
4 * Copyright 2000 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
41 /* FIXME: Need to hold locale for each LC_* type and aggregate
42 * string to produce lc_all.
44 #define MAX_ELEM_LEN 64 /* Max length of country/language/CP string */
45 #define MAX_LOCALE_LENGTH 256
46 MSVCRT__locale_t MSVCRT_locale
= NULL
;
47 int MSVCRT___lc_codepage
;
48 int MSVCRT___lc_collate_cp
;
49 HANDLE MSVCRT___lc_handle
[MSVCRT_LC_MAX
- MSVCRT_LC_MIN
+ 1] = { 0 };
50 unsigned char charmax
= CHAR_MAX
;
53 #define LOCK_LOCALE _mlock(_SETLOCALE_LOCK);
54 #define UNLOCK_LOCALE _munlock(_SETLOCALE_LOCK);
56 #define MSVCRT_LEADBYTE 0x8000
58 /* Friendly country strings & iso codes for synonym support.
59 * Based on MS documentation for setlocale().
61 static const char * const _country_synonyms
[] =
69 "United Kingdom","GB",
70 "United-Kingdom","GB",
79 /* INTERNAL: Map a synonym to an ISO code */
80 static void remap_synonym(char *name
)
83 for (i
= 0; i
< sizeof(_country_synonyms
)/sizeof(char*); i
+= 2 )
85 if (!strcasecmp(_country_synonyms
[i
],name
))
87 TRACE(":Mapping synonym %s to %s\n",name
,_country_synonyms
[i
+1]);
88 name
[0] = _country_synonyms
[i
+1][0];
89 name
[1] = _country_synonyms
[i
+1][1];
96 /* Note: Flags are weighted in order of matching importance */
97 #define FOUND_LANGUAGE 0x4
98 #define FOUND_COUNTRY 0x2
99 #define FOUND_CODEPAGE 0x1
102 char search_language
[MAX_ELEM_LEN
];
103 char search_country
[MAX_ELEM_LEN
];
104 char search_codepage
[MAX_ELEM_LEN
];
105 char found_language
[MAX_ELEM_LEN
];
106 char found_country
[MAX_ELEM_LEN
];
107 char found_codepage
[MAX_ELEM_LEN
];
108 unsigned int match_flags
;
109 LANGID found_lang_id
;
112 #define CONTINUE_LOOKING TRUE
113 #define STOP_LOOKING FALSE
115 /* INTERNAL: Get and compare locale info with a given string */
116 static int compare_info(LCID lcid
, DWORD flags
, char* buff
, const char* cmp
)
119 GetLocaleInfoA(lcid
, flags
|LOCALE_NOUSEROVERRIDE
,buff
, MAX_ELEM_LEN
);
120 if (!buff
[0] || !cmp
[0])
122 /* Partial matches are allowed, e.g. "Germ" matches "Germany" */
123 return !strncasecmp(cmp
, buff
, strlen(cmp
));
127 find_best_locale_proc(HMODULE hModule
, LPCSTR type
, LPCSTR name
, WORD LangID
, LONG_PTR lParam
)
129 locale_search_t
*res
= (locale_search_t
*)lParam
;
130 const LCID lcid
= MAKELCID(LangID
, SORT_DEFAULT
);
131 char buff
[MAX_ELEM_LEN
];
132 unsigned int flags
= 0;
134 if(PRIMARYLANGID(LangID
) == LANG_NEUTRAL
)
135 return CONTINUE_LOOKING
;
138 if (compare_info(lcid
,LOCALE_SISO639LANGNAME
,buff
,res
->search_language
) ||
139 compare_info(lcid
,LOCALE_SABBREVLANGNAME
,buff
,res
->search_language
) ||
140 compare_info(lcid
,LOCALE_SENGLANGUAGE
,buff
,res
->search_language
))
142 TRACE(":Found language: %s->%s\n", res
->search_language
, buff
);
143 flags
|= FOUND_LANGUAGE
;
144 memcpy(res
->found_language
,res
->search_language
,MAX_ELEM_LEN
);
146 else if (res
->match_flags
& FOUND_LANGUAGE
)
148 return CONTINUE_LOOKING
;
152 if (compare_info(lcid
,LOCALE_SISO3166CTRYNAME
,buff
,res
->search_country
) ||
153 compare_info(lcid
,LOCALE_SABBREVCTRYNAME
,buff
,res
->search_country
) ||
154 compare_info(lcid
,LOCALE_SENGCOUNTRY
,buff
,res
->search_country
))
156 TRACE("Found country:%s->%s\n", res
->search_country
, buff
);
157 flags
|= FOUND_COUNTRY
;
158 memcpy(res
->found_country
,res
->search_country
,MAX_ELEM_LEN
);
160 else if (res
->match_flags
& FOUND_COUNTRY
)
162 return CONTINUE_LOOKING
;
166 if (compare_info(lcid
,LOCALE_IDEFAULTCODEPAGE
,buff
,res
->search_codepage
) ||
167 (compare_info(lcid
,LOCALE_IDEFAULTANSICODEPAGE
,buff
,res
->search_codepage
)))
169 TRACE("Found codepage:%s->%s\n", res
->search_codepage
, buff
);
170 flags
|= FOUND_CODEPAGE
;
171 memcpy(res
->found_codepage
,res
->search_codepage
,MAX_ELEM_LEN
);
173 else if (res
->match_flags
& FOUND_CODEPAGE
)
175 return CONTINUE_LOOKING
;
178 if (flags
> res
->match_flags
)
180 /* Found a better match than previously */
181 res
->match_flags
= flags
;
182 res
->found_lang_id
= LangID
;
184 if ((flags
& (FOUND_LANGUAGE
| FOUND_COUNTRY
| FOUND_CODEPAGE
)) ==
185 (FOUND_LANGUAGE
| FOUND_COUNTRY
| FOUND_CODEPAGE
))
187 TRACE(":found exact locale match\n");
190 return CONTINUE_LOOKING
;
193 extern int atoi(const char *);
195 /* Internal: Find the LCID for a locale specification */
196 static LCID
MSVCRT_locale_to_LCID(const char *locale
)
199 locale_search_t search
;
202 memset(&search
, 0, sizeof(locale_search_t
));
204 cp
= strchr(locale
, '.');
205 region
= strchr(locale
, '_');
207 lstrcpynA(search
.search_language
, locale
, MAX_ELEM_LEN
);
209 lstrcpynA(search
.search_country
, region
+1, MAX_ELEM_LEN
);
210 if(region
-locale
< MAX_ELEM_LEN
)
211 search
.search_language
[region
-locale
] = '\0';
213 search
.search_country
[0] = '\0';
216 lstrcpynA(search
.search_codepage
, cp
+1, MAX_ELEM_LEN
);
217 if(cp
-region
< MAX_ELEM_LEN
)
218 search
.search_country
[cp
-region
] = '\0';
219 if(cp
-locale
< MAX_ELEM_LEN
)
220 search
.search_language
[cp
-locale
] = '\0';
222 search
.search_codepage
[0] = '\0';
224 /* FIXME: MSVCRT_locale_to_LCID is not finding remaped values */
225 remap_synonym(search
.search_country
);
227 EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), (LPSTR
)RT_STRING
,
228 (LPCSTR
)LOCALE_ILANGUAGE
,find_best_locale_proc
,
231 if (!search
.match_flags
)
234 /* If we were given something that didn't match, fail */
235 if (search
.search_country
[0] && !(search
.match_flags
& FOUND_COUNTRY
))
238 lcid
= MAKELCID(search
.found_lang_id
, SORT_DEFAULT
);
240 /* Populate partial locale, translating LCID to locale string elements */
241 if (!search
.found_codepage
[0]) {
242 /* Even if a codepage is not enumerated for a locale
243 * it can be set if valid */
244 if (search
.search_codepage
[0]) {
245 if (IsValidCodePage(atoi(search
.search_codepage
)))
246 memcpy(search
.found_codepage
,search
.search_codepage
,MAX_ELEM_LEN
);
248 /* Special codepage values: OEM & ANSI */
249 if (strcasecmp(search
.search_codepage
,"OCP")) {
250 GetLocaleInfoA(lcid
, LOCALE_IDEFAULTCODEPAGE
,
251 search
.found_codepage
, MAX_ELEM_LEN
);
252 } else if (strcasecmp(search
.search_codepage
,"ACP")) {
253 GetLocaleInfoA(lcid
, LOCALE_IDEFAULTANSICODEPAGE
,
254 search
.found_codepage
, MAX_ELEM_LEN
);
258 if (!atoi(search
.found_codepage
))
262 /* Prefer ANSI codepages if present */
263 GetLocaleInfoA(lcid
, LOCALE_IDEFAULTANSICODEPAGE
,
264 search
.found_codepage
, MAX_ELEM_LEN
);
265 if (!search
.found_codepage
[0] || !atoi(search
.found_codepage
))
266 GetLocaleInfoA(lcid
, LOCALE_IDEFAULTCODEPAGE
,
267 search
.found_codepage
, MAX_ELEM_LEN
);
271 GetLocaleInfoA(lcid
, LOCALE_SENGLANGUAGE
|LOCALE_NOUSEROVERRIDE
,
272 search
.found_language
, MAX_ELEM_LEN
);
273 GetLocaleInfoA(lcid
, LOCALE_SENGCOUNTRY
|LOCALE_NOUSEROVERRIDE
,
274 search
.found_country
, MAX_ELEM_LEN
);
278 /* INTERNAL: Set lc_handle, lc_id and lc_category in threadlocinfo struct */
279 static BOOL
update_threadlocinfo_category(LCID lcid
, MSVCRT__locale_t loc
, int category
)
284 if(GetLocaleInfoA(lcid
, LOCALE_ILANGUAGE
, buf
, 256)) {
287 loc
->locinfo
->lc_id
[category
].wLanguage
= 0;
289 loc
->locinfo
->lc_id
[category
].wLanguage
*= 16;
292 loc
->locinfo
->lc_id
[category
].wLanguage
+= *p
-'0';
294 loc
->locinfo
->lc_id
[category
].wLanguage
+= *p
-'a'+10;
299 loc
->locinfo
->lc_id
[category
].wCountry
=
300 loc
->locinfo
->lc_id
[category
].wLanguage
;
303 if(GetLocaleInfoA(lcid
, LOCALE_IDEFAULTANSICODEPAGE
, buf
, 256))
304 loc
->locinfo
->lc_id
[category
].wCodePage
= atoi(buf
);
306 loc
->locinfo
->lc_handle
[category
] = lcid
;
309 len
+= GetLocaleInfoA(lcid
, LOCALE_SLANGUAGE
, buf
, 256);
311 len
+= GetLocaleInfoA(lcid
, LOCALE_SCOUNTRY
, &buf
[len
], 256-len
);
313 len
+= GetLocaleInfoA(lcid
, LOCALE_IDEFAULTANSICODEPAGE
, &buf
[len
], 256-len
);
315 loc
->locinfo
->lc_category
[category
].locale
= MSVCRT_malloc(sizeof(char[len
]));
316 loc
->locinfo
->lc_category
[category
].refcount
= MSVCRT_malloc(sizeof(int));
317 if(!loc
->locinfo
->lc_category
[category
].locale
318 || !loc
->locinfo
->lc_category
[category
].refcount
) {
319 MSVCRT_free(loc
->locinfo
->lc_category
[category
].locale
);
320 MSVCRT_free(loc
->locinfo
->lc_category
[category
].refcount
);
321 loc
->locinfo
->lc_category
[category
].locale
= NULL
;
322 loc
->locinfo
->lc_category
[category
].refcount
= NULL
;
325 memcpy(loc
->locinfo
->lc_category
[category
].locale
, buf
, sizeof(char[len
]));
326 *loc
->locinfo
->lc_category
[category
].refcount
= 1;
331 /* INTERNAL: swap pointers values */
332 static inline void swap_pointers(void **p1
, void **p2
) {
340 /* INTERNAL: returns _locale_t struct for current locale */
341 MSVCRT__locale_t
get_locale(void) {
342 thread_data_t
*data
= msvcrt_get_thread_data();
344 if(!data
|| !data
->locale
)
345 return MSVCRT_locale
;
351 /*********************************************************************
352 * wsetlocale (MSVCRT.@)
354 MSVCRT_wchar_t
* CDECL
MSVCRT__wsetlocale(int category
, const MSVCRT_wchar_t
* locale
)
356 static MSVCRT_wchar_t fake
[] = {
357 'E','n','g','l','i','s','h','_','U','n','i','t','e','d',' ',
358 'S','t','a','t','e','s','.','1','2','5','2',0 };
360 FIXME("%d %s\n", category
, debugstr_w(locale
));
365 /*********************************************************************
366 * _Getdays (MSVCRT.@)
368 const char* CDECL
_Getdays(void)
370 static const char MSVCRT_days
[] = ":Sun:Sunday:Mon:Monday:Tue:Tuesday:Wed:"
371 "Wednesday:Thu:Thursday:Fri:Friday:Sat:Saturday";
372 /* FIXME: Use locale */
373 TRACE("(void) semi-stub\n");
377 /*********************************************************************
378 * _Getmonths (MSVCRT.@)
380 const char* CDECL
_Getmonths(void)
382 static const char MSVCRT_months
[] = ":Jan:January:Feb:February:Mar:March:Apr:"
383 "April:May:May:Jun:June:Jul:July:Aug:August:Sep:September:Oct:"
384 "October:Nov:November:Dec:December";
385 /* FIXME: Use locale */
386 TRACE("(void) semi-stub\n");
387 return MSVCRT_months
;
390 /*********************************************************************
391 * _Gettnames (MSVCRT.@)
393 const char* CDECL
_Gettnames(void)
396 TRACE("(void) stub\n");
400 /*********************************************************************
401 * _Strftime (MSVCRT.@)
403 const char* CDECL
_Strftime(char *out
, unsigned int len
, const char *fmt
,
404 const void *tm
, void *foo
)
407 TRACE("(%p %d %s %p %p) stub\n", out
, len
, fmt
, tm
, foo
);
411 /*********************************************************************
412 * __crtLCMapStringA (MSVCRT.@)
414 int CDECL
__crtLCMapStringA(
415 LCID lcid
, DWORD mapflags
, const char* src
, int srclen
, char* dst
,
416 int dstlen
, unsigned int codepage
, int xflag
418 FIXME("(lcid %x, flags %x, %s(%d), %p(%d), %x, %d), partial stub!\n",
419 lcid
,mapflags
,src
,srclen
,dst
,dstlen
,codepage
,xflag
);
420 /* FIXME: A bit incorrect. But msvcrt itself just converts its
421 * arguments to wide strings and then calls LCMapStringW
423 return LCMapStringA(lcid
,mapflags
,src
,srclen
,dst
,dstlen
);
426 /*********************************************************************
427 * __crtCompareStringA (MSVCRT.@)
429 int CDECL
__crtCompareStringA( LCID lcid
, DWORD flags
, const char *src1
, int len1
,
430 const char *src2
, int len2
)
432 FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n",
433 lcid
, flags
, debugstr_a(src1
), len1
, debugstr_a(src2
), len2
);
434 /* FIXME: probably not entirely right */
435 return CompareStringA( lcid
, flags
, src1
, len1
, src2
, len2
);
438 /*********************************************************************
439 * __crtCompareStringW (MSVCRT.@)
441 int CDECL
__crtCompareStringW( LCID lcid
, DWORD flags
, const MSVCRT_wchar_t
*src1
, int len1
,
442 const MSVCRT_wchar_t
*src2
, int len2
)
444 FIXME("(lcid %x, flags %x, %s(%d), %s(%d), partial stub\n",
445 lcid
, flags
, debugstr_w(src1
), len1
, debugstr_w(src2
), len2
);
446 /* FIXME: probably not entirely right */
447 return CompareStringW( lcid
, flags
, src1
, len1
, src2
, len2
);
450 /*********************************************************************
451 * __crtGetLocaleInfoW (MSVCRT.@)
453 int CDECL
__crtGetLocaleInfoW( LCID lcid
, LCTYPE type
, MSVCRT_wchar_t
*buffer
, int len
)
455 FIXME("(lcid %x, type %x, %p(%d), partial stub\n", lcid
, type
, buffer
, len
);
456 /* FIXME: probably not entirely right */
457 return GetLocaleInfoW( lcid
, type
, buffer
, len
);
460 /*********************************************************************
461 * localeconv (MSVCRT.@)
463 struct MSVCRT_lconv
* CDECL
MSVCRT_localeconv(void)
465 static struct MSVCRT_lconv xlconv
;
466 struct lconv
*ylconv
= localeconv();
468 xlconv
.decimal_point
= ylconv
->decimal_point
;
469 xlconv
.thousands_sep
= ylconv
->thousands_sep
;
470 xlconv
.grouping
= ylconv
->grouping
; /* FIXME: fixup charmax here too */
471 xlconv
.int_curr_symbol
= ylconv
->int_curr_symbol
;
472 xlconv
.currency_symbol
= ylconv
->currency_symbol
;
473 xlconv
.mon_decimal_point
= ylconv
->mon_decimal_point
;
474 xlconv
.mon_thousands_sep
= ylconv
->mon_thousands_sep
;
475 xlconv
.mon_grouping
= ylconv
->mon_grouping
;
476 xlconv
.positive_sign
= ylconv
->positive_sign
;
477 xlconv
.negative_sign
= ylconv
->negative_sign
;
478 xlconv
.int_frac_digits
= ylconv
->int_frac_digits
;
479 xlconv
.frac_digits
= ylconv
->frac_digits
;
480 xlconv
.p_cs_precedes
= ylconv
->p_cs_precedes
;
481 xlconv
.p_sep_by_space
= ylconv
->p_sep_by_space
;
482 xlconv
.n_cs_precedes
= ylconv
->n_cs_precedes
;
483 xlconv
.n_sep_by_space
= ylconv
->n_sep_by_space
;
484 xlconv
.p_sign_posn
= ylconv
->p_sign_posn
;
485 xlconv
.n_sign_posn
= ylconv
->n_sign_posn
;
487 if (ylconv
->int_frac_digits
== CHAR_MAX
) xlconv
.int_frac_digits
= charmax
;
488 if (ylconv
->frac_digits
== CHAR_MAX
) xlconv
.frac_digits
= charmax
;
489 if (ylconv
->p_cs_precedes
== CHAR_MAX
) xlconv
.p_cs_precedes
= charmax
;
490 if (ylconv
->p_sep_by_space
== CHAR_MAX
) xlconv
.p_sep_by_space
= charmax
;
491 if (ylconv
->n_cs_precedes
== CHAR_MAX
) xlconv
.n_cs_precedes
= charmax
;
492 if (ylconv
->n_sep_by_space
== CHAR_MAX
) xlconv
.n_sep_by_space
= charmax
;
493 if (ylconv
->p_sign_posn
== CHAR_MAX
) xlconv
.p_sign_posn
= charmax
;
494 if (ylconv
->n_sign_posn
== CHAR_MAX
) xlconv
.n_sign_posn
= charmax
;
499 /*********************************************************************
500 * __lconv_init (MSVCRT.@)
502 void CDECL
__lconv_init(void)
504 /* this is used to make chars unsigned */
508 /*********************************************************************
509 * ___lc_handle_func (MSVCRT.@)
511 HANDLE
* CDECL
___lc_handle_func(void)
513 return MSVCRT___lc_handle
;
516 /*********************************************************************
517 * ___lc_codepage_func (MSVCRT.@)
519 int CDECL
___lc_codepage_func(void)
521 return MSVCRT___lc_codepage
;
524 /*********************************************************************
525 * ___lc_collate_cp_func (MSVCRT.@)
527 int CDECL
___lc_collate_cp_func(void)
529 return MSVCRT___lc_collate_cp
;
532 /* _free_locale - not exported in native msvcrt */
533 void CDECL
_free_locale(MSVCRT__locale_t locale
)
537 for(i
=MSVCRT_LC_MIN
+1; i
<=MSVCRT_LC_MAX
; i
++) {
538 MSVCRT_free(locale
->locinfo
->lc_category
[i
].locale
);
539 MSVCRT_free(locale
->locinfo
->lc_category
[i
].refcount
);
542 if(locale
->locinfo
->lconv
) {
543 MSVCRT_free(locale
->locinfo
->lconv
->decimal_point
);
544 MSVCRT_free(locale
->locinfo
->lconv
->thousands_sep
);
545 MSVCRT_free(locale
->locinfo
->lconv
->grouping
);
546 MSVCRT_free(locale
->locinfo
->lconv
->int_curr_symbol
);
547 MSVCRT_free(locale
->locinfo
->lconv
->currency_symbol
);
548 MSVCRT_free(locale
->locinfo
->lconv
->mon_decimal_point
);
549 MSVCRT_free(locale
->locinfo
->lconv
->mon_thousands_sep
);
550 MSVCRT_free(locale
->locinfo
->lconv
->mon_grouping
);
551 MSVCRT_free(locale
->locinfo
->lconv
->positive_sign
);
552 MSVCRT_free(locale
->locinfo
->lconv
->negative_sign
);
554 MSVCRT_free(locale
->locinfo
->lconv_intl_refcount
);
555 MSVCRT_free(locale
->locinfo
->lconv_num_refcount
);
556 MSVCRT_free(locale
->locinfo
->lconv_mon_refcount
);
557 MSVCRT_free(locale
->locinfo
->lconv
);
559 MSVCRT_free(locale
->locinfo
->ctype1_refcount
);
560 MSVCRT_free(locale
->locinfo
->ctype1
);
562 MSVCRT_free(locale
->locinfo
->pclmap
);
563 MSVCRT_free(locale
->locinfo
->pcumap
);
565 MSVCRT_free(locale
->locinfo
);
566 MSVCRT_free(locale
->mbcinfo
);
570 /* _create_locale - not exported in native msvcrt */
571 MSVCRT__locale_t
_create_locale(int category
, const char *locale
)
573 static const char collate
[] = "COLLATE=";
574 static const char ctype
[] = "CTYPE=";
575 static const char monetary
[] = "MONETARY=";
576 static const char numeric
[] = "NUMERIC=";
577 static const char time
[] = "TIME=";
579 MSVCRT__locale_t loc
;
580 LCID lcid
[6] = { 0 };
584 TRACE("(%d %s)\n", category
, locale
);
586 if(category
<MSVCRT_LC_MIN
|| category
>MSVCRT_LC_MAX
|| !locale
)
589 if(locale
[0]=='C' && !locale
[1])
592 lcid
[0] = GetSystemDefaultLCID();
593 else if (locale
[0] == 'L' && locale
[1] == 'C' && locale
[2] == '_') {
597 locale
+= 3; /* LC_ */
598 if(!memcmp(locale
, collate
, sizeof(collate
)-1)) {
599 i
= MSVCRT_LC_COLLATE
;
600 locale
+= sizeof(collate
)-1;
601 } else if(!memcmp(locale
, ctype
, sizeof(ctype
)-1)) {
603 locale
+= sizeof(ctype
)-1;
604 } else if(!memcmp(locale
, monetary
, sizeof(monetary
)-1)) {
605 i
= MSVCRT_LC_MONETARY
;
606 locale
+= sizeof(monetary
)-1;
607 } else if(!memcmp(locale
, numeric
, sizeof(numeric
)-1)) {
608 i
= MSVCRT_LC_NUMERIC
;
609 locale
+= sizeof(numeric
)-1;
610 } else if(!memcmp(locale
, time
, sizeof(time
)-1)) {
612 locale
+= sizeof(time
)-1;
616 p
= strchr(locale
, ';');
618 memcpy(buf
, locale
, p
-locale
);
619 lcid
[i
] = MSVCRT_locale_to_LCID(buf
);
621 lcid
[i
] = MSVCRT_locale_to_LCID(locale
);
626 if(!p
|| *(p
+1)!='L' || *(p
+2)!='C' || *(p
+3)!='_')
632 lcid
[0] = MSVCRT_locale_to_LCID(locale
);
642 loc
= MSVCRT_malloc(sizeof(MSVCRT__locale_tstruct
));
646 loc
->locinfo
= MSVCRT_malloc(sizeof(MSVCRT_threadlocinfo
));
652 loc
->mbcinfo
= MSVCRT_malloc(sizeof(MSVCRT_threadmbcinfo
));
654 MSVCRT_free(loc
->locinfo
);
659 memset(loc
->locinfo
, 0, sizeof(MSVCRT_threadlocinfo
));
660 memset(loc
->mbcinfo
, 0, sizeof(MSVCRT_threadmbcinfo
));
662 loc
->locinfo
->lconv
= MSVCRT_malloc(sizeof(struct MSVCRT_lconv
));
663 if(!loc
->locinfo
->lconv
) {
667 memset(loc
->locinfo
->lconv
, 0, sizeof(struct MSVCRT_lconv
));
669 loc
->locinfo
->pclmap
= MSVCRT_malloc(sizeof(char[256]));
670 loc
->locinfo
->pcumap
= MSVCRT_malloc(sizeof(char[256]));
671 if(!loc
->locinfo
->pclmap
|| !loc
->locinfo
->pcumap
) {
676 loc
->locinfo
->refcount
= 1;
678 if(lcid
[MSVCRT_LC_COLLATE
] && (category
==MSVCRT_LC_ALL
|| category
==MSVCRT_LC_COLLATE
)) {
679 if(update_threadlocinfo_category(lcid
[MSVCRT_LC_COLLATE
], loc
, MSVCRT_LC_COLLATE
)) {
684 loc
->locinfo
->lc_category
[MSVCRT_LC_COLLATE
].locale
= strdup("C");
686 if(lcid
[MSVCRT_LC_CTYPE
] && (category
==MSVCRT_LC_ALL
|| category
==MSVCRT_LC_CTYPE
)) {
689 if(update_threadlocinfo_category(lcid
[MSVCRT_LC_CTYPE
], loc
, MSVCRT_LC_CTYPE
)) {
694 loc
->locinfo
->lc_codepage
= loc
->locinfo
->lc_id
[MSVCRT_LC_CTYPE
].wCodePage
;
695 loc
->locinfo
->lc_collate_cp
= loc
->locinfo
->lc_codepage
;
696 loc
->locinfo
->lc_clike
= 1;
697 if(!GetCPInfo(loc
->locinfo
->lc_codepage
, &cp
)) {
701 loc
->locinfo
->mb_cur_max
= cp
.MaxCharSize
;
703 loc
->locinfo
->ctype1_refcount
= MSVCRT_malloc(sizeof(int));
704 loc
->locinfo
->ctype1
= MSVCRT_malloc(sizeof(short[257]));
705 if(!loc
->locinfo
->ctype1_refcount
|| !loc
->locinfo
->ctype1
) {
710 *loc
->locinfo
->ctype1_refcount
= 1;
711 loc
->locinfo
->ctype1
[0] = 0;
712 loc
->locinfo
->pctype
= loc
->locinfo
->ctype1
+1;
714 buf
[1] = buf
[2] = '\0';
715 for(i
=1; i
<257; i
++) {
718 GetStringTypeA(lcid
[MSVCRT_LC_CTYPE
], CT_CTYPE1
, buf
,
719 1, loc
->locinfo
->ctype1
+i
);
720 loc
->locinfo
->ctype1
[i
] |= 0x200;
723 loc
->locinfo
->lc_clike
= 1;
724 loc
->locinfo
->mb_cur_max
= 1;
725 loc
->locinfo
->pctype
= MSVCRT__ctype
+1;
726 loc
->locinfo
->lc_category
[MSVCRT_LC_CTYPE
].locale
= strdup("C");
732 LCMapStringA(lcid
[MSVCRT_LC_CTYPE
], LCMAP_LOWERCASE
, buf
, 256,
733 (char*)loc
->locinfo
->pclmap
, 256);
734 LCMapStringA(lcid
[MSVCRT_LC_CTYPE
], LCMAP_UPPERCASE
, buf
, 256,
735 (char*)loc
->locinfo
->pcumap
, 256);
737 loc
->mbcinfo
->refcount
= 1;
738 loc
->mbcinfo
->mbcodepage
= loc
->locinfo
->lc_id
[MSVCRT_LC_CTYPE
].wCodePage
;
740 for(i
=0; i
<256; i
++) {
741 if(loc
->locinfo
->pclmap
[i
] != i
) {
742 loc
->mbcinfo
->mbctype
[i
+1] |= 0x10;
743 loc
->mbcinfo
->mbcasemap
[i
] = loc
->locinfo
->pclmap
[i
];
744 } else if(loc
->locinfo
->pcumap
[i
] != i
) {
745 loc
->mbcinfo
->mbctype
[i
+1] |= 0x20;
746 loc
->mbcinfo
->mbcasemap
[i
] = loc
->locinfo
->pcumap
[i
];
750 if(lcid
[MSVCRT_LC_MONETARY
] && (category
==MSVCRT_LC_ALL
|| category
==MSVCRT_LC_MONETARY
)) {
751 if(update_threadlocinfo_category(lcid
[MSVCRT_LC_MONETARY
], loc
, MSVCRT_LC_MONETARY
)) {
756 loc
->locinfo
->lconv_intl_refcount
= MSVCRT_malloc(sizeof(int));
757 loc
->locinfo
->lconv_mon_refcount
= MSVCRT_malloc(sizeof(int));
758 if(!loc
->locinfo
->lconv_intl_refcount
|| !loc
->locinfo
->lconv_mon_refcount
) {
763 *loc
->locinfo
->lconv_intl_refcount
= 1;
764 *loc
->locinfo
->lconv_mon_refcount
= 1;
766 i
= GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_SINTLSYMBOL
, buf
, 256);
767 if(i
&& (loc
->locinfo
->lconv
->int_curr_symbol
= MSVCRT_malloc(sizeof(char[i
]))))
768 memcpy(loc
->locinfo
->lconv
->int_curr_symbol
, buf
, sizeof(char[i
]));
774 i
= GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_SCURRENCY
, buf
, 256);
775 if(i
&& (loc
->locinfo
->lconv
->currency_symbol
= MSVCRT_malloc(sizeof(char[i
]))))
776 memcpy(loc
->locinfo
->lconv
->currency_symbol
, buf
, sizeof(char[i
]));
782 i
= GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_SMONDECIMALSEP
, buf
, 256);
783 if(i
&& (loc
->locinfo
->lconv
->mon_decimal_point
= MSVCRT_malloc(sizeof(char[i
]))))
784 memcpy(loc
->locinfo
->lconv
->mon_decimal_point
, buf
, sizeof(char[i
]));
790 i
= GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_SMONTHOUSANDSEP
, buf
, 256);
791 if(i
&& (loc
->locinfo
->lconv
->mon_thousands_sep
= MSVCRT_malloc(sizeof(char[i
]))))
792 memcpy(loc
->locinfo
->lconv
->mon_thousands_sep
, buf
, sizeof(char[i
]));
798 i
= GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_SMONGROUPING
, buf
, 256);
800 i
= i
/2 + (buf
[i
-2]=='0'?0:1);
801 if(i
&& (loc
->locinfo
->lconv
->mon_grouping
= MSVCRT_malloc(sizeof(char[i
])))) {
802 for(i
=0; buf
[i
+1]==';'; i
+=2)
803 loc
->locinfo
->lconv
->mon_grouping
[i
/2] = buf
[i
]-'0';
804 loc
->locinfo
->lconv
->mon_grouping
[i
/2] = buf
[i
]-'0';
806 loc
->locinfo
->lconv
->mon_grouping
[i
/2+1] = 127;
812 i
= GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_SPOSITIVESIGN
, buf
, 256);
813 if(i
&& (loc
->locinfo
->lconv
->positive_sign
= MSVCRT_malloc(sizeof(char[i
]))))
814 memcpy(loc
->locinfo
->lconv
->positive_sign
, buf
, sizeof(char[i
]));
820 i
= GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_SNEGATIVESIGN
, buf
, 256);
821 if(i
&& (loc
->locinfo
->lconv
->negative_sign
= MSVCRT_malloc(sizeof(char[i
]))))
822 memcpy(loc
->locinfo
->lconv
->negative_sign
, buf
, sizeof(char[i
]));
828 if(GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_IINTLCURRDIGITS
, buf
, 256))
829 loc
->locinfo
->lconv
->int_frac_digits
= atoi(buf
);
835 if(GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_ICURRDIGITS
, buf
, 256))
836 loc
->locinfo
->lconv
->frac_digits
= atoi(buf
);
842 if(GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_IPOSSYMPRECEDES
, buf
, 256))
843 loc
->locinfo
->lconv
->p_cs_precedes
= atoi(buf
);
849 if(GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_IPOSSEPBYSPACE
, buf
, 256))
850 loc
->locinfo
->lconv
->p_sep_by_space
= atoi(buf
);
856 if(GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_INEGSYMPRECEDES
, buf
, 256))
857 loc
->locinfo
->lconv
->n_cs_precedes
= atoi(buf
);
863 if(GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_INEGSEPBYSPACE
, buf
, 256))
864 loc
->locinfo
->lconv
->n_sep_by_space
= atoi(buf
);
870 if(GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_IPOSSIGNPOSN
, buf
, 256))
871 loc
->locinfo
->lconv
->p_sign_posn
= atoi(buf
);
877 if(GetLocaleInfoA(lcid
[MSVCRT_LC_MONETARY
], LOCALE_INEGSIGNPOSN
, buf
, 256))
878 loc
->locinfo
->lconv
->n_sign_posn
= atoi(buf
);
884 loc
->locinfo
->lconv
->int_curr_symbol
= MSVCRT_malloc(sizeof(char));
885 loc
->locinfo
->lconv
->currency_symbol
= MSVCRT_malloc(sizeof(char));
886 loc
->locinfo
->lconv
->mon_decimal_point
= MSVCRT_malloc(sizeof(char));
887 loc
->locinfo
->lconv
->mon_thousands_sep
= MSVCRT_malloc(sizeof(char));
888 loc
->locinfo
->lconv
->mon_grouping
= MSVCRT_malloc(sizeof(char));
889 loc
->locinfo
->lconv
->positive_sign
= MSVCRT_malloc(sizeof(char));
890 loc
->locinfo
->lconv
->negative_sign
= MSVCRT_malloc(sizeof(char));
892 if(!loc
->locinfo
->lconv
->int_curr_symbol
|| !loc
->locinfo
->lconv
->currency_symbol
893 || !loc
->locinfo
->lconv
->mon_decimal_point
|| !loc
->locinfo
->lconv
->mon_thousands_sep
894 || !loc
->locinfo
->lconv
->mon_grouping
|| !loc
->locinfo
->lconv
->positive_sign
895 || !loc
->locinfo
->lconv
->negative_sign
) {
900 loc
->locinfo
->lconv
->int_curr_symbol
[0] = '\0';
901 loc
->locinfo
->lconv
->currency_symbol
[0] = '\0';
902 loc
->locinfo
->lconv
->mon_decimal_point
[0] = '\0';
903 loc
->locinfo
->lconv
->mon_thousands_sep
[0] = '\0';
904 loc
->locinfo
->lconv
->mon_grouping
[0] = '\0';
905 loc
->locinfo
->lconv
->positive_sign
[0] = '\0';
906 loc
->locinfo
->lconv
->negative_sign
[0] = '\0';
907 loc
->locinfo
->lconv
->int_frac_digits
= 127;
908 loc
->locinfo
->lconv
->frac_digits
= 127;
909 loc
->locinfo
->lconv
->p_cs_precedes
= 127;
910 loc
->locinfo
->lconv
->p_sep_by_space
= 127;
911 loc
->locinfo
->lconv
->n_cs_precedes
= 127;
912 loc
->locinfo
->lconv
->n_sep_by_space
= 127;
913 loc
->locinfo
->lconv
->p_sign_posn
= 127;
914 loc
->locinfo
->lconv
->n_sign_posn
= 127;
916 loc
->locinfo
->lc_category
[MSVCRT_LC_MONETARY
].locale
= strdup("C");
919 if(lcid
[MSVCRT_LC_NUMERIC
] && (category
==MSVCRT_LC_ALL
|| category
==MSVCRT_LC_NUMERIC
)) {
920 if(update_threadlocinfo_category(lcid
[MSVCRT_LC_NUMERIC
], loc
, MSVCRT_LC_NUMERIC
)) {
925 if(!loc
->locinfo
->lconv_intl_refcount
)
926 loc
->locinfo
->lconv_intl_refcount
= MSVCRT_malloc(sizeof(int));
927 loc
->locinfo
->lconv_num_refcount
= MSVCRT_malloc(sizeof(int));
928 if(!loc
->locinfo
->lconv_intl_refcount
|| !loc
->locinfo
->lconv_num_refcount
) {
933 *loc
->locinfo
->lconv_intl_refcount
= 1;
934 *loc
->locinfo
->lconv_num_refcount
= 1;
936 i
= GetLocaleInfoA(lcid
[MSVCRT_LC_NUMERIC
], LOCALE_SDECIMAL
, buf
, 256);
937 if(i
&& (loc
->locinfo
->lconv
->decimal_point
= MSVCRT_malloc(sizeof(char[i
]))))
938 memcpy(loc
->locinfo
->lconv
->decimal_point
, buf
, sizeof(char[i
]));
944 i
= GetLocaleInfoA(lcid
[MSVCRT_LC_NUMERIC
], LOCALE_STHOUSAND
, buf
, 256);
945 if(i
&& (loc
->locinfo
->lconv
->thousands_sep
= MSVCRT_malloc(sizeof(char[i
]))))
946 memcpy(loc
->locinfo
->lconv
->thousands_sep
, buf
, sizeof(char[i
]));
952 i
= GetLocaleInfoA(lcid
[MSVCRT_LC_NUMERIC
], LOCALE_SGROUPING
, buf
, 256);
954 i
= i
/2 + (buf
[i
-2]=='0'?0:1);
955 if(i
&& (loc
->locinfo
->lconv
->grouping
= MSVCRT_malloc(sizeof(char[i
])))) {
956 for(i
=0; buf
[i
+1]==';'; i
+=2)
957 loc
->locinfo
->lconv
->grouping
[i
/2] = buf
[i
]-'0';
958 loc
->locinfo
->lconv
->grouping
[i
/2] = buf
[i
]-'0';
960 loc
->locinfo
->lconv
->grouping
[i
/2+1] = 127;
966 loc
->locinfo
->lconv
->decimal_point
= MSVCRT_malloc(sizeof(char[2]));
967 loc
->locinfo
->lconv
->thousands_sep
= MSVCRT_malloc(sizeof(char));
968 loc
->locinfo
->lconv
->grouping
= MSVCRT_malloc(sizeof(char));
969 if(!loc
->locinfo
->lconv
->decimal_point
|| !loc
->locinfo
->lconv
->thousands_sep
970 || !loc
->locinfo
->lconv
->grouping
) {
975 loc
->locinfo
->lconv
->decimal_point
[0] = '.';
976 loc
->locinfo
->lconv
->decimal_point
[1] = '\0';
977 loc
->locinfo
->lconv
->thousands_sep
[0] = '\0';
978 loc
->locinfo
->lconv
->grouping
[0] = '\0';
980 loc
->locinfo
->lc_category
[MSVCRT_LC_NUMERIC
].locale
= strdup("C");
983 if(lcid
[MSVCRT_LC_TIME
] && (category
==MSVCRT_LC_ALL
|| category
==MSVCRT_LC_TIME
)) {
984 if(update_threadlocinfo_category(lcid
[MSVCRT_LC_TIME
], loc
, MSVCRT_LC_TIME
)) {
989 loc
->locinfo
->lc_category
[MSVCRT_LC_TIME
].locale
= strdup("C");
994 /* _configthreadlocale - not exported in native msvcrt */
995 int CDECL
_configthreadlocale(int type
)
997 thread_data_t
*data
= msvcrt_get_thread_data();
1003 ret
= (data
->locale
? MSVCRT__ENABLE_PER_THREAD_LOCALE
: MSVCRT__DISABLE_PER_THREAD_LOCALE
);
1005 if(type
== MSVCRT__ENABLE_PER_THREAD_LOCALE
) {
1007 /* Copy current global locale */
1008 data
->locale
= _create_locale(MSVCRT_LC_ALL
, MSVCRT_setlocale(MSVCRT_LC_ALL
, NULL
));
1016 if(type
== MSVCRT__DISABLE_PER_THREAD_LOCALE
) {
1018 _free_locale(data
->locale
);
1019 data
->locale
= NULL
;
1031 /*********************************************************************
1032 * setlocale (MSVCRT.@)
1034 char* CDECL
MSVCRT_setlocale(int category
, const char* locale
)
1036 static char current_lc_all
[MAX_LOCALE_LENGTH
];
1038 MSVCRT__locale_t loc
;
1040 if(locale
== NULL
) {
1041 if(category
== MSVCRT_LC_ALL
) {
1042 sprintf(current_lc_all
,
1043 "LC_COLLATE=%s;LC_CTYPE=%s;LC_MONETARY=%s;LC_NUMERIC=%s;LC_TIME=%s",
1044 MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_COLLATE
].locale
,
1045 MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_CTYPE
].locale
,
1046 MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_MONETARY
].locale
,
1047 MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_NUMERIC
].locale
,
1048 MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_TIME
].locale
);
1050 return current_lc_all
;
1053 return MSVCRT_locale
->locinfo
->lc_category
[category
].locale
;
1056 loc
= _create_locale(category
, locale
);
1066 case MSVCRT_LC_COLLATE
:
1067 MSVCRT_locale
->locinfo
->lc_handle
[MSVCRT_LC_COLLATE
] =
1068 loc
->locinfo
->lc_handle
[MSVCRT_LC_COLLATE
];
1069 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_COLLATE
].locale
,
1070 (void**)&loc
->locinfo
->lc_category
[MSVCRT_LC_COLLATE
].locale
);
1071 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_COLLATE
].refcount
,
1072 (void**)&loc
->locinfo
->lc_category
[MSVCRT_LC_COLLATE
].refcount
);
1074 if(category
!= MSVCRT_LC_ALL
)
1076 case MSVCRT_LC_CTYPE
:
1077 MSVCRT_locale
->locinfo
->lc_handle
[MSVCRT_LC_CTYPE
] =
1078 loc
->locinfo
->lc_handle
[MSVCRT_LC_CTYPE
];
1079 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_CTYPE
].locale
,
1080 (void**)&loc
->locinfo
->lc_category
[MSVCRT_LC_CTYPE
].locale
);
1081 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_CTYPE
].refcount
,
1082 (void**)&loc
->locinfo
->lc_category
[MSVCRT_LC_CTYPE
].refcount
);
1084 MSVCRT_locale
->locinfo
->lc_codepage
= loc
->locinfo
->lc_codepage
;
1085 MSVCRT_locale
->locinfo
->lc_collate_cp
= loc
->locinfo
->lc_collate_cp
;
1086 MSVCRT_locale
->locinfo
->lc_clike
= loc
->locinfo
->lc_clike
;
1087 MSVCRT_locale
->locinfo
->mb_cur_max
= loc
->locinfo
->mb_cur_max
;
1089 swap_pointers((void**)&MSVCRT_locale
->locinfo
->ctype1_refcount
,
1090 (void**)&loc
->locinfo
->ctype1_refcount
);
1091 swap_pointers((void**)&MSVCRT_locale
->locinfo
->ctype1
, (void**)&loc
->locinfo
->ctype1
);
1092 swap_pointers((void**)&MSVCRT_locale
->locinfo
->pctype
, (void**)&loc
->locinfo
->pctype
);
1093 swap_pointers((void**)&MSVCRT_locale
->locinfo
->pclmap
, (void**)&loc
->locinfo
->pclmap
);
1094 swap_pointers((void**)&MSVCRT_locale
->locinfo
->pcumap
, (void**)&loc
->locinfo
->pcumap
);
1096 memcpy(MSVCRT_locale
->mbcinfo
, loc
->mbcinfo
, sizeof(MSVCRT_threadmbcinfo
));
1098 if(category
!= MSVCRT_LC_ALL
)
1100 case MSVCRT_LC_MONETARY
:
1101 MSVCRT_locale
->locinfo
->lc_handle
[MSVCRT_LC_MONETARY
] =
1102 loc
->locinfo
->lc_handle
[MSVCRT_LC_MONETARY
];
1103 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_MONETARY
].locale
,
1104 (void**)&loc
->locinfo
->lc_category
[MSVCRT_LC_MONETARY
].locale
);
1105 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_MONETARY
].refcount
,
1106 (void**)&loc
->locinfo
->lc_category
[MSVCRT_LC_MONETARY
].refcount
);
1108 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lconv
->int_curr_symbol
,
1109 (void**)&loc
->locinfo
->lconv
->int_curr_symbol
);
1110 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lconv
->currency_symbol
,
1111 (void**)&loc
->locinfo
->lconv
->currency_symbol
);
1112 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lconv
->mon_decimal_point
,
1113 (void**)&loc
->locinfo
->lconv
->mon_decimal_point
);
1114 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lconv
->mon_thousands_sep
,
1115 (void**)&loc
->locinfo
->lconv
->mon_thousands_sep
);
1116 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lconv
->mon_grouping
,
1117 (void**)&loc
->locinfo
->lconv
->mon_grouping
);
1118 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lconv
->positive_sign
,
1119 (void**)&loc
->locinfo
->lconv
->positive_sign
);
1120 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lconv
->negative_sign
,
1121 (void**)&loc
->locinfo
->lconv
->negative_sign
);
1122 MSVCRT_locale
->locinfo
->lconv
->int_frac_digits
= loc
->locinfo
->lconv
->int_frac_digits
;
1123 MSVCRT_locale
->locinfo
->lconv
->frac_digits
= loc
->locinfo
->lconv
->frac_digits
;
1124 MSVCRT_locale
->locinfo
->lconv
->p_cs_precedes
= loc
->locinfo
->lconv
->p_cs_precedes
;
1125 MSVCRT_locale
->locinfo
->lconv
->p_sep_by_space
= loc
->locinfo
->lconv
->p_sep_by_space
;
1126 MSVCRT_locale
->locinfo
->lconv
->n_cs_precedes
= loc
->locinfo
->lconv
->n_cs_precedes
;
1127 MSVCRT_locale
->locinfo
->lconv
->n_sep_by_space
= loc
->locinfo
->lconv
->n_sep_by_space
;
1128 MSVCRT_locale
->locinfo
->lconv
->p_sign_posn
= loc
->locinfo
->lconv
->p_sign_posn
;
1129 MSVCRT_locale
->locinfo
->lconv
->n_sign_posn
= loc
->locinfo
->lconv
->n_sign_posn
;
1131 if(category
!= MSVCRT_LC_ALL
)
1133 case MSVCRT_LC_NUMERIC
:
1134 MSVCRT_locale
->locinfo
->lc_handle
[MSVCRT_LC_NUMERIC
] =
1135 loc
->locinfo
->lc_handle
[MSVCRT_LC_NUMERIC
];
1136 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_NUMERIC
].locale
,
1137 (void**)&loc
->locinfo
->lc_category
[MSVCRT_LC_NUMERIC
].locale
);
1138 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_NUMERIC
].refcount
,
1139 (void**)&loc
->locinfo
->lc_category
[MSVCRT_LC_NUMERIC
].refcount
);
1141 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lconv
->decimal_point
,
1142 (void**)&loc
->locinfo
->lconv
->decimal_point
);
1143 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lconv
->thousands_sep
,
1144 (void**)&loc
->locinfo
->lconv
->thousands_sep
);
1145 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lconv
->grouping
,
1146 (void**)&loc
->locinfo
->lconv
->grouping
);
1148 if(category
!= MSVCRT_LC_ALL
)
1150 case MSVCRT_LC_TIME
:
1151 MSVCRT_locale
->locinfo
->lc_handle
[MSVCRT_LC_TIME
] =
1152 loc
->locinfo
->lc_handle
[MSVCRT_LC_TIME
];
1153 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_TIME
].locale
,
1154 (void**)&loc
->locinfo
->lc_category
[MSVCRT_LC_TIME
].locale
);
1155 swap_pointers((void**)&MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_TIME
].refcount
,
1156 (void**)&loc
->locinfo
->lc_category
[MSVCRT_LC_TIME
].refcount
);
1158 if(category
!= MSVCRT_LC_ALL
)
1163 MSVCRT_locale
= loc
;
1169 MSVCRT___lc_codepage
= MSVCRT_locale
->locinfo
->lc_codepage
;
1170 MSVCRT___lc_collate_cp
= MSVCRT_locale
->locinfo
->lc_collate_cp
;
1171 MSVCRT___mb_cur_max
= MSVCRT_locale
->locinfo
->mb_cur_max
;
1172 MSVCRT__pctype
= MSVCRT_locale
->locinfo
->pctype
;
1174 if(category
== MSVCRT_LC_ALL
)
1175 return MSVCRT_locale
->locinfo
->lc_category
[MSVCRT_LC_COLLATE
].locale
;
1177 return MSVCRT_locale
->locinfo
->lc_category
[category
].locale
;