[PATCH libinput 6/7] util: add a helper function to split a string into substrings
Peter Hutterer
peter.hutterer at who-t.net
Mon Nov 28 05:20:49 UTC 2016
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
src/libinput-util.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/libinput-util.h | 18 ++++++++++++
test/misc.c | 45 +++++++++++++++++++++++++++++
3 files changed, 145 insertions(+)
diff --git a/src/libinput-util.c b/src/libinput-util.c
index 4cf310b..a0b423b 100644
--- a/src/libinput-util.c
+++ b/src/libinput-util.c
@@ -285,3 +285,85 @@ parse_dimension_property(const char *prop, size_t *w, size_t *h)
*h = (size_t)y;
return true;
}
+
+/**
+ * Return the next word in a string pointed to by state before the first
+ * separator character. Call repeatedly to tokenize a whole string.
+ *
+ * @param state Current state
+ * @param len String length of the word returned
+ * @param separators List of separator characters
+ *
+ * @return The first word in *state, NOT null-terminated
+ */
+static const char *
+next_word(const char **state, size_t *len, const char *separators)
+{
+ const char *next = *state;
+ size_t l;
+
+ if (!*next)
+ return NULL;
+
+ next += strspn(next, separators);
+ if (!*next) {
+ *state = next;
+ return NULL;
+ }
+
+ l = strcspn(next, separators);
+ *state = next + l;
+ *len = l;
+
+ return next;
+}
+
+/**
+ * Return a null-terminated string array with the tokens in the input
+ * string, e.g. "one two\tthree" with a separator list of " \t" will return
+ * an array [ "one", "two", "three", NULL ].
+ *
+ * Use strv_free() to free the array.
+ *
+ * @param in Input string
+ * @param separators List of separator characters
+ *
+ * @return A null-terminated string array or NULL on errors
+ */
+char **
+strv_from_string(const char *in, const char *separators)
+{
+ const char *s, *word;
+ char **strv = NULL;
+ int nelems = 0, idx;
+ size_t l;
+
+ assert(in != NULL);
+
+ s = in;
+ while ((word = next_word(&s, &l, separators)) != NULL)
+ nelems++;
+
+ if (nelems == 0)
+ return NULL;
+
+ nelems++; /* NULL-terminated */
+ strv = zalloc(nelems * sizeof *strv);
+ if (!strv)
+ return NULL;
+
+ idx = 0;
+
+ s = in;
+ while ((word = next_word(&s, &l, separators)) != NULL) {
+ char *copy = strndup(word, l);
+ if (!copy) {
+ strv_free(strv);
+ return NULL;
+ }
+
+ strv[idx++] = copy;
+ }
+
+ return strv;
+}
diff --git a/src/libinput-util.h b/src/libinput-util.h
index 9b10e7d..3fd3747 100644
--- a/src/libinput-util.h
+++ b/src/libinput-util.h
@@ -456,4 +456,22 @@ safe_atod(const char *str, double *val)
return true;
}
+char **strv_from_string(const char *string, const char *separator);
+
+static inline void
+strv_free(char **strv) {
+ char **s = strv;
+
+ if (!strv)
+ return;
+
+ while (*s != NULL) {
+ free(*s);
+ *s = (char*)0x1; /* detect use-after-free */
+ s++;
+ }
+
+ free (strv);
+}
+
#endif /* LIBINPUT_UTIL_H */
diff --git a/test/misc.c b/test/misc.c
index b514f90..eadeae3 100644
--- a/test/misc.c
+++ b/test/misc.c
@@ -951,6 +951,50 @@ START_TEST(safe_atod_test)
}
END_TEST
+struct strsplit_test {
+ const char *string;
+ const char *delim;
+ const char *results[10];
+};
+
+START_TEST(strsplit_test)
+{
+ struct strsplit_test tests[] = {
+ { "one two three", " ", { "one", "two", "three", NULL } },
+ { "one", " ", { "one", NULL } },
+ { "one two ", " ", { "one", "two", NULL } },
+ { "one two", " ", { "one", "two", NULL } },
+ { " one two", " ", { "one", "two", NULL } },
+ { "one", "\t \r", { "one", NULL } },
+ { "one two three", " t", { "one", "wo", "hree", NULL } },
+ { " one two three", "te", { " on", " ", "wo ", "hr", NULL } },
+ { "one", "ne", { "o", NULL } },
+ { "onene", "ne", { "o", NULL } },
+ { NULL, NULL, { NULL }}
+ };
+ struct strsplit_test *t = tests;
+
+ while (t->string) {
+ char **strv;
+ int idx = 0;
+ strv = strv_from_string(t->string, t->delim);
+ while (t->results[idx]) {
+ ck_assert_str_eq(t->results[idx], strv[idx]);
+ idx++;
+ }
+ ck_assert_ptr_eq(strv[idx], NULL);
+ strv_free(strv);
+ t++;
+ }
+
+ /* Special cases */
+ ck_assert_ptr_eq(strv_from_string("", " "), NULL);
+ ck_assert_ptr_eq(strv_from_string(" ", " "), NULL);
+ ck_assert_ptr_eq(strv_from_string(" ", " "), NULL);
+ ck_assert_ptr_eq(strv_from_string("oneoneone", "one"), NULL);
+}
+END_TEST
+
static int open_restricted_leak(const char *path, int flags, void *data)
{
return *(int*)data;
@@ -1080,6 +1124,7 @@ litest_setup_tests_misc(void)
litest_add_no_device("misc:parser", dimension_prop_parser);
litest_add_no_device("misc:parser", safe_atoi_test);
litest_add_no_device("misc:parser", safe_atod_test);
+ litest_add_no_device("misc:parser", strsplit_test);
litest_add_no_device("misc:time", time_conversion);
litest_add_no_device("misc:fd", fd_no_event_leak);
--
2.9.3
More information about the wayland-devel
mailing list