2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) any later version.
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 * Support for the verb/device/modifier core logic and API,
17 * command line tool and file parser was kindly sponsored by
18 * Texas Instruments Inc.
19 * Support for multiple active modifiers and devices,
20 * transition sequences, multiple client access and user defined use
21 * cases was kindly sponsored by Wolfson Microelectronics PLC.
23 * Copyright (C) 2019 Red Hat Inc.
24 * Authors: Jaroslav Kysela <perex@perex.cz>
27 #include "ucm_local.h"
29 static int get_string(snd_config_t *compound, const char *key, const char **str)
34 err = snd_config_search(compound, key, &node);
37 return snd_config_get_string(node, str);
40 static int if_eval_string(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval)
42 const char *string1 = NULL, *string2 = NULL;
46 err = get_string(eval, "String1", &string1);
47 if (err < 0 && err != -ENOENT) {
48 uc_error("String error (If.Condition.String1)");
52 err = get_string(eval, "String2", &string2);
53 if (err < 0 && err != -ENOENT) {
54 uc_error("String error (If.Condition.String2)");
58 if (string1 || string2) {
59 if (string1 == NULL) {
60 uc_error("If.Condition.String1 not defined");
63 if (string2 == NULL) {
64 uc_error("If.Condition.String2 not defined");
67 err = uc_mgr_get_substituted_value(uc_mgr, &s1, string1);
70 err = uc_mgr_get_substituted_value(uc_mgr, &s2, string2);
75 err = strcasecmp(string1, string2) == 0;
81 err = get_string(eval, "Haystack", &string1);
82 if (err < 0 && err != -ENOENT) {
83 uc_error("String error (If.Condition.Haystack)");
87 err = get_string(eval, "Needle", &string2);
88 if (err < 0 && err != -ENOENT) {
89 uc_error("String error (If.Condition.Needle)");
93 if (string1 || string2) {
94 if (string1 == NULL) {
95 uc_error("If.Condition.Haystack not defined");
98 if (string2 == NULL) {
99 uc_error("If.Condition.Needle not defined");
102 err = uc_mgr_get_substituted_value(uc_mgr, &s1, string1);
105 err = uc_mgr_get_substituted_value(uc_mgr, &s2, string2);
110 err = strstr(string1, string2) == 0;
116 uc_error("Unknown String condition arguments");
120 static int if_eval_control_exists(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval)
123 const char *device = NULL, *ctldef;
124 snd_ctl_elem_id_t *elem_id;
125 snd_ctl_elem_info_t *elem_info;
130 snd_ctl_elem_id_alloca(&elem_id);
131 snd_ctl_elem_info_alloca(&elem_info);
133 err = get_string(eval, "Device", &device);
134 if (err < 0 && err != -ENOENT) {
135 uc_error("ControlExists error (If.Condition.Device)");
139 err = get_string(eval, "Control", &ctldef);
141 uc_error("ControlExists error (If.Condition.Control)");
145 err = uc_mgr_get_substituted_value(uc_mgr, &s, ctldef);
148 err = snd_ctl_ascii_elem_id_parse(elem_id, s);
151 uc_error("unable to parse element identificator (%s)", ctldef);
155 if (device == NULL) {
156 ctl = uc_mgr_get_ctl(uc_mgr);
158 uc_error("cannot determine control device");
162 err = uc_mgr_get_substituted_value(uc_mgr, &s, device);
165 err = uc_mgr_open_ctl(uc_mgr, &ctl, s);
171 snd_ctl_elem_info_set_id(elem_info, elem_id);
172 err = snd_ctl_elem_info(ctl, elem_info);
179 static int if_eval(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval)
184 if (snd_config_get_type(eval) != SND_CONFIG_TYPE_COMPOUND) {
185 uc_error("compound type expected for If.Condition");
189 err = get_string(eval, "Type", &type);
191 uc_error("type block error (If.Condition)");
195 if (strcmp(type, "ControlExists") == 0)
196 return if_eval_control_exists(uc_mgr, eval);
198 if (strcmp(type, "String") == 0)
199 return if_eval_string(uc_mgr, eval);
201 uc_error("unknown If.Condition.Type");
205 static int if_eval_one(snd_use_case_mgr_t *uc_mgr,
207 snd_config_t **result)
209 snd_config_t *expr, *_true = NULL, *_false = NULL;
214 if (snd_config_get_type(cond) != SND_CONFIG_TYPE_COMPOUND) {
215 uc_error("compound type expected for If.1");
219 if (snd_config_search(cond, "Condition", &expr) < 0) {
220 uc_error("condition block expected (If)");
224 err = snd_config_search(cond, "True", &_true);
225 if (err < 0 && err != -ENOENT) {
226 uc_error("true block error (If)");
230 err = snd_config_search(cond, "False", &_false);
231 if (err < 0 && err != -ENOENT) {
232 uc_error("false block error (If)");
236 err = if_eval(uc_mgr, expr);
240 } else if (err == 0) {
249 static void config_dump(snd_config_t *cfg)
252 snd_output_stdio_attach(&out, stderr, 0);
253 snd_output_printf(out, "-----\n");
254 snd_config_save(cfg, out);
255 snd_output_close(out);
259 static int compound_merge(snd_config_t *dst, snd_config_t *src)
261 snd_config_iterator_t i, next;
265 if (snd_config_get_type(src) != SND_CONFIG_TYPE_COMPOUND) {
266 uc_error("compound type expected for If True/False block");
270 snd_config_for_each(i, next, src) {
271 n = snd_config_iterator_entry(i);
272 err = snd_config_remove(n);
275 err = snd_config_add(dst, n);
285 * put back the result from all conditions to the parent
287 int uc_mgr_evaluate_condition(snd_use_case_mgr_t *uc_mgr,
288 snd_config_t *parent,
291 snd_config_iterator_t i, i2, next, next2;
292 snd_config_t *a, *n, *n2, *parent2;
296 if (uc_mgr->conf_format < 2) {
297 uc_error("conditions are not supported for v1 syntax");
301 if (snd_config_get_type(cond) != SND_CONFIG_TYPE_COMPOUND) {
302 uc_error("compound type expected for If");
306 snd_config_for_each(i, next, cond) {
307 n = snd_config_iterator_entry(i);
308 err = if_eval_one(uc_mgr, n, &a);
311 err = snd_config_search(a, "If", &n2);
312 if (err < 0 && err != -ENOENT) {
313 uc_error("If block error (If)");
315 } else if (err == 0) {
316 err = uc_mgr_evaluate_condition(uc_mgr, a, n2);
319 snd_config_delete(n2);
321 snd_config_for_each(i2, next2, a) {
322 n2 = snd_config_iterator_entry(i2);
323 err = snd_config_remove(n2);
326 err = snd_config_get_id(n2, &id);
329 err = snd_config_add(parent, n2);
334 err = snd_config_search(parent, id, &parent2);
337 err = compound_merge(parent2, n2);
341 snd_config_delete(n2);