From c58e1e7506862f8e75bc7f9ee099b00a615f5986 Mon Sep 17 00:00:00 2001 From: Marko Kreen Date: Thu, 8 Oct 2015 19:25:10 +0300 Subject: [PATCH] string: strpcpy, strpcat alternatives for strlcpy, strlcat --- m4/usual.m4 | 5 +- test/test_string.c | 116 +++++++++++++++++++++++++++++++++++++++++++++ usual/string.c | 28 +++++++++++ usual/string.h | 31 ++++++++++++ 4 files changed, 178 insertions(+), 2 deletions(-) diff --git a/m4/usual.m4 b/m4/usual.m4 index 59a82de..d82b2d3 100644 --- a/m4/usual.m4 +++ b/m4/usual.m4 @@ -210,8 +210,9 @@ dnl AC_DEFUN([AC_USUAL_FUNCTION_CHECK], [ ### Functions provided if missing dnl AC_CHECK_FUNCS(basename dirname) # unstable, provide always -AC_CHECK_FUNCS(strlcpy strlcat strsep memmem getpeereid sigaction sigqueue) -AC_CHECK_FUNCS(inet_ntop inet_pton poll getline memrchr regcomp) +AC_CHECK_FUNCS(strlcpy strlcat strsep getpeereid sigaction sigqueue) +AC_CHECK_FUNCS(memmem memrchr mempcpy) +AC_CHECK_FUNCS(inet_ntop inet_pton poll getline regcomp) AC_CHECK_FUNCS(err errx warn warnx getprogname setprogname) AC_CHECK_FUNCS(posix_memalign memalign valloc explicit_bzero memset_s reallocarray) AC_CHECK_FUNCS(getopt getopt_long getopt_long_only) diff --git a/test/test_string.c b/test/test_string.c index 6e3d7a3..9b09bae 100644 --- a/test/test_string.c +++ b/test/test_string.c @@ -142,6 +142,119 @@ static void test_memmem(void *p) end:; } +/* + * mempcpy + */ + +static void test_mempcpy(void *p) +{ + char buf[128]; + memset(buf, 0, sizeof buf); + tt_assert(mempcpy(buf, "xx", 0) == buf); str_check(buf, ""); + tt_assert(mempcpy(buf, "xx", 1) == buf+1); str_check(buf, "x"); + tt_assert(mempcpy(buf, "yy", 2) == buf+2); str_check(buf, "yy"); +end:; +} + +/* + * strpcpy + */ + +static int run_strpcpy(char *dst, const char *src, int size) +{ + char *res; + memcpy(dst, "XXX", 4); + res = strpcpy(dst, src, size); + if (res == NULL) { + if (size == 0) { + if (strcmp(dst, "XXX") != 0) + return -10; + } else { + if (memcmp(dst, src, size - 1) != 0) + return -11; + if (dst[size-1] != '\0') + return -12; + } + return -1; + } + if (*res != '\0') + return -13; + if (memcmp(dst, src, res-dst) != 0) + return -14; + if (res < dst) + return -15; + return res - dst; +} + +static void test_strpcpy(void *p) +{ + char buf[128]; + memset(buf, 0, sizeof buf); + int_check(run_strpcpy(buf, "", 0), -1); + int_check(run_strpcpy(buf, "", 1), 0); + int_check(run_strpcpy(buf, "a", 0), -1); + int_check(run_strpcpy(buf, "a", 1), -1); + int_check(run_strpcpy(buf, "a", 2), 1); + int_check(run_strpcpy(buf, "asd", 1), -1); + int_check(run_strpcpy(buf, "asd", 2), -1); + int_check(run_strpcpy(buf, "asd", 3), -1); + int_check(run_strpcpy(buf, "asd", 4), 3); + int_check(run_strpcpy(buf, "asd", 5), 3); +end:; +} + +/* + * strpcat + */ + +static int run_strpcat(char *dst, const char *src, int size) +{ + char *res; + char copydst[1024]; + char copy[1024]; + strlcpy(copydst, dst, sizeof copy); + strlcpy(copy, dst, sizeof copy); + strlcat(copy, src, sizeof copy); + res = strpcat(dst, src, size); + if (res == NULL) { + if (size == 0) { + if (strcmp(dst, copydst) != 0) + return -10; + } else { + if (memcmp(dst, copy, size - 1) != 0) + return -11; + if (dst[size-1] != '\0') + return -12; + } + return -1; + } + if (*res != '\0') + return -13; + if (memcmp(dst, copy, res-dst) != 0) + return -14; + if (res < dst) + return -15; + return res - dst; +} + +static void test_strpcat(void *p) +{ + char buf[128]; + memset(buf, 0, sizeof buf); + int_check(run_strpcat(buf, "", 0), -1); + int_check(run_strpcat(buf, "", 1), 0); + int_check(run_strpcat(buf, "a", 1), -1); + int_check(run_strpcat(buf, "a", 2), 1); + str_check(buf, "a"); + + int_check(run_strpcat(buf, "b", 0), -1); + int_check(run_strpcat(buf, "b", 1), -12); + int_check(run_strpcat(buf, "b", 2), -1); + int_check(run_strpcat(buf, "b", 3), 2); + str_check(buf, "ab"); +end:; +} + /* * basename */ @@ -500,7 +613,10 @@ struct testcase_t string_tests[] = { { "mempbrk", test_mempbrk }, { "memcspn", test_memcspn }, { "memspn", test_memspn}, + { "mempcpy", test_mempcpy }, { "strsep", test_strsep }, + { "strpcpy", test_strpcpy }, + { "strpcat", test_strpcat }, { "basename", test_basename }, { "dirname", test_dirname }, { "strlist", test_strlist }, diff --git a/usual/string.c b/usual/string.c index 553e591..f360a25 100644 --- a/usual/string.c +++ b/usual/string.c @@ -216,6 +216,34 @@ size_t strlcat(char *dst, const char *src, size_t n) } #endif +char *strpcpy(char *dst, const char *src, size_t n) +{ + if (n == 0) + return NULL; + for (; n > 0; n--, dst++, src++) { + if ((*dst = *src) == '\0') + return dst; + } + dst[-1] = '\0'; + return NULL; +} + +char *strpcat(char *dst, const char *src, size_t n) +{ + size_t dstlen = strnlen(dst, n); + if (dstlen < n) + return strpcpy(dst + dstlen, src, n - dstlen); + return NULL; +} + +#ifndef HAVE_MEMPCPY +void *mempcpy(void *dst, const void *src, size_t n) +{ + memcpy(dst, src, n); + return (char *)(dst) + n; +} +#endif + #ifndef HAVE_MEMRCHR void *memrchr(const void *s, int c, size_t n) { diff --git a/usual/string.h b/usual/string.h index d440abb..8bf939c 100644 --- a/usual/string.h +++ b/usual/string.h @@ -66,6 +66,31 @@ size_t strlcpy(char *dst, const char *src, size_t n); size_t strlcat(char *dst, const char *src, size_t n); #endif +#undef strpcpy +#define strpcpy(a,b,c) usual_strpcpy(a,b,c) + +/** + * Safe string copy. + * + * Returns pointer to end of string in dst or NULL + * if truncation occured. Destination will be + * zero-terminated unless dstlen is 0. + */ +char *strpcpy(char *dst, const char *src, size_t dstlen); + +#undef strpcat +#define strpcat(a,b,c) usual_strpcat(a,b,c) + +/** + * Safe string concat. + * + * Returns pointer to end of string in dst or NULL if truncation occured. + * Destination will be zero-terminated, unless dstlen is 0 or existing + * contents were not zero-terminated. + */ +char *strpcat(char *dst, const char *src, size_t dstlen); + + #ifndef HAVE_MEMRCHR #define memrchr(a,b,c) usual_memrchr(a,b,c) /** Compat: find byte in reverse direction */ @@ -78,6 +103,12 @@ void *memrchr(const void *s, int c, size_t n); void *memmem(const void *s, size_t slen, const void *q, size_t qlen); #endif +#ifndef HAVE_MEMPCPY +#define mempcpy(a,b,c) usual_mempcpy(a,b,c) +/** Copy memory, return pointer to end. */ +void *mempcpy(void *dst, const void *src, size_t len); +#endif + /** Return position to first byte that is in 'find'. */ void *mempbrk(const void *data, size_t dlen, const void *find, size_t flen);