diff --git a/src/libinput-util.h b/src/libinput-util.h index c6d40efc..1f6994be 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -560,4 +560,67 @@ strv_free(char **strv) { free (strv); } +struct key_value_double { + double key; + double value; +}; + +static inline ssize_t +kv_double_from_string(const char *string, + const char *pair_separator, + const char *kv_separator, + struct key_value_double **result_out) + +{ + char **pairs; + char **pair; + struct key_value_double *result = NULL; + ssize_t npairs = 0; + unsigned int idx = 0; + + if (!pair_separator || pair_separator[0] == '\0' || + !kv_separator || kv_separator[0] == '\0') + return -1; + + pairs = strv_from_string(string, pair_separator); + if (!pairs) + return -1; + + for (pair = pairs; *pair; pair++) + npairs++; + + if (npairs == 0) + return -1; + + result = zalloc(npairs * sizeof *result); + + for (pair = pairs; *pair; pair++) { + char **kv = strv_from_string(*pair, kv_separator); + double k, v; + + if (!kv || !kv[0] || !kv[1] || kv[2] || + !safe_atod(kv[0], &k) || + !safe_atod(kv[1], &v)) { + strv_free(kv); + goto error; + } + + result[idx].key = k; + result[idx].value = v; + idx++; + + strv_free(kv); + } + + strv_free(pairs); + + *result_out = result; + + return npairs; + +error: + strv_free(pairs); + free(result); + return -1; +} #endif /* LIBINPUT_UTIL_H */ diff --git a/test/test-misc.c b/test/test-misc.c index c62cd03e..7222a84c 100644 --- a/test/test-misc.c +++ b/test/test-misc.c @@ -1292,6 +1292,58 @@ START_TEST(strsplit_test) } END_TEST +struct kvsplit_dbl_test { + const char *string; + const char *psep; + const char *kvsep; + ssize_t nresults; + struct { + double a; + double b; + } results[32]; +}; + +START_TEST(kvsplit_double_test) +{ + struct kvsplit_dbl_test tests[] = { + { "1:2;3:4;5:6", ";", ":", 3, { {1, 2}, {3, 4}, {5, 6}}}, + { "1.0x2.3 -3.2x4.5 8.090909x-6.00", " ", "x", 3, { {1.0, 2.3}, {-3.2, 4.5}, {8.090909, -6}}}, + + { "1:2", "x", ":", 1, {{1, 2}}}, + { "1:2", ":", "x", -1, {}}, + { "1:2", NULL, "x", -1, {}}, + { "1:2", "", "x", -1, {}}, + { "1:2", "x", NULL, -1, {}}, + { "1:2", "x", "", -1, {}}, + { "a:b", "x", ":", -1, {}}, + { "", " ", "x", -1, {}}, + { "1.2.3.4.5", ".", "", -1, {}}, + { NULL } + }; + struct kvsplit_dbl_test *t = tests; + + while (t->string) { + struct key_value_double *result = NULL; + ssize_t npairs; + + npairs = kv_double_from_string(t->string, + t->psep, + t->kvsep, + &result); + ck_assert_int_eq(npairs, t->nresults); + + for (ssize_t i = 0; i < npairs; i++) { + ck_assert_double_eq(t->results[i].a, result[i].key); + ck_assert_double_eq(t->results[i].b, result[i].value); + } + + + free(result); + t++; + } +} +END_TEST + static int open_restricted_leak(const char *path, int flags, void *data) { return *(int*)data; @@ -1528,6 +1580,7 @@ TEST_COLLECTION(misc) litest_add_no_device("misc:parser", safe_atoi_base_8_test); 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:time", time_conversion); litest_add_no_device("misc:fd", fd_no_event_leak);