siphash \
sparse_bsearch \
str \
+ stringbuilder \
stringmap \
strmap \
strset \
--- /dev/null
+../../licenses/CC0
\ No newline at end of file
--- /dev/null
+#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, "', '",
+ * argc, (const char**)argv);
+ * 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");
+ * 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@longlandclan.yi.org>
+ */
+int main(int argc, char *argv[])
+{
+ if (argc != 2)
+ return 1;
+
+ if (strcmp(argv[1], "depends") == 0) {
+ /*
+ * This triggers a circular dependency!
+ * printf("ccan/str\n");
+ */
+ return 0;
+ }
+
+ return 1;
+}
--- /dev/null
+/* CC0 (Public domain) - see LICENSE file for details */
+#include <ccan/stringbuilder/stringbuilder.h>
+#include <string.h>
+#include <errno.h>
+
+int stringbuilder_args(char* str, size_t str_sz, const char* delim, ...)
+{
+ int res;
+ va_list ap;
+ va_start(ap, delim);
+ res = stringbuilder_va(str, str_sz, delim, ap);
+ va_end(ap);
+ return res;
+}
+
+static int stringbuilder_cpy(
+ char** str, size_t* str_sz, const char* s, size_t s_len)
+{
+ if (!s)
+ return 0;
+
+ 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(char* str, size_t str_sz, const char* delim, 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);
+
+ res = stringbuilder_cpy(&str, &str_sz, s, 0);
+ s = va_arg(ap, const char*);
+ while(s && !res) {
+ res = stringbuilder_cpy(&str, &str_sz,
+ delim, delim_len);
+ if (!res) {
+ res = stringbuilder_cpy(&str, &str_sz,
+ s, 0);
+ s = va_arg(ap, const char*);
+ }
+ }
+ return res;
+}
+
+int stringbuilder_array(char* str, size_t str_sz, const char* delim,
+ size_t n_strings, const char** strings)
+{
+ int res = 0;
+ size_t delim_len = 0;
+
+ if (delim)
+ delim_len = strlen(delim);
+
+ res = stringbuilder_cpy(&str, &str_sz,
+ *(strings++), 0);
+ while(--n_strings && !res) {
+ res = stringbuilder_cpy(&str, &str_sz,
+ delim, delim_len);
+ if (!res)
+ res = stringbuilder_cpy(&str, &str_sz,
+ *(strings++), 0);
+ }
+ return res;
+
+}
--- /dev/null
+/* 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*. If the first argument is str,
+ * then the contents of str are preserved and appended to.
+ *
+ * @str: A pointer to a string buffer that will receive the result.
+ * @str_sz: Size of the buffer pointed to by str.
+ * @delim: A delimiter to separate the strings with, or NULL.
+ *
+ * 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");
+ * if (res)
+ * printf("Failed to determine file name: %s",
+ * strerror(res));
+ * else
+ * printf("File is at %s", file_name);
+ */
+#define stringbuilder(str, str_sz, delim, ...) \
+ stringbuilder_args(str, str_sz, delim, __VA_ARGS__, NULL)
+/**
+ * stringbuilder_args - 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.
+ *
+ * @str: A pointer to a string buffer that will receive the result.
+ * @str_sz: Size of the buffer pointed to by str.
+ * @delim: A delimiter to separate the strings with, or NULL.
+ *
+ * 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_args(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_args(char* str, size_t str_sz, const char* delim, ...);
+
+/**
+ * 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.
+ *
+ * @str: A pointer to a string buffer that will receive the result.
+ * @str_sz: Size of the buffer pointed to by str.
+ * @delim: A delimiter to separate the strings with, or NULL.
+ *
+ * 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(char* str, size_t str_sz,
+ * const char* delim, ...);
+ *
+ * int my_stringbuilder(char* str, size_t str_sz,
+ * const char* delim, ...)
+ * {
+ * int res;
+ * va_list ap;
+ * va_start(ap, delim);
+ * res = stringbuilder_va(str, str_sz, delim, 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(char* str, size_t str_sz, const char* delim, va_list ap);
+
+/**
+ * stringbuilder_array - Join strings from an array of const char* pointers.
+ *
+ * @str: A pointer to a string buffer that will receive the result.
+ * @str_sz: Size of the buffer pointed to by str.
+ * @delim: A delimiter to separate the strings with, or NULL.
+ * @n_strings: The number of strings to join.
+ * @strings: The array 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), ", ",
+ * argc, (const char**)argv);
+ * if (res)
+ * printf("Failed to list arguments: %s",
+ * strerror(res));
+ * else
+ * printf("My arguments were %s", my_args);
+ */
+int stringbuilder_array(char* str, size_t str_sz, const char* delim,
+ size_t n_strings, const char** strings);
+
+#endif /* CCAN_STRINGBUILDER_H */
--- /dev/null
+#include <ccan/stringbuilder/stringbuilder.h>
+#include <ccan/stringbuilder/stringbuilder.c>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+/*
+ * This triggers a circular dependency
+ * #include <ccan/str/str.h>
+ *
+ * We only want the following macro:
+ */
+#define streq(s1,s2) (!strcmp(s1,s2))
+
+#include <ccan/tap/tap.h>
+
+int main(int argc, char *argv[])
+{
+ char string[20];
+ const char* str_array[] = {
+ "xxx", "yyy"
+ };
+ int res;
+
+ res = stringbuilder(string, sizeof(string), NULL,
+ "aaa", "bbb");
+ printf("res: %s, string: %s\n",
+ strerror(res), string);
+ ok1(res == 0);
+ ok1(streq(string, "aaabbb"));
+
+ res = stringbuilder(string, sizeof(string), NULL,
+ "aaaaa", "bbbbb", "ccccc", "ddddd",
+ "eeeee", "fffff");
+ printf("res: %s, string: %s\n",
+ strerror(res), string);
+ ok1(res == EMSGSIZE);
+
+ res = stringbuilder(string, sizeof(string), ", ",
+ "aaa");
+ printf("res: %s, string: %s\n",
+ strerror(res), string);
+ ok1(res == 0);
+ ok1(streq(string, "aaa"));
+
+ res = stringbuilder(string, sizeof(string), ", ",
+ "aaa", "bbb");
+ printf("res: %s, string: %s\n",
+ strerror(res), string);
+ ok1(res == 0);
+ ok1(streq(string, "aaa, bbb"));
+
+ res = stringbuilder_array(string, sizeof(string), NULL,
+ sizeof(str_array)/sizeof(str_array[0]), str_array);
+ printf("res: %s, string: %s\n",
+ strerror(res), string);
+ ok1(res == 0);
+ ok1(streq(string, "xxxyyy"));
+
+ res = stringbuilder_array(string, sizeof(string), ", ",
+ sizeof(str_array)/sizeof(str_array[0]), str_array);
+ printf("res: %s, string: %s\n",
+ strerror(res), string);
+ ok1(res == 0);
+ ok1(streq(string, "xxx, yyy"));
+
+ return exit_status();
+}