-- v3: msvcrt/tests: Add tests of _strnicmp_l(). include: Add _strnicmp_l() declaration. msvcrt/tests: Test _stricmp() with multiple bytes characters. msvcrt: Correct the result of non-ASCII characters for _strnicmp_l(). msvcrt/tests: Test _tolower_l() with DBCS. msvcrt: Improve DBCS support for _tolower_l(). msvcrt/tests: Test tolower() with DBCS.
From: Jactry Zeng jzeng@codeweavers.com
--- dlls/msvcrt/tests/string.c | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index 23f4205e785..ddfab54daf3 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -3387,6 +3387,46 @@ static void test_tolower(void) ret = p_tolower((unsigned char)0xD0); ok(ret == 0xF0, "ret = %x\n", ret);
+ ok(setlocale(LC_ALL, "Japanese_Japan.932") != NULL, "setlocale failed.\n"); + errno = 0xdeadbeef; + ret = p_tolower((signed char)0xd0); + ok(ret == 0xd0, "Got %#x.\n", ret); + ok(errno == EILSEQ, "Got errno %d.\n", errno); + errno = 0xdeadbeef; + ret = p_tolower((unsigned char)0xd0); + ok(ret == 0xd0, "Got %#x.\n", ret); + ok(errno == 0xdeadbeef, "Got errno %d.\n", errno); + + ok(setlocale(LC_ALL, "Chinese_China.936") != NULL, "setlocale failed.\n"); + errno = 0xdeadbeef; + ret = p_tolower((signed char)0xd0); + ok(ret == (signed char)0xd0, "Got %#x.\n", ret); + ok(errno == EILSEQ, "Got errno %d.\n", errno); + errno = 0xdeadbeef; + ret = p_tolower((unsigned char)0xd0); + todo_wine ok(ret == 0xd0, "Got %#x.\n", ret); + ok(errno == 0xdeadbeef, "Got errno %d.\n", errno); + + ok(setlocale(LC_ALL, "Korean_Korea.949") != NULL, "setlocale failed.\n"); + errno = 0xdeadbeef; + ret = p_tolower((signed char)0xd0); + ok(ret == (signed char)0xd0, "Got %#x.\n", ret); + ok(errno == EILSEQ, "Got errno %d.\n", errno); + errno = 0xdeadbeef; + ret = p_tolower((unsigned char)0xd0); + todo_wine ok(ret == 0xd0, "Got %#x.\n", ret); + ok(errno == 0xdeadbeef, "Got errno %d.\n", errno); + + ok(setlocale(LC_ALL, "Chinese_Taiwan.950") != NULL, "setlocale failed.\n"); + errno = 0xdeadbeef; + ret = p_tolower((signed char)0xd0); + ok(ret == (signed char)0xd0, "Got %#x.\n", ret); + ok(errno == EILSEQ, "Got errno %d.\n", errno); + errno = 0xdeadbeef; + ret = p_tolower((unsigned char)0xd0); + todo_wine ok(ret == 0xd0, "Got %#x.\n", ret); + ok(errno == 0xdeadbeef, "Got errno %d.\n", errno); + setlocale(LC_ALL, "C"); }
From: Jactry Zeng jzeng@codeweavers.com
--- dlls/msvcrt/ctype.c | 4 ++++ dlls/msvcrt/tests/string.c | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/dlls/msvcrt/ctype.c b/dlls/msvcrt/ctype.c index a1805324c1f..311cfacb71c 100644 --- a/dlls/msvcrt/ctype.c +++ b/dlls/msvcrt/ctype.c @@ -536,7 +536,11 @@ int CDECL _tolower_l(int c, _locale_t locale) locinfo = locale->locinfo;
if((unsigned)c < 256) + { + if(locinfo->pctype[c] & _LEADBYTE) + return c; return locinfo->pclmap[c]; + }
if(locinfo->pctype[(c>>8)&255] & _LEADBYTE) *p++ = (c>>8) & 255; diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index ddfab54daf3..70da88707a4 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -3404,7 +3404,7 @@ static void test_tolower(void) ok(errno == EILSEQ, "Got errno %d.\n", errno); errno = 0xdeadbeef; ret = p_tolower((unsigned char)0xd0); - todo_wine ok(ret == 0xd0, "Got %#x.\n", ret); + ok(ret == 0xd0, "Got %#x.\n", ret); ok(errno == 0xdeadbeef, "Got errno %d.\n", errno);
ok(setlocale(LC_ALL, "Korean_Korea.949") != NULL, "setlocale failed.\n"); @@ -3414,7 +3414,7 @@ static void test_tolower(void) ok(errno == EILSEQ, "Got errno %d.\n", errno); errno = 0xdeadbeef; ret = p_tolower((unsigned char)0xd0); - todo_wine ok(ret == 0xd0, "Got %#x.\n", ret); + ok(ret == 0xd0, "Got %#x.\n", ret); ok(errno == 0xdeadbeef, "Got errno %d.\n", errno);
ok(setlocale(LC_ALL, "Chinese_Taiwan.950") != NULL, "setlocale failed.\n"); @@ -3424,7 +3424,7 @@ static void test_tolower(void) ok(errno == EILSEQ, "Got errno %d.\n", errno); errno = 0xdeadbeef; ret = p_tolower((unsigned char)0xd0); - todo_wine ok(ret == 0xd0, "Got %#x.\n", ret); + ok(ret == 0xd0, "Got %#x.\n", ret); ok(errno == 0xdeadbeef, "Got errno %d.\n", errno);
setlocale(LC_ALL, "C");
From: Jactry Zeng jzeng@codeweavers.com
--- dlls/msvcrt/tests/string.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index 70da88707a4..4113c77f498 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -4824,6 +4824,37 @@ static void test_mbsrev(void) _setmbcp(cp); }
+static void test__tolower_l(void) +{ + int ret; + + ok(setlocale(LC_ALL, "english") != NULL, "setlocale failed.\n"); + ret = _tolower_l('\xa5', 0); + ok(ret == 165, "Got %d.\n", ret); + ret = _tolower_l('\xb9', 0); + ok(ret == 185, "Got %d.\n", ret); + ret = _tolower_l('a', 0); + ok(ret == 97, "Got %d.\n", ret); + + ok(setlocale(LC_ALL, ".936") != NULL, "setlocale failed.\n"); + ret = _tolower_l('\xa5', 0); + ok(ret == -91, "Got %d.\n", ret); + ret = _tolower_l('\xb9', 0); + ok(ret == -71, "Got %d.\n", ret); + ret = _tolower_l('a', 0); + ok(ret == 97, "Got %d.\n", ret); + + ok(setlocale(LC_ALL, "chinese-simplified") != NULL, "setlocale failed.\n"); + ret = _tolower_l('\xa5', 0); + ok(ret == -91, "Got %d.\n", ret); + ret = _tolower_l('\xb9', 0); + ok(ret == -71, "Got %d.\n", ret); + ret = _tolower_l('a', 0); + ok(ret == 97, "Got %d.\n", ret); + + setlocale(LC_ALL, "C"); +} + START_TEST(string) { char mem[100]; @@ -4986,4 +5017,5 @@ START_TEST(string) test__mbbtype(); test_wcsncpy(); test_mbsrev(); + test__tolower_l(); }
From: Jactry Zeng jzeng@codeweavers.com
--- dlls/msvcrt/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c index 571ca34b847..90538533d95 100644 --- a/dlls/msvcrt/string.c +++ b/dlls/msvcrt/string.c @@ -3338,7 +3338,7 @@ int __cdecl _strnicmp_l(const char *s1, const char *s2, c2 -= 'A' - 'a'; }while(--count && c1 && c1==c2);
- return c1-c2; + return (unsigned char)c1 - (unsigned char)c2; }
do {
From: Jactry Zeng jzeng@codeweavers.com
--- dlls/msvcrt/tests/string.c | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index 4113c77f498..c9335860fff 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -3531,6 +3531,10 @@ static void test__stricmp(void) ok(ret > 0, "_stricmp returned %d\n", ret); ret = _stricmp("\xa5", "\xb9"); ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\xa5\xa1", "\xb9\xa1"); /* valid gbk characters */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("abc\xa5\xa1", "abc"); + ok(ret > 0, "_stricmp returned %d\n", ret);
if(!setlocale(LC_ALL, "polish")) { win_skip("stricmp tests\n"); @@ -3547,6 +3551,48 @@ static void test__stricmp(void) ok(ret == 0, "_stricmp returned %d\n", ret); ret = _stricmp("a", "\xb9"); ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\xa5\xa1", "\xb9\xa1"); /* valid gbk characters */ + ok(ret == 0, "_stricmp returned %d\n", ret); + ret = _stricmp("abc\xa5\xa1", "abc"); + ok(ret > 0, "_stricmp returned %d\n", ret); + + ok(setlocale(LC_ALL, ".936") != NULL, "setlocale failed.\n"); + ret = _stricmp("test", "test"); + ok(ret == 0, "_stricmp returned %d\n", ret); + ret = _stricmp("a", "z"); + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("z", "a"); + ok(ret > 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\xa5", "\xb9"); + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("a", "\xb9"); + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\xa5\xa1", "\xb9\xa1"); /* valid gbk characters */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\x82\xa0", "\x83\x41"); /* valid shift-jis characters */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\x81\x00", "\x81\x01"); /* invalid for gbk and shift-jis */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("abc\xa5\xa1", "abc"); + ok(ret > 0, "_stricmp returned %d\n", ret); + + ok(setlocale(LC_ALL, ".932") != NULL, "setlocale failed.\n"); + ret = _stricmp("test", "test"); + ok(ret == 0, "_stricmp returned %d\n", ret); + ret = _stricmp("a", "z"); + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("z", "a"); + ok(ret > 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\xa5", "\xb9"); + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\xa5\xa1", "\xb9\xa1"); /* valid gbk characters */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\x82\xa0", "\x83\x41"); /* valid shift-jis characters */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("\x81\x00", "\x81\x01"); /* invalid for gbk and shift-jis */ + ok(ret < 0, "_stricmp returned %d\n", ret); + ret = _stricmp("abc\x82\xa0", "abc"); + ok(ret > 0, "_stricmp returned %d\n", ret);
setlocale(LC_ALL, "C"); }
From: Jactry Zeng jzeng@codeweavers.com
--- include/msvcrt/string.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/msvcrt/string.h b/include/msvcrt/string.h index 18d424b1e6a..10fbf12e99e 100644 --- a/include/msvcrt/string.h +++ b/include/msvcrt/string.h @@ -34,6 +34,7 @@ _ACRTIMP errno_t __cdecl _strlwr_s(char*,size_t); _ACRTIMP int __cdecl _strncoll(const char*, const char*, size_t); _ACRTIMP int __cdecl _strncoll_l(const char*, const char*, size_t, _locale_t); _ACRTIMP int __cdecl _strnicmp(const char*,const char*,size_t); +_ACRTIMP int __cdecl _strnicmp_l(const char*, const char*, size_t, _locale_t); _ACRTIMP int __cdecl _strnicoll(const char*, const char*, size_t); _ACRTIMP int __cdecl _strnicoll_l(const char*, const char*, size_t, _locale_t); _ACRTIMP char* __cdecl _strnset(char*,int,size_t);
From: Jactry Zeng jzeng@codeweavers.com
--- dlls/msvcrt/tests/string.c | 75 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index c9335860fff..a94590fbf37 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -120,6 +120,7 @@ static int (__cdecl *p__memicmp_l)(const char*, const char*, size_t, _locale_t); static size_t (__cdecl *p___strncnt)(const char*, size_t); static unsigned int (__cdecl *p_mbsnextc_l)(const unsigned char*, _locale_t); static int (__cdecl *p_mbscmp_l)(const unsigned char*, const unsigned char*, _locale_t); +static int (__cdecl *p__strnicmp_l)(const char*, const char*, size_t, _locale_t);
int CDECL __STRINGTOLD(_LDOUBLE*, char**, const char*, int);
@@ -4901,6 +4902,78 @@ static void test__tolower_l(void) setlocale(LC_ALL, "C"); }
+static void test__strnicmp_l(void) +{ + static const struct { + const char *str1; + const char *str2; + } tests[] = { + { "wine", "win" }, + /* GBK string tests */ + { "\xce\xac", "ceac" }, + { "\xce\xac\xc4\xe1", "\xce\xac" }, + { "\xce\xac""abc", "\xce\xac" }, + { "abc\xce\xac", "abc" }, + { "\xce\xac\xc4\xe1", "\xc4\xe1" }, + { "\xce\xac", "\xc4\xe1" }, + { "\xb8\xdf", "\xb8\xdb" }, + { "\xb9", "\xa5" }, + }; + _locale_t locale; + int ret, i; + + if (!p__strnicmp_l) + { + win_skip("_strnicmp_l isn't available.\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + ret = p__strnicmp_l(tests[i].str1, tests[i].str2, INT_MAX, 0); + ok(ret > 0, "tests[%d]: Got %d.\n", i, ret); + + ret = p__strnicmp_l(tests[i].str2, tests[i].str1, INT_MAX, 0); + ok(ret < 0, "tests[%d]: Got %d.\n", i, ret); + } + + if (!p__create_locale) + win_skip("_create_locale isn't available.\n"); + else + { + locale = p__create_locale(LC_ALL, ".936"); + ok(locale != NULL, "Failed to create locale.\n"); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + ret = p__strnicmp_l(tests[i].str1, tests[i].str2, INT_MAX, locale); + ok(ret > 0, "tests[%d]: Got %d.\n", i, ret); + + ret = p__strnicmp_l(tests[i].str2, tests[i].str1, INT_MAX, locale); + ok(ret < 0, "tests[%d]: Got %d.\n", i, ret); + } + + p__free_locale(locale); + } + + if (!setlocale(LC_ALL, ".936")) + { + win_skip("Skip testing _strnicmp_l with 936 code page.\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + ret = p__strnicmp_l(tests[i].str1, tests[i].str2, INT_MAX, 0); + ok(ret > 0, "tests[%d]: Got %d.\n", i, ret); + + ret = p__strnicmp_l(tests[i].str2, tests[i].str1, INT_MAX, 0); + ok(ret < 0, "tests[%d]: Got %d.\n", i, ret); + } + + setlocale(LC_ALL, "C"); +} + START_TEST(string) { char mem[100]; @@ -4976,6 +5049,7 @@ START_TEST(string) p___strncnt = (void*)GetProcAddress(hMsvcrt, "__strncnt"); p_mbsnextc_l = (void*)GetProcAddress(hMsvcrt, "_mbsnextc_l"); p_mbscmp_l = (void*)GetProcAddress(hMsvcrt, "_mbscmp_l"); + p__strnicmp_l = (void*)GetProcAddress(hMsvcrt, "_strnicmp_l");
/* MSVCRT memcpy behaves like memmove for overlapping moves, MFC42 CString::Insert seems to rely on that behaviour */ @@ -5064,4 +5138,5 @@ START_TEST(string) test_wcsncpy(); test_mbsrev(); test__tolower_l(); + test__strnicmp_l(); }
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=149155
Your paranoid android.
=== debian11 (32 bit hi:IN report) ===
msvcrt: string.c:3588: Test failed: _stricmp returned 50 string.c:3590: Test failed: _stricmp returned 50
On Mon Oct 21 13:18:47 2024 +0000, Jactry Zeng wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/6703/diffs?diff_id=139152&start_sha=c943402ed88cb1c2a149deef850c232013e14429#e59c6aa5875051a8fdb20e28186dc6a0f471b55f_538_538)
This is because _create_locale() doesn't handle a codepage-only locale string (likes ".932") very well, it won't respect the codepage first, but create ctype1/pclmap from the system's language, here is a test about it: https://gitlab.winehq.org/jactry/wine/-/commit/cce85ba8f397faa312c5dc0fbf2ba... Anyway, using a locale with the full name will avoid it, if you don't mind, I will use it for this serial first and try to fix the _create_locale() in another serial later. :)