]> git.alsa-project.org Git - alsa-lib.git/commitdiff
ucm: fix variant issue where variables or macros are overwritten
authorJaroslav Kysela <perex@perex.cz>
Fri, 7 Nov 2025 16:59:12 +0000 (17:59 +0100)
committerJaroslav Kysela <perex@perex.cz>
Fri, 7 Nov 2025 17:09:26 +0000 (18:09 +0100)
It is necessary to reset the state logic before each verb variant
is parsed. So save the original variable list and macros and
restore them before each parser iteration.

BugLink: https://github.com/alsa-project/alsa-ucm-conf/pull/633
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
src/ucm/parser.c
src/ucm/ucm_local.h
src/ucm/utils.c

index d46ec87a0d52f97d19ada99d01b5857a69462dc6..7a8c6d390d1c3b329ba7c65f461fd27680b3438b 100644 (file)
@@ -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:
index 18b29871da5f97947577bbd554da5b66f3742930..5e9b23fb94d0d1d203dc191e77f380c903a2a02f 100644 (file)
@@ -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);
index 67d51226d7c2d155be6066f6d0c4c65a3f6afdf9..8b591ceee59a3f078510ba1ae10f7062d781f918 100644 (file)
@@ -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;