From: Nikolay Sivov Subject: [PATCH] msvcrt: Implement _memicmp_l() Message-Id: <20171023065456.10728-1-nsivov@codeweavers.com> Date: Mon, 23 Oct 2017 09:54:56 +0300 Signed-off-by: Nikolay Sivov --- For https://bugs.winehq.org/show_bug.cgi?id=43884 .../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 | 56 +++++++++ dlls/ucrtbase/tests/string.c | 135 ++++++++++++++++++++- dlls/ucrtbase/ucrtbase.spec | 4 +- 16 files changed, 398 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@Context@Concurrency@@SAIXZ"); SET(p_CurrentScheduler_Detach, "?Detach@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 5c5a6bf362..678cda9cde 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@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..83f5b8be8c 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,56 @@ 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(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); + + 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); + + 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 +3374,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 +3438,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..574828779b 100644 --- a/dlls/ucrtbase/tests/string.c +++ b/dlls/ucrtbase/tests/string.c @@ -28,6 +28,34 @@ #include +#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,96 @@ 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); + ret = p__memicmp(NULL, NULL, 1); + ok(ret == _NLSCMPERROR, "got %d\n", ret); +todo_wine + 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); +todo_wine + 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); +todo_wine + 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); +todo_wine + 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); +todo_wine + 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); +todo_wine + 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(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