From d58b385b385b9ba244377c534f2a7e09c50aa997 Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Thu, 15 Apr 2010 14:25:13 +0200 Subject: [PATCH] msvcrt: Change implementation of setlocale. --- dlls/msvcrt/ctype.c | 9 +- dlls/msvcrt/locale.c | 380 +++++++++++++++++++++++---------------------------- dlls/msvcrt/main.c | 13 +- dlls/msvcrt/msvcrt.h | 5 +- 4 files changed, 188 insertions(+), 219 deletions(-) diff --git a/dlls/msvcrt/ctype.c b/dlls/msvcrt/ctype.c index 39d13ea0218..1e1257d274b 100644 --- a/dlls/msvcrt/ctype.c +++ b/dlls/msvcrt/ctype.c @@ -50,15 +50,12 @@ WORD MSVCRT__ctype [257] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -/* Internal: Current ctype table for locale */ -WORD MSVCRT_current_ctype[257]; - /* pctype is used by macros in the Win32 headers. It must point * To a table of flags exactly like ctype. To allow locale * changes to affect ctypes (i.e. isleadbyte), we use a second table * and update its flags whenever the current locale changes. */ -WORD* MSVCRT__pctype = MSVCRT_current_ctype + 1; +WORD* MSVCRT__pctype; /********************************************************************* * __pctype_func (MSVCRT.@) @@ -87,8 +84,8 @@ int CDECL _isctype(int c, int type) *pconv++ = c & 0xff; *pconv = 0; /* FIXME: Use ctype LCID, not lc_all */ - if (GetStringTypeExA(MSVCRT_current_lc_all_lcid, CT_CTYPE1, - convert, convert[1] ? 2 : 1, &typeInfo)) + if (GetStringTypeExA(MSVCRT_locale->locinfo->lc_handle[MSVCRT_LC_CTYPE], + CT_CTYPE1, convert, convert[1] ? 2 : 1, &typeInfo)) return typeInfo & type; } return 0; diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 07a793b3c9a..c30b90751a5 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -43,10 +43,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); */ #define MAX_ELEM_LEN 64 /* Max length of country/language/CP string */ #define MAX_LOCALE_LENGTH 256 -char MSVCRT_current_lc_all[MAX_LOCALE_LENGTH] = { 0 }; -LCID MSVCRT_current_lc_all_lcid = 0; -int MSVCRT___lc_codepage = 0; -int MSVCRT___lc_collate_cp = 0; +MSVCRT__locale_t MSVCRT_locale = NULL; +int MSVCRT___lc_codepage; +int MSVCRT___lc_collate_cp; HANDLE MSVCRT___lc_handle[MSVCRT_LC_MAX - MSVCRT_LC_MIN + 1] = { 0 }; unsigned char charmax = CHAR_MAX; @@ -256,49 +255,8 @@ static LCID MSVCRT_locale_to_LCID(locale_search_t* locale) return lcid; } -/* INTERNAL: Set ctype behaviour for a codepage */ -static void msvcrt_set_ctype(unsigned int codepage, LCID lcid) -{ - CPINFO cp; - - memset(&cp, 0, sizeof(CPINFO)); - - if (GetCPInfo(codepage, &cp)) - { - int i; - char str[3]; - unsigned char *traverse = cp.LeadByte; - - memset(MSVCRT_current_ctype, 0, sizeof(MSVCRT__ctype)); - MSVCRT___lc_codepage = codepage; - MSVCRT___lc_collate_cp = codepage; - - /* Switch ctype macros to MBCS if needed */ - MSVCRT___mb_cur_max = cp.MaxCharSize; - - /* Set remaining ctype flags: FIXME: faster way to do this? */ - str[1] = str[2] = 0; - for (i = 0; i < 256; i++) - { - if (!(MSVCRT__pctype[i] & MSVCRT_LEADBYTE)) - { - str[0] = i; - GetStringTypeA(lcid, CT_CTYPE1, str, 1, MSVCRT__pctype + i); - } - } - - /* Set leadbyte flags */ - while (traverse[0] || traverse[1]) - { - for( i = traverse[0]; i <= traverse[1]; i++ ) - MSVCRT_current_ctype[i+1] |= MSVCRT_LEADBYTE; - traverse += 2; - }; - } -} - /* INTERNAL: Set lc_handle, lc_id and lc_category in threadlocinfo struct */ -BOOL update_threadlocinfo_category(LCID lcid, MSVCRT__locale_t loc, int category) +static BOOL update_threadlocinfo_category(LCID lcid, MSVCRT__locale_t loc, int category) { char buf[256], *p; int len; @@ -350,170 +308,16 @@ BOOL update_threadlocinfo_category(LCID lcid, MSVCRT__locale_t loc, int category return FALSE; } +/* INTERNAL: swap pointers values */ +static inline void swap_pointers(void **p1, void **p2) { + void *hlp; -/********************************************************************* - * setlocale (MSVCRT.@) - */ -char* CDECL MSVCRT_setlocale(int category, const char* locale) -{ - LCID lcid = 0; - locale_search_t lc; - int haveLang, haveCountry, haveCP; - char* next; - int lc_all = 0; - - TRACE("(%d %s)\n",category,locale); - - if (category < MSVCRT_LC_MIN || category > MSVCRT_LC_MAX) - return NULL; - - if (locale == NULL) - { - /* Report the current Locale */ - return MSVCRT_current_lc_all; - } - - LOCK_LOCALE; - - if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') - { - FIXME(":restore previous locale not implemented!\n"); - /* FIXME: Easiest way to do this is parse the string and - * call this function recursively with its elements, - * Where they differ for each lc_ type. - */ - UNLOCK_LOCALE; - return MSVCRT_current_lc_all; - } - - /* Default Locale: Special case handling */ - if (!strlen(locale) || ((toupper(locale[0]) == 'C') && !locale[1])) - { - MSVCRT_current_lc_all[0] = 'C'; - MSVCRT_current_lc_all[1] = '\0'; - MSVCRT___lc_codepage = GetACP(); - MSVCRT___lc_collate_cp = GetACP(); - - switch (category) { - case MSVCRT_LC_ALL: - lc_all = 1; /* Fall through all cases ... */ - case MSVCRT_LC_COLLATE: - if (!lc_all) break; - case MSVCRT_LC_CTYPE: - /* Restore C locale ctype info */ - MSVCRT___mb_cur_max = 1; - memcpy(MSVCRT_current_ctype, MSVCRT__ctype, sizeof(MSVCRT__ctype)); - if (!lc_all) break; - case MSVCRT_LC_MONETARY: - if (!lc_all) break; - case MSVCRT_LC_NUMERIC: - if (!lc_all) break; - case MSVCRT_LC_TIME: - break; - } - UNLOCK_LOCALE; - return MSVCRT_current_lc_all; - } - - /* Get locale elements */ - haveLang = haveCountry = haveCP = 0; - memset(&lc,0,sizeof(lc)); - - next = strchr(locale,'_'); - if (next && next != locale) - { - haveLang = 1; - memcpy(lc.search_language,locale,next-locale); - locale += next-locale+1; - } - - next = strchr(locale,'.'); - if (next) - { - haveCP = 1; - if (next == locale) - { - locale++; - lstrcpynA(lc.search_codepage, locale, MAX_ELEM_LEN); - } - else - { - if (haveLang) - { - haveCountry = 1; - memcpy(lc.search_country,locale,next-locale); - locale += next-locale+1; - } - else - { - haveLang = 1; - memcpy(lc.search_language,locale,next-locale); - locale += next-locale+1; - } - lstrcpynA(lc.search_codepage, locale, MAX_ELEM_LEN); - } - } - else - { - if (haveLang) - { - haveCountry = 1; - lstrcpynA(lc.search_country, locale, MAX_ELEM_LEN); - } - else - { - haveLang = 1; - lstrcpynA(lc.search_language, locale, MAX_ELEM_LEN); - } - } - - if (haveCountry) - remap_synonym(lc.search_country); - - if (haveCP && !haveCountry && !haveLang) - { - FIXME(":Codepage only locale not implemented\n"); - /* FIXME: Use default lang/country and skip locale_to_LCID() - * call below... - */ - UNLOCK_LOCALE; - return NULL; - } - - lcid = MSVCRT_locale_to_LCID(&lc); - - TRACE(":found LCID %d\n",lcid); - - if (lcid == 0) - { - UNLOCK_LOCALE; - return NULL; - } - - MSVCRT_current_lc_all_lcid = lcid; - - snprintf(MSVCRT_current_lc_all,MAX_LOCALE_LENGTH,"%s_%s.%s", - lc.found_language,lc.found_country,lc.found_codepage); - - switch (category) { - case MSVCRT_LC_ALL: - lc_all = 1; /* Fall through all cases ... */ - case MSVCRT_LC_COLLATE: - if (!lc_all) break; - case MSVCRT_LC_CTYPE: - msvcrt_set_ctype(atoi(lc.found_codepage),lcid); - if (!lc_all) break; - case MSVCRT_LC_MONETARY: - if (!lc_all) break; - case MSVCRT_LC_NUMERIC: - if (!lc_all) break; - case MSVCRT_LC_TIME: - break; - } - UNLOCK_LOCALE; - return MSVCRT_current_lc_all; + hlp = *p1; + *p1 = *p2; + *p2 = hlp; } + /********************************************************************* * wsetlocale (MSVCRT.@) */ @@ -750,7 +554,14 @@ MSVCRT__locale_t _create_locale(int category, const char *locale) lcid = CP_ACP; else if(!locale[0]) lcid = GetSystemDefaultLCID(); - else { + else if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') { + FIXME(":restore previous locale not implemented!\n"); + /* FIXME: Easiest way to do this is parse the string and + * call this function recursively with its elements, + * Where they differ for each lc_ type. + */ + return NULL; + } else { locale_search_t search; char *cp, *region; @@ -776,6 +587,9 @@ MSVCRT__locale_t _create_locale(int category, const char *locale) } else search.search_codepage[0] = '\0'; + /* FIXME: MSVCRT_locale_to_LCID is not finding remaped values */ + remap_synonym(search.search_country); + lcid = MSVCRT_locale_to_LCID(&search); if(!lcid) return NULL; @@ -834,6 +648,7 @@ MSVCRT__locale_t _create_locale(int category, const char *locale) } loc->locinfo->lc_codepage = loc->locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage; + loc->locinfo->lc_collate_cp = loc->locinfo->lc_codepage; loc->locinfo->lc_clike = 1; if(!GetCPInfo(loc->locinfo->lc_codepage, &cp)) { _free_locale(loc); @@ -1128,3 +943,152 @@ MSVCRT__locale_t _create_locale(int category, const char *locale) return loc; } + +/********************************************************************* + * setlocale (MSVCRT.@) + */ +char* CDECL MSVCRT_setlocale(int category, const char* locale) +{ + static char current_lc_all[MAX_LOCALE_LENGTH]; + + MSVCRT__locale_t loc; + + if(locale == NULL) { + if(category == MSVCRT_LC_ALL) { + sprintf(current_lc_all, + "LC_COLLATE=%s;LC_CTYPE=%s;LC_MONETARY=%s;LC_NUMERIC=%s;LC_TIME=%s", + MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_COLLATE].locale, + MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_CTYPE].locale, + MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_MONETARY].locale, + MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_NUMERIC].locale, + MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_TIME].locale); + + return current_lc_all; + } + + return MSVCRT_locale->locinfo->lc_category[category].locale; + } + + loc = _create_locale(category, locale); + if(!loc) + return NULL; + + LOCK_LOCALE; + + switch(category) { + case MSVCRT_LC_ALL: + if(!MSVCRT_locale) + break; + case MSVCRT_LC_COLLATE: + MSVCRT_locale->locinfo->lc_handle[MSVCRT_LC_COLLATE] = + loc->locinfo->lc_handle[MSVCRT_LC_COLLATE]; + swap_pointers((void**)&MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_COLLATE].locale, + (void**)&loc->locinfo->lc_category[MSVCRT_LC_COLLATE].locale); + swap_pointers((void**)&MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_COLLATE].refcount, + (void**)&loc->locinfo->lc_category[MSVCRT_LC_COLLATE].refcount); + + if(category != MSVCRT_LC_ALL) + break; + case MSVCRT_LC_CTYPE: + MSVCRT_locale->locinfo->lc_handle[MSVCRT_LC_CTYPE] = + loc->locinfo->lc_handle[MSVCRT_LC_CTYPE]; + swap_pointers((void**)&MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_CTYPE].locale, + (void**)&loc->locinfo->lc_category[MSVCRT_LC_CTYPE].locale); + swap_pointers((void**)&MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_CTYPE].refcount, + (void**)&loc->locinfo->lc_category[MSVCRT_LC_CTYPE].refcount); + + MSVCRT_locale->locinfo->lc_codepage = loc->locinfo->lc_codepage; + MSVCRT_locale->locinfo->lc_collate_cp = loc->locinfo->lc_collate_cp; + MSVCRT_locale->locinfo->lc_clike = loc->locinfo->lc_clike; + MSVCRT_locale->locinfo->mb_cur_max = loc->locinfo->mb_cur_max; + + swap_pointers((void**)&MSVCRT_locale->locinfo->ctype1_refcount, + (void**)&loc->locinfo->ctype1_refcount); + swap_pointers((void**)&MSVCRT_locale->locinfo->ctype1, (void**)&loc->locinfo->ctype1); + swap_pointers((void**)&MSVCRT_locale->locinfo->pctype, (void**)&loc->locinfo->pctype); + swap_pointers((void**)&MSVCRT_locale->locinfo->pclmap, (void**)&loc->locinfo->pclmap); + swap_pointers((void**)&MSVCRT_locale->locinfo->pcumap, (void**)&loc->locinfo->pcumap); + + memcpy(MSVCRT_locale->mbcinfo, loc->mbcinfo, sizeof(MSVCRT_threadmbcinfo)); + + if(category != MSVCRT_LC_ALL) + break; + case MSVCRT_LC_MONETARY: + MSVCRT_locale->locinfo->lc_handle[MSVCRT_LC_MONETARY] = + loc->locinfo->lc_handle[MSVCRT_LC_MONETARY]; + swap_pointers((void**)&MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_MONETARY].locale, + (void**)&loc->locinfo->lc_category[MSVCRT_LC_MONETARY].locale); + swap_pointers((void**)&MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_MONETARY].refcount, + (void**)&loc->locinfo->lc_category[MSVCRT_LC_MONETARY].refcount); + + swap_pointers((void**)&MSVCRT_locale->locinfo->lconv->int_curr_symbol, + (void**)&loc->locinfo->lconv->int_curr_symbol); + swap_pointers((void**)&MSVCRT_locale->locinfo->lconv->currency_symbol, + (void**)&loc->locinfo->lconv->currency_symbol); + swap_pointers((void**)&MSVCRT_locale->locinfo->lconv->mon_decimal_point, + (void**)&loc->locinfo->lconv->mon_decimal_point); + swap_pointers((void**)&MSVCRT_locale->locinfo->lconv->mon_thousands_sep, + (void**)&loc->locinfo->lconv->mon_thousands_sep); + swap_pointers((void**)&MSVCRT_locale->locinfo->lconv->mon_grouping, + (void**)&loc->locinfo->lconv->mon_grouping); + swap_pointers((void**)&MSVCRT_locale->locinfo->lconv->positive_sign, + (void**)&loc->locinfo->lconv->positive_sign); + swap_pointers((void**)&MSVCRT_locale->locinfo->lconv->negative_sign, + (void**)&loc->locinfo->lconv->negative_sign); + MSVCRT_locale->locinfo->lconv->int_frac_digits = loc->locinfo->lconv->int_frac_digits; + MSVCRT_locale->locinfo->lconv->frac_digits = loc->locinfo->lconv->frac_digits; + MSVCRT_locale->locinfo->lconv->p_cs_precedes = loc->locinfo->lconv->p_cs_precedes; + MSVCRT_locale->locinfo->lconv->p_sep_by_space = loc->locinfo->lconv->p_sep_by_space; + MSVCRT_locale->locinfo->lconv->n_cs_precedes = loc->locinfo->lconv->n_cs_precedes; + MSVCRT_locale->locinfo->lconv->n_sep_by_space = loc->locinfo->lconv->n_sep_by_space; + MSVCRT_locale->locinfo->lconv->p_sign_posn = loc->locinfo->lconv->p_sign_posn; + MSVCRT_locale->locinfo->lconv->n_sign_posn = loc->locinfo->lconv->n_sign_posn; + + if(category != MSVCRT_LC_ALL) + break; + case MSVCRT_LC_NUMERIC: + MSVCRT_locale->locinfo->lc_handle[MSVCRT_LC_NUMERIC] = + loc->locinfo->lc_handle[MSVCRT_LC_NUMERIC]; + swap_pointers((void**)&MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_NUMERIC].locale, + (void**)&loc->locinfo->lc_category[MSVCRT_LC_NUMERIC].locale); + swap_pointers((void**)&MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_NUMERIC].refcount, + (void**)&loc->locinfo->lc_category[MSVCRT_LC_NUMERIC].refcount); + + swap_pointers((void**)&MSVCRT_locale->locinfo->lconv->decimal_point, + (void**)&loc->locinfo->lconv->decimal_point); + swap_pointers((void**)&MSVCRT_locale->locinfo->lconv->thousands_sep, + (void**)&loc->locinfo->lconv->thousands_sep); + swap_pointers((void**)&MSVCRT_locale->locinfo->lconv->grouping, + (void**)&loc->locinfo->lconv->grouping); + + if(category != MSVCRT_LC_ALL) + break; + case MSVCRT_LC_TIME: + MSVCRT_locale->locinfo->lc_handle[MSVCRT_LC_TIME] = + loc->locinfo->lc_handle[MSVCRT_LC_TIME]; + swap_pointers((void**)&MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_TIME].locale, + (void**)&loc->locinfo->lc_category[MSVCRT_LC_TIME].locale); + swap_pointers((void**)&MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_TIME].refcount, + (void**)&loc->locinfo->lc_category[MSVCRT_LC_TIME].refcount); + + if(category != MSVCRT_LC_ALL) + break; + } + + if(!MSVCRT_locale) + MSVCRT_locale = loc; + else + _free_locale(loc); + + UNLOCK_LOCALE; + + MSVCRT___lc_codepage = MSVCRT_locale->locinfo->lc_codepage; + MSVCRT___lc_collate_cp = MSVCRT_locale->locinfo->lc_collate_cp; + MSVCRT___mb_cur_max = MSVCRT_locale->locinfo->mb_cur_max; + MSVCRT__pctype = MSVCRT_locale->locinfo->pctype; + + if(category == MSVCRT_LC_ALL) + return MSVCRT_locale->locinfo->lc_category[MSVCRT_LC_COLLATE].locale; + + return MSVCRT_locale->locinfo->lc_category[category].locale; +} diff --git a/dlls/msvcrt/main.c b/dlls/msvcrt/main.c index e64f0ba5da2..a8b77e1c5d5 100644 --- a/dlls/msvcrt/main.c +++ b/dlls/msvcrt/main.c @@ -86,14 +86,20 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) switch (fdwReason) { case DLL_PROCESS_ATTACH: - if (!msvcrt_init_tls()) - return FALSE; msvcrt_init_mt_locks(); + if(!MSVCRT_setlocale(0, "C")) { + msvcrt_free_mt_locks(); + return FALSE; + } + if (!msvcrt_init_tls()) { + _free_locale(MSVCRT_locale); + msvcrt_free_mt_locks(); + return FALSE; + } msvcrt_init_io(); msvcrt_init_console(); msvcrt_init_args(); msvcrt_init_signals(); - MSVCRT_setlocale(0, "C"); _setmbcp(_MB_CP_LOCALE); TRACE("finished process init\n"); break; @@ -108,6 +114,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) msvcrt_free_tls_mem(); if (!msvcrt_free_tls()) return FALSE; + _free_locale(MSVCRT_locale); TRACE("finished process free\n"); break; case DLL_THREAD_DETACH: diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 03180123f4a..34d1c9efbca 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -124,9 +124,7 @@ extern thread_data_t *msvcrt_get_thread_data(void); extern int MSVCRT___lc_codepage; extern int MSVCRT___lc_collate_cp; extern int MSVCRT___mb_cur_max; -extern LCID MSVCRT_current_lc_all_lcid; extern WORD MSVCRT__ctype [257]; -extern WORD MSVCRT_current_ctype[257]; extern WORD* MSVCRT__pctype; void msvcrt_set_errno(int); @@ -792,6 +790,9 @@ typedef struct MSVCRT_localeinfo_struct MSVCRT_pthreadmbcinfo mbcinfo; } MSVCRT__locale_tstruct, *MSVCRT__locale_t; +extern MSVCRT__locale_t MSVCRT_locale; +void __cdecl _free_locale(MSVCRT__locale_t); + #ifndef __WINE_MSVCRT_TEST int __cdecl MSVCRT__write(int,const void*,unsigned int); int __cdecl _getch(void); -- 2.11.4.GIT