From: Paul Gofman pgofman@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);