From: Paul Gofman <pgofman(a)codeweavers.com>
---
dlls/msvcr100/msvcr100.spec | 4 +-
dlls/msvcr110/msvcr110.spec | 4 +-
dlls/msvcr120/msvcr120.spec | 4 +-
dlls/msvcr80/msvcr80.spec | 4 +-
dlls/msvcr80/tests/msvcr80.c | 247 ++++++++++++++++++++++++++++++++++-
dlls/msvcr90/msvcr90.spec | 4 +-
dlls/msvcrt/mbcs.c | 77 +++++++++++
dlls/ucrtbase/tests/string.c | 178 +++++++++++++++++++++++++
dlls/ucrtbase/ucrtbase.spec | 8 +-
include/msvcrt/mbstring.h | 2 +
10 files changed, 517 insertions(+), 15 deletions(-)
diff --git a/dlls/msvcr100/msvcr100.spec b/dlls/msvcr100/msvcr100.spec
index 68e502af597..7e6397051e9 100644
--- a/dlls/msvcr100/msvcr100.spec
+++ b/dlls/msvcr100/msvcr100.spec
@@ -1157,8 +1157,8 @@
@ stub _mbsncoll_l
@ cdecl _mbsncpy(ptr str long)
@ cdecl _mbsncpy_l(ptr str long ptr)
-@ stub _mbsncpy_s
-@ stub _mbsncpy_s_l
+@ cdecl _mbsncpy_s(ptr long str long)
+@ cdecl _mbsncpy_s_l(ptr long str long ptr)
@ cdecl _mbsnextc(str)
@ cdecl _mbsnextc_l(str ptr)
@ cdecl _mbsnicmp(str str long)
diff --git a/dlls/msvcr110/msvcr110.spec b/dlls/msvcr110/msvcr110.spec
index 560002e59ed..010d222d665 100644
--- a/dlls/msvcr110/msvcr110.spec
+++ b/dlls/msvcr110/msvcr110.spec
@@ -1514,8 +1514,8 @@
@ stub _mbsncoll_l
@ cdecl _mbsncpy(ptr str long)
@ cdecl _mbsncpy_l(ptr str long ptr)
-@ stub _mbsncpy_s
-@ stub _mbsncpy_s_l
+@ cdecl _mbsncpy_s(ptr long str long)
+@ cdecl _mbsncpy_s_l(ptr long str long ptr)
@ cdecl _mbsnextc(str)
@ cdecl _mbsnextc_l(str ptr)
@ cdecl _mbsnicmp(str str long)
diff --git a/dlls/msvcr120/msvcr120.spec b/dlls/msvcr120/msvcr120.spec
index 46715817932..caddf750038 100644
--- a/dlls/msvcr120/msvcr120.spec
+++ b/dlls/msvcr120/msvcr120.spec
@@ -1525,8 +1525,8 @@
@ stub _mbsncoll_l
@ cdecl _mbsncpy(ptr str long)
@ cdecl _mbsncpy_l(ptr str long ptr)
-@ stub _mbsncpy_s
-@ stub _mbsncpy_s_l
+@ cdecl _mbsncpy_s(ptr long str long)
+@ cdecl _mbsncpy_s_l(ptr long str long ptr)
@ cdecl _mbsnextc(str)
@ cdecl _mbsnextc_l(str ptr)
@ cdecl _mbsnicmp(str str long)
diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec
index 6cce6ee22ee..b4548945236 100644
--- a/dlls/msvcr80/msvcr80.spec
+++ b/dlls/msvcr80/msvcr80.spec
@@ -829,8 +829,8 @@
@ stub _mbsncoll_l
@ cdecl _mbsncpy(ptr str long)
@ cdecl _mbsncpy_l(ptr str long ptr)
-@ stub _mbsncpy_s
-@ stub _mbsncpy_s_l
+@ cdecl _mbsncpy_s(ptr long str long)
+@ cdecl _mbsncpy_s_l(ptr long str long ptr)
@ cdecl _mbsnextc(str)
@ cdecl _mbsnextc_l(str ptr)
@ cdecl _mbsnicmp(str str long)
diff --git a/dlls/msvcr80/tests/msvcr80.c b/dlls/msvcr80/tests/msvcr80.c
index 6e48ecf2894..506d3e695e9 100644
--- a/dlls/msvcr80/tests/msvcr80.c
+++ b/dlls/msvcr80/tests/msvcr80.c
@@ -37,8 +37,48 @@
#define WX_TTY 0x40
#define WX_TEXT 0x80
+#define _MB_CP_SBCS 0
+
#define MSVCRT_FD_BLOCK_SIZE 32
+#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 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 = %Ix\n", arg);
+}
+
typedef struct
{
HANDLE handle;
@@ -57,6 +97,7 @@ typedef struct
static ioinfo **__pioinfo;
+static _invalid_parameter_handler (__cdecl
*p__set_invalid_parameter_handler)(_invalid_parameter_handler);
static int (WINAPIV *p__open)(const char *, int, ...);
static int (__cdecl *p__close)(int);
static intptr_t (__cdecl *p__get_osfhandle)(int);
@@ -65,6 +106,10 @@ static int (__cdecl *p_strncmp)(const char *, const char *, size_t);
static int (__cdecl *p_dupenv_s)(char **, size_t *, const char *);
static int (__cdecl *p_wdupenv_s)(wchar_t **, size_t *, const wchar_t *);
static int* (__cdecl *p_errno)(void);
+static errno_t (__cdecl *p__mbsncpy_s)(unsigned char*,size_t,const unsigned
char*,size_t);
+static int (__cdecl *p__ismbblead_l)(unsigned int,_locale_t);
+static int (__cdecl *p__getmbcp)(void);
+static int (__cdecl *p__setmbcp)(int);
/* make sure we use the correct errno */
#undef errno
@@ -83,6 +128,8 @@ static BOOL init(void)
return FALSE;
}
+ SET(p__set_invalid_parameter_handler, "_set_invalid_parameter_handler");
+
SET(__pioinfo, "__pioinfo");
SET(p__open,"_open");
SET(p__close,"_close");
@@ -93,7 +140,10 @@ static BOOL init(void)
SET(p_dupenv_s, "_dupenv_s");
SET(p_wdupenv_s, "_wdupenv_s");
SET(p_errno, "_errno");
-
+ SET(p__mbsncpy_s, "_mbsncpy_s");
+ SET(p__ismbblead_l, "_ismbblead_l");
+ SET(p__getmbcp, "_getmbcp");
+ SET(p__setmbcp, "_setmbcp");
return TRUE;
}
@@ -222,13 +272,208 @@ static void test_wdupenv_s(void)
ok( !tmp, "_wdupenv_s returned pointer is %p\n", tmp );
}
+static char *buf_to_string(const unsigned char *bin, int len, int nr)
+{
+ static char buf[2][1024];
+ char *w = buf[nr];
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ sprintf(w, "%02x ", (unsigned char)bin[i]);
+ w += strlen(w);
+ }
+ return buf[nr];
+}
+
+#define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret,
#expr " expected " format " got " format "\n", value, ret);
}
+#define expect_bin(buf, value, len) { ok(memcmp((buf), value, len) == 0, "Binary
buffer mismatch - expected %s, got %s\n", buf_to_string((unsigned char *)value, len,
1), buf_to_string((buf), len, 0)); }
+
+static void test__mbsncpy_s(void)
+{
+ unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5\x0";
+ unsigned char *mbstring2 = (unsigned char *)"\xb0\x0";
+ unsigned char buf[16];
+ errno_t err;
+ int oldcp;
+
+ oldcp = p__getmbcp();
+ if (p__setmbcp(936))
+ {
+ skip("Code page 936 is not available, skipping test.\n");
+ return;
+ }
+
+ errno = 0xdeadbeef;
+ memset(buf, 0xcc, sizeof(buf));
+ err = p__mbsncpy_s(NULL, 0, mbstring, 0);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+
+ errno = 0xdeadbeef;
+ memset(buf, 0xcc, sizeof(buf));
+ err = p__mbsncpy_s(buf, 6, mbstring, 1);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+ expect_bin(buf, "\xb0\xb1\0\xcc", 4);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 6, mbstring, 2);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+ expect_bin(buf, "\xb0\xb1\xb2\xb3\0\xcc", 6);
+
+ errno = 0xdeadbeef;
+ memset(buf, 0xcc, sizeof(buf));
+ err = p__mbsncpy_s(buf, 2, mbstring, _TRUNCATE);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(err == STRUNCATE, "got %d.\n", err);
+ expect_bin(buf, "\x00\xb1\xcc", 3);
+
+ memset(buf, 0xcc, sizeof(buf));
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 2, mbstring, 1);
+ ok(errno == err, "got %d.\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+ ok(err == ERANGE, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc\xcc", 3);
+
+ memset(buf, 0xcc, sizeof(buf));
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 2, mbstring, 3);
+ ok(errno == err, "got %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+ ok(err == ERANGE, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc\xcc", 3);
+
+ memset(buf, 0xcc, sizeof(buf));
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 1, mbstring, 3);
+ ok(errno == err, "got %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+ ok(err == ERANGE, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 0, mbstring, 3);
+ ok(errno == err, "got %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+ ok(err == EINVAL, "got %d.\n", err);
+ expect_bin(buf, "\xcc", 1);
+
+ memset(buf, 0xcc, sizeof(buf));
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 0, mbstring, 0);
+ ok(errno == err, "got %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+ ok(err == EINVAL, "got %d.\n", err);
+ expect_bin(buf, "\xcc", 1);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, -1, mbstring, 0);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, -1, mbstring, 256);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+ expect_bin(buf, "\xb0\xb1\xb2\xb3Q\xb4\xb5\x0\xcc", 9);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 1, mbstring2, 4);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 2, mbstring2, 4);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 1, mbstring2, _TRUNCATE);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(err == STRUNCATE, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 2, mbstring2, _TRUNCATE);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+ expect_bin(buf, "\xb0\x0\xcc", 3);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 1, mbstring2, 1);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 2, mbstring2, 1);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 3, mbstring2, 1);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = p__mbsncpy_s(buf, 3, mbstring2, 2);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ p__setmbcp(oldcp);
+}
+
START_TEST(msvcr80)
{
if(!init())
return;
+ ok(p__set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
+ "Invalid parameter handler was already set\n");
+
test_ioinfo_flags();
test_strcmp();
test_dupenv_s();
test_wdupenv_s();
+
+ winetest_push_context("_MB_CP_SBCS");
+ p__setmbcp(_MB_CP_SBCS);
+ test__mbsncpy_s();
+ winetest_pop_context();
+ if (!p__setmbcp(936))
+ {
+ winetest_push_context("CP 936");
+ test__mbsncpy_s();
+ winetest_pop_context();
+ }
+ else
+ {
+ skip("Code page 936 is not available.\n");
+ }
}
diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec
index ca22d7460be..c19f7298235 100644
--- a/dlls/msvcr90/msvcr90.spec
+++ b/dlls/msvcr90/msvcr90.spec
@@ -807,8 +807,8 @@
@ stub _mbsncoll_l
@ cdecl _mbsncpy(ptr str long)
@ cdecl _mbsncpy_l(ptr str long ptr)
-@ stub _mbsncpy_s
-@ stub _mbsncpy_s_l
+@ cdecl _mbsncpy_s(ptr long str long)
+@ cdecl _mbsncpy_s_l(ptr long str long ptr)
@ cdecl _mbsnextc(str)
@ cdecl _mbsnextc_l(str ptr)
@ cdecl _mbsnicmp(str str long)
diff --git a/dlls/msvcrt/mbcs.c b/dlls/msvcrt/mbcs.c
index ce8a3115eeb..0bac4c9f8d9 100644
--- a/dlls/msvcrt/mbcs.c
+++ b/dlls/msvcrt/mbcs.c
@@ -900,6 +900,83 @@ unsigned char* CDECL _mbsncpy_l(unsigned char* dst, const unsigned
char* src, si
return ret;
}
+#if _MSVCR_VER>=80
+errno_t CDECL _mbsncpy_s_l(unsigned char* dst, size_t maxsize, const unsigned char* src,
size_t n, _locale_t locale)
+{
+ BOOL truncate = (n == _TRUNCATE);
+ unsigned char *start = dst, *last;
+ pthreadmbcinfo mbcinfo;
+ unsigned int curlen;
+
+ if (!dst && !maxsize && !n)
+ return 0;
+
+ if (!MSVCRT_CHECK_PMT(dst != NULL)) return EINVAL;
+ if (!MSVCRT_CHECK_PMT(maxsize != 0)) return EINVAL;
+ if (!MSVCRT_CHECK_PMT(src != NULL))
+ {
+ *start = 0;
+ return EINVAL;
+ }
+
+ if (!n)
+ {
+ *start = 0;
+ return 0;
+ }
+
+ if (locale)
+ mbcinfo = locale->mbcinfo;
+ else
+ mbcinfo = get_mbcinfo();
+
+ curlen = 0;
+ last = dst;
+ while (*src && n && maxsize)
+ {
+ if (curlen)
+ {
+ --maxsize;
+ *dst++ = *src++;
+ if (!--curlen) --n;
+ continue;
+ }
+ last = dst;
+ if (!(mbcinfo->ismbcodepage && _ismbblead_l(*src, locale)))
+ {
+ curlen = 1;
+ continue;
+ }
+ curlen = 2;
+ if (!truncate && maxsize <= curlen) maxsize = 0;
+ }
+
+ if (!maxsize && truncate)
+ {
+ *last = 0;
+ return STRUNCATE;
+ }
+ if (!truncate && curlen && !src[curlen - 1])
+ {
+ *_errno() = EILSEQ;
+ *start = 0;
+ return EILSEQ;
+ }
+ if (!maxsize)
+ {
+ *start = 0;
+ if (!MSVCRT_CHECK_PMT_ERR(FALSE, ERANGE)) return ERANGE;
+ }
+ *dst = 0;
+ return 0;
+}
+
+errno_t CDECL _mbsncpy_s(unsigned char* dst, size_t maxsize, const unsigned char* src,
size_t n)
+{
+ return _mbsncpy_s_l(dst, maxsize, src, n, NULL);
+}
+#endif
+
/*********************************************************************
* _mbsncpy(MSVCRT.@)
* REMARKS
diff --git a/dlls/ucrtbase/tests/string.c b/dlls/ucrtbase/tests/string.c
index 6dcd15fb5b9..2c77a3356e1 100644
--- a/dlls/ucrtbase/tests/string.c
+++ b/dlls/ucrtbase/tests/string.c
@@ -651,6 +651,183 @@ static void test_strcmp(void)
ok( ret == 0, "wrong ret %d\n", ret );
}
+static char *buf_to_string(const unsigned char *bin, int len, int nr)
+{
+ static char buf[2][1024];
+ char *w = buf[nr];
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ sprintf(w, "%02x ", (unsigned char)bin[i]);
+ w += strlen(w);
+ }
+ return buf[nr];
+}
+
+#define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret,
#expr " expected " format " got " format "\n", value, ret);
}
+#define expect_bin(buf, value, len) { ok(memcmp((buf), value, len) == 0, "Binary
buffer mismatch - expected %s, got %s\n", buf_to_string((unsigned char *)value, len,
1), buf_to_string((buf), len, 0)); }
+
+static void test__mbsncpy_s(void)
+{
+ unsigned char *mbstring = (unsigned char *)"\xb0\xb1\xb2\xb3Q\xb4\xb5\x0";
+ unsigned char *mbstring2 = (unsigned char *)"\xb0\x0";
+ unsigned char buf[16];
+ errno_t err;
+ int oldcp;
+
+ oldcp = _getmbcp();
+ if (_setmbcp(936))
+ {
+ skip("Code page 936 is not available, skipping test.\n");
+ return;
+ }
+
+ errno = 0xdeadbeef;
+ memset(buf, 0xcc, sizeof(buf));
+ err = _mbsncpy_s(NULL, 0, mbstring, 0);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+
+ errno = 0xdeadbeef;
+ memset(buf, 0xcc, sizeof(buf));
+ err = _mbsncpy_s(buf, 6, mbstring, 1);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+ expect_bin(buf, "\xb0\xb1\0\xcc", 4);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 6, mbstring, 2);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+ expect_bin(buf, "\xb0\xb1\xb2\xb3\0\xcc", 6);
+
+ errno = 0xdeadbeef;
+ memset(buf, 0xcc, sizeof(buf));
+ err = _mbsncpy_s(buf, 2, mbstring, _TRUNCATE);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(err == STRUNCATE, "got %d.\n", err);
+ expect_bin(buf, "\x00\xb1\xcc", 3);
+
+ memset(buf, 0xcc, sizeof(buf));
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 2, mbstring, 1);
+ ok(errno == err, "got %d.\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+ ok(err == ERANGE, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc\xcc", 3);
+
+ memset(buf, 0xcc, sizeof(buf));
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 2, mbstring, 3);
+ ok(errno == err, "got %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+ ok(err == ERANGE, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc\xcc", 3);
+
+ memset(buf, 0xcc, sizeof(buf));
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 1, mbstring, 3);
+ ok(errno == err, "got %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+ ok(err == ERANGE, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 0, mbstring, 3);
+ ok(errno == err, "got %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+ ok(err == EINVAL, "got %d.\n", err);
+ expect_bin(buf, "\xcc", 1);
+
+ memset(buf, 0xcc, sizeof(buf));
+ SET_EXPECT(invalid_parameter_handler);
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 0, mbstring, 0);
+ ok(errno == err, "got %d\n", errno);
+ CHECK_CALLED(invalid_parameter_handler);
+ ok(err == EINVAL, "got %d.\n", err);
+ expect_bin(buf, "\xcc", 1);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, -1, mbstring, 0);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, -1, mbstring, 256);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+ expect_bin(buf, "\xb0\xb1\xb2\xb3Q\xb4\xb5\x0\xcc", 9);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 1, mbstring2, 4);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 2, mbstring2, 4);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 1, mbstring2, _TRUNCATE);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(err == STRUNCATE, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 2, mbstring2, _TRUNCATE);
+ ok(errno == 0xdeadbeef, "got %d\n", errno);
+ ok(!err, "got %d.\n", err);
+ expect_bin(buf, "\xb0\x0\xcc", 3);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 1, mbstring2, 1);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 2, mbstring2, 1);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 3, mbstring2, 1);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ memset(buf, 0xcc, sizeof(buf));
+ errno = 0xdeadbeef;
+ err = _mbsncpy_s(buf, 3, mbstring2, 2);
+ ok(errno == err, "got %d\n", errno);
+ ok(err == EILSEQ, "got %d.\n", err);
+ expect_bin(buf, "\x0\xcc", 2);
+
+ _setmbcp(oldcp);
+}
+
START_TEST(string)
{
ok(_set_invalid_parameter_handler(test_invalid_parameter_handler) == NULL,
@@ -669,4 +846,5 @@ START_TEST(string)
test_SpecialCasing();
test__mbbtype_l();
test_strcmp();
+ test__mbsncpy_s();
}
diff --git a/dlls/ucrtbase/ucrtbase.spec b/dlls/ucrtbase/ucrtbase.spec
index 449b734ad34..054fc4055f4 100644
--- a/dlls/ucrtbase/ucrtbase.spec
+++ b/dlls/ucrtbase/ucrtbase.spec
@@ -673,8 +673,8 @@
@ stub _mbsncoll_l
@ cdecl _mbsncpy(ptr str long)
@ cdecl _mbsncpy_l(ptr str long ptr)
-@ stub _mbsncpy_s
-@ stub _mbsncpy_s_l
+@ cdecl _mbsncpy_s(ptr long str long)
+@ cdecl _mbsncpy_s_l(ptr long str long ptr)
@ cdecl _mbsnextc(str)
@ cdecl _mbsnextc_l(str ptr)
@ cdecl _mbsnicmp(str str long)
@@ -1242,8 +1242,8 @@
@ stub _o__mbsncoll_l
@ cdecl _o__mbsncpy(ptr str long) _mbsncpy
@ cdecl _o__mbsncpy_l(ptr str long ptr) _mbsncpy_l
-@ stub _o__mbsncpy_s
-@ stub _o__mbsncpy_s_l
+@ cdecl _o__mbsncpy_s(ptr long str long) _mbsncpy_s
+@ cdecl _o__mbsncpy_s_l(ptr long str long ptr) _mbsncpy_s_l
@ cdecl _o__mbsnextc(str) _mbsnextc
@ cdecl _o__mbsnextc_l(str ptr) _mbsnextc_l
@ cdecl _o__mbsnicmp(str str long) _mbsnicmp
diff --git a/include/msvcrt/mbstring.h b/include/msvcrt/mbstring.h
index 28a0e41f10d..f51d8ed6bc3 100644
--- a/include/msvcrt/mbstring.h
+++ b/include/msvcrt/mbstring.h
@@ -93,6 +93,8 @@ _ACRTIMP size_t __cdecl _mbsnccnt(const unsigned char*,size_t);
_ACRTIMP int __cdecl _mbsncmp(const unsigned char*,const unsigned
char*,size_t);
_ACRTIMP int __cdecl _mbsncoll(const unsigned char*,const unsigned
char*,size_t);
_ACRTIMP unsigned char* __cdecl _mbsncpy(unsigned char*,const unsigned char*,size_t);
+_ACRTIMP errno_t __cdecl _mbsncpy_s(unsigned char*,size_t,const unsigned
char*,size_t);
+_ACRTIMP errno_t __cdecl _mbsncpy_s_l(unsigned char*,size_t,const unsigned
char*,size_t,_locale_t);
_ACRTIMP unsigned int __cdecl _mbsnextc(const unsigned char*);
_ACRTIMP unsigned int __cdecl _mbsnextc_l(const unsigned char*,_locale_t);
_ACRTIMP int __cdecl _mbsnicmp(const unsigned char*,const unsigned
char*,size_t);
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/5547