From: Jactry Zeng jzeng@codeweavers.com
--- dlls/msvcrt/tests/string.c | 80 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+)
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index f1aac03f8eb..54b15b577c4 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -5022,6 +5022,85 @@ static void test_toupper(void) setlocale(LC_ALL, "C"); }
+static void test_locale_info(void) +{ + pthreadlocinfo locinfo, locinfo2; + _locale_t locale, locale2; + int ret; + + if (!p__create_locale) + { + win_skip("_create_locale isn't available.\n"); + return; + } + + if (PRIMARYLANGID(GetUserDefaultLangID()) == LANG_JAPANESE) + skip("Skip language-specific tests on Japanese system.\n"); + else + { + locale = p__create_locale(LC_ALL, "Japanese_Japan.932"); + locale2 = p__create_locale(LC_ALL, ".932"); + locinfo = locale->locinfo; + locinfo2 = locale2->locinfo; + + ok(locinfo->mb_cur_max == locinfo2->mb_cur_max, "Got wrong max char size %d %d.\n", + locinfo->mb_cur_max, locinfo2->mb_cur_max); + ok(locinfo->ctype1_refcount != locinfo2->ctype1_refcount, "Got wrong refcount pointer %p vs %p.\n", + locinfo->ctype1_refcount, locinfo2->ctype1_refcount); + ok(locinfo->lc_codepage == 932 && locinfo->lc_codepage == locinfo2->lc_codepage, + "Got wrong codepage %d vs %d.\n", locinfo->lc_codepage, locinfo2->lc_codepage); + ok(locinfo->lc_id[LC_CTYPE].wCodePage == 932 + && locinfo->lc_id[LC_CTYPE].wCodePage == locinfo2->lc_id[LC_CTYPE].wCodePage, + "Got wrong LC_CTYPE codepage %d vs %d.\n", locinfo->lc_id[LC_CTYPE].wCodePage, + locinfo2->lc_id[LC_CTYPE].wCodePage); + ret = strcmp(locinfo->lc_category[LC_CTYPE].locale, locinfo2->lc_category[LC_CTYPE].locale); + ok(!!ret, "Got locale name %s vs %s.\n", locinfo->lc_category[LC_CTYPE].locale, + locinfo2->lc_category[LC_CTYPE].locale); + ret = memcmp(locinfo->ctype1, locinfo2->ctype1, 257 * sizeof(*locinfo->ctype1)); + todo_wine ok(!ret, "Got wrong ctype1 data.\n"); + ret = memcmp(locinfo->pclmap, locinfo2->pclmap, 256 * sizeof(*locinfo->pclmap)); + todo_wine ok(!ret, "Got wrong pclmap data.\n"); + ret = memcmp(locinfo->pcumap, locinfo2->pcumap, 256 * sizeof(*locinfo->pcumap)); + todo_wine ok(!ret, "Got wrong pcumap data.\n"); + ok(locinfo->lc_handle[LC_CTYPE] != locinfo2->lc_handle[LC_CTYPE], + "Got wrong LC_CTYPE %#lx vs %#lx.\n", locinfo->lc_handle[LC_CTYPE], locinfo2->lc_handle[LC_CTYPE]); + + p__free_locale(locale2); + locale2 = p__create_locale(LC_ALL, "Japanese_Japan.1252"); + locinfo2 = locale2->locinfo; + + ok(locinfo->mb_cur_max != locinfo2->mb_cur_max, "Got wrong max char size %d %d.\n", + locinfo->mb_cur_max, locinfo2->mb_cur_max); + ok(locinfo->ctype1_refcount != locinfo2->ctype1_refcount, "Got wrong refcount pointer %p vs %p.\n", + locinfo->ctype1_refcount, locinfo2->ctype1_refcount); + ok(locinfo2->lc_codepage == 1252, "Got wrong codepage %d.\n", locinfo2->lc_codepage); + ok(locinfo2->lc_id[LC_CTYPE].wCodePage == 1252, "Got wrong LC_CTYPE codepage %d.\n", + locinfo2->lc_id[LC_CTYPE].wCodePage); + ok(locinfo->lc_codepage != locinfo2->lc_codepage, "Got wrong codepage %d vs %d.\n", + locinfo->lc_codepage, locinfo2->lc_codepage); + ok(locinfo->lc_id[LC_CTYPE].wCodePage != locinfo2->lc_id[LC_CTYPE].wCodePage, + "Got wrong LC_CTYPE codepage %d vs %d.\n", locinfo->lc_id[LC_CTYPE].wCodePage, + locinfo2->lc_id[LC_CTYPE].wCodePage); + ret = strcmp(locinfo->lc_category[LC_CTYPE].locale, locinfo2->lc_category[LC_CTYPE].locale); + ok(!!ret, "Got locale name %s vs %s.\n", locinfo->lc_category[LC_CTYPE].locale, + locinfo2->lc_category[LC_CTYPE].locale); + ret = memcmp(locinfo->ctype1, locinfo2->ctype1, 257 * sizeof(*locinfo->ctype1)); + ok(!!ret, "Got wrong ctype1 data.\n"); + ret = memcmp(locinfo->pclmap, locinfo2->pclmap, 256 * sizeof(*locinfo->pclmap)); + ok(!!ret, "Got wrong pclmap data.\n"); + ret = memcmp(locinfo->pcumap, locinfo2->pcumap, 256 * sizeof(*locinfo->pcumap)); + ok(!!ret, "Got wrong pcumap data.\n"); + ok(locinfo->lc_handle[LC_CTYPE] == locinfo2->lc_handle[LC_CTYPE], + "Got wrong LC_CTYPE %#lx vs %#lx.\n", locinfo->lc_handle[LC_CTYPE], locinfo2->lc_handle[LC_CTYPE]); + + p__free_locale(locale2); + locale2 = p__create_locale(LC_ALL, "Japanese_Japan.3000"); /* an invalid codepage */ + ok(!locale2, "Got %p.\n", locale2); + + p__free_locale(locale); + } +} + START_TEST(string) { char mem[100]; @@ -5189,4 +5268,5 @@ START_TEST(string) test__tolower_l(); test__strnicmp_l(); test_toupper(); + test_locale_info(); }
From: Jactry Zeng jzeng@codeweavers.com
--- dlls/msvcrt/locale.c | 29 ++++++++++++++++++++++++++--- dlls/msvcrt/tests/string.c | 6 +++--- 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 013b6b10ed8..febb972ac47 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -243,6 +243,7 @@ static BOOL remap_synonym(char *name) typedef struct { WCHAR search_language[MAX_ELEM_LEN]; WCHAR search_country[MAX_ELEM_LEN]; + WCHAR search_codepage[MAX_ELEM_LEN]; WCHAR found_lang_sname[LOCALE_NAME_MAX_LENGTH]; unsigned int match_flags; BOOL allow_sname; @@ -280,6 +281,14 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) WCHAR buff[MAX_ELEM_LEN]; unsigned int flags = 0;
+ if (*res->search_codepage && compare_info(name, LOCALE_IDEFAULTANSICODEPAGE, buff, res->search_codepage, TRUE)) + { + TRACE("Found locale %s by codepage %s.\n", wine_dbgstr_w(name), wine_dbgstr_w(res->search_codepage)); + res->match_flags = FOUND_SNAME; + wcscpy(res->found_lang_sname, name); + return STOP_LOOKING; + } + if (res->allow_sname && compare_info(name,LOCALE_SNAME,buff,res->search_language, TRUE)) { TRACE(":Found locale: %s->%s\n", wine_dbgstr_w(res->search_language), wine_dbgstr_w(buff)); @@ -1275,6 +1284,18 @@ static __lc_time_data* create_time_data(WCHAR *sname) return cur; }
+static LCID lcid_from_codepage(int codepage) +{ + locale_search_t search; + + memset(&search, 0, sizeof(locale_search_t)); + _itow(codepage, search.search_codepage, 10); + EnumSystemLocalesEx(find_best_locale_proc, LOCALE_NEUTRALDATA, (LPARAM)&search, NULL); + if (search.match_flags & FOUND_SNAME) + return LocaleNameToLCID(search.found_lang_sname, LCID_CONVERSION_FLAGS); + return 0; +} + static pthreadlocinfo create_locinfo(int category, const char *locale, const threadlocinfo *old_locinfo) { @@ -1483,6 +1504,7 @@ static pthreadlocinfo create_locinfo(int category, InterlockedIncrement((LONG *)locinfo->ctype1_refcount); } else if(locale_sname[LC_CTYPE]) { CPINFO cp_info; + LCID cp_lcid; int j;
if(!update_threadlocinfo_category(locale_sname[LC_CTYPE], @@ -1513,6 +1535,7 @@ static pthreadlocinfo create_locinfo(int category, locinfo->ctype1[0] = 0; locinfo->pctype = locinfo->ctype1+1;
+ cp_lcid = lcid_from_codepage(locinfo->lc_codepage); buf[1] = buf[2] = '\0'; for(i=1; i<257; i++) { buf[0] = i-1; @@ -1520,7 +1543,7 @@ static pthreadlocinfo create_locinfo(int category, /* builtin GetStringTypeA doesn't set output to 0 on invalid input */ locinfo->ctype1[i] = 0;
- GetStringTypeA(locinfo->lc_handle[LC_CTYPE], CT_CTYPE1, buf, + GetStringTypeA(cp_lcid ? cp_lcid : locinfo->lc_handle[LC_CTYPE], CT_CTYPE1, buf, 1, locinfo->ctype1+i); }
@@ -1535,9 +1558,9 @@ static pthreadlocinfo create_locinfo(int category, buf[i] = i; }
- LCMapStringA(locinfo->lc_handle[LC_CTYPE], LCMAP_LOWERCASE, buf, 256, + LCMapStringA(cp_lcid ? cp_lcid : locinfo->lc_handle[LC_CTYPE], LCMAP_LOWERCASE, buf, 256, (char*)locinfo->pclmap, 256); - LCMapStringA(locinfo->lc_handle[LC_CTYPE], LCMAP_UPPERCASE, buf, 256, + LCMapStringA(cp_lcid ? cp_lcid : locinfo->lc_handle[LC_CTYPE], LCMAP_UPPERCASE, buf, 256, (char*)locinfo->pcumap, 256); } else { locinfo->lc_clike = 1; diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index 54b15b577c4..edce8bf3ae4 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -5057,11 +5057,11 @@ static void test_locale_info(void) ok(!!ret, "Got locale name %s vs %s.\n", locinfo->lc_category[LC_CTYPE].locale, locinfo2->lc_category[LC_CTYPE].locale); ret = memcmp(locinfo->ctype1, locinfo2->ctype1, 257 * sizeof(*locinfo->ctype1)); - todo_wine ok(!ret, "Got wrong ctype1 data.\n"); + ok(!ret, "Got wrong ctype1 data.\n"); ret = memcmp(locinfo->pclmap, locinfo2->pclmap, 256 * sizeof(*locinfo->pclmap)); - todo_wine ok(!ret, "Got wrong pclmap data.\n"); + ok(!ret, "Got wrong pclmap data.\n"); ret = memcmp(locinfo->pcumap, locinfo2->pcumap, 256 * sizeof(*locinfo->pcumap)); - todo_wine ok(!ret, "Got wrong pcumap data.\n"); + ok(!ret, "Got wrong pcumap data.\n"); ok(locinfo->lc_handle[LC_CTYPE] != locinfo2->lc_handle[LC_CTYPE], "Got wrong LC_CTYPE %#lx vs %#lx.\n", locinfo->lc_handle[LC_CTYPE], locinfo2->lc_handle[LC_CTYPE]);
Piotr Caban (@piotr) commented about dlls/msvcrt/tests/string.c:
test__tolower_l(); test__strnicmp_l(); test_toupper();
- test_locale_info();
The tests belong to msvcrt/tests/locale.c file.
Piotr Caban (@piotr) commented about dlls/msvcrt/locale.c:
locinfo->ctype1[0] = 0; locinfo->pctype = locinfo->ctype1+1;
cp_lcid = lcid_from_codepage(locinfo->lc_codepage);
This will not work for codepages that don't have lcid that uses them as default ansi code page (e.g. 437). I think that the correct approach is to use MultiByteToWideChar/LCMapStringW/WideCharToMultiByte instead.