From: Shaun Ren sren@codeweavers.com
Some programs, such as Final Fantasy IV (3D remake), expect strncmp to return exactly +/-1 when the strings are not equal.
Signed-off-by: Shaun Ren sren@codeweavers.com --- configure | 2 + configure.ac | 2 + dlls/msvcr100/tests/msvcr100.c | 47 ++++++++++++++++++ dlls/msvcr110/tests/msvcr110.c | 38 +++++++++++++++ dlls/msvcr120/tests/msvcr120.c | 36 ++++++++++++++ dlls/msvcr70/tests/Makefile.in | 4 ++ dlls/msvcr70/tests/msvcr70.c | 87 ++++++++++++++++++++++++++++++++++ dlls/msvcr71/tests/Makefile.in | 4 ++ dlls/msvcr71/tests/msvcr71.c | 87 ++++++++++++++++++++++++++++++++++ dlls/msvcr80/tests/msvcr80.c | 46 ++++++++++++++++++ dlls/msvcr90/tests/msvcr90.c | 45 ++++++++++++++++++ dlls/msvcrt/string.c | 7 +++ dlls/msvcrt/tests/string.c | 15 ++++-- dlls/ucrtbase/tests/string.c | 32 +++++++++++++ 14 files changed, 449 insertions(+), 3 deletions(-) create mode 100644 dlls/msvcr70/tests/Makefile.in create mode 100644 dlls/msvcr70/tests/msvcr70.c create mode 100644 dlls/msvcr71/tests/Makefile.in create mode 100644 dlls/msvcr71/tests/msvcr71.c
diff --git a/configure b/configure index 8104ac5f0ba..781a3a5a601 100755 --- a/configure +++ b/configure @@ -21711,7 +21711,9 @@ wine_fn_config_makefile dlls/msvcr120 enable_msvcr120 wine_fn_config_makefile dlls/msvcr120/tests enable_tests wine_fn_config_makefile dlls/msvcr120_app enable_msvcr120_app wine_fn_config_makefile dlls/msvcr70 enable_msvcr70 +wine_fn_config_makefile dlls/msvcr70/tests enable_tests wine_fn_config_makefile dlls/msvcr71 enable_msvcr71 +wine_fn_config_makefile dlls/msvcr71/tests enable_tests wine_fn_config_makefile dlls/msvcr80 enable_msvcr80 wine_fn_config_makefile dlls/msvcr80/tests enable_tests wine_fn_config_makefile dlls/msvcr90 enable_msvcr90 diff --git a/configure.ac b/configure.ac index 49d414e1d17..1dc8aab8dc8 100644 --- a/configure.ac +++ b/configure.ac @@ -2850,7 +2850,9 @@ WINE_CONFIG_MAKEFILE(dlls/msvcr120) WINE_CONFIG_MAKEFILE(dlls/msvcr120/tests) WINE_CONFIG_MAKEFILE(dlls/msvcr120_app) WINE_CONFIG_MAKEFILE(dlls/msvcr70) +WINE_CONFIG_MAKEFILE(dlls/msvcr70/tests) WINE_CONFIG_MAKEFILE(dlls/msvcr71) +WINE_CONFIG_MAKEFILE(dlls/msvcr71/tests) WINE_CONFIG_MAKEFILE(dlls/msvcr80) WINE_CONFIG_MAKEFILE(dlls/msvcr80/tests) WINE_CONFIG_MAKEFILE(dlls/msvcr90) diff --git a/dlls/msvcr100/tests/msvcr100.c b/dlls/msvcr100/tests/msvcr100.c index 4319f31a400..7bde5c7935d 100644 --- a/dlls/msvcr100/tests/msvcr100.c +++ b/dlls/msvcr100/tests/msvcr100.c @@ -237,6 +237,9 @@ static int (__cdecl *p__memicmp_l)(const char*, const char*, size_t,_locale_t); static char* (__cdecl *p_setlocale)(int, const char*); static size_t (__cdecl *p___strncnt)(const char*, size_t);
+static int (__cdecl *p_strcmp)(const char *, const char *); +static int (__cdecl *p_strncmp)(const char *, const char *, size_t); + /* make sure we use the correct errno */ #undef errno #define errno (*p_errno()) @@ -277,6 +280,9 @@ static BOOL init(void) SET(p_CurrentScheduler_Detach, "?Detach@CurrentScheduler@Concurrency@@SAXXZ"); SET(p_CurrentScheduler_Id, "?Id@CurrentScheduler@Concurrency@@SAIXZ");
+ SET(p_strcmp, "strcmp"); + SET(p_strncmp, "strncmp"); + if(sizeof(void*) == 8) { /* 64-bit initialization */ SET(pSpinWait_ctor_yield, "??0?$_SpinWait@$00@details@Concurrency@@QEAA@P6AXXZ@Z"); SET(pSpinWait_dtor, "??_F?$_SpinWait@$00@details@Concurrency@@QEAAXXZ"); @@ -1106,6 +1112,46 @@ static void test___strncnt(void) } }
+static void test_strcmp(void) +{ + int ret = p_strcmp( "abc", "abcd" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "", "abc" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "abc", "ab\xa0" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xb0", "ab\xa0" ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xc2", "ab\xc2" ); + ok( ret == 0, "wrong ret %d\n", ret ); + + ret = p_strncmp( "abc", "abcd", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); +#ifdef _WIN64 + ret = p_strncmp( "", "abc", 3 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 1, "wrong ret %d\n", ret ); +#else + ret = p_strncmp( "", "abc", 3 ); + ok( ret == 0 - 'a', "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == 'c' - 0xa0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 0xb0 - 0xa0, "wrong ret %d\n", ret ); +#endif + ret = p_strncmp( "ab\xb0", "ab\xa0", 2 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xc2", "ab\xc2", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abd", 0 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abc", 12 ); + ok( ret == 0, "wrong ret %d\n", ret ); +} + START_TEST(msvcr100) { if (!init()) @@ -1126,4 +1172,5 @@ START_TEST(msvcr100) test__memicmp_l(); test_setlocale(); test___strncnt(); + test_strcmp(); } diff --git a/dlls/msvcr110/tests/msvcr110.c b/dlls/msvcr110/tests/msvcr110.c index d6502b0f0fa..255c68b0796 100644 --- a/dlls/msvcr110/tests/msvcr110.c +++ b/dlls/msvcr110/tests/msvcr110.c @@ -52,6 +52,9 @@ static unsigned int (CDECL *p__CurrentScheduler__Id)(void); static Context* (__cdecl *p_Context_CurrentContext)(void); static _Context* (__cdecl *p__Context__CurrentContext)(_Context*);
+static int (__cdecl *p_strcmp)(const char *, const char *); +static int (__cdecl *p_strncmp)(const char *, const char *, size_t); + #define SETNOFAIL(x,y) x = (void*)GetProcAddress(module,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0)
@@ -84,6 +87,9 @@ static BOOL init(void) SET(p_Context_CurrentContext, "?CurrentContext@Context@Concurrency@@SAPAV12@XZ"); }
+ SET(p_strcmp, "strcmp"); + SET(p_strncmp, "strncmp"); + return TRUE; }
@@ -192,6 +198,37 @@ static void test_CurrentContext(void) ok(ret == &_ctx, "expected %p, got %p\n", &_ctx, ret); }
+static void test_strcmp(void) +{ + int ret = p_strcmp( "abc", "abcd" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "", "abc" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "abc", "ab\xa0" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xb0", "ab\xa0" ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xc2", "ab\xc2" ); + ok( ret == 0, "wrong ret %d\n", ret ); + + ret = p_strncmp( "abc", "abcd", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "", "abc", 3 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 2 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xc2", "ab\xc2", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abd", 0 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abc", 12 ); + ok( ret == 0, "wrong ret %d\n", ret ); +} + START_TEST(msvcr110) { if (!init()) return; @@ -199,4 +236,5 @@ START_TEST(msvcr110) test_setlocale(); test___strncnt(); test_CurrentContext(); + test_strcmp(); } diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c index ac35076af03..91e9bae1cf8 100644 --- a/dlls/msvcr120/tests/msvcr120.c +++ b/dlls/msvcr120/tests/msvcr120.c @@ -220,6 +220,8 @@ static float (__cdecl *p_nexttowardf)(float, double); static double (__cdecl *p_nexttowardl)(double, double); static wctrans_t (__cdecl *p_wctrans)(const char*); static wint_t (__cdecl *p_towctrans)(wint_t, wctrans_t); +static int (__cdecl *p_strcmp)(const char *, const char *); +static int (__cdecl *p_strncmp)(const char *, const char *, size_t);
/* make sure we use the correct errno */ #undef errno @@ -306,6 +308,8 @@ static BOOL init(void) SET(p_wctrans, "wctrans"); SET(p_towctrans, "towctrans"); SET(p__Context__CurrentContext, "?_CurrentContext@_Context@details@Concurrency@@SA?AV123@XZ"); + SET(p_strcmp, "strcmp"); + SET(p_strncmp, "strncmp"); if(sizeof(void*) == 8) { /* 64-bit initialization */ SET(p__StructuredTaskCollection_ctor, "??0_StructuredTaskCollection@details@Concurrency@@QEAA@PEAV_CancellationTokenState@12@@Z"); @@ -1591,6 +1595,37 @@ static void test_StructuredTaskCollection(void) CloseHandle(chore_evt2); }
+static void test_strcmp(void) +{ + int ret = p_strcmp( "abc", "abcd" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "", "abc" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "abc", "ab\xa0" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xb0", "ab\xa0" ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xc2", "ab\xc2" ); + ok( ret == 0, "wrong ret %d\n", ret ); + + ret = p_strncmp( "abc", "abcd", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "", "abc", 3 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 2 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xc2", "ab\xc2", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abd", 0 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abc", 12 ); + ok( ret == 0, "wrong ret %d\n", ret ); +} + START_TEST(msvcr120) { if (!init()) return; @@ -1614,4 +1649,5 @@ START_TEST(msvcr120) test_towctrans(); test_CurrentContext(); test_StructuredTaskCollection(); + test_strcmp(); } diff --git a/dlls/msvcr70/tests/Makefile.in b/dlls/msvcr70/tests/Makefile.in new file mode 100644 index 00000000000..2c6a08d55e4 --- /dev/null +++ b/dlls/msvcr70/tests/Makefile.in @@ -0,0 +1,4 @@ +TESTDLL = msvcr70.dll + +C_SRCS = \ + msvcr70.c diff --git a/dlls/msvcr70/tests/msvcr70.c b/dlls/msvcr70/tests/msvcr70.c new file mode 100644 index 00000000000..0b6f395ba32 --- /dev/null +++ b/dlls/msvcr70/tests/msvcr70.c @@ -0,0 +1,87 @@ +/* + * Copyright 2022 Shaun Ren for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> + +#include <windef.h> +#include <winbase.h> +#include <errno.h> +#include "wine/test.h" + +static int (__cdecl *p_strcmp)(const char *, const char *); +static int (__cdecl *p_strncmp)(const char *, const char *, size_t); + +#define SETNOFAIL(x,y) x = (void*)GetProcAddress(hcrt,y) +#define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) +static BOOL init(void) +{ + HMODULE hcrt; + + SetLastError(0xdeadbeef); + hcrt = LoadLibraryA("msvcr70.dll"); + if (!hcrt) { + win_skip("msvcr70.dll not installed (got %ld)\n", GetLastError()); + return FALSE; + } + + SET(p_strcmp, "strcmp"); + SET(p_strncmp, "strncmp"); + + return TRUE; +} + +static void test_strcmp(void) +{ + int ret = p_strcmp( "abc", "abcd" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "", "abc" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "abc", "ab\xa0" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xb0", "ab\xa0" ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xc2", "ab\xc2" ); + ok( ret == 0, "wrong ret %d\n", ret ); + + ret = p_strncmp( "abc", "abcd", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "", "abc", 3 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 2 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xc2", "ab\xc2", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abd", 0 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abc", 12 ); + ok( ret == 0, "wrong ret %d\n", ret ); +} + +START_TEST(msvcr70) +{ + if(!init()) + return; + + test_strcmp(); +} diff --git a/dlls/msvcr71/tests/Makefile.in b/dlls/msvcr71/tests/Makefile.in new file mode 100644 index 00000000000..7a65a611479 --- /dev/null +++ b/dlls/msvcr71/tests/Makefile.in @@ -0,0 +1,4 @@ +TESTDLL = msvcr71.dll + +C_SRCS = \ + msvcr71.c diff --git a/dlls/msvcr71/tests/msvcr71.c b/dlls/msvcr71/tests/msvcr71.c new file mode 100644 index 00000000000..a42f74f68a5 --- /dev/null +++ b/dlls/msvcr71/tests/msvcr71.c @@ -0,0 +1,87 @@ +/* + * Copyright 2022 Shaun Ren for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> + +#include <windef.h> +#include <winbase.h> +#include <errno.h> +#include "wine/test.h" + +static int (__cdecl *p_strcmp)(const char *, const char *); +static int (__cdecl *p_strncmp)(const char *, const char *, size_t); + +#define SETNOFAIL(x,y) x = (void*)GetProcAddress(hcrt,y) +#define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) +static BOOL init(void) +{ + HMODULE hcrt; + + SetLastError(0xdeadbeef); + hcrt = LoadLibraryA("msvcr71.dll"); + if (!hcrt) { + win_skip("msvcr71.dll not installed (got %ld)\n", GetLastError()); + return FALSE; + } + + SET(p_strcmp, "strcmp"); + SET(p_strncmp, "strncmp"); + + return TRUE; +} + +static void test_strcmp(void) +{ + int ret = p_strcmp( "abc", "abcd" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "", "abc" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "abc", "ab\xa0" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xb0", "ab\xa0" ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xc2", "ab\xc2" ); + ok( ret == 0, "wrong ret %d\n", ret ); + + ret = p_strncmp( "abc", "abcd", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "", "abc", 3 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 2 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xc2", "ab\xc2", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abd", 0 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abc", 12 ); + ok( ret == 0, "wrong ret %d\n", ret ); +} + +START_TEST(msvcr71) +{ + if(!init()) + return; + + test_strcmp(); +} diff --git a/dlls/msvcr80/tests/msvcr80.c b/dlls/msvcr80/tests/msvcr80.c index c74cd8b93a2..81f05a472e7 100644 --- a/dlls/msvcr80/tests/msvcr80.c +++ b/dlls/msvcr80/tests/msvcr80.c @@ -60,6 +60,8 @@ static ioinfo **__pioinfo; static int (__cdecl *p__open)(const char *, int, ...); static int (__cdecl *p__close)(int); static intptr_t (__cdecl *p__get_osfhandle)(int); +static int (__cdecl *p_strcmp)(const char *, const char *); +static int (__cdecl *p_strncmp)(const char *, const char *, size_t);
#define SETNOFAIL(x,y) x = (void*)GetProcAddress(hcrt,y) #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0) @@ -79,6 +81,9 @@ static BOOL init(void) SET(p__close,"_close"); SET(p__get_osfhandle, "_get_osfhandle");
+ SET(p_strcmp, "strcmp"); + SET(p_strncmp, "strncmp"); + return TRUE; }
@@ -139,10 +144,51 @@ static void test_ioinfo_flags(void) free(tempf); }
+static void test_strcmp(void) +{ + int ret = p_strcmp( "abc", "abcd" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "", "abc" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "abc", "ab\xa0" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xb0", "ab\xa0" ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xc2", "ab\xc2" ); + ok( ret == 0, "wrong ret %d\n", ret ); + + ret = p_strncmp( "abc", "abcd", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); +#ifdef _WIN64 + ret = p_strncmp( "", "abc", 3 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 1, "wrong ret %d\n", ret ); +#else + ret = p_strncmp( "", "abc", 3 ); + ok( ret == 0 - 'a', "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == 'c' - 0xa0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 0xb0 - 0xa0, "wrong ret %d\n", ret ); +#endif + ret = p_strncmp( "ab\xb0", "ab\xa0", 2 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xc2", "ab\xc2", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abd", 0 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abc", 12 ); + ok( ret == 0, "wrong ret %d\n", ret ); +} + START_TEST(msvcr80) { if(!init()) return;
test_ioinfo_flags(); + test_strcmp(); } diff --git a/dlls/msvcr90/tests/msvcr90.c b/dlls/msvcr90/tests/msvcr90.c index 5b6a1d08399..cf73097b818 100644 --- a/dlls/msvcr90/tests/msvcr90.c +++ b/dlls/msvcr90/tests/msvcr90.c @@ -171,6 +171,8 @@ static int (__cdecl *p____mb_cur_max_l_func)(_locale_t locale); static _locale_t (__cdecl *p__create_locale)(int, const char*); static void (__cdecl *p__free_locale)(_locale_t); static _locale_t (__cdecl *p__get_current_locale)(void); +static int (__cdecl *p_strcmp)(const char *, const char *); +static int (__cdecl *p_strncmp)(const char *, const char *, size_t);
struct __lc_time_data { const char *short_wday[7]; @@ -471,6 +473,8 @@ static BOOL init(void) SET(p__create_locale, "_create_locale"); SET(p__free_locale, "_free_locale"); SET(p__get_current_locale, "_get_current_locale"); + SET(p_strcmp, "strcmp"); + SET(p_strncmp, "strncmp");
if (sizeof(void *) == 8) { @@ -2441,6 +2445,46 @@ static void test_ioinfo_flags(void) free(tempf); }
+static void test_strcmp(void) +{ + int ret = p_strcmp( "abc", "abcd" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "", "abc" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "abc", "ab\xa0" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xb0", "ab\xa0" ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = p_strcmp( "ab\xc2", "ab\xc2" ); + ok( ret == 0, "wrong ret %d\n", ret ); + + ret = p_strncmp( "abc", "abcd", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); +#ifdef _WIN64 + ret = p_strncmp( "", "abc", 3 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 1, "wrong ret %d\n", ret ); +#else + ret = p_strncmp( "", "abc", 3 ); + ok( ret == 0 - 'a', "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == 'c' - 0xa0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 0xb0 - 0xa0, "wrong ret %d\n", ret ); +#endif + ret = p_strncmp( "ab\xb0", "ab\xa0", 2 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xc2", "ab\xc2", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abd", 0 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "abc", 12 ); + ok( ret == 0, "wrong ret %d\n", ret ); +} + START_TEST(msvcr90) { if(!init()) @@ -2483,4 +2527,5 @@ START_TEST(msvcr90) test____mb_cur_max_l_func(); test__get_current_locale(); test_ioinfo_flags(); + test_strcmp(); } diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c index dd392abd203..d1bdf73d209 100644 --- a/dlls/msvcrt/string.c +++ b/dlls/msvcrt/string.c @@ -3289,7 +3289,14 @@ int __cdecl strncmp(const char *str1, const char *str2, size_t len) { if (!len) return 0; while (--len && *str1 && *str1 == *str2) { str1++; str2++; } + +#if defined(_WIN64) || defined(_UCRT) || _MSVCR_VER == 70 || _MSVCR_VER == 71 || _MSVCR_VER >= 110 + if ((unsigned char)*str1 > (unsigned char)*str2) return 1; + if ((unsigned char)*str1 < (unsigned char)*str2) return -1; + return 0; +#else return (unsigned char)*str1 - (unsigned char)*str2; +#endif }
/********************************************************************* diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index 4b224bd1a17..4e525193ced 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -662,12 +662,21 @@ static void test_strcmp(void)
ret = p_strncmp( "abc", "abcd", 3 ); ok( ret == 0, "wrong ret %d\n", ret ); +#ifdef _WIN64 ret = p_strncmp( "", "abc", 3 ); - ok( ret == 0 - 'a' || ret == -1, "wrong ret %d\n", ret ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "abc", "ab\xa0", 4 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 1, "wrong ret %d\n", ret ); +#else + ret = p_strncmp( "", "abc", 3 ); + ok( ret == 0 - 'a', "wrong ret %d\n", ret ); ret = p_strncmp( "abc", "ab\xa0", 4 ); - ok( ret == 'c' - 0xa0 || ret == -1, "wrong ret %d\n", ret ); + ok( ret == 'c' - 0xa0, "wrong ret %d\n", ret ); ret = p_strncmp( "ab\xb0", "ab\xa0", 3 ); - ok( ret == 0xb0 - 0xa0 || ret == 1, "wrong ret %d\n", ret ); + ok( ret == 0xb0 - 0xa0, "wrong ret %d\n", ret ); +#endif ret = p_strncmp( "ab\xb0", "ab\xa0", 2 ); ok( ret == 0, "wrong ret %d\n", ret ); ret = p_strncmp( "ab\xc2", "ab\xc2", 3 ); diff --git a/dlls/ucrtbase/tests/string.c b/dlls/ucrtbase/tests/string.c index 806ae08f253..2c6a02da7ae 100644 --- a/dlls/ucrtbase/tests/string.c +++ b/dlls/ucrtbase/tests/string.c @@ -602,6 +602,37 @@ static void test__mbbtype_l(void) } }
+static void test_strcmp(void) +{ + int ret = strcmp( "abc", "abcd" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = strcmp( "", "abc" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = strcmp( "abc", "ab\xa0" ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = strcmp( "ab\xb0", "ab\xa0" ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = strcmp( "ab\xc2", "ab\xc2" ); + ok( ret == 0, "wrong ret %d\n", ret ); + + ret = strncmp( "abc", "abcd", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = strncmp( "", "abc", 3 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = strncmp( "abc", "ab\xa0", 4 ); + ok( ret == -1, "wrong ret %d\n", ret ); + ret = strncmp( "ab\xb0", "ab\xa0", 3 ); + ok( ret == 1, "wrong ret %d\n", ret ); + ret = strncmp( "ab\xb0", "ab\xa0", 2 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = strncmp( "ab\xc2", "ab\xc2", 3 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = strncmp( "abc", "abd", 0 ); + ok( ret == 0, "wrong ret %d\n", ret ); + ret = strncmp( "abc", "abc", 12 ); + ok( ret == 0, "wrong ret %d\n", ret ); +} + START_TEST(string) { ok(_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL, @@ -619,4 +650,5 @@ START_TEST(string) test_wcsnicmp(); test_SpecialCasing(); test__mbbtype_l(); + test_strcmp(); }