-- v2: ucrtbase: Fix case mapping and ctype1 tables for utf8 locale. ucrtbase: Fix CP_UTF8 handling in _tolower_l. ucrtbase: Fix CP_UTF8 handling in _toupper_l. msvcrt: Print FIXME when WideCharToMultiByte() fails in create_locinfo().
From: Paul Gofman pgofman@codeweavers.com
--- dlls/msvcrt/locale.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 5fdede174a0..6fc45b3bdbe 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -1292,7 +1292,7 @@ static pthreadlocinfo create_locinfo(int category, char buf[256]; BOOL sname_match; wchar_t wbuf[256], map_buf[256]; - int i; + int i, ret;
TRACE("(%d %s)\n", category, locale);
@@ -1514,9 +1514,13 @@ static pthreadlocinfo create_locinfo(int category,
MultiByteToWideChar(locinfo->lc_codepage, 0, buf, 256, wbuf, 256); LCMapStringW(LOCALE_INVARIANT, LCMAP_LOWERCASE, wbuf, 256, map_buf, 256); - WideCharToMultiByte(locinfo->lc_codepage, 0, map_buf, 256, (char *)locinfo->pclmap, 256, NULL, NULL); + if ((ret = WideCharToMultiByte(locinfo->lc_codepage, 0, map_buf, 256, + (char *)locinfo->pclmap, 256, NULL, NULL)) != 256) + FIXME("WideCharToMultiByte failed, ret %d, error %lu.\n", ret, GetLastError()); LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, wbuf, 256, map_buf, 256); - WideCharToMultiByte(locinfo->lc_codepage, 0, map_buf, 256, (char *)locinfo->pcumap, 256, NULL, NULL); + if ((ret = WideCharToMultiByte(locinfo->lc_codepage, 0, map_buf, 256, + (char *)locinfo->pcumap, 256, NULL, NULL)) != 256) + FIXME("WideCharToMultiByte failed, ret %d, error %lu.\n", ret, GetLastError()); } else { locinfo->lc_clike = 1; locinfo->mb_cur_max = 1;
From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcrt/ctype.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/msvcrt/ctype.c b/dlls/msvcrt/ctype.c index 1297bc56046..89d25e5e5e5 100644 --- a/dlls/msvcrt/ctype.c +++ b/dlls/msvcrt/ctype.c @@ -483,9 +483,9 @@ int CDECL _toupper_l(int c, _locale_t locale)
if((unsigned)c < 256) { - if(locinfo->pctype[c] & _LEADBYTE) - return c; - return locinfo->pcumap[c]; + if(locinfo->pctype[c] & _LOWER) + return locinfo->pcumap[c]; + return c; }
if(locinfo->pctype[(c>>8)&255] & _LEADBYTE)
From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcrt/ctype.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/msvcrt/ctype.c b/dlls/msvcrt/ctype.c index 89d25e5e5e5..ddb7e7ab9cc 100644 --- a/dlls/msvcrt/ctype.c +++ b/dlls/msvcrt/ctype.c @@ -541,9 +541,9 @@ int CDECL _tolower_l(int c, _locale_t locale)
if((unsigned)c < 256) { - if(locinfo->pctype[c] & _LEADBYTE) - return c; - return locinfo->pclmap[c]; + if(locinfo->pctype[c] & _UPPER) + return locinfo->pclmap[c]; + return c; }
if(locinfo->pctype[(c>>8)&255] & _LEADBYTE)
From: Piotr Caban piotr@codeweavers.com
--- dlls/msvcrt/locale.c | 7 ++++++- dlls/ucrtbase/tests/file.c | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c index 6fc45b3bdbe..380571b72fc 100644 --- a/dlls/msvcrt/locale.c +++ b/dlls/msvcrt/locale.c @@ -1506,7 +1506,12 @@ static pthreadlocinfo create_locinfo(int category, locinfo->ctype1[j+1] |= _LEADBYTE;
for(i=0; i<256; i++) { - if(locinfo->pctype[i] & _LEADBYTE) + if (locinfo->lc_codepage == CP_UTF8) + { + buf[i] = (i >= 0x80) ? ' ' : i; + if (i >= 0x80) locinfo->ctype1[i+1] = (i >= 0xc2 && i <= 0xf4) ? _LEADBYTE : 0; + } + else if(locinfo->pctype[i] & _LEADBYTE) buf[i] = ' '; else buf[i] = i; diff --git a/dlls/ucrtbase/tests/file.c b/dlls/ucrtbase/tests/file.c index d5303a6020c..47971c76f95 100644 --- a/dlls/ucrtbase/tests/file.c +++ b/dlls/ucrtbase/tests/file.c @@ -232,6 +232,7 @@ static void test_utf8(const char *argv0) intptr_t hfind, hproc; WCHAR bufW[256], *pW; struct _stat64 stat; + unsigned int i; FILE *f; int ret;
@@ -241,6 +242,24 @@ static void test_utf8(const char *argv0) return; }
+ for (i = 128; i < 256; ++i) + { + unsigned int v; + + winetest_push_context("%#x", i); + v = tolower(i); + ok(i == v, "got %#x.\n", v); + v = toupper(i); + ok(i == v, "got %#x.\n", v); + + v = _isctype(i, ~0u); + if (i >= 0xc2 && i <= 0xf4) + ok(v == _LEADBYTE, "got %#x.\n", v); + else + ok(!v, "got %#x.\n", v); + winetest_pop_context(); + } + ret = _mkdir(dir); if (ret == -1 && errno == ENOENT) {
On Wed Jun 4 21:06:34 2025 +0000, Piotr Caban wrote:
Can you push these patches to the MR? I prefer this solution since it makes create_locinfo simpler (and the function is already a hard to review mess). Also depending on character case makes more sense in tolower/toupper functions.
Done.
Unrelated here, but we are probably also missing proper character length detection for UTF8 locale across the board.
This merge request was approved by Paul Gofman.
This merge request was approved by Piotr Caban.