conf: add @ modifier for JSON array element matching

Properties like pipewire.sec.gids are now serialized as JSON arrays
(e.g. [ 138, 137, 135 ]) rather than space-separated strings. Without
a dedicated modifier, config files must use fragile regexes to check
array membership. Add @ as a match modifier that iterates the property
value as a JSON array and succeeds if any element equals the check
value. Warn if @ and ~ are combined since that is not supported.
This commit is contained in:
Torkel Niklasson 2026-05-25 19:31:00 +02:00
parent 1066ec98a8
commit fded4d11b8

View file

@ -625,6 +625,7 @@ static int load_module(struct pw_context *context, const char *key, const char *
* {
* # all keys must match the value. ~ in value starts regex.
* # ! as the first char of the value negates the match
* # @ checks if the value is an element in a JSON array property
* <key> = <value>
* ...
* }
@ -636,6 +637,8 @@ static int load_module(struct pw_context *context, const char *key, const char *
* !null -> matches when the property is found (any value)
* "!null" -> same as !null
* !"null" and "!\"null\"" matches anything that is not the string "null"
* @138 -> matches when the property is a JSON array containing "138"
* !@138 -> matches when the property is a JSON array not containing "138"
*/
SPA_EXPORT
bool pw_conf_find_match(struct spa_json *arr, const struct spa_dict *props, bool condition)
@ -651,7 +654,7 @@ bool pw_conf_find_match(struct spa_json *arr, const struct spa_dict *props, bool
int len;
while ((len = spa_json_object_next(&it[0], key, sizeof(key), &value)) > 0) {
bool success = false, is_null, reg = false, parse_string = true;
bool success = false, is_null, reg = false, in_array = false, parse_string = true;
int skip = 0;
/* first decode a string, when there was a string, we assume it
@ -680,6 +683,16 @@ bool pw_conf_find_match(struct spa_json *arr, const struct spa_dict *props, bool
skip++;
parse_string = true;
}
if (len > skip && value[skip] == '@') {
in_array = true;
skip++;
parse_string = true;
}
if (SPA_UNLIKELY(in_array && reg)) {
pw_log_warn("@ and ~ modifiers cannot be combined in '%.*s'",
az, as);
continue;
}
str = spa_dict_lookup(props, key);
@ -701,7 +714,18 @@ bool pw_conf_find_match(struct spa_json *arr, const struct spa_dict *props, bool
continue;
}
if (reg) {
if (in_array) {
struct spa_json arr_iter;
char elem[256];
if (spa_json_begin_array_relax(&arr_iter, str, strlen(str)) > 0) {
while (spa_json_get_string(&arr_iter, elem, sizeof(elem)) > 0) {
if (strcmp(elem, val) == 0) {
success = !success;
break;
}
}
}
} else if (reg) {
regex_t preg;
int res;
if ((res = regcomp(&preg, val, REG_EXTENDED | REG_NOSUB)) != 0) {