* str: added str_[n]dup and str_[n]app
authorUrban Wallasch <urban.wallasch@freenet.de>
Wed, 30 Oct 2019 18:52:31 +0000 (19:52 +0100)
committerUrban Wallasch <urban.wallasch@freenet.de>
Wed, 30 Oct 2019 18:52:31 +0000 (19:52 +0100)
str/str.h
str/str_test.c

index a9ad4fa9eeed55bd89975258ecc4542499732a5d..adb2cc8b0f1c8b51ff153a38882a0a09ff1bbb47 100644 (file)
--- a/str/str.h
+++ b/str/str.h
  *
  * 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 <string.h>
 #include <ctype.h>
 #include <stdbool.h>
+#include <stdlib.h>
 
 
 /*
@@ -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
index 81117bb51986d2102081ed31820b0f896db325b1..9414f957879d7f1ed25dd65629074ed85ea8b067 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <assert.h>
 #include <inttypes.h>
-#include <stdbool.h>
 #include <stdio.h>
 
 #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;
 }