[v3 PATCH] msvcrt: Implement _memicmp_l()
Nikolay Sivov
nsivov at codeweavers.com
Tue Nov 7 07:24:41 CST 2017
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
v3: fixed ucrtbase test failures
v2: fixed test crashes on XP
.../api-ms-win-crt-string-l1-1-0.spec | 2 +-
dlls/msvcr100/msvcr100.spec | 4 +-
dlls/msvcr100/tests/msvcr100.c | 87 +++++++++++++
dlls/msvcr110/msvcr110.spec | 4 +-
dlls/msvcr120/msvcr120.spec | 4 +-
dlls/msvcr120_app/msvcr120_app.spec | 2 +-
dlls/msvcr70/msvcr70.spec | 2 +-
dlls/msvcr71/msvcr71.spec | 2 +-
dlls/msvcr80/msvcr80.spec | 4 +-
dlls/msvcr90/msvcr90.spec | 4 +-
dlls/msvcr90/tests/msvcr90.c | 69 +++++++++++
dlls/msvcrt/msvcrt.spec | 4 +-
dlls/msvcrt/string.c | 34 ++++++
dlls/msvcrt/tests/string.c | 66 ++++++++++
dlls/ucrtbase/tests/string.c | 134 ++++++++++++++++++++-
dlls/ucrtbase/ucrtbase.spec | 4 +-
16 files changed, 407 insertions(+), 19 deletions(-)
diff --git a/dlls/api-ms-win-crt-string-l1-1-0/api-ms-win-crt-string-l1-1-0.spec b/dlls/api-ms-win-crt-string-l1-1-0/api-ms-win-crt-string-l1-1-0.spec
index 1daaadc13a..d045996756 100644
--- a/dlls/api-ms-win-crt-string-l1-1-0/api-ms-win-crt-string-l1-1-0.spec
+++ b/dlls/api-ms-win-crt-string-l1-1-0/api-ms-win-crt-string-l1-1-0.spec
@@ -37,7 +37,7 @@
@ cdecl _isxdigit_l(long ptr) ucrtbase._isxdigit_l
@ cdecl _memccpy(ptr ptr long long) ucrtbase._memccpy
@ cdecl _memicmp(str str long) ucrtbase._memicmp
-@ stub _memicmp_l
+@ cdecl _memicmp_l(str str long ptr) ucrtbase._memicmp_l
@ cdecl _strcoll_l(str str ptr) ucrtbase._strcoll_l
@ cdecl _strdup(str) ucrtbase._strdup
@ cdecl _stricmp(str str) ucrtbase._stricmp
diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec
index f015fa1aa0..a04bedfbf8 100644
--- a/dlls/msvcr100/msvcr100.spec
+++ b/dlls/msvcr100/msvcr100.spec
@@ -1205,8 +1205,8 @@
@ stub _mbsupr_s_l
@ cdecl _mbtowc_l(ptr str long ptr) MSVCRT_mbtowc_l
@ cdecl _memccpy(ptr ptr long long) ntdll._memccpy
-@ cdecl _memicmp(str str long) ntdll._memicmp
-@ stub _memicmp_l
+@ cdecl _memicmp(str str long) MSVCRT__memicmp
+@ cdecl _memicmp_l(str str long ptr) MSVCRT__memicmp_l
@ cdecl _mkdir(str) MSVCRT__mkdir
@ cdecl _mkgmtime32(ptr) MSVCRT__mkgmtime32
@ cdecl _mkgmtime64(ptr) MSVCRT__mkgmtime64
diff --git a/dlls/msvcr100/tests/msvcr100.c b/dlls/msvcr100/tests/msvcr100.c
index 1089bfc7f5..b2346a89b5 100644
--- a/dlls/msvcr100/tests/msvcr100.c
+++ b/dlls/msvcr100/tests/msvcr100.c
@@ -229,6 +229,9 @@ static Scheduler* (__cdecl *p_CurrentScheduler_Get)(void);
static void (__cdecl *p_CurrentScheduler_Detach)(void);
static unsigned int (__cdecl *p_CurrentScheduler_Id)(void);
+static int (__cdecl *p__memicmp)(const char*, const char*, size_t);
+static int (__cdecl *p__memicmp_l)(const char*, const char*, size_t,_locale_t);
+
/* make sure we use the correct errno */
#undef errno
#define errno (*p_errno())
@@ -260,6 +263,8 @@ static BOOL init(void)
SET(p__aligned_free, "_aligned_free");
SET(p__aligned_msize, "_aligned_msize");
SET(p_atoi, "atoi");
+ SET(p__memicmp, "_memicmp");
+ SET(p__memicmp_l, "_memicmp_l");
SET(p_Context_Id, "?Id at Context@Concurrency@@SAIXZ");
SET(p_CurrentScheduler_Detach, "?Detach at CurrentScheduler@Concurrency@@SAXXZ");
@@ -966,6 +971,86 @@ static void test_Scheduler(void)
call_func1(p_SchedulerPolicy_dtor, &policy);
}
+static void test__memicmp(void)
+{
+ static const char *s1 = "abc";
+ static const char *s2 = "aBd";
+ int ret;
+
+ ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
+ "Invalid parameter handler was already set\n");
+
+ ret = p__memicmp(NULL, NULL, 0);
+ ok(!ret, "got %d\n", ret);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp(NULL, NULL, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == EINVAL, "errno = %d, expected EINVAL\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp(s1, NULL, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == EINVAL, "errno = %d, expected EINVAL\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp(NULL, s2, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == EINVAL, "errno = %d, expected EINVAL\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ ret = p__memicmp(s1, s2, 2);
+ ok(!ret, "got %d\n", ret);
+
+ ret = p__memicmp(s1, s2, 3);
+ ok(ret == -1, "got %d\n", ret);
+
+ ok(p_set_invalid_parameter_handler(NULL) == test_invalid_parameter_handler,
+ "Cannot reset invalid parameter handler\n");
+}
+
+static void test__memicmp_l(void)
+{
+ static const char *s1 = "abc";
+ static const char *s2 = "aBd";
+ int ret;
+
+ ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
+ "Invalid parameter handler was already set\n");
+
+ ret = p__memicmp_l(NULL, NULL, 0, NULL);
+ ok(!ret, "got %d\n", ret);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp_l(NULL, NULL, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == EINVAL, "errno = %d, expected EINVAL\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp_l(s1, NULL, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == EINVAL, "errno = %d, expected EINVAL\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp_l(NULL, s2, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == EINVAL, "errno = %d, expected EINVAL\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ ret = p__memicmp_l(s1, s2, 2, NULL);
+ ok(!ret, "got %d\n", ret);
+
+ ret = p__memicmp_l(s1, s2, 3, NULL);
+ ok(ret == -1, "got %d\n", ret);
+
+ ok(p_set_invalid_parameter_handler(NULL) == test_invalid_parameter_handler,
+ "Cannot reset invalid parameter handler\n");
+}
+
START_TEST(msvcr100)
{
if (!init())
@@ -982,4 +1067,6 @@ START_TEST(msvcr100)
test_reader_writer_lock();
test__ReentrantBlockingLock();
test_event();
+ test__memicmp();
+ test__memicmp_l();
}
diff --git a/dlls/msvcr110/msvcr110.spec b/dlls/msvcr110/msvcr110.spec
index fbbef72d16..a0aebc047c 100644
--- a/dlls/msvcr110/msvcr110.spec
+++ b/dlls/msvcr110/msvcr110.spec
@@ -1562,8 +1562,8 @@
@ stub _mbsupr_s_l
@ cdecl _mbtowc_l(ptr str long ptr) MSVCRT_mbtowc_l
@ cdecl _memccpy(ptr ptr long long) ntdll._memccpy
-@ cdecl _memicmp(str str long) ntdll._memicmp
-@ stub _memicmp_l
+@ cdecl _memicmp(str str long) MSVCRT__memicmp
+@ cdecl _memicmp_l(str str long ptr) MSVCRT__memicmp_l
@ cdecl _mkdir(str) MSVCRT__mkdir
@ cdecl _mkgmtime32(ptr) MSVCRT__mkgmtime32
@ cdecl _mkgmtime64(ptr) MSVCRT__mkgmtime64
diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec
index cf9f42fb03..b7c31599c6 100644
--- a/dlls/msvcr120/msvcr120.spec
+++ b/dlls/msvcr120/msvcr120.spec
@@ -1572,8 +1572,8 @@
@ stub _mbsupr_s_l
@ cdecl _mbtowc_l(ptr str long ptr) MSVCRT_mbtowc_l
@ cdecl _memccpy(ptr ptr long long) ntdll._memccpy
-@ cdecl _memicmp(str str long) ntdll._memicmp
-@ stub _memicmp_l
+@ cdecl _memicmp(str str long) MSVCRT__memicmp
+@ cdecl _memicmp_l(str str long ptr) MSVCRT__memicmp_l
@ cdecl _mkdir(str) MSVCRT__mkdir
@ cdecl _mkgmtime32(ptr) MSVCRT__mkgmtime32
@ cdecl _mkgmtime64(ptr) MSVCRT__mkgmtime64
diff --git a/dlls/msvcr120_app/msvcr120_app.spec b/dlls/msvcr120_app/msvcr120_app.spec
index 08455dbed1..cd8554c77e 100644
--- a/dlls/msvcr120_app/msvcr120_app.spec
+++ b/dlls/msvcr120_app/msvcr120_app.spec
@@ -1310,7 +1310,7 @@
@ cdecl _mbtowc_l(ptr str long ptr) msvcr120._mbtowc_l
@ cdecl _memccpy(ptr ptr long long) msvcr120._memccpy
@ cdecl _memicmp(str str long) msvcr120._memicmp
-@ stub _memicmp_l
+@ cdecl _memicmp_l(str str long ptr) msvcr120._memicmp_l
@ cdecl _mkdir(str) msvcr120._mkdir
@ cdecl _mkgmtime32(ptr) msvcr120._mkgmtime32
@ cdecl _mkgmtime64(ptr) msvcr120._mkgmtime64
diff --git a/dlls/msvcr70/msvcr70.spec b/dlls/msvcr70/msvcr70.spec
index 9816067fc4..a31cd1bc80 100644
--- a/dlls/msvcr70/msvcr70.spec
+++ b/dlls/msvcr70/msvcr70.spec
@@ -472,7 +472,7 @@
@ cdecl _mbstrlen(str)
@ cdecl _mbsupr(str)
@ cdecl _memccpy(ptr ptr long long) ntdll._memccpy
-@ cdecl _memicmp(str str long) ntdll._memicmp
+@ cdecl _memicmp(str str long) MSVCRT__memicmp
@ cdecl _mkdir(str) MSVCRT__mkdir
@ cdecl _mktemp(str) MSVCRT__mktemp
@ cdecl _mktime64(ptr) MSVCRT__mktime64
diff --git a/dlls/msvcr71/msvcr71.spec b/dlls/msvcr71/msvcr71.spec
index 90516b7f1b..1927376700 100644
--- a/dlls/msvcr71/msvcr71.spec
+++ b/dlls/msvcr71/msvcr71.spec
@@ -467,7 +467,7 @@
@ cdecl _mbstrlen(str)
@ cdecl _mbsupr(str)
@ cdecl _memccpy(ptr ptr long long) ntdll._memccpy
-@ cdecl _memicmp(str str long) ntdll._memicmp
+@ cdecl _memicmp(str str long) MSVCRT__memicmp
@ cdecl _mkdir(str) MSVCRT__mkdir
@ cdecl _mktemp(str) MSVCRT__mktemp
@ cdecl _mktime64(ptr) MSVCRT__mktime64
diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec
index 6737467940..d9c29fd09b 100644
--- a/dlls/msvcr80/msvcr80.spec
+++ b/dlls/msvcr80/msvcr80.spec
@@ -877,8 +877,8 @@
@ stub _mbsupr_s_l
@ cdecl _mbtowc_l(ptr str long ptr) MSVCRT_mbtowc_l
@ cdecl _memccpy(ptr ptr long long) ntdll._memccpy
-@ cdecl _memicmp(str str long) ntdll._memicmp
-@ stub _memicmp_l
+@ cdecl _memicmp(str str long) MSVCRT__memicmp
+@ cdecl _memicmp_l(str str long ptr) MSVCRT__memicmp_l
@ cdecl _mkdir(str) MSVCRT__mkdir
@ cdecl _mkgmtime32(ptr) MSVCRT__mkgmtime32
@ cdecl _mkgmtime64(ptr) MSVCRT__mkgmtime64
diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec
index c6f4a0b01e..b76a353f52 100644
--- a/dlls/msvcr90/msvcr90.spec
+++ b/dlls/msvcr90/msvcr90.spec
@@ -855,8 +855,8 @@
@ stub _mbsupr_s_l
@ cdecl _mbtowc_l(ptr str long ptr) MSVCRT_mbtowc_l
@ cdecl _memccpy(ptr ptr long long) ntdll._memccpy
-@ cdecl _memicmp(str str long) ntdll._memicmp
-@ stub _memicmp_l
+@ cdecl _memicmp(str str long) MSVCRT__memicmp
+@ cdecl _memicmp_l(str str long ptr) MSVCRT__memicmp_l
@ cdecl _mkdir(str) MSVCRT__mkdir
@ cdecl _mkgmtime32(ptr) MSVCRT__mkgmtime32
@ cdecl _mkgmtime64(ptr) MSVCRT__mkgmtime64
diff --git a/dlls/msvcr90/tests/msvcr90.c b/dlls/msvcr90/tests/msvcr90.c
index 5a82c1488d..0975d00331 100644
--- a/dlls/msvcr90/tests/msvcr90.c
+++ b/dlls/msvcr90/tests/msvcr90.c
@@ -131,6 +131,8 @@ static size_t (__cdecl *p_mbstowcs)(wchar_t*, const char*, size_t);
static size_t (__cdecl *p_wcstombs)(char*, const wchar_t*, size_t);
static char* (__cdecl *p_setlocale)(int, const char*);
static int (__cdecl *p__fpieee_flt)(ULONG, EXCEPTION_POINTERS*, int (__cdecl *handler)(_FPIEEE_RECORD*));
+static int (__cdecl *p__memicmp)(const char*, const char*, size_t);
+static int (__cdecl *p__memicmp_l)(const char*, const char*, size_t, _locale_t);
/* make sure we use the correct errno */
#undef errno
@@ -397,6 +399,9 @@ static BOOL init(void)
SET(p_wcstombs, "wcstombs");
SET(p_setlocale, "setlocale");
SET(p__fpieee_flt, "_fpieee_flt");
+ SET(p__memicmp, "_memicmp");
+ SET(p__memicmp_l, "_memicmp_l");
+
if (sizeof(void *) == 8)
{
SET(p_type_info_name_internal_method, "?_name_internal_method at type_info@@QEBAPEBDPEAU__type_info_node@@@Z");
@@ -1797,6 +1802,68 @@ static void test__fpieee_flt(void)
}
#endif
+static void test__memicmp(void)
+{
+ static const char *s1 = "abc";
+ static const char *s2 = "aBd";
+ int ret;
+
+ ret = p__memicmp(NULL, NULL, 0);
+ ok(!ret, "got %d\n", ret);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp(NULL, NULL, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ CHECK_CALLED(invalid_parameter_handler, EINVAL);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp(s1, NULL, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ CHECK_CALLED(invalid_parameter_handler, EINVAL);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp(NULL, s2, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ CHECK_CALLED(invalid_parameter_handler, EINVAL);
+
+ ret = p__memicmp(s1, s2, 2);
+ ok(!ret, "got %d\n", ret);
+
+ ret = p__memicmp(s1, s2, 3);
+ ok(ret == -1, "got %d\n", ret);
+}
+
+static void test__memicmp_l(void)
+{
+ static const char *s1 = "abc";
+ static const char *s2 = "aBd";
+ int ret;
+
+ ret = p__memicmp_l(NULL, NULL, 0, NULL);
+ ok(!ret, "got %d\n", ret);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp_l(NULL, NULL, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ CHECK_CALLED(invalid_parameter_handler, EINVAL);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp_l(s1, NULL, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ CHECK_CALLED(invalid_parameter_handler, EINVAL);
+
+ SET_EXPECT(invalid_parameter_handler);
+ ret = p__memicmp_l(NULL, s2, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ CHECK_CALLED(invalid_parameter_handler, EINVAL);
+
+ ret = p__memicmp_l(s1, s2, 2, NULL);
+ ok(!ret, "got %d\n", ret);
+
+ ret = p__memicmp_l(s1, s2, 3, NULL);
+ ok(ret == -1, "got %d\n", ret);
+}
+
START_TEST(msvcr90)
{
if(!init())
@@ -1828,6 +1895,8 @@ START_TEST(msvcr90)
test_mbstowcs();
test_strtok_s();
test__mbstok_s();
+ test__memicmp();
+ test__memicmp_l();
#ifdef __i386__
test__fpieee_flt();
#endif
diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec
index 57d2a7889e..2f20699d3b 100644
--- a/dlls/msvcrt/msvcrt.spec
+++ b/dlls/msvcrt/msvcrt.spec
@@ -824,8 +824,8 @@
# stub _mbsupr_s_l(str long ptr)
@ cdecl _mbtowc_l(ptr str long ptr) MSVCRT_mbtowc_l
@ cdecl _memccpy(ptr ptr long long) ntdll._memccpy
-@ cdecl _memicmp(str str long) ntdll._memicmp
-# stub _memicmp_l(str str long ptr)
+@ cdecl _memicmp(str str long) MSVCRT__memicmp
+@ cdecl _memicmp_l(str str long ptr) MSVCRT__memicmp_l
@ cdecl _mkdir(str) MSVCRT__mkdir
@ cdecl _mkgmtime(ptr) MSVCRT__mkgmtime
@ cdecl _mkgmtime32(ptr) MSVCRT__mkgmtime32
diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c
index 8d6b48ccec..f56ac54a8d 100644
--- a/dlls/msvcrt/string.c
+++ b/dlls/msvcrt/string.c
@@ -1940,3 +1940,37 @@ char* __cdecl MSVCRT_strstr(const char *haystack, const char *needle)
{
return strstr(haystack, needle);
}
+
+/*********************************************************************
+ * _memicmp_l (MSVCRT.@)
+ */
+int __cdecl MSVCRT__memicmp_l(const char *s1, const char *s2, MSVCRT_size_t len, MSVCRT__locale_t locale)
+{
+ int ret = 0;
+
+ if (!s1 || !s2)
+ {
+#if _MSVCR_VER >= 100
+ if (len)
+ MSVCRT_INVALID_PMT(NULL, EINVAL);
+#endif
+ return len ? MSVCRT__NLSCMPERROR : 0;
+ }
+
+ while (len--)
+ {
+ if ((ret = MSVCRT__tolower_l(*s1, locale) - MSVCRT__tolower_l(*s2, locale)))
+ break;
+ s1++;
+ s2++;
+ }
+ return ret;
+}
+
+/*********************************************************************
+ * _memicmp (MSVCRT.@)
+ */
+int __cdecl MSVCRT__memicmp(const char *s1, const char *s2, MSVCRT_size_t len)
+{
+ return MSVCRT__memicmp_l(s1, s2, len, NULL);
+}
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c
index 955a092494..f66c27c5a8 100644
--- a/dlls/msvcrt/tests/string.c
+++ b/dlls/msvcrt/tests/string.c
@@ -98,6 +98,8 @@ static int (__cdecl *p__strnset_s)(char*,size_t,int,size_t);
static int (__cdecl *p__wcsset_s)(wchar_t*,size_t,wchar_t);
static size_t (__cdecl *p__mbsnlen)(const unsigned char*, size_t);
static int (__cdecl *p__mbccpy_s)(unsigned char*, size_t, int*, const unsigned char*);
+static int (__cdecl *p__memicmp)(const char*, const char*, size_t);
+static int (__cdecl *p__memicmp_l)(const char*, const char*, size_t, _locale_t);
#define SETNOFAIL(x,y) x = (void*)GetProcAddress(hMsvcrt,y)
#define SET(x,y) SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y)
@@ -3266,6 +3268,66 @@ static void test__ismbclx(void)
_setmbcp(cp);
}
+static void test__memicmp(void)
+{
+ static const char *s1 = "abc";
+ static const char *s2 = "aBd";
+ int ret;
+
+ ret = p__memicmp(NULL, NULL, 0);
+ ok(!ret, "got %d\n", ret);
+
+ ret = p__memicmp(s1, s2, 2);
+ ok(!ret, "got %d\n", ret);
+
+ ret = p__memicmp(s1, s2, 3);
+ ok(ret == -1, "got %d\n", ret);
+
+ if (!p__memicmp_l)
+ return;
+
+ /* Following calls crash on WinXP/W2k3. */
+ ret = p__memicmp(NULL, NULL, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+
+ ret = p__memicmp(s1, NULL, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+
+ ret = p__memicmp(NULL, s2, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+}
+
+static void test__memicmp_l(void)
+{
+ static const char *s1 = "abc";
+ static const char *s2 = "aBd";
+ int ret;
+
+ if (!p__memicmp_l)
+ {
+ win_skip("_memicmp_l not found.\n");
+ return;
+ }
+
+ ret = p__memicmp_l(NULL, NULL, 0, NULL);
+ ok(!ret, "got %d\n", ret);
+
+ ret = p__memicmp_l(NULL, NULL, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+
+ ret = p__memicmp_l(s1, NULL, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+
+ ret = p__memicmp_l(NULL, s2, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+
+ ret = p__memicmp_l(s1, s2, 2, NULL);
+ ok(!ret, "got %d\n", ret);
+
+ ret = p__memicmp_l(s1, s2, 3, NULL);
+ ok(ret == -1, "got %d\n", ret);
+}
+
START_TEST(string)
{
char mem[100];
@@ -3322,6 +3384,8 @@ START_TEST(string)
p__wcsset_s = (void*)GetProcAddress(hMsvcrt, "_wcsset_s");
p__mbsnlen = (void*)GetProcAddress(hMsvcrt, "_mbsnlen");
p__mbccpy_s = (void*)GetProcAddress(hMsvcrt, "_mbccpy_s");
+ p__memicmp = (void*)GetProcAddress(hMsvcrt, "_memicmp");
+ p__memicmp_l = (void*)GetProcAddress(hMsvcrt, "_memicmp_l");
/* MSVCRT memcpy behaves like memmove for overlapping moves,
MFC42 CString::Insert seems to rely on that behaviour */
@@ -3384,4 +3448,6 @@ START_TEST(string)
test__wcsset_s();
test__mbscmp();
test__ismbclx();
+ test__memicmp();
+ test__memicmp_l();
}
diff --git a/dlls/ucrtbase/tests/string.c b/dlls/ucrtbase/tests/string.c
index c251558607..96de238848 100644
--- a/dlls/ucrtbase/tests/string.c
+++ b/dlls/ucrtbase/tests/string.c
@@ -28,6 +28,34 @@
#include <math.h>
+#define DEFINE_EXPECT(func) \
+ static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+ expect_ ## func = TRUE
+
+#define CHECK_EXPECT2(func) \
+ do { \
+ ok(expect_ ##func, "unexpected call " #func "\n"); \
+ called_ ## func = TRUE; \
+ }while(0)
+
+#define CHECK_EXPECT(func) \
+ do { \
+ CHECK_EXPECT2(func); \
+ expect_ ## func = FALSE; \
+ }while(0)
+
+#define CHECK_CALLED(func) \
+ do { \
+ ok(called_ ## func, "expected " #func "\n"); \
+ expect_ ## func = called_ ## func = FALSE; \
+ }while(0)
+
+DEFINE_EXPECT(invalid_parameter_handler);
+
+static _invalid_parameter_handler (__cdecl *p_set_invalid_parameter_handler)(_invalid_parameter_handler);
+
#ifndef INFINITY
static inline float __port_infinity(void)
{
@@ -46,7 +74,21 @@ static inline float __port_nan(void)
#define NAN __port_nan()
#endif
-static double (CDECL *p_strtod)(const char*, char** end);
+static void __cdecl test_invalid_parameter_handler(const wchar_t *expression,
+ const wchar_t *function, const wchar_t *file,
+ unsigned line, uintptr_t arg)
+{
+ CHECK_EXPECT(invalid_parameter_handler);
+ ok(expression == NULL, "expression is not NULL\n");
+ ok(function == NULL, "function is not NULL\n");
+ ok(file == NULL, "file is not NULL\n");
+ ok(line == 0, "line = %u\n", line);
+ ok(arg == 0, "arg = %lx\n", (UINT_PTR)arg);
+}
+
+static double (__cdecl *p_strtod)(const char*, char** end);
+static int (__cdecl *p__memicmp)(const char*, const char*, size_t);
+static int (__cdecl *p__memicmp_l)(const char*, const char*, size_t,_locale_t);
static BOOL init(void)
{
@@ -59,7 +101,10 @@ static BOOL init(void)
return FALSE;
}
+ p_set_invalid_parameter_handler = (void*)GetProcAddress(module, "_set_invalid_parameter_handler");
p_strtod = (void*)GetProcAddress(module, "strtod");
+ p__memicmp = (void*)GetProcAddress(module, "_memicmp");
+ p__memicmp_l = (void*)GetProcAddress(module, "_memicmp_l");
return TRUE;
}
@@ -114,8 +159,95 @@ static void test_strtod(void)
test_strtod_str("0x1p1a", 2, 5);
}
+static void test__memicmp(void)
+{
+ static const char *s1 = "abc";
+ static const char *s2 = "aBd";
+ int ret;
+
+ ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
+ "Invalid parameter handler was already set\n");
+
+ ret = p__memicmp(NULL, NULL, 0);
+ ok(!ret, "got %d\n", ret);
+
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ ret = p__memicmp(NULL, NULL, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == 0xdeadbeef, "Unexpected errno = %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ ret = p__memicmp(s1, NULL, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == 0xdeadbeef, "Unexpected errno = %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ ret = p__memicmp(NULL, s2, 1);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == 0xdeadbeef, "Unexpected errno = %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ ret = p__memicmp(s1, s2, 2);
+ ok(!ret, "got %d\n", ret);
+
+ ret = p__memicmp(s1, s2, 3);
+ ok(ret == -1, "got %d\n", ret);
+
+ ok(p_set_invalid_parameter_handler(NULL) == test_invalid_parameter_handler,
+ "Cannot reset invalid parameter handler\n");
+}
+
+static void test__memicmp_l(void)
+{
+ static const char *s1 = "abc";
+ static const char *s2 = "aBd";
+ int ret;
+
+ ok(p_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
+ "Invalid parameter handler was already set\n");
+
+ ret = p__memicmp_l(NULL, NULL, 0, NULL);
+ ok(!ret, "got %d\n", ret);
+
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ ret = p__memicmp_l(NULL, NULL, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == 0xdeadbeef, "Unexpected errno = %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ ret = p__memicmp_l(s1, NULL, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == 0xdeadbeef, "Unexpected errno = %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ ret = p__memicmp_l(NULL, s2, 1, NULL);
+ ok(ret == _NLSCMPERROR, "got %d\n", ret);
+ ok(errno == 0xdeadbeef, "Unexpected errno = %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+
+ ret = p__memicmp_l(s1, s2, 2, NULL);
+ ok(!ret, "got %d\n", ret);
+
+ ret = p__memicmp_l(s1, s2, 3, NULL);
+ ok(ret == -1, "got %d\n", ret);
+
+ ok(p_set_invalid_parameter_handler(NULL) == test_invalid_parameter_handler,
+ "Cannot reset invalid parameter handler\n");
+}
START_TEST(string)
{
if (!init()) return;
test_strtod();
+ test__memicmp();
+ test__memicmp_l();
}
diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec
index 5495746827..a2c16e4e32 100644
--- a/dlls/ucrtbase/ucrtbase.spec
+++ b/dlls/ucrtbase/ucrtbase.spec
@@ -718,8 +718,8 @@
@ stub _mbsupr_s_l
@ cdecl _mbtowc_l(ptr str long ptr) MSVCRT_mbtowc_l
@ cdecl _memccpy(ptr ptr long long) ntdll._memccpy
-@ cdecl _memicmp(str str long) ntdll._memicmp
-@ stub _memicmp_l
+@ cdecl _memicmp(str str long) MSVCRT__memicmp
+@ cdecl _memicmp_l(str str long ptr) MSVCRT__memicmp_l
@ cdecl _mkdir(str) MSVCRT__mkdir
@ cdecl _mkgmtime32(ptr) MSVCRT__mkgmtime32
@ cdecl _mkgmtime64(ptr) MSVCRT__mkgmtime64
--
2.14.2
More information about the wine-patches
mailing list