From 130686cbfca578baa233669559c42e8f0ce0ee8b Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Sun, 9 May 2010 23:39:17 +0200 Subject: [PATCH] msvcrt: Fix synonym handling in setlocale/create_locale. --- dlls/msvcrt/locale.c | 101 ++++++++++++++++++++----------------- dlls/msvcrt/tests/locale.c | 84 ++++++++++++++---------------- 2 files changed, 93 insertions(+), 92 deletions(-) diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 066e3ed0ca9..38d39a27f32 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -38,9 +38,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); -/* FIXME: Need to hold locale for each LC_* type and aggregate - * string to produce lc_all. - */ #define MAX_ELEM_LEN 64 /* Max length of country/language/CP string */ #define MAX_LOCALE_LENGTH 256 MSVCRT__locale_t MSVCRT_locale = NULL; @@ -56,25 +53,42 @@ unsigned char charmax = CHAR_MAX; #define MSVCRT_LEADBYTE 0x8000 #define MSVCRT_C1_DEFINED 0x200 -/* Friendly country strings & iso codes for synonym support. - * Based on MS documentation for setlocale(). - */ +/* Friendly country strings & language names abbreviations. */ static const char * const _country_synonyms[] = { - "Hong Kong","HK", - "Hong-Kong","HK", - "New Zealand","NZ", - "New-Zealand","NZ", - "PR China","CN", - "PR-China","CN", - "United Kingdom","GB", - "United-Kingdom","GB", - "Britain","GB", - "England","GB", - "Great Britain","GB", - "United States","US", - "United-States","US", - "America","US" + "american", "enu", + "american english", "enu", + "american-english", "enu", + "english-american", "enu", + "english-us", "enu", + "english-usa", "enu", + "us", "enu", + "usa", "enu", + "australian", "ena", + "english-aus", "ena", + "belgian", "nlb", + "french-belgian", "frb", + "canadian", "enc", + "english-can", "enc", + "french-canadian", "frc", + "chinese", "chs", + "chinese-simplified", "chs", + "chinese-traditional", "cht", + "dutch-belgian", "nlb", + "english-nz", "enz", + "uk", "eng", + "english-uk", "eng", + "french-swiss", "frs", + "swiss", "des", + "german-swiss", "des", + "italian-swiss", "its", + "german-austrian", "dea", + "portugese", "ptb", + "portuguese-brazil", "ptb", + "spanish-mexican", "esm", + "norwegian-bokmal", "nor", + "norwegian-nynorsk", "non", + "spanish-modern", "esn" }; /* INTERNAL: Map a synonym to an ISO code */ @@ -86,9 +100,7 @@ static void remap_synonym(char *name) if (!strcasecmp(_country_synonyms[i],name)) { TRACE(":Mapping synonym %s to %s\n",name,_country_synonyms[i+1]); - name[0] = _country_synonyms[i+1][0]; - name[1] = _country_synonyms[i+1][1]; - name[2] = '\0'; + memcpy(name, _country_synonyms[i+1], sizeof(_country_synonyms[i+1])); return; } } @@ -103,8 +115,6 @@ typedef struct { char search_language[MAX_ELEM_LEN]; char search_country[MAX_ELEM_LEN]; char search_codepage[MAX_ELEM_LEN]; - char found_language[MAX_ELEM_LEN]; - char found_country[MAX_ELEM_LEN]; char found_codepage[MAX_ELEM_LEN]; unsigned int match_flags; LANGID found_lang_id; @@ -114,14 +124,21 @@ 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) +static int compare_info(LCID lcid, DWORD flags, char* buff, const char* cmp, BOOL exact) { + int len; + buff[0] = 0; - GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE,buff, MAX_ELEM_LEN); + GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN); if (!buff[0] || !cmp[0]) return 0; - /* Partial matches are allowed, e.g. "Germ" matches "Germany" */ - return !strncasecmp(cmp, buff, strlen(cmp)); + + /* Partial matches are only allowed on language/country names */ + len = strlen(cmp); + if(exact || len<=3) + return !strcasecmp(cmp, buff); + else + return !strncasecmp(cmp, buff, len); } static BOOL CALLBACK @@ -136,13 +153,12 @@ find_best_locale_proc(HMODULE hModule, LPCSTR type, LPCSTR name, WORD LangID, LO return CONTINUE_LOOKING; /* Check Language */ - if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language) || - compare_info(lcid,LOCALE_SABBREVLANGNAME,buff,res->search_language) || - compare_info(lcid,LOCALE_SENGLANGUAGE,buff,res->search_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)) { TRACE(":Found language: %s->%s\n", res->search_language, buff); flags |= FOUND_LANGUAGE; - memcpy(res->found_language,res->search_language,MAX_ELEM_LEN); } else if (res->match_flags & FOUND_LANGUAGE) { @@ -150,13 +166,12 @@ find_best_locale_proc(HMODULE hModule, LPCSTR type, LPCSTR name, WORD LangID, LO } /* Check Country */ - if (compare_info(lcid,LOCALE_SISO3166CTRYNAME,buff,res->search_country) || - compare_info(lcid,LOCALE_SABBREVCTRYNAME,buff,res->search_country) || - compare_info(lcid,LOCALE_SENGCOUNTRY,buff,res->search_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)) { TRACE("Found country:%s->%s\n", res->search_country, buff); flags |= FOUND_COUNTRY; - memcpy(res->found_country,res->search_country,MAX_ELEM_LEN); } else if (res->match_flags & FOUND_COUNTRY) { @@ -164,8 +179,8 @@ find_best_locale_proc(HMODULE hModule, LPCSTR type, LPCSTR name, WORD LangID, LO } /* Check codepage */ - if (compare_info(lcid,LOCALE_IDEFAULTCODEPAGE,buff,res->search_codepage) || - (compare_info(lcid,LOCALE_IDEFAULTANSICODEPAGE,buff,res->search_codepage))) + if (compare_info(lcid,LOCALE_IDEFAULTCODEPAGE,buff,res->search_codepage, TRUE) || + (compare_info(lcid,LOCALE_IDEFAULTANSICODEPAGE,buff,res->search_codepage, TRUE))) { TRACE("Found codepage:%s->%s\n", res->search_codepage, buff); flags |= FOUND_CODEPAGE; @@ -222,8 +237,8 @@ static LCID MSVCRT_locale_to_LCID(const char *locale) } else search.search_codepage[0] = '\0'; - /* FIXME: MSVCRT_locale_to_LCID is not finding remaped values */ - remap_synonym(search.search_country); + if(!search.search_country[0] && !search.search_codepage[0]) + remap_synonym(search.search_language); EnumResourceLanguagesA(GetModuleHandleA("KERNEL32"), (LPSTR)RT_STRING, (LPCSTR)LOCALE_ILANGUAGE,find_best_locale_proc, @@ -269,10 +284,6 @@ static LCID MSVCRT_locale_to_LCID(const char *locale) } } - GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE, - search.found_language, MAX_ELEM_LEN); - GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY|LOCALE_NOUSEROVERRIDE, - search.found_country, MAX_ELEM_LEN); return lcid; } diff --git a/dlls/msvcrt/tests/locale.c b/dlls/msvcrt/tests/locale.c index 0533217a450..cf51c4c7eed 100644 --- a/dlls/msvcrt/tests/locale.c +++ b/dlls/msvcrt/tests/locale.c @@ -77,38 +77,33 @@ static void test_setlocale(void) ret = setlocale(LC_ALL, "German"); ok(!strcmp(ret, "German_Germany.1252"), "ret = %s\n", ret); - /* This test shows that _country_synonyms table is incorrect */ - /* It translates "America" to "US" */ - ret = setlocale(LC_ALL, "America"); - ok(ret == NULL, "ret = %s\n", ret); - ret = setlocale(LC_ALL, "american"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "american english"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "american-english"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "australian"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_Australia.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "belgian"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "Dutch_Belgium.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "canadian"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_Canada.1252"), "ret = %s\n", ret); @@ -119,15 +114,15 @@ static void test_setlocale(void) || broken(!strcmp(ret, "Chinese_Taiwan.950")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "chinese-simplified"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) - ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936") + todo_wine ok(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936") || broken(!strcmp(ret, "Chinese_People's Republic of China.936")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "chinese-traditional"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + 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"); @@ -183,7 +178,7 @@ static void test_setlocale(void) ok(!strcmp(ret, "Dutch_Netherlands.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "dutch-belgian"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "Dutch_Belgium.1252") || broken(!strcmp(ret, "Dutch_Netherlands.1252")), "ret = %s\n", ret); @@ -208,7 +203,7 @@ static void test_setlocale(void) ret = setlocale(LC_ALL, "eng"); ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) - todo_wine ok(!strcmp(ret, "English_United Kingdom.1252") + ok(!strcmp(ret, "English_United Kingdom.1252") || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "enu"); @@ -228,41 +223,41 @@ static void test_setlocale(void) ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "english-american"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "english-aus"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_Australia.1252") || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "english-can"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_Canada.1252") || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "english-nz"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_New Zealand.1252") || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "english-uk"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_United Kingdom.1252") || broken(!strcmp(ret, "English_United States.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "english-us"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "english-usa"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret); @@ -316,19 +311,19 @@ static void test_setlocale(void) ok(!strcmp(ret, "French_France.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "french-belgian"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "French_Belgium.1252") || broken(!strcmp(ret, "French_France.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "french-canadian"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "French_Canada.1252") || broken(!strcmp(ret, "French_France.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "french-swiss"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "French_Switzerland.1252") || broken(!strcmp(ret, "French_France.1252")), "ret = %s\n", ret); @@ -345,13 +340,13 @@ static void test_setlocale(void) ok(!strcmp(ret, "German_Germany.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "german-austrian"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "German_Austria.1252") || broken(!strcmp(ret, "German_Germany.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "german-swiss"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "German_Switzerland.1252") || broken(!strcmp(ret, "German_Germany.1252")), "ret = %s\n", ret); @@ -392,7 +387,7 @@ static void test_setlocale(void) ok(!strcmp(ret, "Italian_Italy.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "italian-swiss"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "Italian_Switzerland.1252") || broken(!strcmp(ret, "Italian_Italy.1252")), "ret = %s\n", ret); @@ -447,15 +442,15 @@ static void test_setlocale(void) || broken(!strcmp(ret, "Norwegian_Norway.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "norwegian-bokmal"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "Norwegian (Bokmål)_Norway.1252") || broken(!strcmp(ret, "Norwegian_Norway.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "norwegian-nynorsk"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) - ok(!strcmp(ret, "Norwegian-Nynorsk_Norway.1252") + todo_wine ok(!strcmp(ret, "Norwegian-Nynorsk_Norway.1252") || broken(!strcmp(ret, "Norwegian_Norway.1252")) || broken(!strcmp(ret, "Norwegian (Nynorsk)_Norway.1252")) || broken(!strcmp(ret, "Norwegian (Bokmål)_Norway.1252")), "ret = %s\n", ret); @@ -471,12 +466,12 @@ static void test_setlocale(void) ok(!strcmp(ret, "Polish_Poland.1250"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "portugese"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "Portuguese_Brazil.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "portuguese-brazil"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "Portuguese_Brazil.1252"), "ret = %s\n", ret); @@ -517,15 +512,15 @@ static void test_setlocale(void) || broken(!strcmp(ret, "Spanish - Traditional Sort_Spain.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "spanish-mexican"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "Spanish_Mexico.1252") || broken(!strcmp(ret, "Spanish_Spain.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "spanish-modern"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) - ok(!strcmp(ret, "Spanish - Modern Sort_Spain.1252") + todo_wine ok(!strcmp(ret, "Spanish - Modern Sort_Spain.1252") || broken(!strcmp(ret, "Spanish_Spain.1252")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "sve"); @@ -539,7 +534,7 @@ static void test_setlocale(void) ok(!strcmp(ret, "Swedish_Sweden.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "swiss"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "German_Switzerland.1252"), "ret = %s\n", ret); @@ -556,21 +551,16 @@ static void test_setlocale(void) ret = setlocale(LC_ALL, "uk"); ok(ret != NULL, "ret == NULL\n"); if(ret) - todo_wine ok(!strcmp(ret, "English_United Kingdom.1252") + ok(!strcmp(ret, "English_United Kingdom.1252") || broken(!strcmp(ret, "Ukrainian_Ukraine.1251")), "ret = %s\n", ret); ret = setlocale(LC_ALL, "us"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret); ret = setlocale(LC_ALL, "usa"); - todo_wine ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); - if(ret) - ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret); - - ret = setlocale(LC_ALL, "US"); - todo_wine ok(ret != NULL, "ret == NULL\n"); + ok(ret != NULL || broken (ret == NULL), "ret == NULL\n"); if(ret) ok(!strcmp(ret, "English_United States.1252"), "ret = %s\n", ret); }