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) 2020 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 include_eval_one(snd_use_case_mgr_t *uc_mgr,
42 snd_config_t **result,
43 snd_config_t **before,
52 if (snd_config_get_type(inc) != SND_CONFIG_TYPE_COMPOUND) {
53 uc_error("compound type expected for Include.1");
57 err = get_string(inc, "File", &file);
59 uc_error("file expected (Include)");
63 err = snd_config_search(inc, "Before", before);
64 if (err < 0 && err != -ENOENT) {
65 uc_error("before block identifier error");
69 err = snd_config_search(inc, "After", after);
70 if (err < 0 && err != -ENOENT) {
71 uc_error("before block identifier error");
75 err = uc_mgr_get_substituted_value(uc_mgr, &s, file);
78 err = uc_mgr_config_load_file(uc_mgr, s, result);
84 static void config_dump(snd_config_t *cfg)
87 snd_output_stdio_attach(&out, stderr, 0);
88 snd_output_printf(out, "-----\n");
89 snd_config_save(cfg, out);
90 snd_output_close(out);
94 static int find_position_node(snd_config_t **res, snd_config_t *dst,
95 const char *id, snd_config_t *pos)
100 err = get_string(pos, id, &s);
101 if (err < 0 && err != -ENOENT)
104 err = snd_config_search(dst, s, res);
105 if (err < 0 && err != -ENOENT)
111 static int merge_it(snd_config_t *dst, snd_config_t *n)
117 err = snd_config_get_id(n, &id);
120 err = snd_config_search(dst, id, &dn);
123 err = snd_config_merge(dn, n, 0); /* merge / append mode */
125 snd_config_delete(n);
129 static int compound_merge(const char *id,
130 snd_config_t *dst, snd_config_t *src,
131 snd_config_t *before, snd_config_t *after)
133 snd_config_iterator_t i, next;
134 snd_config_t *n, *_before = NULL, *_after = NULL;
138 if (snd_config_get_type(src) != SND_CONFIG_TYPE_COMPOUND) {
139 uc_error("compound type expected for the merged block");
144 err = find_position_node(&_before, dst, id, before);
149 err = find_position_node(&_after, dst, id, after);
155 if (!_before && !_after)
156 return snd_config_merge(dst, src, 0); /* merge / append mode */
158 if (_before && _after) {
159 uc_error("defined both before and after identifiers in the If or Include block");
163 array = snd_config_is_array(dst);
165 uc_error("destination configuration node is not a compound");
168 if (array && snd_config_is_array(src) <= 0) {
169 uc_error("source configuration node is not an array");
175 /* for array, use a temporary non-clashing identifier */
177 snd_config_for_each(i, next, dst) {
178 n = snd_config_iterator_entry(i);
179 snprintf(tmpid, sizeof(tmpid), "_tmp_%d", idx++);
180 err = snd_config_set_id(n, tmpid);
186 snd_config_for_each(i, next, src) {
187 n = snd_config_iterator_entry(i);
188 err = snd_config_remove(n);
191 /* for array, use a temporary non-clashing identifier */
193 snprintf(tmpid, sizeof(tmpid), "_tmp_%d", idx++);
194 err = snd_config_set_id(n, tmpid);
199 err = snd_config_add_before(_before, n);
201 err = merge_it(dst, n);
207 err = snd_config_add_after(_after, n);
209 err = merge_it(dst, n);
216 /* set new indexes for the final array */
219 snd_config_for_each(i, next, dst) {
220 n = snd_config_iterator_entry(i);
221 snprintf(tmpid, sizeof(tmpid), "%d", idx++);
222 err = snd_config_set_id(n, tmpid);
228 snd_config_delete(src);
232 int uc_mgr_config_tree_merge(snd_use_case_mgr_t *uc_mgr,
233 snd_config_t *parent, snd_config_t *new_ctx,
234 snd_config_t *before, snd_config_t *after)
236 snd_config_iterator_t i, next;
237 snd_config_t *n, *parent2;
241 err = uc_mgr_substitute_tree(uc_mgr, new_ctx);
245 snd_config_for_each(i, next, new_ctx) {
246 n = snd_config_iterator_entry(i);
247 err = snd_config_remove(n);
250 err = snd_config_get_id(n, &id);
253 err = snd_config_add(parent, n);
257 err = snd_config_search(parent, id, &parent2);
260 err = compound_merge(id, parent2, n, before, after);
262 snd_config_delete(n);
271 * put back the included configuration to the parent
273 int uc_mgr_evaluate_include(snd_use_case_mgr_t *uc_mgr,
274 snd_config_t *parent,
277 snd_config_iterator_t i, next;
278 snd_config_t *a, *n, *before, *after;
281 if (uc_mgr->conf_format < 3) {
282 uc_error("in-place include is supported in v3+ syntax");
286 if (snd_config_get_type(inc) != SND_CONFIG_TYPE_COMPOUND) {
287 uc_error("compound type expected for Include");
291 snd_config_for_each(i, next, inc) {
292 n = snd_config_iterator_entry(i);
293 before = after = NULL;
294 err = include_eval_one(uc_mgr, n, &a, &before, &after);
299 err = uc_mgr_evaluate_inplace(uc_mgr, a);
302 err = uc_mgr_config_tree_merge(uc_mgr, parent, a, before, after);
305 snd_config_delete(a);