-- v4: 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..74ef7a6ed9f 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, "Japanese_Japan.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 74ef7a6ed9f..9ffc6201848 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(); }
Piotr Caban (@piotr) commented about dlls/msvcrt/tests/string.c:
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);
This cast is not needed.
I'm also not sure about some setlocale calls - we used to have to skip tests if locale is unavailable. Since testbot is not complaining I'm tempted to ignore it hoping it was needed for Windows XP.