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 | 4 +- dlls/msvcrt/locale.c | 77 +++++++++++++++++----------------- 3 files changed, 44 insertions(+), 45 deletions(-)
diff --git a/dlls/msvcr110/tests/msvcr110.c b/dlls/msvcr110/tests/msvcr110.c index 2ad17195796..35ba370bb49 100644 --- a/dlls/msvcr110/tests/msvcr110.c +++ b/dlls/msvcr110/tests/msvcr110.c @@ -170,7 +170,7 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "chinese"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Chinese_China.936") + ok((!strcmp(ret, "Chinese_China.936") || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")) /* Vista */ || broken(!strcmp(ret, "Chinese_People's Republic of China.936"))), /* 7 */ "setlocale chinese failed, got %s\n", ret); @@ -179,7 +179,7 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "Chinese_China.936"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Chinese_China.936") + ok((!strcmp(ret, "Chinese_China.936") || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936")) /* Vista */ || broken(!strcmp(ret, "Chinese_People's Republic of China.936"))), /* 7 */ "setlocale Chinese_China.936 failed, got %s\n", ret); @@ -188,7 +188,7 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "chinese-simplified"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Chinese_China.936") + ok((!strcmp(ret, "Chinese_China.936") || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936"))), /* Vista */ "setlocale chinese-simplified failed, got %s\n", ret);
@@ -196,7 +196,7 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "chs"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Chinese_China.936") + ok((!strcmp(ret, "Chinese_China.936") || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936"))), /* Vista */ "setlocale chs failed, got %s\n", ret);
diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index 04870632853..838338c83f8 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -598,11 +598,11 @@ static void test____lc_locale_name_func(void)
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])); + ok(!lstrcmpW(lc_names[1], L"zh-Hans"), "lc_names[1] expected zh-Hans got %s\n", wine_dbgstr_w(lc_names[1]));
p_setlocale(LC_ALL, "zh-Hant"); lc_names = p____lc_locale_name_func(); - todo_wine ok(!lstrcmpW(lc_names[1], L"zh-Hant"), "lc_names[1] expected zh-Hant got %s\n", wine_dbgstr_w(lc_names[1])); + ok(!lstrcmpW(lc_names[1], L"zh-Hant"), "lc_names[1] expected zh-Hant got %s\n", wine_dbgstr_w(lc_names[1]));
p_setlocale(LC_ALL, "C"); lc_names = p____lc_locale_name_func(); diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index acb5cb704b7..5d58464abaa 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -235,11 +235,11 @@ static BOOL 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;
@@ -247,50 +247,48 @@ typedef struct { #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) +static int compare_info(WCHAR *name, DWORD flags, WCHAR *buff, const WCHAR *cmp, BOOL exact) { int len;
if(!cmp[0]) - return 0; + return 0;
buff[0] = 0; - GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN); + GetLocaleInfoEx(name, flags|LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN); if (!buff[0]) return 0;
/* Partial matches are only allowed on language/country names */ - len = strlen(cmp); + len = wcslen(cmp); + if(exact || len<=3) - return !_stricmp(cmp, buff); + 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; - - 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; }
/* 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) @@ -299,11 +297,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)) @@ -315,7 +313,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)) @@ -348,27 +346,27 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m if(!locale[0] || (cp == locale && !region)) { GetUserDefaultLocaleName(sname, sname_size); } else { - WCHAR wbuf[LOCALE_NAME_MAX_LENGTH]; + char search_language_buf[MAX_ELEM_LEN] = { 0 }, search_country_buf[MAX_ELEM_LEN] = { 0 }; locale_search_t search; BOOL remapped = FALSE;
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 ((remapped = remap_synonym(search.search_language))) + if ((remapped = remap_synonym(search_language_buf))) { search.allow_sname = TRUE; } @@ -380,14 +378,15 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m } #endif
- MultiByteToWideChar(CP_ACP, 0, search.search_language, -1, wbuf, LOCALE_NAME_MAX_LENGTH); - if (search.allow_sname && IsValidLocaleName(wbuf)) + MultiByteToWideChar(CP_ACP, 0, search_language_buf, -1, search.search_language, MAX_ELEM_LEN); + if (search.allow_sname && IsValidLocaleName(search.search_language)) { search.match_flags = FOUND_SNAME; - wcsncpy(sname, wbuf, sname_size); + wcsncpy(sname, search.search_language, sname_size); } else { + 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) @@ -399,7 +398,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY)) return FALSE;
- LCIDToLocaleName(search.found_lang_id, sname, sname_size, LOCALE_ALLOW_NEUTRAL_NAMES); + wcsncpy(sname, search.found_lang_sname, sname_size); }
is_sname = !remapped && (search.match_flags & FOUND_SNAME) != 0; @@ -496,8 +495,8 @@ static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat) |LOCALE_NOUSEROVERRIDE, buf, 100); if(!len) return FALSE;
- if(LocaleNameToLCID(buf, 0) != lcid) - len = LCIDToLocaleName(lcid, buf, 100, 0); + if(LocaleNameToLCID(buf, LOCALE_ALLOW_NEUTRAL_NAMES) != lcid) + len = LCIDToLocaleName(lcid, buf, 100, LOCALE_ALLOW_NEUTRAL_NAMES);
if(!len || !(locinfo->lc_name[cat] = malloc(len*sizeof(wchar_t)))) return FALSE;