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