Module: wine Branch: master Commit: 9582f5c719ab426b13c1913cf9708d032e99525e URL: http://source.winehq.org/git/wine.git/?a=commit;h=9582f5c719ab426b13c1913cf9...
Author: Stefan Dösinger stefan@codeweavers.com Date: Fri Nov 16 11:36:03 2007 +0100
msvcrt: Implement strcat_s.
---
dlls/msvcrt/msvcrt.spec | 1 + dlls/msvcrt/string.c | 29 +++++++++++++++++++ dlls/msvcrt/tests/string.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 0 deletions(-)
diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index 63ed4aa..567f193 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -711,6 +711,7 @@ @ cdecl srand(long) MSVCRT_srand @ varargs sscanf(str str) MSVCRT_sscanf @ cdecl strcat(str str) ntdll.strcat +@ cdecl strcat_s(str long str) MSVCRT_strcat_s @ cdecl strchr(str long) ntdll.strchr @ cdecl strcmp(str str) ntdll.strcmp @ cdecl strcoll(str str) MSVCRT_strcoll diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c index e46ff49..660b94d 100644 --- a/dlls/msvcrt/string.c +++ b/dlls/msvcrt/string.c @@ -176,6 +176,35 @@ int CDECL MSVCRT_strcpy_s( char* dst, MSVCRT_size_t elem, const char* src ) }
/********************************************************************* + * strcat_s (MSVCRT.@) + */ +int CDECL MSVCRT_strcat_s( char* dst, MSVCRT_size_t elem, const char* src ) +{ + MSVCRT_size_t i, j; + if(!dst) return EINVAL; + if(elem == 0) return EINVAL; + if(!src) + { + dst[0] = '\0'; + return EINVAL; + } + + for(i = 0; i < elem; i++) + { + if(dst[i] == '\0') + { + for(j = 0; (j + i) < elem; j++) + { + if((dst[j + i] = src[j]) == '\0') return 0; + } + } + } + /* Set the first element to 0, not the first element after the skipped part */ + dst[0] = '\0'; + return ERANGE; +} + +/********************************************************************* * strxfrm (MSVCRT.@) */ MSVCRT_size_t CDECL MSVCRT_strxfrm( char *dest, const char *src, MSVCRT_size_t len ) diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c index 25d41c1..9e96605 100644 --- a/dlls/msvcrt/tests/string.c +++ b/dlls/msvcrt/tests/string.c @@ -48,6 +48,7 @@ static char *buf_to_string(const unsigned char *bin, int len, int nr) static void* (*pmemcpy)(void *, const void *, size_t n); static int* (*pmemcmp)(void *, const void *, size_t n); static int (*pstrcpy_s)(char *dst, size_t len, const char *src); +static int (*pstrcat_s)(char *dst, size_t len, const char *src);
#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) @@ -450,6 +451,69 @@ static void test_strcpy_s(void) ok(ret == EINVAL, "Copying a big string a NULL dest returned %d, expected EINVAL\n", ret); }
+static void test_strcat_s(void) +{ + char dest[8]; + const char *small = "sma"; + int ret; + + if(!pstrcat_s) + { + skip("strcat_s not found\n"); + return; + } + + memset(dest, 'X', sizeof(dest)); + dest[0] = '\0'; + ret = pstrcat_s(dest, sizeof(dest), small); + ok(ret == 0, "strcat_s: Copying a string into a big enough destination returned %d, expected 0\n", ret); + ok(dest[0] == 's' && dest[1] == 'm' && dest[2] == 'a' && dest[3] == '\0'&& + dest[4] == 'X' && dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + ret = pstrcat_s(dest, sizeof(dest), small); + ok(ret == 0, "strcat_s: Attaching a string to a big enough destination returned %d, expected 0\n", ret); + ok(dest[0] == 's' && dest[1] == 'm' && dest[2] == 'a' && dest[3] == 's' && + dest[4] == 'm' && dest[5] == 'a' && dest[6] == '\0'&& dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + ret = pstrcat_s(dest, sizeof(dest), small); + ok(ret == ERANGE, "strcat_s: Attaching a string to a filled up destination returned %d, expected ERANGE\n", ret); + ok(dest[0] == '\0'&& dest[1] == 'm' && dest[2] == 'a' && dest[3] == 's' && + dest[4] == 'm' && dest[5] == 'a' && dest[6] == 's' && dest[7] == 'm', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + memset(dest, 'X', sizeof(dest)); + dest[0] = 'a'; + dest[1] = '\0'; + + ret = pstrcat_s(dest, 0, small); + ok(ret == EINVAL, "strcat_s: Source len = 0 returned %d, expected EINVAL\n", ret); + ok(dest[0] == 'a' && dest[1] == '\0'&& dest[2] == 'X' && dest[3] == 'X' && + dest[4] == 'X' && dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + ret = pstrcat_s(dest, 0, NULL); + ok(ret == EINVAL, "strcat_s: len = 0 and src = NULL returned %d, expected EINVAL\n", ret); + ok(dest[0] == 'a' && dest[1] == '\0'&& dest[2] == 'X' && dest[3] == 'X' && + dest[4] == 'X' && dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + ret = pstrcat_s(dest, sizeof(dest), NULL); + ok(ret == EINVAL, "strcat_s: Sourcing from NULL returned %d, expected EINVAL\n", ret); + ok(dest[0] == '\0'&& dest[1] == '\0'&& dest[2] == 'X' && dest[3] == 'X' && + dest[4] == 'X' && dest[5] == 'X' && dest[6] == 'X' && dest[7] == 'X', + "Unexpected return data from strcpy_s: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + + ret = pstrcat_s(NULL, sizeof(dest), small); + ok(ret == EINVAL, "strcat_s: Writing to a NULL string returned %d, expected EINVAL\n", ret); +} + START_TEST(string) { char mem[100]; @@ -463,6 +527,7 @@ START_TEST(string) SET(pmemcpy,"memcpy"); SET(pmemcmp,"memcmp"); SET(pstrcpy_s,"strcpy_s"); + SET(pstrcat_s,"strcat_s");
/* MSVCRT memcpy behaves like memmove for overlapping moves, MFC42 CString::Insert seems to rely on that behaviour */ @@ -483,4 +548,5 @@ START_TEST(string) /* test _strdup */ test_strdup(); test_strcpy_s(); + test_strcat_s(); }