From cf7cd05c56a59636765278734629ef3e1b4f8460 Mon Sep 17 00:00:00 2001 From: Urban Wallasch Date: Wed, 30 Oct 2019 19:52:31 +0100 Subject: [PATCH] * str: added str_[n]dup and str_[n]app --- str/str.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++ str/str_test.c | 50 +++++++++++++++++++++++- 2 files changed, 153 insertions(+), 1 deletion(-) diff --git a/str/str.h b/str/str.h index a9ad4fa..adb2cc8 100644 --- a/str/str.h +++ b/str/str.h @@ -52,6 +52,12 @@ * * str_ncpy - copy initial part of a string (a better strncpy) * + * str_dup, + * str_ndup - duplicate (part of) a string + * + * str_app, + * str_napp - append (part of) a string to another + * */ #ifndef STR_H_ @@ -64,6 +70,7 @@ extern "C" { #include #include #include +#include /* @@ -432,6 +439,103 @@ static inline char *str_ncpy(char *dest, const char *src, size_t n) { } +/* + * str_dup, str_ndup - duplicate (part of) a string + * + * The str_dup() function returns a pointer to a new string which is a + * duplicate of the string s. Memory for the new string is obtained with + * malloc(), and can be freed with free(). + * + * The str_ndup() function is similar, but copies at most n bytes. If s + * is longer than n, only n bytes are copied, and a terminating null byte + * ('\0') is added. For str_ndup() s2 does not need to be null- + * terminated, if it contains n or more bytes. + * + * On success, the str_dup() and str_ndup() functions return a pointer to + * the duplicated string. NULL is returned if insufficient memory was + * available, with errno set to indicate the cause of the error. + */ +static inline char *str_dup(const char *s) { + char *d; + size_t n; + + n = strlen(s) + 1; + d = malloc(n); + if (d) { + memcpy(d, s, n); + } + return d; +} + +static inline char *str_ndup(const char *s, size_t n) { + char *d; + + n = str_nlen(s, n); + d = malloc(n + 1); + if (d) { + memcpy(d, s, n); + d[n] = '\0'; + } + return d; +} + + +/* + * str_app, str_napp - append one string to another + * + * The str_app() function appends the string s2 to the string *s1. It + * first resizes the buffer pointed to by *s1 using realloc() to fit the + * resulting null terminated combined string. Then the string s2 is + * appended to the end of *s1. The pointer pointed to by s1 shall either + * equal NULL or else must have been returned by a previous call to + * malloc(), calloc(), or realloc(). + * + * The str_napp() function is similar, but copies at most n bytes of s2. + * If s2 is longer than n, only n bytes are copied, and a terminating + * null byte ('\0') is added. For str_napp() s2 does not need to be + * null-terminated, if it contains n or more bytes. + * + * On success str_app() and str_napp() return the memory location + * returned by realloc() and the pointer in *s1 is updated to refer to + * the same location. If insufficient memory was available, NULL is + * returned with errno set to indicate the cause of the error, and the + * original pointer in *s1 remains unchanged. + * + * CAVEAT: + * If any attempt is made to dereference a pointer to the location *s1 + * originally pointed to after a successful invocation of str_append(), + * the behavior is undefined. + */ +static inline char *str_app(char **s1, const char *s2) { + char *d; + size_t l1, l2; + + l1 = *s1 ? strlen(*s1) : 0; + l2 = strlen(s2) + 1; + d = realloc(*s1, l1 + l2); + if (d) { + memcpy(d + l1, s2, l2); + *s1 = d; + } + return d; +} + +static inline char *str_napp(char **s1, const char *s2, size_t n) { + char *d; + size_t l1; + + l1 = *s1 ? strlen(*s1) : 0; + n = str_nlen(s2, n); + d = realloc(*s1, l1 + n + 1); + if (d) { + memcpy(d + l1, s2, n); + d[l1 + n] = '\0'; + *s1 = d; + } + return d; +} + + #ifdef cplusplus } #endif diff --git a/str/str_test.c b/str/str_test.c index 81117bb..9414f95 100644 --- a/str/str_test.c +++ b/str/str_test.c @@ -12,7 +12,6 @@ #include #include -#include #include #include "str.h" @@ -397,6 +396,55 @@ int main(void) { /*****************************************/ + { + H("str_dup, str_ndup"); + char *p, *q, s[] = "fizzbuzz\0..x"; + D(s); + T((p=str_dup(s)) != NULL); + T((q=str_dup(s)) != NULL); + T(p!=s); + T(p!=q); + T(strcmp(p,s) == 0); + T(strcmp(p,q) == 0); + free(p); + free(q); + char t[] = { 'f', 'o', 'o', 'x' }; /* unterminated! */ + D(t); + T((p=str_ndup(t, 3)) != NULL); + T((q=str_ndup(t, 4)) != NULL); + T(p!=s); + T(p!=q); + T(strcmp(p, "foo") == 0); + T(strcmp(q, "foox") == 0); + free(p); + free(q); + } + + /*****************************************/ + + { + H("str_app, str_napp"); + char *p, *s, s_[] = "pfx "; + D(s_); + T((s = str_dup(s_)) != NULL); + T((p=str_app(&s, " 01")) != NULL); + T((p=str_app(&s, " 02")) != NULL); + T(strcmp(s, "pfx 01 02") == 0); + free(s); + char t[] = { 'f', 'o', 'o', 'x' }; /* unterminated! */ + char u[] = "uhu "; + D(t); + D(u); + T((s = str_dup(s_)) != NULL); + T((p=str_napp(&s, t, 2)) != NULL); + T((p=str_napp(&s, u, 42)) != NULL); + T((p=str_napp(&s, t, 4)) != NULL); + T(strcmp(s, "pfx fouhu foox") == 0); + free(s); + } + + /*****************************************/ + H("All tests passed."); return 0; } -- 2.30.2