[ccan] [PATCH] stringbuilder: Functions for joining strings.
stuartl at longlandclan.yi.org
stuartl at longlandclan.yi.org
Sun Aug 17 21:16:05 EST 2014
From: Stuart Longland <stuartl at longlandclan.yi.org>
This is a small couple of functions for joining lists of strings
together. The lists can either be varadic arguments or arrays, and
delimiters are optional.
---
Makefile-ccan | 1 +
ccan/stringbuilder/LICENSE | 1 +
ccan/stringbuilder/_info | 55 ++++++++++++++++++
ccan/stringbuilder/stringbuilder.c | 71 ++++++++++++++++++++++++
ccan/stringbuilder/stringbuilder.h | 111 +++++++++++++++++++++++++++++++++++++
ccan/stringbuilder/test/run.c | 68 +++++++++++++++++++++++
6 files changed, 307 insertions(+)
create mode 120000 ccan/stringbuilder/LICENSE
create mode 100644 ccan/stringbuilder/_info
create mode 100644 ccan/stringbuilder/stringbuilder.c
create mode 100644 ccan/stringbuilder/stringbuilder.h
create mode 100644 ccan/stringbuilder/test/run.c
diff --git a/Makefile-ccan b/Makefile-ccan
index 40d0389..cc865ca 100644
--- a/Makefile-ccan
+++ b/Makefile-ccan
@@ -83,6 +83,7 @@ MODS_WITH_SRC := antithread \
siphash \
sparse_bsearch \
str \
+ stringbuilder \
stringmap \
strmap \
strset \
diff --git a/ccan/stringbuilder/LICENSE b/ccan/stringbuilder/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/stringbuilder/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0
\ No newline at end of file
diff --git a/ccan/stringbuilder/_info b/ccan/stringbuilder/_info
new file mode 100644
index 0000000..f2780e7
--- /dev/null
+++ b/ccan/stringbuilder/_info
@@ -0,0 +1,55 @@
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+
+/**
+ * stringbuilder - join lists of strings
+ *
+ * This is a small set of functions for building up strings from a list.
+ * The destination buffer is bounds-checked, the functions return failure
+ * if the concatenated strings overflow the buffer.
+ *
+ * Example:
+ * #include <stdio.h>
+ * #include <string.h>
+ * #include <errno.h>
+ * #include <ccan/stringbuilder/stringbuilder.h>
+ *
+ * int main(int argc, char *argv[])
+ * {
+ * char mystring[128];
+ * int res;
+ *
+ * res = stringbuilder_array("', '", mystring, 128,
+ * (const char**)argv, argc);
+ * if (!res)
+ * printf("My arguments: '%s'\n", mystring);
+ * else
+ * printf("Failed to join arguments: %s\n",
+ * strerror(res));
+ * if (!res) {
+ * res = stringbuilder(", ", mystring, 128,
+ * "This", "Is", "A", "Test", NULL);
+ * if (!res)
+ * printf("My string: '%s'\n", mystring);
+ * else
+ * printf("Failed to join strings: %s\n",
+ * strerror(res));
+ * }
+ * return 0;
+ * }
+ *
+ * License: CC0 (Public domain)
+ * Author: Stuart Longland <stuartl at longlandclan.yi.org>
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0) {
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/ccan/stringbuilder/stringbuilder.c b/ccan/stringbuilder/stringbuilder.c
new file mode 100644
index 0000000..cb2bc2d
--- /dev/null
+++ b/ccan/stringbuilder/stringbuilder.c
@@ -0,0 +1,71 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#include <ccan/stringbuilder/stringbuilder.h>
+#include <string.h>
+#include <errno.h>
+
+int stringbuilder(const char* delim, char* str, size_t str_sz, ...)
+{
+ int res;
+ va_list ap;
+ va_start(ap, str_sz);
+ res = stringbuilder_va(delim, str, str_sz, ap);
+ va_end(ap);
+ return res;
+}
+
+static inline int stringbuilder_cpy(
+ char** str, size_t* str_sz, const char* s, size_t s_len)
+{
+ if (*str != s) {
+ if (!s_len)
+ s_len = strlen(s);
+ if (s_len > *str_sz)
+ return EMSGSIZE;
+ strcpy(*str, s);
+ }
+ *str += s_len;
+ *str_sz -= s_len;
+ return 0;
+}
+
+int stringbuilder_va(const char* delim, char* str, size_t str_sz, va_list ap)
+{
+ int res = 0;
+ size_t delim_len = 0;
+ const char* s = va_arg(ap, const char*);
+
+ if (delim)
+ delim_len = strlen(delim);
+
+ if (s)
+ res = stringbuilder_cpy(&str, &str_sz, s, 0);
+ while(s && !res) {
+ s = va_arg(ap, const char*);
+ if (s && delim)
+ res = stringbuilder_cpy(&str, &str_sz,
+ delim, delim_len);
+ if (s && !res)
+ res = stringbuilder_cpy(&str, &str_sz,
+ s, 0);
+ }
+ return res;
+}
+
+int stringbuilder_array(const char* delim, char* str, size_t str_sz,
+ const char** strings, size_t strings_sz)
+{
+ int res = 0;
+ size_t delim_len = 0;
+
+ if (delim)
+ delim_len = strlen(delim);
+
+ while(strings_sz-- && !res) {
+ res = stringbuilder_cpy(&str, &str_sz, *(strings++), 0);
+ if (!res && delim)
+ res = stringbuilder_cpy(&str, &str_sz,
+ delim, delim_len);
+ }
+ return res;
+
+}
diff --git a/ccan/stringbuilder/stringbuilder.h b/ccan/stringbuilder/stringbuilder.h
new file mode 100644
index 0000000..0d02dcb
--- /dev/null
+++ b/ccan/stringbuilder/stringbuilder.h
@@ -0,0 +1,111 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_STRINGBUILDER_H
+#define CCAN_STRINGBUILDER_H
+#include "config.h"
+#include <stdarg.h>
+#include <sys/types.h>
+
+/**
+ * stringbuilder - Join strings from a varadic list. The list of arguments
+ * are all assumed to be of type const char* and must end with a NULL. If the
+ * first argument is str, then the contents of str are preserved and appended
+ * to.
+ *
+ * @delim: A delimiter to separate the strings with, or NULL.
+ * @str: A pointer to a string buffer that will receive the result.
+ * @str_sz: Size of the buffer pointed to by str.
+ *
+ * Returns: 0 on success
+ * EMSGSIZE if the resulting string would overflow the buffer.
+ * If an overflow condition is detected, the buffer content is
+ * NOT defined.
+ *
+ * Example:
+ * int res;
+ * char file_name[80];
+ * res = stringbuilder("/", file_name, sizeof(file_name),
+ * "/var/lib/foo", "bar", "baz",
+ * NULL);
+ * if (res)
+ * printf("Failed to determine file name: %s",
+ * strerror(res));
+ * else
+ * printf("File is at %s", file_name);
+ */
+int stringbuilder(const char* delim, char* str, size_t str_sz, ...);
+
+/**
+ * stringbuilder_va - Join strings from a varadic list. The list of arguments
+ * are all assumed to be of type const char* and must end with a NULL. If the
+ * first argument is str, then the contents of str are preserved and appended
+ * to.
+ *
+ * @delim: A delimiter to separate the strings with, or NULL.
+ * @str: A pointer to a string buffer that will receive the result.
+ * @str_sz: Size of the buffer pointed to by str.
+ *
+ * Returns: 0 on success
+ * EMSGSIZE if the resulting string would overflow the buffer.
+ * If an overflow condition is detected, the buffer content is
+ * NOT defined.
+ *
+ * Example:
+ * #include <ccan/stringbuilder/stringbuilder.h>
+ * #include <stdarg.h>
+ * #include <stdio.h>
+ * #include <string.h>
+ * #include <errno.h>
+ *
+ * int my_stringbuilder(const char* delim, char* str,
+ * size_t str_sz, ...);
+ *
+ * int my_stringbuilder(const char* delim, char* str,
+ * size_t str_sz, ...)
+ * {
+ * int res;
+ * va_list ap;
+ * va_start(ap, str_sz);
+ * res = stringbuilder_va(delim, str, str_sz, ap);
+ * va_end(ap);
+ * return res;
+ * }
+ *
+ * int main(void) {
+ * char my_string[80];
+ * int res = my_stringbuilder(" ", my_string,
+ * sizeof(my_string), "foo", "bar", NULL);
+ * if (!res)
+ * printf("%s\n", my_string);
+ * return res ? 1 : 0;
+ * }
+ */
+int stringbuilder_va(const char* delim, char* str, size_t str_sz, va_list ap);
+
+/**
+ * stringbuilder_array - Join strings from an array of const char* pointers.
+ *
+ * @delim: A delimiter to separate the strings with, or NULL.
+ * @str: A pointer to a string buffer that will receive the result.
+ * @str_sz: Size of the buffer pointed to by str.
+ * @strings: The array of strings to join.
+ * @strings_sz: The number of strings to join.
+ *
+ * Returns: 0 on success
+ * EMSGSIZE if the resulting string would overflow the buffer.
+ * If an overflow condition is detected, the buffer content is
+ * NOT defined.
+ *
+ * Example:
+ * char my_args[128];
+ * int res = stringbuilder_array(", ", my_args, sizeof(my_args),
+ * (const char**)argv, argc);
+ * if (res)
+ * printf("Failed to list arguments: %s",
+ * strerror(res));
+ * else
+ * printf("My arguments were %s", my_args);
+ */
+int stringbuilder_array(const char* delim, char* str, size_t str_sz,
+ const char** strings, size_t strings_sz);
+
+#endif /* CCAN_STRINGBUILDER_H */
diff --git a/ccan/stringbuilder/test/run.c b/ccan/stringbuilder/test/run.c
new file mode 100644
index 0000000..08d61a0
--- /dev/null
+++ b/ccan/stringbuilder/test/run.c
@@ -0,0 +1,68 @@
+#include <ccan/stringbuilder/stringbuilder.h>
+#include <ccan/stringbuilder/stringbuilder.c>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ccan/tap/tap.h>
+
+/*
+ * Even though stringbuilder is implemented using
+ * stringbuilder_va, we need to test it explicitly.
+ */
+int test_stringbuilder_va(const char* delim, char* str, size_t str_sz, ...);
+
+int test_stringbuilder_va(const char* delim, char* str, size_t str_sz, ...)
+{
+ int res;
+ va_list ap;
+ va_start(ap, str_sz);
+ res = stringbuilder_va(delim, str, str_sz, ap);
+ va_end(ap);
+ return res;
+}
+
+int main(int argc, char *argv[])
+{
+ char string[20];
+ const char* str_array[] = {
+ "xxx", "yyy"
+ };
+ int res;
+
+ res = test_stringbuilder_va(NULL, string, sizeof(string),
+ "aaa", "bbb", NULL);
+ printf("res: %s, string: %s\n",
+ strerror(res), string);
+ ok1(res == 0);
+ ok1(!strcmp(string, "aaabbb"));
+
+ res = stringbuilder(NULL, string, sizeof(string),
+ "aaa", "bbb", NULL);
+ printf("res: %s, string: %s\n",
+ strerror(res), string);
+ ok1(res == 0);
+ ok1(!strcmp(string, "aaabbb"));
+
+ res = stringbuilder(NULL, string, sizeof(string),
+ "aaaaa", "bbbbb", "ccccc", "ddddd",
+ "eeeee", "fffff", NULL);
+ printf("res: %s, string: %s\n",
+ strerror(res), string);
+ ok1(res == EMSGSIZE);
+
+ res = stringbuilder(", ", string, sizeof(string),
+ "aaa", "bbb", NULL);
+ printf("res: %s, string: %s\n",
+ strerror(res), string);
+ ok1(res == 0);
+ ok1(!strcmp(string, "aaa, bbb"));
+
+ res = stringbuilder_array(NULL, string, sizeof(string),
+ str_array, sizeof(str_array)/sizeof(str_array[0]));
+ printf("res: %s, string: %s\n",
+ strerror(res), string);
+ ok1(res == 0);
+ ok1(!strcmp(string, "xxxyyy"));
+
+ return exit_status();
+}
--
1.8.5.5
More information about the ccan
mailing list