mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-26 08:40:06 +01:00
util: add a strv_for_each helper function
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1038>
This commit is contained in:
parent
910d59e836
commit
ea7ad8d25c
3 changed files with 102 additions and 0 deletions
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue