diff options
| author | Jaroslav Kysela <perex@perex.cz> | 2020-05-16 15:47:19 +0200 |
|---|---|---|
| committer | Jaroslav Kysela <perex@perex.cz> | 2020-05-25 19:20:53 +0200 |
| commit | 3edfebc522b701c559678ca5b3ecd0f2babbefd8 (patch) | |
| tree | 8b01179ec27643b4d5ca990b08ac670cd00b1906 /src/ucm/ucm_include.c | |
| parent | 14636be4a87ea1cbb13bf8942d07d2066d626e71 (diff) | |
| download | alsa-lib-3edfebc522b701c559678ca5b3ecd0f2babbefd8.tar.gz | |
ucm: configuration - implement in-place Include
An example:
Include {
File "Inc.conf"
Before.SectionDevice "Mic"
}
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'src/ucm/ucm_include.c')
| -rw-r--r-- | src/ucm/ucm_include.c | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/src/ucm/ucm_include.c b/src/ucm/ucm_include.c new file mode 100644 index 00000000..cd8fb57d --- /dev/null +++ b/src/ucm/ucm_include.c @@ -0,0 +1,259 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Support for the verb/device/modifier core logic and API, + * command line tool and file parser was kindly sponsored by + * Texas Instruments Inc. + * Support for multiple active modifiers and devices, + * transition sequences, multiple client access and user defined use + * cases was kindly sponsored by Wolfson Microelectronics PLC. + * + * Copyright (C) 2020 Red Hat Inc. + * Authors: Jaroslav Kysela <perex@perex.cz> + */ + +#include "ucm_local.h" + +static int get_string(snd_config_t *compound, const char *key, const char **str) +{ + snd_config_t *node; + int err; + + err = snd_config_search(compound, key, &node); + if (err < 0) + return err; + return snd_config_get_string(node, str); +} + +static int include_eval_one(snd_use_case_mgr_t *uc_mgr, + snd_config_t *inc, + snd_config_t **result, + snd_config_t **before, + snd_config_t **after) +{ + const char *file; + int err; + + *result = NULL; + + if (snd_config_get_type(inc) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for Include.1"); + return -EINVAL; + } + + err = get_string(inc, "File", &file); + if (err < 0) { + uc_error("file expected (Include)"); + return -EINVAL; + } + + err = snd_config_search(inc, "Before", before); + if (err < 0 && err != -ENOENT) { + uc_error("before block identifier error"); + return -EINVAL; + } + + err = snd_config_search(inc, "After", after); + if (err < 0 && err != -ENOENT) { + uc_error("before block identifier error"); + return -EINVAL; + } + + return uc_mgr_config_load_file(uc_mgr, file, result); +} + + + +#if 0 +static void config_dump(snd_config_t *cfg) +{ + snd_output_t *out; + snd_output_stdio_attach(&out, stderr, 0); + snd_output_printf(out, "-----\n"); + snd_config_save(cfg, out); + snd_output_close(out); +} +#endif + +static int compound_merge(const char *id, + snd_config_t *dst, snd_config_t *src, + snd_config_t *before, snd_config_t *after) +{ + snd_config_iterator_t i, next; + snd_config_t *n, *_before = NULL, *_after = NULL; + const char *s; + char tmpid[32]; + int err, array, idx; + + if (snd_config_get_type(src) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for the merged block"); + return -EINVAL; + } + + if (before) { + err = get_string(before, id, &s); + if (err < 0 && err != -ENOENT) + return err; + if (err == 0) { + err = snd_config_search(dst, s, &_before); + if (err < 0 && err != -ENOENT) + return err; + } + } + if (after) { + err = get_string(after, id, &s); + if (err < 0 && err != -ENOENT) + return err; + if (err == 0) { + err = snd_config_search(dst, s, &_after); + if (err < 0 && err != -ENOENT) + return err; + } + } + + if (_before && _after) { + uc_error("defined both before and after identifiers in the If or Include block"); + return -EINVAL; + } + + array = snd_config_is_array(dst); + if (array < 0) { + uc_error("destination configuration node is not a compound"); + return array; + } + if (array && snd_config_is_array(src) <= 0) { + uc_error("source configuration node is not an array"); + return -EINVAL; + } + + idx = 0; + snd_config_for_each(i, next, src) { + n = snd_config_iterator_entry(i); + err = snd_config_remove(n); + if (err < 0) + return err; + /* for array, use a temporary non-clashing identifier */ + if (array > 0) { + snprintf(tmpid, sizeof(tmpid), "_tmp_%d", idx++); + err = snd_config_set_id(n, tmpid); + if (err < 0) + return err; + } + if (_before) { + err = snd_config_add_before(_before, n); + if (err < 0) + return err; + _before = NULL; + _after = n; + } else if (_after) { + err = snd_config_add_after(_after, n); + if (err < 0) + return err; + _after = n; + } else { + err = snd_config_add(dst, n); + if (err < 0) + return err; + } + } + + /* set new indexes for the final array */ + if (array > 0) { + idx = 0; + snd_config_for_each(i, next, dst) { + n = snd_config_iterator_entry(i); + snprintf(tmpid, sizeof(tmpid), "%d", idx++); + err = snd_config_set_id(n, tmpid); + if (err < 0) + return err; + } + } + + return 0; +} + +int uc_mgr_config_tree_merge(snd_config_t *parent, snd_config_t *new_ctx, + snd_config_t *before, snd_config_t *after) +{ + snd_config_iterator_t i, next; + snd_config_t *n, *parent2; + const char *id; + int err; + + snd_config_for_each(i, next, new_ctx) { + n = snd_config_iterator_entry(i); + err = snd_config_remove(n); + if (err < 0) + return err; + err = snd_config_get_id(n, &id); + if (err < 0) { +__add: + err = snd_config_add(parent, n); + if (err < 0) + return err; + continue; + } else { + err = snd_config_search(parent, id, &parent2); + if (err == -ENOENT) + goto __add; + err = compound_merge(id, parent2, n, before, after); + if (err < 0) + return err; + } + snd_config_delete(n); + } + return 0; +} + +/* + * put back the included configuration to the parent + */ +int uc_mgr_evaluate_include(snd_use_case_mgr_t *uc_mgr, + snd_config_t *parent, + snd_config_t *inc) +{ + snd_config_iterator_t i, next; + snd_config_t *a, *n, *before, *after; + int err; + + if (uc_mgr->conf_format < 3) { + uc_error("in-place include is supported in v3+ syntax"); + return -EINVAL; + } + + if (snd_config_get_type(inc) != SND_CONFIG_TYPE_COMPOUND) { + uc_error("compound type expected for Include"); + return -EINVAL; + } + + snd_config_for_each(i, next, inc) { + n = snd_config_iterator_entry(i); + before = after = NULL; + err = include_eval_one(uc_mgr, n, &a, &before, &after); + if (err < 0) + return err; + if (a == NULL) + continue; + err = uc_mgr_evaluate_inplace(uc_mgr, a); + if (err < 0) + return err; + err = uc_mgr_config_tree_merge(parent, a, before, after); + if (err < 0) + return err; + snd_config_delete(a); + + } + return 0; +} |
