diff --git a/dlls/msvcr90/tests/msvcr90.c b/dlls/msvcr90/tests/msvcr90.c index ca5349e3387..08eb4a7ac64 100644 --- a/dlls/msvcr90/tests/msvcr90.c +++ b/dlls/msvcr90/tests/msvcr90.c @@ -130,6 +130,7 @@ static int (__cdecl *p_fflush_nolock)(FILE*); static size_t (__cdecl *p_mbstowcs)(wchar_t*, const char*, size_t); static size_t (__cdecl *p_wcstombs)(char*, const wchar_t*, size_t); static char* (__cdecl *p_setlocale)(int, const char*); +static int (__cdecl *p__setmbcp)(int); static int (__cdecl *p__fpieee_flt)(ULONG, EXCEPTION_POINTERS*, int (__cdecl *handler)(_FPIEEE_RECORD*)); static int (__cdecl *p__memicmp)(const char*, const char*, size_t); static int (__cdecl *p__memicmp_l)(const char*, const char*, size_t, _locale_t); @@ -160,6 +161,16 @@ struct __lc_time_data { #undef errno #define errno (*p_errno()) +typedef struct threadmbcinfostruct { + int refcount; + int mbcodepage; + int ismbcodepage; + int mblcid; + unsigned short mbulinfo[6]; + unsigned char mbctype[257]; + unsigned char mbcasemap[256]; +} threadmbcinfo; + /* type info */ typedef struct __type_info { @@ -415,6 +426,7 @@ static BOOL init(void) SET(p_mbstowcs, "mbstowcs"); SET(p_wcstombs, "wcstombs"); SET(p_setlocale, "setlocale"); + SET(p__setmbcp, "_setmbcp"); SET(p__fpieee_flt, "_fpieee_flt"); SET(p__memicmp, "_memicmp"); SET(p__memicmp_l, "_memicmp_l"); @@ -1979,9 +1991,13 @@ static void test____mb_cur_max_l_func(void) static void test__get_current_locale(void) { - _locale_t l = p__get_current_locale(), l2 = p__get_current_locale(); + _locale_t l, l2; int i; + ok(!p__setmbcp(1252), "_setmbcp failed\n"); + l = p__get_current_locale(); + l2 = p__get_current_locale(); + ok(!strcmp(l->locinfo->lc_category[LC_COLLATE].locale, "C"), "LC_COLLATE = \"%s\"\n", l->locinfo->lc_category[LC_COLLATE].locale); ok(!strcmp(l->locinfo->lc_category[LC_CTYPE].locale, "C"), @@ -1992,6 +2008,7 @@ static void test__get_current_locale(void) "LC_NUMERIC = \"%s\"\n", l->locinfo->lc_category[LC_NUMERIC].locale); ok(!strcmp(l->locinfo->lc_category[LC_TIME].locale, "C"), "LC_TIME = \"%s\"\n", l->locinfo->lc_category[LC_TIME].locale); + ok(l->mbcinfo->mbcodepage == 1252, "mbcodepage = %d\n", l->mbcinfo->mbcodepage); ok(l->locinfo->refcount == 3, "refcount = %d\n", l->locinfo->refcount); @@ -2001,6 +2018,7 @@ static void test__get_current_locale(void) p__free_locale(l2); return; } + ok(!p__setmbcp(932), "_setmbcp failed\n"); ok(!strcmp(l->locinfo->lc_category[LC_COLLATE].locale, "C"), "LC_COLLATE = \"%s\"\n", l->locinfo->lc_category[LC_COLLATE].locale); @@ -2012,6 +2030,7 @@ static void test__get_current_locale(void) "LC_NUMERIC = \"%s\"\n", l->locinfo->lc_category[LC_NUMERIC].locale); ok(!strcmp(l->locinfo->lc_category[LC_TIME].locale, "C"), "LC_TIME = \"%s\"\n", l->locinfo->lc_category[LC_TIME].locale); + ok(l->mbcinfo->mbcodepage == 1252, "mbcodepage = %d\n", l->mbcinfo->mbcodepage); ok(l->locinfo->refcount == 2, "refcount = %d\n", l->locinfo->refcount); ok(l->locinfo == l2->locinfo, "different locinfo pointers\n"); @@ -2143,9 +2162,7 @@ static void test__get_current_locale(void) p__free_locale(l2); - trace("before: %s\n", p_setlocale(LC_ALL, NULL)); - trace("current locale is: %s\n", p_setlocale(LC_MONETARY, "C")); - trace("after: %s\n", p_setlocale(LC_ALL, NULL)); + p_setlocale(LC_MONETARY, "C"); l2 = p__get_current_locale(); ok(l->locinfo->refcount == 1, "refcount = %d\n", l->locinfo->refcount); diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 8543b3f1713..2cedc89530e 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -597,14 +597,18 @@ MSVCRT_pthreadlocinfo CDECL get_locinfo(void) { return *get_locinfo_ptr(); } -/* INTERNAL: returns pthreadmbcinfo struct */ -MSVCRT_pthreadmbcinfo CDECL get_mbcinfo(void) { +MSVCRT_pthreadmbcinfo* CDECL get_mbcinfo_ptr(void) { thread_data_t *data = msvcrt_get_thread_data(); if(!data || !data->have_locale) - return MSVCRT_locale->mbcinfo; + return &MSVCRT_locale->mbcinfo; - return data->mbcinfo; + return &data->mbcinfo; +} + +/* INTERNAL: returns pthreadmbcinfo struct */ +MSVCRT_pthreadmbcinfo CDECL get_mbcinfo(void) { + return *get_mbcinfo_ptr(); } /* INTERNAL: constructs string returned by setlocale */ @@ -1964,16 +1968,13 @@ MSVCRT__locale_t CDECL MSVCRT__create_locale(int category, const char *locale) return NULL; } - loc->mbcinfo = MSVCRT_malloc(sizeof(MSVCRT_threadmbcinfo)); + loc->mbcinfo = create_mbcinfo(loc->locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage, + loc->locinfo->lc_handle[MSVCRT_LC_CTYPE], NULL); if(!loc->mbcinfo) { free_locinfo(loc->locinfo); MSVCRT_free(loc); return NULL; } - - loc->mbcinfo->refcount = 1; - _setmbcp_l(loc->locinfo->lc_id[MSVCRT_LC_CTYPE].wCodePage, - loc->locinfo->lc_handle[MSVCRT_LC_CTYPE], loc->mbcinfo); return loc; } diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c index f9a38184436..1454004610d 100644 --- a/dlls/msvcrt/mbcs.c +++ b/dlls/msvcrt/mbcs.c @@ -211,10 +211,9 @@ int CDECL ___mb_cur_max_l_func(MSVCRT__locale_t locale) /********************************************************************* * INTERNAL: _setmbcp_l */ -int _setmbcp_l(int cp, LCID lcid, MSVCRT_pthreadmbcinfo mbcinfo) +MSVCRT_threadmbcinfo* create_mbcinfo(int cp, LCID lcid, MSVCRT_threadmbcinfo *old_mbcinfo) { - const char format[] = ".%d"; - + MSVCRT_threadmbcinfo *mbcinfo; int newcp; CPINFO cpi; BYTE *bytes; @@ -225,8 +224,16 @@ int _setmbcp_l(int cp, LCID lcid, MSVCRT_pthreadmbcinfo mbcinfo) int ret; int i; + if(old_mbcinfo && cp==old_mbcinfo->mbcodepage + && (lcid==-1 || lcid==old_mbcinfo->mblcid)) { + InterlockedIncrement(&old_mbcinfo->refcount); + return old_mbcinfo; + } + + mbcinfo = MSVCRT_malloc(sizeof(MSVCRT_threadmbcinfo)); if(!mbcinfo) - mbcinfo = get_mbcinfo(); + return NULL; + mbcinfo->refcount = 1; switch (cp) { @@ -250,7 +257,7 @@ int _setmbcp_l(int cp, LCID lcid, MSVCRT_pthreadmbcinfo mbcinfo) } if(lcid == -1) { - MSVCRT_sprintf(bufA, format, newcp); + MSVCRT_sprintf(bufA, ".%d", newcp); mbcinfo->mblcid = MSVCRT_locale_to_LCID(bufA, NULL, NULL); } else { mbcinfo->mblcid = lcid; @@ -265,8 +272,8 @@ int _setmbcp_l(int cp, LCID lcid, MSVCRT_pthreadmbcinfo mbcinfo) if (!GetCPInfo(newcp, &cpi)) { WARN("Codepage %d not found\n", newcp); - *MSVCRT__errno() = MSVCRT_EINVAL; - return -1; + MSVCRT_free(mbcinfo); + return NULL; } /* setup the _mbctype */ @@ -370,10 +377,7 @@ int _setmbcp_l(int cp, LCID lcid, MSVCRT_pthreadmbcinfo mbcinfo) } mbcinfo->mbcodepage = newcp; - if(MSVCRT_locale && mbcinfo == MSVCRT_locale->mbcinfo) - memcpy(MSVCRT_mbctype, MSVCRT_locale->mbcinfo->mbctype, sizeof(MSVCRT_mbctype)); - - return 0; + return mbcinfo; } /********************************************************************* @@ -381,7 +385,21 @@ int _setmbcp_l(int cp, LCID lcid, MSVCRT_pthreadmbcinfo mbcinfo) */ int CDECL _setmbcp(int cp) { - return _setmbcp_l(cp, -1, NULL); + MSVCRT_threadmbcinfo **old_mbcinfo = get_mbcinfo_ptr(); + MSVCRT_threadmbcinfo *mbcinfo; + + mbcinfo = create_mbcinfo(cp, -1, *old_mbcinfo); + if(!mbcinfo) { + *MSVCRT__errno() = MSVCRT_EINVAL; + return -1; + } + + free_mbcinfo(*old_mbcinfo); + *old_mbcinfo = mbcinfo; + + if(mbcinfo == MSVCRT_locale->mbcinfo) + memcpy(MSVCRT_mbctype, MSVCRT_locale->mbcinfo->mbctype, sizeof(MSVCRT_mbctype)); + return 0; } /********************************************************************* diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 503aea33bd0..6c103ee3ca2 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -1136,10 +1136,11 @@ MSVCRT__locale_t CDECL get_current_locale_noalloc(MSVCRT__locale_t locale) DECLS void CDECL free_locale_noalloc(MSVCRT__locale_t locale) DECLSPEC_HIDDEN; MSVCRT_pthreadlocinfo CDECL get_locinfo(void) DECLSPEC_HIDDEN; MSVCRT_pthreadmbcinfo CDECL get_mbcinfo(void) DECLSPEC_HIDDEN; +MSVCRT_pthreadmbcinfo* CDECL get_mbcinfo_ptr(void) DECLSPEC_HIDDEN; void __cdecl MSVCRT__free_locale(MSVCRT__locale_t); +MSVCRT_threadmbcinfo* create_mbcinfo(int, LCID, MSVCRT_threadmbcinfo*) DECLSPEC_HIDDEN; void free_locinfo(MSVCRT_pthreadlocinfo) DECLSPEC_HIDDEN; void free_mbcinfo(MSVCRT_pthreadmbcinfo) DECLSPEC_HIDDEN; -int _setmbcp_l(int, LCID, MSVCRT_pthreadmbcinfo) DECLSPEC_HIDDEN; int __cdecl __crtLCMapStringA(LCID, DWORD, const char*, int, char*, int, unsigned int, int) DECLSPEC_HIDDEN; #ifndef __WINE_MSVCRT_TEST