return strv;
}
+
+/**
+ * Return a newly allocated string with all elements joined by the
+ * joiner, same as Python's string.join() basically.
+ * A strv of ["one", "two", "three", NULL] with a joiner of ", " results
+ * in "one, two, three".
+ *
+ * An empty strv ([NULL]) returns NULL, same for passing NULL as either
+ * argument.
+ *
+ * @param strv Input string arrray
+ * @param joiner Joiner between the elements in the final string
+ *
+ * @return A null-terminated string joining all elements
+ */
+char *
+strv_join(char **strv, const char *joiner)
+{
+ char **s;
+ char *str;
+ size_t slen = 0;
+ size_t count = 0;
+
+ if (!strv || !joiner)
+ return NULL;
+
+ s = strv;
+ for (s = strv, count = 0; *s; s++, count++) {
+ slen += strlen(*s);
+ }
+
+ slen += (count - 1) * strlen(joiner);
+
+ str = zalloc(slen + 1); /* trailing \0 */
+ for (s = strv; *s; s++) {
+ strcat(str, *s);
+ --count;
+ if (count > 0)
+ strcat(str, joiner);
+ }
+
+ return str;
+}
}
END_TEST
+struct strjoin_test {
+ char *strv[10];
+ const char *joiner;
+ const char *result;
+};
+
+START_TEST(strjoin_test)
+{
+ struct strjoin_test tests[] = {
+ { { "one", "two", "three", NULL }, " ", "one two three" },
+ { { "one", NULL }, "x", "one" },
+ { { "one", "two", NULL }, "x", "onextwo" },
+ { { "one", "two", NULL }, ",", "one,two" },
+ { { "one", "two", NULL }, ", ", "one, two" },
+ { { "one", "two", NULL }, "one", "oneonetwo" },
+ { { "one", "two", NULL }, NULL, NULL },
+ { { "", "", "", NULL }, " ", " " },
+ { { "a", "b", "c", NULL }, "", "abc" },
+ { { "", "b", "c", NULL }, "x", "xbxc" },
+ { { "", "", "", NULL }, "", "" },
+ { { NULL }, NULL, NULL }
+ };
+ struct strjoin_test *t = tests;
+
+ while (t->strv[0]) {
+ char *str;
+ str = strv_join(t->strv, t->joiner);
+ if (t->result == NULL)
+ ck_assert_ptr_null(str);
+ else
+ ck_assert_str_eq(str, t->result);
+ free(str);
+ t++;
+ }
+}
+END_TEST
+
static int open_restricted_leak(const char *path, int flags, void *data)
{
return *(int*)data;
litest_add_no_device("misc:parser", safe_atod_test);
litest_add_no_device("misc:parser", strsplit_test);
litest_add_no_device("misc:parser", kvsplit_double_test);
+ litest_add_no_device("misc:parser", strjoin_test);
litest_add_no_device("misc:time", time_conversion);
litest_add_no_device("misc:fd", fd_no_event_leak);