From: Peter Hutterer Date: Tue, 3 Sep 2024 04:31:02 +0000 (+1000) Subject: util: add a strv_for_each helper function X-Git-Tag: 1.27.0~153 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ea7ad8d25c3dd5547a0b4877445c1fcdef018441;p=platform%2Fupstream%2Flibinput.git util: add a strv_for_each helper function Part-of: --- diff --git a/src/util-strings.c b/src/util-strings.c index 1f9b8a74..8732cc5e 100644 --- a/src/util-strings.c +++ b/src/util-strings.c @@ -24,6 +24,8 @@ #include "config.h" +#include + #include "util-strings.h" /** @@ -199,6 +201,38 @@ strv_join(char **strv, const char *joiner) return str; } +/** + * Iterate through strv, calling func with each string and its respective index. + * Iteration stops successfully after max elements or at the last element, + * whichever occurs first. + * + * If func returns non-zero, iteration stops and strv_for_each returns + * that value. + * + * @return zero on success, otherwise the error returned by the callback + */ +int strv_for_each_n(const char **strv, size_t max, strv_foreach_callback_t func, void *data) +{ + for (size_t i = 0; i < max && strv && strv[i]; i++) { + int ret = func(strv[i], i, data); + if (ret) + return ret; + } + return 0; +} + +/** + * Iterate through strv, calling func with each string and its respective index. + * If func returns non-zero, iteration stops and strv_for_each returns + * that value. + * + * @return zero on success, otherwise the error returned by the callback + */ +int strv_for_each(const char **strv, strv_foreach_callback_t func, void *data) +{ + return strv_for_each_n(strv, SIZE_MAX, func, data); +} + /** * Return a pointer to the basename within filename. * If the filename the empty string or a directory (i.e. the last char of diff --git a/src/util-strings.h b/src/util-strings.h index b0916815..85e9081d 100644 --- a/src/util-strings.h +++ b/src/util-strings.h @@ -266,6 +266,10 @@ char **strv_from_argv(int argc, char **argv); char **strv_from_string(const char *in, const char *separator, size_t *num_elements); char *strv_join(char **strv, const char *joiner); +typedef int (*strv_foreach_callback_t)(const char *str, size_t index, void *data); +int strv_for_each(const char **strv, strv_foreach_callback_t func, void *data); +int strv_for_each_n(const char **strv, size_t max, strv_foreach_callback_t func, void *data); + static inline void strv_free(char **strv) { char **s = strv; diff --git a/test/test-utils.c b/test/test-utils.c index 8ac0bd66..ee9cc606 100644 --- a/test/test-utils.c +++ b/test/test-utils.c @@ -1120,6 +1120,69 @@ START_TEST(strsplit_test) } END_TEST +struct strv_test_data { + const char *terminate_at; + unsigned char bitmask[1]; +}; + +static int strv_test_set_bitmask(const char *str, size_t index, void *data) +{ + struct strv_test_data *td = data; + + if (streq(str, td->terminate_at)) + return index + 1; + + set_bit(td->bitmask, index); + + return 0; +} + +START_TEST(strv_for_each_test) +{ + struct test_data { + const char *terminator; + int index; + unsigned int bitmask; + } test_data[] = { + { "one", 1, 0x0 }, + { "two", 2, 0x1 }, + { "three", 3, 0x3 }, + { "four", 4, 0x7 }, + { "five", 5, 0xf }, + { "does-not-exist", 0, 0x1f }, + { NULL, 0, 0x1f }, + { NULL, 0 }, + }; + const char *array[] = { "one", "two", "three", "four", "five", NULL }; + struct test_data *t = test_data; + + while (t->terminator || t->bitmask) { + const int max = 3; + struct strv_test_data td = { + .terminate_at = t->terminator, + .bitmask = { 0 }, + }; + + int rc = strv_for_each(array, strv_test_set_bitmask, &td); + ck_assert_int_eq(rc, t->index); + ck_assert_int_eq(td.bitmask[0], t->bitmask); + + struct strv_test_data tdmax = { + .terminate_at = t->terminator, + .bitmask = { 0 }, + }; + + rc = strv_for_each_n(array, max, strv_test_set_bitmask, &tdmax); + if (max < t->index) + ck_assert_int_eq(rc, 0); + else + ck_assert_int_eq(rc, t->index); + ck_assert_int_eq(tdmax.bitmask[0], t->bitmask & ((1 << max) - 1)); + + t++; + } +} + START_TEST(double_array_from_string_test) { struct double_array_from_string_test { @@ -1653,6 +1716,7 @@ litest_utils_suite(void) tcase_add_test(tc, safe_atou_base_8_test); tcase_add_test(tc, safe_atod_test); tcase_add_test(tc, strsplit_test); + tcase_add_test(tc, strv_for_each_test); tcase_add_test(tc, double_array_from_string_test); tcase_add_test(tc, strargv_test); tcase_add_test(tc, kvsplit_double_test);