util: add a strv_join() helper function
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 2 May 2018 00:25:47 +0000 (10:25 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Thu, 3 May 2018 02:31:30 +0000 (12:31 +1000)
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
src/libinput-util.c
src/libinput-util.h
test/test-misc.c

index e774fb78e2cb4d88258780de6dbd518ebf31368e..bd5f1e174ce844f6d915e39abea7cd8d04da98fe 100644 (file)
@@ -535,3 +535,46 @@ strv_from_string(const char *in, const char *separators)
 
        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;
+}
index 1f6994bec05ae9b2179f030bbf612e90d8d8ae38..50d36e7d53df955990e41006c999fe9140aaa88d 100644 (file)
@@ -543,6 +543,7 @@ safe_atod(const char *str, double *val)
 }
 
 char **strv_from_string(const char *string, const char *separator);
+char *strv_join(char **strv, const char *separator);
 
 static inline void
 strv_free(char **strv) {
index 9cd96d8cde0a1433cf504c867ad8720dd0edc8ef..f685f4d87462f84742f26a8bcdfde538142400ec 100644 (file)
@@ -1343,6 +1343,43 @@ START_TEST(kvsplit_double_test)
 }
 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;
@@ -1580,6 +1617,7 @@ TEST_COLLECTION(misc)
        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);