msvcrt: Fix synonym handling in setlocale/create_locale.

This commit is contained in:
Piotr Caban 2010-05-09 23:39:17 +02:00 committed by Alexandre Julliard
parent 0697c5dc0e
commit 130686cbfc
2 changed files with 93 additions and 92 deletions

View file

@ -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;
}

View file

@ -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);
}