From: Jactry Zeng jzeng@codeweavers.com
--- dlls/msvcrt/tests/string.c | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+)
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index 23f4205e785..7f09b572459 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -4784,6 +4784,52 @@ static void test_mbsrev(void) _setmbcp(cp); }
+static void test__tolower_l(void) +{ + int ret; + + if (!setlocale(LC_ALL, "english")) + { + win_skip("Skip _tolower_l tests.\n"); + return; + } + + 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); + + if (!setlocale(LC_ALL, ".936")) + { + win_skip("Skip _tolower_l tests.\n"); + return; + } + + 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); + + if (!setlocale(LC_ALL, "chinese-simplified")) + { + win_skip("Skip _tolower_l tests.\n"); + return; + } + + 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]; @@ -4946,4 +4992,5 @@ START_TEST(string) test__mbbtype(); test_wcsncpy(); test_mbsrev(); + test__tolower_l(); }
From: Jactry Zeng jzeng@codeweavers.com
--- dlls/msvcrt/string.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c index 571ca34b847..89e9176b2ad 100644 --- a/dlls/msvcrt/string.c +++ b/dlls/msvcrt/string.c @@ -3312,7 +3312,8 @@ int __cdecl _strnicmp_l(const char *s1, const char *s2, size_t count, _locale_t locale) { pthreadlocinfo locinfo; - int c1, c2; + BOOL is_dbcs_cp = FALSE; + int c1, c2, cp;
if(!count) return 0; @@ -3329,7 +3330,11 @@ int __cdecl _strnicmp_l(const char *s1, const char *s2, else locinfo = locale->locinfo;
- if(!locinfo->lc_handle[LC_CTYPE]) + cp = locinfo->lc_codepage; + if(cp == 932 || cp == 936 || cp == 949 || cp == 950) + is_dbcs_cp = TRUE; + + if(!locinfo->lc_handle[LC_CTYPE] || is_dbcs_cp) { do { if ((c1 = *s1++) >= 'A' && c1 <= 'Z') @@ -3338,7 +3343,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 | 58 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+)
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index 7f09b572459..bfd57e52101 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -3491,6 +3491,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"); @@ -3507,6 +3511,60 @@ 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); + + setlocale(LC_ALL, "C"); + + if(!setlocale(LC_ALL, ".936")) { + win_skip("stricmp tests\n"); + return; + } + + 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); + + setlocale(LC_ALL, "C"); + + if(!setlocale(LC_ALL, ".932")) { + win_skip("stricmp tests\n"); + return; + } + + 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 bfd57e52101..1430e47f50c 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);
@@ -4888,6 +4889,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 = _strnicmp_l(tests[i].str1, tests[i].str2, INT_MAX, 0); + ok(ret > 0, "tests[%d]: Got %d.\n", i, ret); + + ret = _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 = _strnicmp_l(tests[i].str1, tests[i].str2, INT_MAX, locale); + ok(ret > 0, "tests[%d]: Got %d.\n", i, ret); + + ret = _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 = _strnicmp_l(tests[i].str1, tests[i].str2, INT_MAX, 0); + ok(ret > 0, "tests[%d]: Got %d.\n", i, ret); + + ret = _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]; @@ -4963,6 +5036,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 */ @@ -5051,4 +5125,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=149126
Your paranoid android.
=== debian11b (64 bit WoW report) ===
Report validation errors: winmm:mci crashed (c0000008)
Piotr Caban (@piotr) commented about dlls/msvcrt/tests/string.c:
- ok(ret == 185, "Got %d.\n", ret);
- ret = _tolower_l('a', 0);
- ok(ret == 97, "Got %d.\n", ret);
- if (!setlocale(LC_ALL, ".936"))
- {
win_skip("Skip _tolower_l tests.\n");
return;
- }
- 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);
I think it's _tolower_l/_toupper_l that needs to be fixed (and C locale handling in strnicmp). Please also add tests with unsigned char cast: ```c ret = _tolower_l((unsigned char)'\xa5', 0); ok(ret == 165, "Got %d.\n", ret); ret = _tolower_l((unsigned char)'\xb9', 0); ok(ret == 185, "Got %d.\n", ret); ```