From: Victor Chiletto vchiletto@codeweavers.com
GetLocaleInfoA doesn't return the proper sname for neutral LCIDs. --- dlls/msvcr110/tests/msvcr110.c | 8 ++-- dlls/msvcr120/tests/msvcr120.c | 7 ++- dlls/msvcrt/locale.c | 81 ++++++++++++++++++---------------- dlls/msvcrt/tests/locale.c | 4 +- 4 files changed, 54 insertions(+), 46 deletions(-)
diff --git a/dlls/msvcr110/tests/msvcr110.c b/dlls/msvcr110/tests/msvcr110.c index 9cdac982941..e87b2508943 100644 --- a/dlls/msvcr110/tests/msvcr110.c +++ b/dlls/msvcr110/tests/msvcr110.c @@ -153,14 +153,14 @@ static void test_setlocale(void) ok(!ret, "setlocale(en-us.1250) succeeded (%s)\n", ret);
ret = p_setlocale(LC_ALL, "zh-Hans"); - todo_wine ok(ret != NULL, "expected success, but got NULL\n"); + ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok(!strcmp(ret, "zh-Hans"), "setlocale zh-Hans failed\n"); + ok(!strcmp(ret, "zh-Hans"), "setlocale zh-Hans failed\n");
ret = p_setlocale(LC_ALL, "zh-Hant"); - todo_wine ok(ret != NULL, "expected success, but got NULL\n"); + ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok(!strcmp(ret, "zh-Hant"), "setlocale zh-Hant failed\n"); + ok(!strcmp(ret, "zh-Hant"), "setlocale zh-Hant failed\n");
/* used to return Chinese (Simplified)_China.936 */ ret = p_setlocale(LC_ALL, "chinese"); diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index 04870632853..1508994ca79 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -567,7 +567,6 @@ static void test____lc_locale_name_func(void) const WCHAR broken_name[10]; } tests[] = { { "American", {'e','n',0}, {'e','n','-','U','S',0} }, - { "Belgian", {'n','l','-','B','E',0} }, { "Chinese", {'z','h',0}, {'z','h','-','C','N',0} }, { "Dutch", {'n','l',0}, {'n','l','-','N','L',0} }, { "English", {'e','n',0}, {'e','n','-','U','S',0} }, @@ -587,7 +586,7 @@ static void test____lc_locale_name_func(void)
lc_names = p____lc_locale_name_func(); ok(lc_names[0] == NULL, "%d - lc_names[0] = %s\n", i, wine_dbgstr_w(lc_names[0])); - ok(!lstrcmpW(lc_names[1], tests[i].name) || broken(!lstrcmpW(lc_names[1], tests[i].broken_name)), + todo_wine ok(!lstrcmpW(lc_names[1], tests[i].name) || broken(!lstrcmpW(lc_names[1], tests[i].broken_name)), "%d - lc_names[1] = %s\n", i, wine_dbgstr_w(lc_names[1]));
for(j=LC_MIN+2; j<=LC_MAX; j++) { @@ -596,6 +595,10 @@ static void test____lc_locale_name_func(void) } }
+ p_setlocale(LC_ALL, "Belgian"); + lc_names = p____lc_locale_name_func(); + ok(!lstrcmpW(lc_names[1], L"nl-BE"), "lc_names[1] expected nl-BE got %s\n", wine_dbgstr_w(lc_names[1])); + p_setlocale(LC_ALL, "zh-Hans"); lc_names = p____lc_locale_name_func(); todo_wine ok(!lstrcmpW(lc_names[1], L"zh-Hans"), "lc_names[1] expected zh-Hans got %s\n", wine_dbgstr_w(lc_names[1])); diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 16ed68cdebd..7fd14f6ee7f 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -222,64 +222,63 @@ static void remap_synonym(char *name) #define FOUND_COUNTRY 0x1
typedef struct { - char search_language[MAX_ELEM_LEN]; - char search_country[MAX_ELEM_LEN]; + WCHAR search_language[MAX_ELEM_LEN]; + WCHAR search_country[MAX_ELEM_LEN]; + WCHAR found_lang_sname[LOCALE_NAME_MAX_LENGTH]; DWORD found_codepage; unsigned int match_flags; - LANGID found_lang_id; BOOL allow_sname; } locale_search_t;
#define CONTINUE_LOOKING TRUE #define STOP_LOOKING FALSE
-/* INTERNAL: Get and compare locale info with a given string */ -static int compare_info(LCID lcid, DWORD flags, char* buff, const char* cmp, BOOL exact) +/* INTERNAL: Compare locale info with given string, using the GetLocaleEx API */ +static int compare_info(WCHAR *name, DWORD flags, WCHAR *buff, const WCHAR *cmp, BOOL exact) { int len;
- if(!cmp[0]) - return 0; + if (!cmp[0]) + return 0; + + GetLocaleInfoEx(name, flags | LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN);
- buff[0] = 0; - GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN); if (!buff[0]) return 0;
- /* Partial matches are only allowed on language/country names */ - len = strlen(cmp); - if(exact || len<=3) - return !_stricmp(cmp, buff); + len = wcslen(cmp); + + if (exact || len <= 3) + return !_wcsicmp(cmp, buff); else - return !_strnicmp(cmp, buff, len); + return !_wcsnicmp(cmp, buff, len); }
static BOOL CALLBACK find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) { locale_search_t *res = (locale_search_t *)lParam; - const LCID lcid = LocaleNameToLCID( name, 0 ); - char buff[MAX_ELEM_LEN]; + WCHAR buff[MAX_ELEM_LEN]; unsigned int flags = 0;
- if (lcid == LOCALE_CUSTOM_UNSPECIFIED) return CONTINUE_LOOKING; + TRACE("%s\n", wine_dbgstr_w(res->search_language));
#if _MSVCR_VER >= 110 - if (res->allow_sname && compare_info(lcid,LOCALE_SNAME,buff,res->search_language, TRUE)) + if (res->allow_sname && compare_info(name,LOCALE_SNAME,buff,res->search_language, TRUE)) { - TRACE(":Found locale: %s->%s\n", res->search_language, buff); + TRACE(":Found locale: %s->%s\n", wine_dbgstr_w(res->search_language), wine_dbgstr_w(buff)); res->match_flags = FOUND_SNAME; - res->found_lang_id = LANGIDFROMLCID(lcid); + wcscpy(res->found_lang_sname, name); return STOP_LOOKING; } #endif
/* Check Language */ - if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language, TRUE) || - compare_info(lcid,LOCALE_SABBREVLANGNAME,buff,res->search_language, TRUE) || - compare_info(lcid,LOCALE_SENGLANGUAGE,buff,res->search_language, FALSE)) + if (compare_info(name,LOCALE_SISO639LANGNAME,buff,res->search_language, TRUE) || + compare_info(name,LOCALE_SABBREVLANGNAME,buff,res->search_language, TRUE) || + compare_info(name,LOCALE_SENGLANGUAGE,buff,res->search_language, FALSE)) { - TRACE(":Found language: %s->%s\n", res->search_language, buff); + TRACE(":Found language: %s->%s\n", wine_dbgstr_w(res->search_language), wine_dbgstr_w(buff)); flags |= FOUND_LANGUAGE; } else if (res->match_flags & FOUND_LANGUAGE) @@ -288,11 +287,11 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) }
/* Check Country */ - if (compare_info(lcid,LOCALE_SISO3166CTRYNAME,buff,res->search_country, TRUE) || - compare_info(lcid,LOCALE_SABBREVCTRYNAME,buff,res->search_country, TRUE) || - compare_info(lcid,LOCALE_SENGCOUNTRY,buff,res->search_country, FALSE)) + if (compare_info(name,LOCALE_SISO3166CTRYNAME,buff,res->search_country, TRUE) || + compare_info(name,LOCALE_SABBREVCTRYNAME,buff,res->search_country, TRUE) || + compare_info(name,LOCALE_SENGCOUNTRY,buff,res->search_country, FALSE)) { - TRACE("Found country:%s->%s\n", res->search_country, buff); + TRACE("Found country:%s->%s\n", wine_dbgstr_w(res->search_country), wine_dbgstr_w(buff)); flags |= FOUND_COUNTRY; } else if (!flags && (res->match_flags & FOUND_COUNTRY)) @@ -304,7 +303,7 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) { /* Found a better match than previously */ res->match_flags = flags; - res->found_lang_id = LANGIDFROMLCID(lcid); + wcscpy(res->found_lang_sname, name); } if ((flags & (FOUND_LANGUAGE | FOUND_COUNTRY)) == (FOUND_LANGUAGE | FOUND_COUNTRY)) @@ -339,29 +338,33 @@ LCID locale_to_LCID(const char *locale, unsigned short *codepage, BOOL *sname) lcid = GetUserDefaultLCID(); } else { locale_search_t search; + char search_language_buf[MAX_ELEM_LEN] = { 0 }, search_country_buf[MAX_ELEM_LEN] = { 0 };
memset(&search, 0, sizeof(locale_search_t)); - lstrcpynA(search.search_language, locale, MAX_ELEM_LEN); + lstrcpynA(search_language_buf, locale, MAX_ELEM_LEN); if(region) { - lstrcpynA(search.search_country, region+1, MAX_ELEM_LEN); + lstrcpynA(search_country_buf, region+1, MAX_ELEM_LEN); if(region-locale < MAX_ELEM_LEN) - search.search_language[region-locale] = '\0'; + search_language_buf[region-locale] = '\0'; } else - search.search_country[0] = '\0'; + search_country_buf[0] = '\0';
if(cp) { if(region && cp-region-1<MAX_ELEM_LEN) - search.search_country[cp-region-1] = '\0'; + search_country_buf[cp-region-1] = '\0'; if(cp-locale < MAX_ELEM_LEN) - search.search_language[cp-locale] = '\0'; + search_language_buf[cp-locale] = '\0'; }
if(!cp && !region) { - remap_synonym(search.search_language); + remap_synonym(search_language_buf); search.allow_sname = TRUE; }
+ MultiByteToWideChar(CP_ACP, 0, search_language_buf, -1, search.search_language, MAX_ELEM_LEN); + MultiByteToWideChar(CP_ACP, 0, search_country_buf, -1, search.search_country, MAX_ELEM_LEN); + EnumSystemLocalesEx( find_best_locale_proc, 0, (LPARAM)&search, NULL);
if (!search.match_flags) @@ -373,7 +376,7 @@ LCID locale_to_LCID(const char *locale, unsigned short *codepage, BOOL *sname) if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY)) return -1;
- lcid = MAKELCID(search.found_lang_id, SORT_DEFAULT); + lcid = LocaleNameToLCID(search.found_lang_sname, LOCALE_ALLOW_NEUTRAL_NAMES); is_sname = (search.match_flags & FOUND_SNAME) != 0; }
@@ -517,9 +520,11 @@ static BOOL update_threadlocinfo_category(LCID lcid, unsigned short cp, set_lc_locale_name(locinfo, category);
if(!locinfo->lc_category[category].locale) { + /* new norwegian nynorsk LCID */ + static const LCID norwegian_nynorsk_lcid = 0x7814; int len = 0;
- if (lcid == MAKELANGID( LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK )) + if (lcid == norwegian_nynorsk_lcid) { /* locale.nls contains "Norwegian Nynorsk" instead for LOCALE_SENGLANGUAGE */ strcpy( buf, "Norwegian-Nynorsk" ); diff --git a/dlls/msvcrt/tests/locale.c b/dlls/msvcrt/tests/locale.c index f77e8f93abb..56fe17f2f68 100644 --- a/dlls/msvcrt/tests/locale.c +++ b/dlls/msvcrt/tests/locale.c @@ -129,7 +129,7 @@ static void test_setlocale(void) ret = setlocale(LC_ALL, "chinese-traditional"); ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) - ok(!strcmp(ret, "Chinese (Traditional)_Taiwan.950") + todo_wine ok(!strcmp(ret, "Chinese (Traditional)_Taiwan.950") || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret);
ret = setlocale(LC_ALL, "chs"); @@ -142,7 +142,7 @@ static void test_setlocale(void) ret = setlocale(LC_ALL, "cht"); ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) - ok(!strcmp(ret, "Chinese (Traditional)_Taiwan.950") + todo_wine ok(!strcmp(ret, "Chinese (Traditional)_Taiwan.950") || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret);
ret = setlocale(LC_ALL, "Chinese_China.936");