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