mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-05-08 04:18:01 +02:00
util: add a helper function to split a string into substrings
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
(cherry picked from commit 33100fe88d)
This commit is contained in:
parent
ed4d674ca2
commit
5181be6cbc
3 changed files with 145 additions and 0 deletions
|
|
@ -285,3 +285,85 @@ parse_dimension_property(const char *prop, size_t *w, size_t *h)
|
||||||
*h = (size_t)y;
|
*h = (size_t)y;
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -456,4 +456,22 @@ safe_atod(const char *str, double *val)
|
||||||
return true;
|
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 */
|
#endif /* LIBINPUT_UTIL_H */
|
||||||
|
|
|
||||||
45
test/misc.c
45
test/misc.c
|
|
@ -910,6 +910,50 @@ START_TEST(safe_atod_test)
|
||||||
}
|
}
|
||||||
END_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)
|
static int open_restricted_leak(const char *path, int flags, void *data)
|
||||||
{
|
{
|
||||||
return *(int*)data;
|
return *(int*)data;
|
||||||
|
|
@ -1038,6 +1082,7 @@ litest_setup_tests_misc(void)
|
||||||
litest_add_no_device("misc:parser", trackpoint_accel_parser);
|
litest_add_no_device("misc:parser", trackpoint_accel_parser);
|
||||||
litest_add_no_device("misc:parser", dimension_prop_parser);
|
litest_add_no_device("misc:parser", dimension_prop_parser);
|
||||||
litest_add_no_device("misc:parser", safe_atod_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:time", time_conversion);
|
||||||
|
|
||||||
litest_add_no_device("misc:fd", fd_no_event_leak);
|
litest_add_no_device("misc:fd", fd_no_event_leak);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue