diff --git a/src/ucm/parser.c b/src/ucm/parser.c index d46ec87a..7a8c6d39 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -2250,15 +2250,52 @@ static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, err = parse_verb_file(uc_mgr, use_case_name, comment, file); } else { /* parse variants */ + struct list_head orig_variable_list; + snd_config_t *orig_macros = NULL; + int first_iteration = 1; + + /* save original variable list */ + err = uc_mgr_duplicate_variables(&orig_variable_list, &uc_mgr->variable_list); + if (err < 0) + goto __error; + + /* save original macros */ + if (uc_mgr->macros) { + err = snd_config_copy(&orig_macros, uc_mgr->macros); + if (err < 0) + goto __variant_error; + } + snd_config_for_each(i, next, variant) { char *vfile, *vcomment; const char *id; + + /* restore variables and macros for second and later iterations */ + if (!first_iteration) { + uc_mgr_free_value(&uc_mgr->variable_list); + + err = uc_mgr_duplicate_variables(&uc_mgr->variable_list, &orig_variable_list); + if (err < 0) + goto __variant_error; + + if (uc_mgr->macros) { + snd_config_delete(uc_mgr->macros); + uc_mgr->macros = NULL; + } + if (orig_macros) { + err = snd_config_copy(&uc_mgr->macros, orig_macros); + if (err < 0) + goto __variant_error; + } + } + first_iteration = 0; + n = snd_config_iterator_entry(i); if (snd_config_get_id(n, &id) < 0) continue; if (!parse_is_name_safe(id)) { err = -EINVAL; - goto __error; + goto __variant_error; } err = parse_variant(uc_mgr, n, &vfile, &vcomment); if (err < 0) @@ -2270,7 +2307,14 @@ static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, uc_mgr->parse_variant = NULL; free(vfile); free(vcomment); + if (err < 0) + break; } + +__variant_error: + uc_mgr_free_value(&orig_variable_list); + if (orig_macros) + snd_config_delete(orig_macros); } __error: diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h index 18b29871..5e9b23fb 100644 --- a/src/ucm/ucm_local.h +++ b/src/ucm/ucm_local.h @@ -327,6 +327,8 @@ struct ctl_list *uc_mgr_get_ctl_by_name(snd_use_case_mgr_t *uc_mgr, snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr); void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr); +void uc_mgr_free_value(struct list_head *base); + int uc_mgr_add_value(struct list_head *base, const char *key, char *val); const char *uc_mgr_get_variable(snd_use_case_mgr_t *uc_mgr, @@ -338,6 +340,8 @@ int uc_mgr_set_variable(snd_use_case_mgr_t *uc_mgr, int uc_mgr_delete_variable(snd_use_case_mgr_t *uc_mgr, const char *name); +int uc_mgr_duplicate_variables(struct list_head *dst, struct list_head *src); + int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr, char **_rvalue, const char *value); diff --git a/src/ucm/utils.c b/src/ucm/utils.c index 67d51226..8b591cee 100644 --- a/src/ucm/utils.c +++ b/src/ucm/utils.c @@ -733,6 +733,39 @@ int uc_mgr_delete_variable(snd_use_case_mgr_t *uc_mgr, const char *name) return -ENOENT; } +int uc_mgr_duplicate_variables(struct list_head *dst, struct list_head *src) +{ + struct list_head *pos; + struct ucm_value *var, *new_var; + int err; + + INIT_LIST_HEAD(dst); + + list_for_each(pos, src) { + var = list_entry(pos, struct ucm_value, list); + new_var = calloc(1, sizeof(*new_var)); + if (new_var == NULL) { + err = -ENOMEM; + goto __error; + } + new_var->name = strdup(var->name); + new_var->data = strdup(var->data); + if (new_var->name == NULL || new_var->data == NULL) { + free(new_var->name); + free(new_var->data); + free(new_var); + err = -ENOMEM; + goto __error; + } + list_add_tail(&new_var->list, dst); + } + return 0; + +__error: + uc_mgr_free_value(dst); + return err; +} + void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr) { struct list_head *pos, *npos;