msvcrt: Change implementation of setlocale.

This commit is contained in:
Piotr Caban 2010-04-15 14:25:13 +02:00 committed by Alexandre Julliard
parent 10023a15d6
commit d58b385b38
4 changed files with 188 additions and 219 deletions

View File

@ -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;

View File

@ -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,169 +308,15 @@ 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;
hlp = *p1;
*p1 = *p2;
*p2 = hlp;
}
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;
}
/*********************************************************************
* 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;
}

View File

@ -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:

View File

@ -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);