mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
conf: improve matching rules a bit more
Handle "null", null, !null, "!null", !"null" and "!\"null\"" matches, copy some docs from wireplumber about the rules and add some more cases.
This commit is contained in:
parent
c52c56621d
commit
0e380de809
2 changed files with 140 additions and 21 deletions
|
|
@ -434,13 +434,105 @@ The general rules object follows the following pattern:
|
|||
}
|
||||
]
|
||||
```
|
||||
Match rules are an array of rules.
|
||||
|
||||
The rules is an array of things to match and what actions to perform
|
||||
when a match is found.
|
||||
A rule is always a JSON object with two keys: matches and actions. The matches key is used to
|
||||
define the conditions that need to be met for the rule to be evaluated as true, and the actions
|
||||
key is used to define the actions that are performed when the rule is evaluated as true.
|
||||
|
||||
The matches key is always a JSON array of objects, where each object defines a condition that needs
|
||||
to be met. Each condition is a list of key-value pairs, where the key is the name of the property
|
||||
that is being matched, and the value is the value that the property needs to have. Within a condition,
|
||||
all the key-value pairs are combined with a logical AND, and all the conditions in the matches
|
||||
array are combined with a logical OR.
|
||||
|
||||
The actions key is always a JSON object, where each key-value pair defines an action that is
|
||||
performed when the rule is evaluated as true. The action name is specific to the rule and is
|
||||
defined by the rule’s documentation, but most frequently you will see the update-props action,
|
||||
which is used to update the properties of the matched object.
|
||||
|
||||
In the matches array, it is also possible to use regular expressions to match property values.
|
||||
For example, to match all nodes with a name that starts with my_, you can use the following condition:
|
||||
|
||||
```
|
||||
matches = [
|
||||
{
|
||||
node.name = "~my_.*"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
The ~ character signifies that the value is a regular expression. The exact syntax of the regular
|
||||
expressions is the POSIX extended regex syntax, as described in the regex (7) man page.
|
||||
|
||||
In addition to regular expressions, you may also use the ! character to negate a condition. For
|
||||
example, to match all nodes with a name that does not start with my_, you can use the following condition:
|
||||
|
||||
```
|
||||
matches = [
|
||||
{
|
||||
node.name = "!~my_.*"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
The ! character can be used with or without a regular expression. For example, to match all
|
||||
nodes with a name that is not equal to my_node, you can use the following condition:
|
||||
|
||||
```
|
||||
matches = [
|
||||
{
|
||||
node.name = "!my_node"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
The null value has a special meaning; it checks if the property is not available
|
||||
(or unset). To check if a property is not set:
|
||||
|
||||
```
|
||||
matches = [
|
||||
{
|
||||
node.name = null
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
To check the existence of a property, one can use the !null condition, for example:
|
||||
|
||||
```
|
||||
matches = [
|
||||
{
|
||||
node.name = "!null"
|
||||
}
|
||||
{
|
||||
node.name = !null # simplified syntax
|
||||
}
|
||||
]
|
||||
```
|
||||
To handle the "null" string, one needs to escape the string. For example, to check
|
||||
if a property has the string value "null", use:
|
||||
|
||||
```
|
||||
matches = [
|
||||
{
|
||||
node.name = "null"
|
||||
}
|
||||
]
|
||||
```
|
||||
To handle anything but the "null" string, use:
|
||||
|
||||
```
|
||||
matches = [
|
||||
{
|
||||
node.name = "!\"null\""
|
||||
}
|
||||
{
|
||||
node.name = !"null" # simplified syntax
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
The available actions and their values depend on the specific rule
|
||||
that is used. Usually it is possible to update some properties or set
|
||||
some quirks on the object.
|
||||
|
||||
# CONTEXT PROPERTIES RULES @IDX@ pipewire.conf
|
||||
|
||||
|
|
|
|||
|
|
@ -594,6 +594,14 @@ static int load_module(struct pw_context *context, const char *key, const char *
|
|||
* <key> = <value>
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* Some things that can match:
|
||||
*
|
||||
* null -> matches when the property is not found
|
||||
* "null" -> matches when the property is found and has the string "null"
|
||||
* !null -> matches when the property is found (any value)
|
||||
* "!null" -> same as !null
|
||||
* !"null" and "!\"null\"" matches anything that is not the string "null"
|
||||
*/
|
||||
static bool find_match(struct spa_json *arr, const struct spa_dict *props)
|
||||
{
|
||||
|
|
@ -606,47 +614,66 @@ static bool find_match(struct spa_json *arr, const struct spa_dict *props)
|
|||
int len;
|
||||
|
||||
while (spa_json_get_string(&it[0], key, sizeof(key)) > 0) {
|
||||
bool success = false, is_null;
|
||||
bool success = false, is_null, reg = false, parse_string = true;
|
||||
int skip = 0;
|
||||
|
||||
if ((len = spa_json_next(&it[0], &value)) <= 0)
|
||||
break;
|
||||
|
||||
if (len > 0 && value[0] == '!') {
|
||||
/* first decode a string, when there was a string, we assume it
|
||||
* can not be null but the "null" string, unless there is a modifier,
|
||||
* see below. */
|
||||
if (spa_json_is_string(value, len)) {
|
||||
if (spa_json_parse_stringn(value, len, val, sizeof(val)) < 0)
|
||||
continue;
|
||||
value = val;
|
||||
len = strlen(val);
|
||||
parse_string = false;
|
||||
}
|
||||
|
||||
/* parse the modifiers, after the modifier we unescape the string
|
||||
* again to be able to detect and handle null and "null" */
|
||||
if (len > skip && value[skip] == '!') {
|
||||
success = !success;
|
||||
skip++;
|
||||
parse_string = true;
|
||||
}
|
||||
if (len > skip && value[skip] == '~') {
|
||||
reg = true;
|
||||
skip++;
|
||||
parse_string = true;
|
||||
}
|
||||
|
||||
str = spa_dict_lookup(props, key);
|
||||
|
||||
is_null = spa_json_is_null(value+skip, len-skip);
|
||||
/* parse the remaining part of the string, if there was a modifier,
|
||||
* we need to check for null again. Otherwise null was in quotes without
|
||||
* a modifier. */
|
||||
is_null = parse_string && spa_json_is_null(value+skip, len-skip);
|
||||
if (is_null || str == NULL) {
|
||||
if (is_null && str == NULL)
|
||||
success = !success;
|
||||
} else {
|
||||
if (spa_json_parse_stringn(value+skip, len-skip, val, sizeof(val)) < 0)
|
||||
/* only unescape string once or again after modifier */
|
||||
if (!parse_string) {
|
||||
memmove(val, value+skip, len-skip);
|
||||
val[len-skip] = '\0';
|
||||
} else if (spa_json_parse_stringn(value+skip, len-skip, val, sizeof(val)) < 0)
|
||||
continue;
|
||||
value = val;
|
||||
len = strlen(val);
|
||||
if (len > 0 && value[0] == '!') {
|
||||
success = !success;
|
||||
skip++;
|
||||
}
|
||||
if (value[skip] == '~') {
|
||||
|
||||
if (reg) {
|
||||
regex_t preg;
|
||||
int res;
|
||||
skip++;
|
||||
if ((res = regcomp(&preg, value+skip, REG_EXTENDED | REG_NOSUB)) != 0) {
|
||||
if ((res = regcomp(&preg, val, REG_EXTENDED | REG_NOSUB)) != 0) {
|
||||
char errbuf[1024];
|
||||
regerror(res, &preg, errbuf, sizeof(errbuf));
|
||||
pw_log_warn("invalid regex %s: %s", value+skip, errbuf);
|
||||
pw_log_warn("invalid regex %s: %s", val, errbuf);
|
||||
} else {
|
||||
if (regexec(&preg, str, 0, NULL, 0) == 0)
|
||||
success = !success;
|
||||
regfree(&preg);
|
||||
}
|
||||
} else if (strncmp(str, value+skip, len-skip) == 0 &&
|
||||
strlen(str) == (size_t)(len-skip)) {
|
||||
} else if (strcmp(str, val) == 0) {
|
||||
success = !success;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue