This MR attempts to bring Wine's handling of `setlocale` and `_create_locale` more in line with the behavior of native >= `msvcr110`. It does this by replacing the usage of the LCID based `GetLocaleInfo` with the sname based `GetLocaleInfoEx`. `GetLocaleInfo` doesn't support neutral locales, even on native, which causes problems with neutral Chinese locales like `zh-Hans` and `zh-Hant`.
It also improves the accuracy of the internal `__lc_locale_name_func`, as tests indicate that it returns `LOCALE_SNAME`s instead of ISO 639 language names.
Potential future improvements: * Modifying the generation of the `pclmap` and `pcumap` fields of `threadlocaleinfostruct` to work on WCHARs. * I've done some changes to `__thread_data` which make it not fully match native, I'll submit a follow up which fixes this.
-- v5: msvcrt: Use GetLocaleInfoEx to compare locale info. msvcrt: Remap synonyms to snames. msvcrt: Simplify set_lc_locale_name. msvcrt: Skip exhaustive locale search with valid snames. msvcrt: Convert locale_to_LCID to snames. msvcrt: Use snames instead of LCIDs in create_locinfo. msvcr120/tests: Check ___lc_locale_name_func with neutral Chinese locales. msvcr110/tests: Add tests for new setlocale behaviors.
From: Victor Chiletto vchiletto@codeweavers.com
A bunch of locales had changes >= msvcr 110. --- dlls/msvcr110/tests/msvcr110.c | 78 ++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+)
diff --git a/dlls/msvcr110/tests/msvcr110.c b/dlls/msvcr110/tests/msvcr110.c index 255c68b0796..cf76720d806 100644 --- a/dlls/msvcr110/tests/msvcr110.c +++ b/dlls/msvcr110/tests/msvcr110.c @@ -152,6 +152,84 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "en-us.1250"); ok(!ret, "setlocale(en-us.1250) succeeded (%s)\n", ret);
+ ret = p_setlocale(LC_ALL, "zh-Hans"); + todo_wine ok((ret != NULL + || broken(ret == NULL)), /* Vista */ + "expected success, but got NULL\n"); + if (ret) + ok(!strcmp(ret, "zh-Hans"), "setlocale zh-Hans failed\n"); + + ret = p_setlocale(LC_ALL, "zh-Hant"); + todo_wine ok((ret != NULL + || broken(ret == NULL)), /* Vista */ + "expected success, but got NULL\n"); + if (ret) + ok(!strcmp(ret, "zh-Hant"), "setlocale zh-Hant failed\n"); + + /* used to return Chinese (Simplified)_China.936 */ + 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") + || 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); + + /* used to return Chinese (Simplified)_China.936 */ + 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") + || 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); + + /* used to return Chinese (Simplified)_China.936 */ + 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") + || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936"))), /* Vista */ + "setlocale chinese-simplified failed, got %s\n", ret); + + /* used to return Chinese (Simplified)_China.936 */ + 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") + || broken(!strcmp(ret, "Chinese (Simplified)_People's Republic of China.936"))), /* Vista */ + "setlocale chs failed, got %s\n", ret); + + /* used to return Chinese (Traditional)_Taiwan.950 */ + ret = p_setlocale(LC_ALL, "cht"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Chinese (Traditional)_Hong Kong SAR.950") + || broken(!strcmp(ret, "Chinese (Traditional)_Taiwan.950"))), /* Vista - 7 */ + "setlocale cht failed, got %s\n", ret); + + /* used to return Chinese (Traditional)_Taiwan.950 */ + ret = p_setlocale(LC_ALL, "chinese-traditional"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Chinese (Traditional)_Hong Kong SAR.950") + || broken(!strcmp(ret, "Chinese (Traditional)_Taiwan.950"))), /* Vista - 7 */ + "setlocale chinese-traditional failed, got %s\n", ret); + + ret = p_setlocale(LC_ALL, "norwegian-nynorsk"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") + || broken(!strcmp(ret, "Norwegian (Nynorsk)_Norway.1252"))), /* Vista - 7 */ + "setlocale norwegian-nynorsk failed, got %s\n", ret); + + ret = p_setlocale(LC_ALL, "non"); + ok(ret != NULL, "expected success, but got NULL\n"); + if (ret) + todo_wine ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") + || broken(!strcmp(ret, "Norwegian (Nynorsk)_Norway.1252"))), /* Vista - 7 */ + "setlocale norwegian-nynorsk failed, got %s\n", ret); + p_setlocale(LC_ALL, "C"); }
From: Victor Chiletto vchiletto@codeweavers.com
--- dlls/msvcr120/tests/msvcr120.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index e5a5ff0435d..04870632853 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -596,6 +596,14 @@ 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])); + + 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])); + p_setlocale(LC_ALL, "C"); lc_names = p____lc_locale_name_func(); ok(!lc_names[1], "___lc_locale_name_func()[1] = %s\n", wine_dbgstr_w(lc_names[1]));
From: Victor Chiletto vchiletto@codeweavers.com
--- dlls/msvcr110/tests/msvcr110.c | 12 +- dlls/msvcrt/locale.c | 459 ++++++++++++++++++--------------- 2 files changed, 257 insertions(+), 214 deletions(-)
diff --git a/dlls/msvcr110/tests/msvcr110.c b/dlls/msvcr110/tests/msvcr110.c index cf76720d806..60d876e3bfc 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);
@@ -219,14 +219,14 @@ static void test_setlocale(void) ret = p_setlocale(LC_ALL, "norwegian-nynorsk"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") + ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") || broken(!strcmp(ret, "Norwegian (Nynorsk)_Norway.1252"))), /* Vista - 7 */ "setlocale norwegian-nynorsk failed, got %s\n", ret);
ret = p_setlocale(LC_ALL, "non"); ok(ret != NULL, "expected success, but got NULL\n"); if (ret) - todo_wine ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") + ok((!strcmp(ret, "Norwegian Nynorsk_Norway.1252") || broken(!strcmp(ret, "Norwegian (Nynorsk)_Norway.1252"))), /* Vista - 7 */ "setlocale norwegian-nynorsk failed, got %s\n", ret);
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 16ed68cdebd..845de26155c 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -51,6 +51,12 @@ BOOL initial_locale = TRUE; #define MSVCRT_LEADBYTE 0x8000 #define MSVCRT_C1_DEFINED 0x200
+#if _MSVCR_VER >= 110 +#define LCID_CONVERSION_FLAGS LOCALE_ALLOW_NEUTRAL_NAMES +#else +#define LCID_CONVERSION_FLAGS 0 +#endif + __lc_time_data cloc_time_data = { {{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", @@ -258,7 +264,7 @@ 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 ); + const LCID lcid = LocaleNameToLCID( name, LCID_CONVERSION_FLAGS ); char buff[MAX_ELEM_LEN]; unsigned int flags = 0;
@@ -469,8 +475,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; @@ -486,13 +492,13 @@ static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat) #endif
/* INTERNAL: Set lc_handle, lc_id and lc_category in threadlocinfo struct */ -static BOOL update_threadlocinfo_category(LCID lcid, unsigned short cp, +static BOOL update_threadlocinfo_category(WCHAR *sname, unsigned short cp, pthreadlocinfo locinfo, int category) { - char buf[256], *p; + WCHAR wbuf[256], *p;
- if(GetLocaleInfoA(lcid, LOCALE_ILANGUAGE|LOCALE_NOUSEROVERRIDE, buf, 256)) { - p = buf; + if(GetLocaleInfoEx(sname, LOCALE_ILANGUAGE|LOCALE_NOUSEROVERRIDE, wbuf, ARRAY_SIZE(wbuf))) { + p = wbuf;
locinfo->lc_id[category].wLanguage = 0; while(*p) { @@ -512,26 +518,32 @@ static BOOL update_threadlocinfo_category(LCID lcid, unsigned short cp,
locinfo->lc_id[category].wCodePage = cp;
- locinfo->lc_handle[category] = lcid; + locinfo->lc_handle[category] = LocaleNameToLCID(sname, LCID_CONVERSION_FLAGS);
set_lc_locale_name(locinfo, category);
if(!locinfo->lc_category[category].locale) { + char buf[256]; int len = 0;
- if (lcid == MAKELANGID( LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK )) +#if _MSVCR_VER < 110 + if (LANGIDFROMLCID(locinfo->lc_handle[category]) == MAKELANGID(LANG_NORWEGIAN, SUBLANG_NORWEGIAN_NYNORSK)) { /* locale.nls contains "Norwegian Nynorsk" instead for LOCALE_SENGLANGUAGE */ - strcpy( buf, "Norwegian-Nynorsk" ); - len = strlen( buf ) + 1; + wcscpy( wbuf, L"Norwegian-Nynorsk" ); + len = wcslen( wbuf ) + 1; } - else len += GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE, buf, 256); - buf[len-1] = '_'; - len += GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY - |LOCALE_NOUSEROVERRIDE, &buf[len], 256-len); - buf[len-1] = '.'; - sprintf(buf+len, "%d", cp); - len += strlen(buf+len); + else +#endif + len += GetLocaleInfoEx(sname, LOCALE_SENGLANGUAGE|LOCALE_NOUSEROVERRIDE, wbuf, ARRAY_SIZE(wbuf)); + wbuf[len-1] = '_'; + len += GetLocaleInfoEx(sname, LOCALE_SENGCOUNTRY + |LOCALE_NOUSEROVERRIDE, &wbuf[len], ARRAY_SIZE(wbuf) - len); + wbuf[len-1] = '.'; + swprintf(wbuf+len, ARRAY_SIZE(wbuf) - len,L"%d", cp); + len += wcslen(wbuf+len); + + WideCharToMultiByte(cp, 0, wbuf, -1, buf, ARRAY_SIZE(buf), NULL, NULL);
return init_category_name(buf, len, locinfo, category); } @@ -1161,13 +1173,22 @@ void CDECL _free_locale(_locale_t locale) }
static inline BOOL category_needs_update(int cat, - const threadlocinfo *locinfo, LCID lcid, unsigned short cp) + const threadlocinfo *locinfo, WCHAR *sname, unsigned short cp) { +#if _MSVCR_VER < 110 + LCID lcid; +#endif if(!locinfo) return TRUE; +#if _MSVCR_VER >= 110 + if(!locinfo->lc_name[cat] || !sname) return TRUE; + return wcscmp(sname, locinfo->lc_name[cat]) != 0 || cp!=locinfo->lc_id[cat].wCodePage; +#else + lcid = sname ? LocaleNameToLCID(sname, 0) : 0; return lcid!=locinfo->lc_handle[cat] || cp!=locinfo->lc_id[cat].wCodePage; +#endif }
-static __lc_time_data* create_time_data(LCID lcid) +static __lc_time_data* create_time_data(WCHAR *sname) { static const DWORD time_data[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, @@ -1189,6 +1210,7 @@ static __lc_time_data* create_time_data(LCID lcid)
__lc_time_data *cur; int i, ret, size; + LCID lcid = LocaleNameToLCID(sname, LCID_CONVERSION_FLAGS);
size = sizeof(__lc_time_data); for(i=0; i<ARRAY_SIZE(time_data); i++) { @@ -1198,14 +1220,14 @@ static __lc_time_data* create_time_data(LCID lcid) size += ret;
#if _MSVCR_VER == 0 || _MSVCR_VER >= 100 - ret = GetLocaleInfoW(lcid, time_data[i], NULL, 0); + ret = GetLocaleInfoEx(sname, time_data[i], NULL, 0); if(!ret) return NULL; size += ret*sizeof(wchar_t); #endif } #if _MSVCR_VER >= 110 - size += LCIDToLocaleName(lcid, NULL, 0, 0)*sizeof(wchar_t); + size += wcslen(sname)*sizeof(wchar_t); #endif
cur = malloc(size); @@ -1220,13 +1242,13 @@ static __lc_time_data* create_time_data(LCID lcid) #if _MSVCR_VER == 0 || _MSVCR_VER >= 100 for(i=0; i<ARRAY_SIZE(time_data); i++) { cur->wstr.wstr[i] = (wchar_t*)&cur->data[ret]; - ret += GetLocaleInfoW(lcid, time_data[i], + ret += GetLocaleInfoEx(sname, time_data[i], (wchar_t*)&cur->data[ret], size-ret)*sizeof(wchar_t); } #endif #if _MSVCR_VER >= 110 cur->locname = (wchar_t*)&cur->data[ret]; - LCIDToLocaleName(lcid, (wchar_t*)&cur->data[ret], (size-ret)/sizeof(wchar_t), 0); + wcsncpy((wchar_t *) &cur->data[ret], sname, size-ret); #else cur->lcid = lcid; #endif @@ -1245,16 +1267,14 @@ static pthreadlocinfo create_locinfo(int category, static const char numeric[] = "NUMERIC="; static const char time[] = "TIME=";
- pthreadlocinfo locinfo; - LCID lcid[6] = { 0 }; + pthreadlocinfo locinfo = NULL; unsigned short cp[6] = { 0 }; const char *locale_name[6] = { 0 }; + WCHAR *locale_sname[6] = { 0 }; int val, locale_len[6] = { 0 }; char buf[256]; - BOOL sname; -#if _MSVCR_VER >= 100 + BOOL sname_match; wchar_t wbuf[256]; -#endif int i;
TRACE("(%d %s)\n", category, locale); @@ -1263,9 +1283,10 @@ static pthreadlocinfo create_locinfo(int category, return NULL;
if(locale[0]=='C' && !locale[1]) { - lcid[0] = 0; + locale_sname[0] = NULL; cp[0] = CP_ACP; } else if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') { + LCID lcid; const char *p;
while(1) { @@ -1286,30 +1307,39 @@ static pthreadlocinfo create_locinfo(int category, i = LC_TIME; locale += sizeof(time)-1; } else - return NULL; + goto fail;
p = strchr(locale, ';'); if(locale[0]=='C' && (locale[1]==';' || locale[1]=='\0')) { - lcid[i] = 0; + lcid = 0; + locale_sname[i] = NULL; cp[i] = CP_ACP; } else if(p) { memcpy(buf, locale, p-locale); buf[p-locale] = '\0'; - lcid[i] = locale_to_LCID(buf, &cp[i], &sname); - if(sname) { + lcid = locale_to_LCID(buf, &cp[i], &sname_match); + if(sname_match) { locale_name[i] = locale; locale_len[i] = p-locale; } } else { - lcid[i] = locale_to_LCID(locale, &cp[i], &sname); - if(sname) { + lcid = locale_to_LCID(locale, &cp[i], &sname_match); + if(sname_match) { locale_name[i] = locale; locale_len[i] = strlen(locale); } }
- if(lcid[i] == -1) - return NULL; + if(lcid == -1) + goto fail; + + if(lcid) { + int sname_size = LCIDToLocaleName(lcid, NULL, 0, LCID_CONVERSION_FLAGS); + locale_sname[i] = malloc(sname_size * sizeof(WCHAR)); + if(!locale_sname[i]) + goto fail; + LCIDToLocaleName(lcid, locale_sname[i], sname_size, LCID_CONVERSION_FLAGS); + }
if(!p || *(p+1)!='L' || *(p+2)!='C' || *(p+3)!='_') break; @@ -1317,16 +1347,26 @@ static pthreadlocinfo create_locinfo(int category, locale = p+1; } } else { - lcid[0] = locale_to_LCID(locale, &cp[0], &sname); - if(lcid[0] == -1) + LCID lcid = locale_to_LCID(locale, &cp[0], &sname_match); + if(lcid == -1) return NULL; - if(sname) { + if(lcid) { + int sname_size = LCIDToLocaleName(lcid, NULL, 0, LCID_CONVERSION_FLAGS); + locale_sname[0] = malloc(sname_size * sizeof(WCHAR)); + if(!locale_sname[0]) + return NULL; + LCIDToLocaleName(lcid, locale_sname[0], sname_size, LCID_CONVERSION_FLAGS); + } + if(sname_match) { locale_name[0] = locale; locale_len[0] = strlen(locale); }
for(i=1; i<6; i++) { - lcid[i] = lcid[0]; + locale_sname[i] = wcsdup(locale_sname[0]); + if(!locale_sname[i]) + goto fail; + cp[i] = cp[0]; locale_name[i] = locale_name[0]; locale_len[i] = locale_len[0]; @@ -1336,18 +1376,51 @@ static pthreadlocinfo create_locinfo(int category, for(i=1; i<6; i++) { #if _MSVCR_VER < 140 if(i==LC_CTYPE && cp[i]==CP_UTF8) { +#if _MSVCR_VER >= 110 + if(old_locinfo) { + locale_sname[i] = wcsdup(old_locinfo->lc_name[i]); + if (old_locinfo->lc_name[i] && !locale_sname[i]) + goto fail; + } +#else + int sname_size; + if(old_locinfo && old_locinfo->lc_handle[i]) { + sname_size = LCIDToLocaleName(old_locinfo->lc_handle[i], NULL, 0, 0); + locale_sname[i] = malloc(sname_size * sizeof(WCHAR)); + if(!locale_sname[i]) + goto fail; + LCIDToLocaleName(old_locinfo->lc_handle[i], locale_sname[i], sname_size, 0); + } else { + locale_sname[i] = NULL; + } +#endif + locale_name[i] = NULL; locale_len[i] = 0; - lcid[i] = old_locinfo ? old_locinfo->lc_handle[i] : 0; cp[i] = old_locinfo ? old_locinfo->lc_id[i].wCodePage : 0; } #endif if(category!=LC_ALL && category!=i) { if(old_locinfo) { - lcid[i] = old_locinfo->lc_handle[i]; +#if _MSVCR_VER >= 110 + locale_sname[i] = wcsdup(old_locinfo->lc_name[i]); + if(old_locinfo->lc_name[i] && !locale_sname[i]) + goto fail; +#else + int sname_size; + if(old_locinfo->lc_handle[i]) { + sname_size = LCIDToLocaleName(old_locinfo->lc_handle[i], NULL, 0, 0); + locale_sname[i] = malloc(sname_size * sizeof(WCHAR)); + if(!locale_sname[i]) + goto fail; + LCIDToLocaleName(old_locinfo->lc_handle[i], locale_sname[i], sname_size, 0); + } else { + locale_sname[i] = NULL; + } +#endif cp[i] = old_locinfo->lc_id[i].wCodePage; } else { - lcid[i] = 0; + locale_sname[i] = NULL; cp[i] = 0; } } @@ -1355,7 +1428,7 @@ static pthreadlocinfo create_locinfo(int category,
locinfo = malloc(sizeof(threadlocinfo)); if(!locinfo) - return NULL; + goto fail;
memset(locinfo, 0, sizeof(threadlocinfo)); locinfo->refcount = 1; @@ -1363,38 +1436,34 @@ static pthreadlocinfo create_locinfo(int category, if(locale_name[LC_COLLATE] && !init_category_name(locale_name[LC_COLLATE], locale_len[LC_COLLATE], locinfo, LC_COLLATE)) { - free_locinfo(locinfo); - return NULL; + goto fail; }
if(!category_needs_update(LC_COLLATE, old_locinfo, - lcid[LC_COLLATE], cp[LC_COLLATE])) { + locale_sname[LC_COLLATE], cp[LC_COLLATE])) { copy_threadlocinfo_category(locinfo, old_locinfo, LC_COLLATE); locinfo->lc_collate_cp = old_locinfo->lc_collate_cp; - } else if(lcid[LC_COLLATE]) { - if(!update_threadlocinfo_category(lcid[LC_COLLATE], + } else if(locale_sname[LC_COLLATE]) { + if(!update_threadlocinfo_category(locale_sname[LC_COLLATE], cp[LC_COLLATE], locinfo, LC_COLLATE)) { - free_locinfo(locinfo); - return NULL; + goto fail; }
locinfo->lc_collate_cp = locinfo->lc_id[LC_COLLATE].wCodePage; } else { if(!init_category_name("C", 1, locinfo, LC_COLLATE)) { - free_locinfo(locinfo); - return NULL; + goto fail; } }
if(locale_name[LC_CTYPE] && !init_category_name(locale_name[LC_CTYPE], locale_len[LC_CTYPE], locinfo, LC_CTYPE)) { - free_locinfo(locinfo); - return NULL; + goto fail; }
if(!category_needs_update(LC_CTYPE, old_locinfo, - lcid[LC_CTYPE], cp[LC_CTYPE])) { + locale_sname[LC_CTYPE], cp[LC_CTYPE])) { copy_threadlocinfo_category(locinfo, old_locinfo, LC_CTYPE); locinfo->lc_codepage = old_locinfo->lc_codepage; locinfo->lc_clike = old_locinfo->lc_clike; @@ -1406,28 +1475,25 @@ static pthreadlocinfo create_locinfo(int category, locinfo->pcumap = old_locinfo->pcumap; if(locinfo->ctype1_refcount) InterlockedIncrement((LONG *)locinfo->ctype1_refcount); - } else if(lcid[LC_CTYPE]) { + } else if(locale_sname[LC_CTYPE]) { CPINFO cp_info; int j;
- if(!update_threadlocinfo_category(lcid[LC_CTYPE], + if(!update_threadlocinfo_category(locale_sname[LC_CTYPE], cp[LC_CTYPE], locinfo, LC_CTYPE)) { - free_locinfo(locinfo); - return NULL; + goto fail; }
locinfo->lc_codepage = locinfo->lc_id[LC_CTYPE].wCodePage; locinfo->lc_clike = 1; if(!GetCPInfo(locinfo->lc_codepage, &cp_info)) { - free_locinfo(locinfo); - return NULL; + goto fail; } locinfo->mb_cur_max = cp_info.MaxCharSize;
locinfo->ctype1_refcount = malloc(sizeof(int)); if(!locinfo->ctype1_refcount) { - free_locinfo(locinfo); - return NULL; + goto fail; } *locinfo->ctype1_refcount = 1;
@@ -1435,8 +1501,7 @@ static pthreadlocinfo create_locinfo(int category, locinfo->pclmap = malloc(sizeof(char[256])); locinfo->pcumap = malloc(sizeof(char[256])); if(!locinfo->ctype1 || !locinfo->pclmap || !locinfo->pcumap) { - free_locinfo(locinfo); - return NULL; + goto fail; }
locinfo->ctype1[0] = 0; @@ -1449,7 +1514,7 @@ static pthreadlocinfo create_locinfo(int category, /* builtin GetStringTypeA doesn't set output to 0 on invalid input */ locinfo->ctype1[i] = 0;
- GetStringTypeA(lcid[LC_CTYPE], CT_CTYPE1, buf, + GetStringTypeA(locinfo->lc_handle[LC_CTYPE], CT_CTYPE1, buf, 1, locinfo->ctype1+i); }
@@ -1464,9 +1529,9 @@ static pthreadlocinfo create_locinfo(int category, buf[i] = i; }
- LCMapStringA(lcid[LC_CTYPE], LCMAP_LOWERCASE, buf, 256, + LCMapStringA(locinfo->lc_handle[LC_CTYPE], LCMAP_LOWERCASE, buf, 256, (char*)locinfo->pclmap, 256); - LCMapStringA(lcid[LC_CTYPE], LCMAP_UPPERCASE, buf, 256, + LCMapStringA(locinfo->lc_handle[LC_CTYPE], LCMAP_UPPERCASE, buf, 256, (char*)locinfo->pcumap, 256); } else { locinfo->lc_clike = 1; @@ -1475,20 +1540,19 @@ static pthreadlocinfo create_locinfo(int category, locinfo->pclmap = cloc_clmap; locinfo->pcumap = cloc_cumap; if(!init_category_name("C", 1, locinfo, LC_CTYPE)) { - free_locinfo(locinfo); - return NULL; + goto fail; } }
if(!category_needs_update(LC_MONETARY, old_locinfo, - lcid[LC_MONETARY], cp[LC_MONETARY]) && + locale_sname[LC_MONETARY], cp[LC_MONETARY]) && !category_needs_update(LC_NUMERIC, old_locinfo, - lcid[LC_NUMERIC], cp[LC_NUMERIC])) { + locale_sname[LC_NUMERIC], cp[LC_NUMERIC])) { locinfo->lconv = old_locinfo->lconv; locinfo->lconv_intl_refcount = old_locinfo->lconv_intl_refcount; if(locinfo->lconv_intl_refcount) InterlockedIncrement((LONG *)locinfo->lconv_intl_refcount); - } else if(lcid[LC_MONETARY] || lcid[LC_NUMERIC]) { + } else if(locale_sname[LC_MONETARY] || locale_sname[LC_NUMERIC]) { locinfo->lconv = malloc(sizeof(struct lconv)); locinfo->lconv_intl_refcount = malloc(sizeof(int)); if(!locinfo->lconv || !locinfo->lconv_intl_refcount) { @@ -1496,8 +1560,7 @@ static pthreadlocinfo create_locinfo(int category, free(locinfo->lconv_intl_refcount); locinfo->lconv = NULL; locinfo->lconv_intl_refcount = NULL; - free_locinfo(locinfo); - return NULL; + goto fail; } memset(locinfo->lconv, 0, sizeof(struct lconv)); *locinfo->lconv_intl_refcount = 1; @@ -1508,12 +1571,11 @@ static pthreadlocinfo create_locinfo(int category, if(locale_name[LC_MONETARY] && !init_category_name(locale_name[LC_MONETARY], locale_len[LC_MONETARY], locinfo, LC_MONETARY)) { - free_locinfo(locinfo); - return NULL; + goto fail; }
if(!category_needs_update(LC_MONETARY, old_locinfo, - lcid[LC_MONETARY], cp[LC_MONETARY])) { + locale_sname[LC_MONETARY], cp[LC_MONETARY])) { copy_threadlocinfo_category(locinfo, old_locinfo, LC_MONETARY); locinfo->lconv_mon_refcount = old_locinfo->lconv_mon_refcount; if(locinfo->lconv_mon_refcount) @@ -1543,59 +1605,58 @@ static pthreadlocinfo create_locinfo(int category, locinfo->lconv->_W_negative_sign = old_locinfo->lconv->_W_negative_sign; #endif } - } else if(lcid[LC_MONETARY]) { - if(!update_threadlocinfo_category(lcid[LC_MONETARY], + } else if(locale_sname[LC_MONETARY]) { + if(!update_threadlocinfo_category(locale_sname[LC_MONETARY], cp[LC_MONETARY], locinfo, LC_MONETARY)) { - free_locinfo(locinfo); - return NULL; + goto fail; }
locinfo->lconv_mon_refcount = malloc(sizeof(int)); if(!locinfo->lconv_mon_refcount) { - free_locinfo(locinfo); - return NULL; + goto fail; }
*locinfo->lconv_mon_refcount = 1;
- i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SINTLSYMBOL - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SINTLSYMBOL + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->int_curr_symbol = malloc(i))) - memcpy(locinfo->lconv->int_curr_symbol, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->int_curr_symbol, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SCURRENCY - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SCURRENCY + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->currency_symbol = malloc(i))) - memcpy(locinfo->lconv->currency_symbol, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->currency_symbol, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SMONDECIMALSEP - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SMONDECIMALSEP + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->mon_decimal_point = malloc(i))) - memcpy(locinfo->lconv->mon_decimal_point, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->mon_decimal_point, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SMONTHOUSANDSEP - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SMONTHOUSANDSEP + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->mon_thousands_sep = malloc(i))) - memcpy(locinfo->lconv->mon_thousands_sep, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->mon_thousands_sep, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SMONGROUPING - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SMONGROUPING + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + WideCharToMultiByte(CP_ACP, 0, wbuf, -1, buf, 256, NULL, NULL); if(i>1) i = i/2 + (buf[i-2]=='0'?0:1); if(i && (locinfo->lconv->mon_grouping = malloc(i))) { @@ -1605,145 +1666,130 @@ static pthreadlocinfo create_locinfo(int category, if(buf[i] != '0') locinfo->lconv->mon_grouping[i/2+1] = 127; } else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SPOSITIVESIGN - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SPOSITIVESIGN + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->positive_sign = malloc(i))) - memcpy(locinfo->lconv->positive_sign, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->positive_sign, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoA(lcid[LC_MONETARY], LOCALE_SNEGATIVESIGN - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SNEGATIVESIGN + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->negative_sign = malloc(i))) - memcpy(locinfo->lconv->negative_sign, buf, i); + WideCharToMultiByte(cp[LC_MONETARY], 0, wbuf, -1, locinfo->lconv->negative_sign, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_IINTLCURRDIGITS + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_IINTLCURRDIGITS |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->int_frac_digits = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_ICURRDIGITS + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_ICURRDIGITS |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->frac_digits = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_IPOSSYMPRECEDES + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_IPOSSYMPRECEDES |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->p_cs_precedes = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_IPOSSEPBYSPACE + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_IPOSSEPBYSPACE |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->p_sep_by_space = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_INEGSYMPRECEDES + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_INEGSYMPRECEDES |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->n_cs_precedes = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_INEGSEPBYSPACE + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_INEGSEPBYSPACE |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->n_sep_by_space = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_IPOSSIGNPOSN + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_IPOSSIGNPOSN |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->p_sign_posn = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- if(GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_INEGSIGNPOSN + if(GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_INEGSIGNPOSN |LOCALE_NOUSEROVERRIDE|LOCALE_RETURN_NUMBER, (WCHAR *)&val, 2)) locinfo->lconv->n_sign_posn = val; else { - free_locinfo(locinfo); - return NULL; + goto fail; }
#if _MSVCR_VER >= 100 - i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SINTLSYMBOL + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SINTLSYMBOL |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_int_curr_symbol = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_int_curr_symbol, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SCURRENCY + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SCURRENCY |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_currency_symbol = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_currency_symbol, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SMONDECIMALSEP + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SMONDECIMALSEP |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_mon_decimal_point = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_mon_decimal_point, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SMONTHOUSANDSEP + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SMONTHOUSANDSEP |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_mon_thousands_sep = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_mon_thousands_sep, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SPOSITIVESIGN + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SPOSITIVESIGN |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_positive_sign = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_positive_sign, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoW(lcid[LC_MONETARY], LOCALE_SNEGATIVESIGN + i = GetLocaleInfoEx(locale_sname[LC_MONETARY], LOCALE_SNEGATIVESIGN |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_negative_sign = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_negative_sign, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; } #endif } else { @@ -1775,20 +1821,18 @@ static pthreadlocinfo create_locinfo(int category, }
if(!init_category_name("C", 1, locinfo, LC_MONETARY)) { - free_locinfo(locinfo); - return NULL; + goto fail; } }
if(locale_name[LC_NUMERIC] && !init_category_name(locale_name[LC_NUMERIC], locale_len[LC_NUMERIC], locinfo, LC_NUMERIC)) { - free_locinfo(locinfo); - return NULL; + goto fail; }
if(!category_needs_update(LC_NUMERIC, old_locinfo, - lcid[LC_NUMERIC], cp[LC_NUMERIC])) { + locale_sname[LC_NUMERIC], cp[LC_NUMERIC])) { copy_threadlocinfo_category(locinfo, old_locinfo, LC_NUMERIC); locinfo->lconv_num_refcount = old_locinfo->lconv_num_refcount; if(locinfo->lconv_num_refcount) @@ -1802,41 +1846,40 @@ static pthreadlocinfo create_locinfo(int category, locinfo->lconv->_W_thousands_sep = old_locinfo->lconv->_W_thousands_sep; #endif } - } else if(lcid[LC_NUMERIC]) { - if(!update_threadlocinfo_category(lcid[LC_NUMERIC], + } else if(locale_sname[LC_NUMERIC]) { + if(!update_threadlocinfo_category(locale_sname[LC_NUMERIC], cp[LC_NUMERIC], locinfo, LC_NUMERIC)) { - free_locinfo(locinfo); - return NULL; + goto fail; }
locinfo->lconv_num_refcount = malloc(sizeof(int)); if(!locinfo->lconv_num_refcount) { - free_locinfo(locinfo); - return NULL; + goto fail; }
*locinfo->lconv_num_refcount = 1;
- i = GetLocaleInfoA(lcid[LC_NUMERIC], LOCALE_SDECIMAL - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_NUMERIC], LOCALE_SDECIMAL + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_NUMERIC], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->decimal_point = malloc(i))) - memcpy(locinfo->lconv->decimal_point, buf, i); + WideCharToMultiByte(cp[LC_NUMERIC], 0, wbuf, -1, locinfo->lconv->decimal_point, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoA(lcid[LC_NUMERIC], LOCALE_STHOUSAND - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_NUMERIC], LOCALE_STHOUSAND + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + i = WideCharToMultiByte(cp[LC_NUMERIC], 0, wbuf, -1, NULL, 0, NULL, NULL); if(i && (locinfo->lconv->thousands_sep = malloc(i))) - memcpy(locinfo->lconv->thousands_sep, buf, i); + WideCharToMultiByte(cp[LC_NUMERIC], 0, wbuf, -1, locinfo->lconv->thousands_sep, i, NULL, NULL); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoA(lcid[LC_NUMERIC], LOCALE_SGROUPING - |LOCALE_NOUSEROVERRIDE, buf, 256); + i = GetLocaleInfoEx(locale_sname[LC_NUMERIC], LOCALE_SGROUPING + |LOCALE_NOUSEROVERRIDE, wbuf, 256); + WideCharToMultiByte(cp[LC_NUMERIC], 0, wbuf, -1, buf, 256, NULL, NULL); if(i>1) i = i/2 + (buf[i-2]=='0'?0:1); if(i && (locinfo->lconv->grouping = malloc(i))) { @@ -1846,27 +1889,24 @@ static pthreadlocinfo create_locinfo(int category, if(buf[i] != '0') locinfo->lconv->grouping[i/2+1] = 127; } else { - free_locinfo(locinfo); - return NULL; + goto fail; }
#if _MSVCR_VER >= 100 - i = GetLocaleInfoW(lcid[LC_NUMERIC], LOCALE_SDECIMAL + i = GetLocaleInfoEx(locale_sname[LC_NUMERIC], LOCALE_SDECIMAL |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_decimal_point = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_decimal_point, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; }
- i = GetLocaleInfoW(lcid[LC_NUMERIC], LOCALE_STHOUSAND + i = GetLocaleInfoEx(locale_sname[LC_NUMERIC], LOCALE_STHOUSAND |LOCALE_NOUSEROVERRIDE, wbuf, 256); if(i && (locinfo->lconv->_W_thousands_sep = malloc(i * sizeof(wchar_t)))) memcpy(locinfo->lconv->_W_thousands_sep, wbuf, i * sizeof(wchar_t)); else { - free_locinfo(locinfo); - return NULL; + goto fail; } #endif } else { @@ -1882,45 +1922,48 @@ static pthreadlocinfo create_locinfo(int category, }
if (!init_category_name("C", 1, locinfo, LC_NUMERIC)) { - free_locinfo(locinfo); - return NULL; + goto fail; } }
if(locale_name[LC_TIME] && !init_category_name(locale_name[LC_TIME], locale_len[LC_TIME], locinfo, LC_TIME)) { - free_locinfo(locinfo); - return NULL; + goto fail; }
if(!category_needs_update(LC_TIME, old_locinfo, - lcid[LC_TIME], cp[LC_TIME])) { + locale_sname[LC_TIME], cp[LC_TIME])) { copy_threadlocinfo_category(locinfo, old_locinfo, LC_TIME); locinfo->lc_time_curr = old_locinfo->lc_time_curr; InterlockedIncrement(&locinfo->lc_time_curr->refcount); - } else if(lcid[LC_TIME]) { - if(!update_threadlocinfo_category(lcid[LC_TIME], + } else if(locale_sname[LC_TIME]) { + if(!update_threadlocinfo_category(locale_sname[LC_TIME], cp[LC_TIME], locinfo, LC_TIME)) { - free_locinfo(locinfo); - return NULL; + goto fail; }
- locinfo->lc_time_curr = create_time_data(lcid[LC_TIME]); + locinfo->lc_time_curr = create_time_data(locale_sname[LC_TIME]); if(!locinfo->lc_time_curr) { - free_locinfo(locinfo); - return NULL; + goto fail; } } else { if(!init_category_name("C", 1, locinfo, LC_TIME)) { - free_locinfo(locinfo); - return NULL; + goto fail; } locinfo->lc_time_curr = &cloc_time_data; InterlockedIncrement(&locinfo->lc_time_curr->refcount); }
return locinfo; + +fail: + free_locinfo(locinfo); + + for (i = 0; i < LC_MAX; i++) + free(locale_sname[i]); + + return NULL; }
/*********************************************************************
From: Victor Chiletto vchiletto@codeweavers.com
--- dlls/msvcrt/locale.c | 95 ++++++++++++++++++++------------------------ dlls/msvcrt/mbcs.c | 3 +- dlls/msvcrt/msvcrt.h | 5 +-- 3 files changed, 48 insertions(+), 55 deletions(-)
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 845de26155c..cfcd4410b52 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -321,28 +321,27 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) return CONTINUE_LOOKING; }
-/* Internal: Find the LCID for a locale specification */ -LCID locale_to_LCID(const char *locale, unsigned short *codepage, BOOL *sname) +/* Internal: Find the sname for a locale specification */ +BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_match, WCHAR *sname, int sname_size) { thread_data_t *data = msvcrt_get_thread_data(); const char *cp, *region; BOOL is_sname = FALSE; DWORD locale_cp; - LCID lcid;
if (!strcmp(locale, data->cached_locale)) { if (codepage) *codepage = data->cached_cp; if (sname) - *sname = data->cached_sname; - return data->cached_lcid; + wcsncpy(sname, data->cached_sname, sname_size); + return TRUE; }
cp = strchr(locale, '.'); region = strchr(locale, '_');
if(!locale[0] || (cp == locale && !region)) { - lcid = GetUserDefaultLCID(); + GetUserDefaultLocaleName(sname, sname_size); } else { locale_search_t search;
@@ -371,26 +370,26 @@ LCID locale_to_LCID(const char *locale, unsigned short *codepage, BOOL *sname) EnumSystemLocalesEx( find_best_locale_proc, 0, (LPARAM)&search, NULL);
if (!search.match_flags) - return -1; + return FALSE;
/* If we were given something that didn't match, fail */ if (search.search_language[0] && !(search.match_flags & (FOUND_SNAME | FOUND_LANGUAGE))) - return -1; + return FALSE; if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY)) - return -1; + return FALSE;
- lcid = MAKELCID(search.found_lang_id, SORT_DEFAULT); + LCIDToLocaleName(search.found_lang_id, sname, sname_size, LOCALE_ALLOW_NEUTRAL_NAMES); is_sname = (search.match_flags & FOUND_SNAME) != 0; }
/* Obtain code page */ if (!cp || !cp[1] || !_strnicmp(cp, ".ACP", 4)) { - GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, + GetLocaleInfoEx(sname, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR *)&locale_cp, sizeof(DWORD)/sizeof(WCHAR)); if (!locale_cp) locale_cp = GetACP(); } else if (!_strnicmp(cp, ".OCP", 4)) { - GetLocaleInfoW(lcid, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER, + GetLocaleInfoEx(sname, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR *)&locale_cp, sizeof(DWORD)/sizeof(WCHAR)); #if _MSVCR_VER >= 140 } else if (!_strnicmp(cp, ".UTF-8", 6) @@ -401,24 +400,23 @@ LCID locale_to_LCID(const char *locale, unsigned short *codepage, BOOL *sname) locale_cp = atoi(cp + 1); } if (!IsValidCodePage(locale_cp)) - return -1; + return FALSE;
if (!locale_cp) - return -1; + return FALSE;
if (codepage) *codepage = locale_cp; - if (sname) - *sname = is_sname; + if (sname_match) + *sname_match = is_sname;
if (strlen(locale) < sizeof(data->cached_locale)) { strcpy(data->cached_locale, locale); - data->cached_lcid = lcid; data->cached_cp = locale_cp; - data->cached_sname = is_sname; + wcscpy(data->cached_sname, sname); }
- return lcid; + return TRUE; }
static void copy_threadlocinfo_category(pthreadlocinfo locinfo, @@ -1286,7 +1284,6 @@ static pthreadlocinfo create_locinfo(int category, locale_sname[0] = NULL; cp[0] = CP_ACP; } else if (locale[0] == 'L' && locale[1] == 'C' && locale[2] == '_') { - LCID lcid; const char *p;
while(1) { @@ -1311,34 +1308,31 @@ static pthreadlocinfo create_locinfo(int category,
p = strchr(locale, ';'); if(locale[0]=='C' && (locale[1]==';' || locale[1]=='\0')) { - lcid = 0; locale_sname[i] = NULL; cp[i] = CP_ACP; - } else if(p) { - memcpy(buf, locale, p-locale); - buf[p-locale] = '\0'; - lcid = locale_to_LCID(buf, &cp[i], &sname_match); - if(sname_match) { - locale_name[i] = locale; - locale_len[i] = p-locale; - } } else { - lcid = locale_to_LCID(locale, &cp[i], &sname_match); - if(sname_match) { - locale_name[i] = locale; - locale_len[i] = strlen(locale); + BOOL locale_found = FALSE; + + if(p) { + memcpy(buf, locale, p-locale); + buf[p-locale] = '\0'; + locale_found = locale_to_sname(buf, &cp[i], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); + locale_sname[i] = wcsdup(wbuf); + if(sname_match) { + locale_name[i] = locale; + locale_len[i] = p-locale; + } + } else { + locale_found = locale_to_sname(buf, &cp[i], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); + locale_sname[i] = wcsdup(wbuf); + if(sname_match) { + locale_name[i] = locale; + locale_len[i] = strlen(locale); + } } - } - - if(lcid == -1) - goto fail;
- if(lcid) { - int sname_size = LCIDToLocaleName(lcid, NULL, 0, LCID_CONVERSION_FLAGS); - locale_sname[i] = malloc(sname_size * sizeof(WCHAR)); - if(!locale_sname[i]) + if(!locale_found || !locale_sname[i]) goto fail; - LCIDToLocaleName(lcid, locale_sname[i], sname_size, LCID_CONVERSION_FLAGS); }
if(!p || *(p+1)!='L' || *(p+2)!='C' || *(p+3)!='_') @@ -1347,16 +1341,15 @@ static pthreadlocinfo create_locinfo(int category, locale = p+1; } } else { - LCID lcid = locale_to_LCID(locale, &cp[0], &sname_match); - if(lcid == -1) + BOOL locale_found = locale_to_sname(locale, &cp[0], &sname_match, wbuf, LOCALE_NAME_MAX_LENGTH); + + if(!locale_found) return NULL; - if(lcid) { - int sname_size = LCIDToLocaleName(lcid, NULL, 0, LCID_CONVERSION_FLAGS); - locale_sname[0] = malloc(sname_size * sizeof(WCHAR)); - if(!locale_sname[0]) - return NULL; - LCIDToLocaleName(lcid, locale_sname[0], sname_size, LCID_CONVERSION_FLAGS); - } + + locale_sname[0] = wcsdup(wbuf); + if(!locale_sname[0]) + return NULL; + if(sname_match) { locale_name[0] = locale; locale_len[0] = strlen(locale); diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c index 16c5c378be7..8598bceb029 100644 --- a/dlls/msvcrt/mbcs.c +++ b/dlls/msvcrt/mbcs.c @@ -252,8 +252,9 @@ threadmbcinfo* create_mbcinfo(int cp, LCID lcid, threadmbcinfo *old_mbcinfo) }
if(lcid == -1) { + WCHAR wbuf[LOCALE_NAME_MAX_LENGTH]; sprintf(bufA, ".%d", newcp); - mbcinfo->mblcid = locale_to_LCID(bufA, NULL, NULL); + mbcinfo->mblcid = locale_to_sname(bufA, NULL, NULL, wbuf, LOCALE_NAME_MAX_LENGTH) ? LocaleNameToLCID(wbuf, LOCALE_ALLOW_NEUTRAL_NAMES) : -1; } else { mbcinfo->mblcid = lcid; } diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index 1d2db6a4d87..42c41c2200c 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -170,8 +170,7 @@ struct __thread_data { int processing_throw; frame_info *frame_info_head; void *unk8[6]; - LCID cached_lcid; - BOOL cached_sname; + WCHAR cached_sname[LOCALE_NAME_MAX_LENGTH]; int unk9[2]; DWORD cached_cp; char cached_locale[131]; @@ -186,7 +185,7 @@ typedef struct __thread_data thread_data_t;
extern thread_data_t *CDECL msvcrt_get_thread_data(void) DECLSPEC_HIDDEN;
-LCID locale_to_LCID(const char*, unsigned short*, BOOL*) DECLSPEC_HIDDEN; +BOOL locale_to_sname(const char*, unsigned short*, BOOL*, WCHAR*, int) DECLSPEC_HIDDEN; extern _locale_t MSVCRT_locale DECLSPEC_HIDDEN; extern __lc_time_data cloc_time_data DECLSPEC_HIDDEN; extern unsigned int MSVCRT___lc_codepage;
From: Victor Chiletto vchiletto@codeweavers.com
--- dlls/msvcr110/tests/msvcr110.c | 4 ++-- dlls/msvcr120/tests/msvcr120.c | 4 ++-- dlls/msvcrt/locale.c | 31 ++++++++++++++++++++++--------- 3 files changed, 26 insertions(+), 13 deletions(-)
diff --git a/dlls/msvcr110/tests/msvcr110.c b/dlls/msvcr110/tests/msvcr110.c index 60d876e3bfc..35ba370bb49 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 + ok((ret != NULL || broken(ret == NULL)), /* Vista */ "expected success, but got NULL\n"); if (ret) ok(!strcmp(ret, "zh-Hans"), "setlocale zh-Hans failed\n");
ret = p_setlocale(LC_ALL, "zh-Hant"); - todo_wine ok((ret != NULL + ok((ret != NULL || broken(ret == NULL)), /* Vista */ "expected success, but got NULL\n"); if (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 cfcd4410b52..12c9bba506c 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -343,6 +343,7 @@ 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]; locale_search_t search;
memset(&search, 0, sizeof(locale_search_t)); @@ -364,21 +365,33 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m if(!cp && !region) { remap_synonym(search.search_language); +#if _MSVCR_VER >= 110 search.allow_sname = TRUE; +#endif + } + + MultiByteToWideChar(CP_ACP, 0, search.search_language, -1, wbuf, LOCALE_NAME_MAX_LENGTH); + if (search.allow_sname && IsValidLocaleName(wbuf)) + { + search.match_flags = FOUND_SNAME; + wcsncpy(sname, wbuf, sname_size); } + else + { + EnumSystemLocalesEx( find_best_locale_proc, 0, (LPARAM)&search, NULL);
- EnumSystemLocalesEx( find_best_locale_proc, 0, (LPARAM)&search, NULL); + if (!search.match_flags) + return FALSE;
- if (!search.match_flags) - return FALSE; + /* If we were given something that didn't match, fail */ + if (search.search_language[0] && !(search.match_flags & (FOUND_SNAME | FOUND_LANGUAGE))) + return FALSE; + if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY)) + return FALSE;
- /* If we were given something that didn't match, fail */ - if (search.search_language[0] && !(search.match_flags & (FOUND_SNAME | FOUND_LANGUAGE))) - return FALSE; - if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY)) - return FALSE; + LCIDToLocaleName(search.found_lang_id, sname, sname_size, LOCALE_ALLOW_NEUTRAL_NAMES); + }
- LCIDToLocaleName(search.found_lang_id, sname, sname_size, LOCALE_ALLOW_NEUTRAL_NAMES); is_sname = (search.match_flags & FOUND_SNAME) != 0; }
From: Victor Chiletto vchiletto@codeweavers.com
--- dlls/msvcrt/locale.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-)
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 12c9bba506c..89118535494 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -471,32 +471,20 @@ static BOOL init_category_name(const char *name, int len, }
#if _MSVCR_VER >= 110 -static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat) +static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat, WCHAR *sname) { - LCID lcid = locinfo->lc_handle[cat]; - WCHAR buf[100]; - int len; - locinfo->lc_category[cat].wrefcount = malloc(sizeof(int)); if(!locinfo->lc_category[cat].wrefcount) return FALSE; *locinfo->lc_category[cat].wrefcount = 1;
- len = GetLocaleInfoW(lcid, LOCALE_SISO639LANGNAME - |LOCALE_NOUSEROVERRIDE, buf, 100); - if(!len) return FALSE; - - 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)))) + if(!(locinfo->lc_name[cat] = wcsdup(sname))) return FALSE;
- memcpy(locinfo->lc_name[cat], buf, len*sizeof(wchar_t)); return TRUE; } #else -static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat) +static inline BOOL set_lc_locale_name(pthreadlocinfo locinfo, int cat, WCHAR *sname) { return TRUE; } @@ -531,7 +519,7 @@ static BOOL update_threadlocinfo_category(WCHAR *sname, unsigned short cp,
locinfo->lc_handle[category] = LocaleNameToLCID(sname, LCID_CONVERSION_FLAGS);
- set_lc_locale_name(locinfo, category); + set_lc_locale_name(locinfo, category, sname);
if(!locinfo->lc_category[category].locale) { char buf[256];
From: Victor Chiletto vchiletto@codeweavers.com
Gives us more control over what we map to which is required due to changes in Chinese locales. --- dlls/msvcrt/locale.c | 98 ++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 41 deletions(-)
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 89118535494..7e759ddc6c6 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -172,43 +172,54 @@ static struct lconv cloc_lconv = /* Friendly country strings & language names abbreviations. */ static const char * const _country_synonyms[] = { - "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", - "portuguese", "ptb", - "portuguese-brazil", "ptb", - "spanish-mexican", "esm", - "norwegian-bokmal", "nor", - "norwegian-nynorsk", "non", - "spanish-modern", "esn" + "american", "en", + "american english", "en-US", + "american-english", "en-US", + "english-american", "en-US", + "english-us", "en-US", + "english-usa", "en-US", + "us", "en-US", + "usa", "en-US", + "australian", "en-AU", + "english-aus", "en-AU", + "belgian", "nl-BE", + "french-belgian", "fr-BE", + "canadian", "en-CA", + "english-can", "en-CA", + "french-canadian", "fr-CA", +#if _MSVCR_VER >= 110 + "chinese", "zh", + "chinese-simplified", "zh", + "chinese-traditional", "zh-HK", + "chs", "zh", + "cht", "zh-HK", +#else + "chinese", "zh-CN", + "chinese-simplified", "zh-CN", + "chinese-traditional", "zh-TW", + "chs", "zh-CN", + "cht", "zh-TW", +#endif + "dutch-belgian", "nl-BE", + "english-nz", "en-NZ", + "uk", "en-GB", + "english-uk", "en-GB", + "french-swiss", "fr-CH", + "swiss", "de-CH", + "german-swiss", "de-CH", + "italian-swiss", "it-CH", + "german-austrian", "de-AT", + "portuguese", "pt-BR", + "portuguese-brazil", "pt-BR", + "spanish-mexican", "es-MX", + "norwegian-bokmal", "nb", + "norwegian-nynorsk", "nn-NO", + "spanish-modern", "es-ES" };
+ /* INTERNAL: Map a synonym to an ISO code */ -static void remap_synonym(char *name) +static BOOL remap_synonym(char *name) { unsigned int i; for (i = 0; i < ARRAY_SIZE(_country_synonyms); i += 2) @@ -217,9 +228,11 @@ static void remap_synonym(char *name) { TRACE(":Mapping synonym %s to %s\n",name,_country_synonyms[i+1]); strcpy(name, _country_synonyms[i+1]); - return; + return TRUE; } } + + return FALSE; }
/* Note: Flags are weighted in order of matching importance */ @@ -270,7 +283,6 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam )
if (lcid == LOCALE_CUSTOM_UNSPECIFIED) return CONTINUE_LOOKING;
-#if _MSVCR_VER >= 110 if (res->allow_sname && compare_info(lcid,LOCALE_SNAME,buff,res->search_language, TRUE)) { TRACE(":Found locale: %s->%s\n", res->search_language, buff); @@ -278,7 +290,6 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) res->found_lang_id = LANGIDFROMLCID(lcid); return STOP_LOOKING; } -#endif
/* Check Language */ if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language, TRUE) || @@ -345,6 +356,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m } else { WCHAR wbuf[LOCALE_NAME_MAX_LENGTH]; locale_search_t search; + BOOL remapped = FALSE;
memset(&search, 0, sizeof(locale_search_t)); lstrcpynA(search.search_language, locale, MAX_ELEM_LEN); @@ -362,13 +374,17 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m search.search_language[cp-locale] = '\0'; }
- if(!cp && !region) + if ((remapped = remap_synonym(search.search_language))) { - remap_synonym(search.search_language); + search.allow_sname = TRUE; + } + #if _MSVCR_VER >= 110 + if(!cp && !region) + { search.allow_sname = TRUE; -#endif } +#endif
MultiByteToWideChar(CP_ACP, 0, search.search_language, -1, wbuf, LOCALE_NAME_MAX_LENGTH); if (search.allow_sname && IsValidLocaleName(wbuf)) @@ -392,7 +408,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m LCIDToLocaleName(search.found_lang_id, sname, sname_size, LOCALE_ALLOW_NEUTRAL_NAMES); }
- is_sname = (search.match_flags & FOUND_SNAME) != 0; + is_sname = !remapped && (search.match_flags & FOUND_SNAME) != 0; }
/* Obtain code page */
From: Victor Chiletto vchiletto@codeweavers.com
GetLocaleInfoA doesn't return the proper sname for neutral LCIDs. --- dlls/msvcrt/locale.c | 73 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 37 deletions(-)
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 7e759ddc6c6..9fa6ba76143 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -241,11 +241,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;
@@ -253,50 +253,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, LCID_CONVERSION_FLAGS ); - 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) @@ -305,11 +303,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)) @@ -321,7 +319,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)) @@ -354,27 +352,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; } @@ -386,14 +384,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) @@ -405,7 +404,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;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=134710
Your paranoid android.
=== debian11 (32 bit report) ===
Report validation errors: mshtml:dom has no test summary line (early exit of the main process?) mshtml:dom has unaccounted for todo messages mshtml:dom returned a non-zero exit code despite reporting no failures
On Wed Jul 12 05:07:28 2023 +0000, Victor Hermann Chiletto wrote:
changed this line in [version 5 of the diff](/wine/wine/-/merge_requests/3050/diffs?diff_id=56996&start_sha=ec37314b55cb519e7ef66c31cc9e23121e13b446#90e640854b517029283ede63e860624a7984b551_541_535)
It shouldn't. It also helps simplify the whole Norwegian Nynorsk thing. Thanks!
v5: * Dropped the make_unicode patch (will open another MR) * LOCALE_ALLOW_NEUTRAL_NAMES is only used on MSVCR >= 110 * Readded a patch that simplified set_lc_locale_name (needed to avoid introducing regressions in the patchset)
This merge request was approved by Piotr Caban.