diff --git a/include/libweston/config-parser.h b/include/libweston/config-parser.h index 8ed14a3b5..c9c771ecc 100644 --- a/include/libweston/config-parser.h +++ b/include/libweston/config-parser.h @@ -32,6 +32,7 @@ extern "C" { #include #include +#include #define WESTON_CONFIG_FILE_ENV_VAR "WESTON_CONFIG_FILE" @@ -107,6 +108,20 @@ int weston_config_next_section(struct weston_config *config, uint32_t weston_config_get_binding_modifier(struct weston_config *config, uint32_t default_mod); +/** Container for an array of strings. */ +struct weston_string_array { + /** Length of \c array. */ + size_t len; + /** Pointer to an array of strings. */ + char **array; +}; + +void +weston_string_array_fini(struct weston_string_array *strarr); + +struct weston_string_array +weston_parse_space_separated_list(const char *str); + #ifdef __cplusplus } #endif diff --git a/shared/option-parser.c b/shared/option-parser.c index 767f13c5d..6e70dd182 100644 --- a/shared/option-parser.c +++ b/shared/option-parser.c @@ -1,5 +1,6 @@ /* * Copyright © 2012 Kristian Høgsberg + * Copyright 2025 Collabora, Ltd. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -33,8 +34,10 @@ #include #include +#include #include #include "string-helpers.h" +#include "xalloc.h" static bool handle_option(const struct weston_option *option, char *value) @@ -209,3 +212,71 @@ parse_options(const struct weston_option *options, return j; } + +/** Free string array contents + * + * Does not free \c strarr itself but resets it. + */ +void +weston_string_array_fini(struct weston_string_array *strarr) +{ + size_t i; + + for (i = 0; i < strarr->len; i++) + free(strarr->array[i]); + free(strarr->array); + strarr->len = 0; + strarr->array = NULL; +} + +static bool +is_space_for_split(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; +} + +/** Split a string at spaces, tabs, CRs, LFs + * + * \param str An arbitrary string, can be empty but not NULL. + * \return An array of sub-strings. Must be finalized with + * weston_string_array_fini(). + * + * Takes the given string, and splits it into items. Empty items are skipped. + * The items are returned in the array in the same order they appeared in the + * string. Spaces, tabs, newlines or carriage returns will not be present in + * the items as they cannot be escaped. + */ +struct weston_string_array +weston_parse_space_separated_list(const char *str) +{ + struct wl_array arr; + const char *p = str; + char **item; + + wl_array_init(&arr); + + while (*p) { + const char *end = p; + while (*end && !is_space_for_split(*end)) + end++; + size_t len = end - p; + + if (len > 0) { + item = wl_array_add(&arr, sizeof *item); + + *item = strndup(p, len); + abort_oom_if_null(*item); + } + + p = end; + + /* Skip whitespaces */ + while (*p && is_space_for_split(*p)) + p++; + } + + return (struct weston_string_array){ + .len = arr.size / sizeof *item, + .array = arr.data + }; +} diff --git a/tests/config-parser-test.c b/tests/config-parser-test.c index bcfba4a17..8b0c7fbd5 100644 --- a/tests/config-parser-test.c +++ b/tests/config-parser-test.c @@ -1,5 +1,6 @@ /* * Copyright © 2013 Intel Corporation + * Copyright 2025 Collabora, Ltd. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -924,3 +925,78 @@ TEST(section_from_null) return RESULT_OK; } + +TEST(parse_comma_separated_list) +{ + const char *matter; + struct weston_string_array strarr; + + matter = ""; + strarr = weston_parse_space_separated_list(matter); + test_assert_u64_eq(strarr.len, 0); + + matter = " "; + strarr = weston_parse_space_separated_list(matter); + test_assert_u64_eq(strarr.len, 0); + + matter = " \t \t \t"; + strarr = weston_parse_space_separated_list(matter); + test_assert_u64_eq(strarr.len, 0); + + matter = "k"; + strarr = weston_parse_space_separated_list(matter); + test_assert_u64_eq(strarr.len, 1); + test_assert_str_eq(strarr.array[0], "k"); + weston_string_array_fini(&strarr); + + matter = " k"; + strarr = weston_parse_space_separated_list(matter); + test_assert_u64_eq(strarr.len, 1); + test_assert_str_eq(strarr.array[0], "k"); + weston_string_array_fini(&strarr); + + matter = "k "; + strarr = weston_parse_space_separated_list(matter); + test_assert_u64_eq(strarr.len, 1); + test_assert_str_eq(strarr.array[0], "k"); + weston_string_array_fini(&strarr); + + matter = " k "; + strarr = weston_parse_space_separated_list(matter); + test_assert_u64_eq(strarr.len, 1); + test_assert_str_eq(strarr.array[0], "k"); + weston_string_array_fini(&strarr); + + matter = "kissa kassi"; + strarr = weston_parse_space_separated_list(matter); + test_assert_u64_eq(strarr.len, 2); + test_assert_str_eq(strarr.array[0], "kissa"); + test_assert_str_eq(strarr.array[1], "kassi"); + weston_string_array_fini(&strarr); + + matter = "kissa\tkassi"; + strarr = weston_parse_space_separated_list(matter); + test_assert_u64_eq(strarr.len, 2); + test_assert_str_eq(strarr.array[0], "kissa"); + test_assert_str_eq(strarr.array[1], "kassi"); + weston_string_array_fini(&strarr); + + matter = " kissa\t kassi"; + strarr = weston_parse_space_separated_list(matter); + test_assert_u64_eq(strarr.len, 2); + test_assert_str_eq(strarr.array[0], "kissa"); + test_assert_str_eq(strarr.array[1], "kassi"); + weston_string_array_fini(&strarr); + + matter = " 4.556\ra bab c \nkoe\t"; + strarr = weston_parse_space_separated_list(matter); + test_assert_u64_eq(strarr.len, 5); + test_assert_str_eq(strarr.array[0], "4.556"); + test_assert_str_eq(strarr.array[1], "a"); + test_assert_str_eq(strarr.array[2], "bab"); + test_assert_str_eq(strarr.array[3], "c"); + test_assert_str_eq(strarr.array[4], "koe"); + weston_string_array_fini(&strarr); + + return RESULT_OK; +}