Skip to content

Commit bd0ce67

Browse files
committed
ucm: fix variant issue where variables or macros are overwritten
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: alsa-project/alsa-ucm-conf#633 Signed-off-by: Jaroslav Kysela <[email protected]>
1 parent f6dce4f commit bd0ce67

File tree

3 files changed

+82
-1
lines changed

3 files changed

+82
-1
lines changed

src/ucm/parser.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2250,15 +2250,52 @@ static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
22502250
err = parse_verb_file(uc_mgr, use_case_name, comment, file);
22512251
} else {
22522252
/* parse variants */
2253+
struct list_head orig_variable_list;
2254+
snd_config_t *orig_macros = NULL;
2255+
int first_iteration = 1;
2256+
2257+
/* save original variable list */
2258+
err = uc_mgr_duplicate_variables(&orig_variable_list, &uc_mgr->variable_list);
2259+
if (err < 0)
2260+
goto __error;
2261+
2262+
/* save original macros */
2263+
if (uc_mgr->macros) {
2264+
err = snd_config_copy(&orig_macros, uc_mgr->macros);
2265+
if (err < 0)
2266+
goto __variant_error;
2267+
}
2268+
22532269
snd_config_for_each(i, next, variant) {
22542270
char *vfile, *vcomment;
22552271
const char *id;
2272+
2273+
/* restore variables and macros for second and later iterations */
2274+
if (!first_iteration) {
2275+
uc_mgr_free_value(&uc_mgr->variable_list);
2276+
2277+
err = uc_mgr_duplicate_variables(&uc_mgr->variable_list, &orig_variable_list);
2278+
if (err < 0)
2279+
goto __variant_error;
2280+
2281+
if (uc_mgr->macros) {
2282+
snd_config_delete(uc_mgr->macros);
2283+
uc_mgr->macros = NULL;
2284+
}
2285+
if (orig_macros) {
2286+
err = snd_config_copy(&uc_mgr->macros, orig_macros);
2287+
if (err < 0)
2288+
goto __variant_error;
2289+
}
2290+
}
2291+
first_iteration = 0;
2292+
22562293
n = snd_config_iterator_entry(i);
22572294
if (snd_config_get_id(n, &id) < 0)
22582295
continue;
22592296
if (!parse_is_name_safe(id)) {
22602297
err = -EINVAL;
2261-
goto __error;
2298+
goto __variant_error;
22622299
}
22632300
err = parse_variant(uc_mgr, n, &vfile, &vcomment);
22642301
if (err < 0)
@@ -2270,7 +2307,14 @@ static int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg,
22702307
uc_mgr->parse_variant = NULL;
22712308
free(vfile);
22722309
free(vcomment);
2310+
if (err < 0)
2311+
break;
22732312
}
2313+
2314+
__variant_error:
2315+
uc_mgr_free_value(&orig_variable_list);
2316+
if (orig_macros)
2317+
snd_config_delete(orig_macros);
22742318
}
22752319

22762320
__error:

src/ucm/ucm_local.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,8 @@ struct ctl_list *uc_mgr_get_ctl_by_name(snd_use_case_mgr_t *uc_mgr,
327327
snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr);
328328
void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr);
329329

330+
void uc_mgr_free_value(struct list_head *base);
331+
330332
int uc_mgr_add_value(struct list_head *base, const char *key, char *val);
331333

332334
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,
338340

339341
int uc_mgr_delete_variable(snd_use_case_mgr_t *uc_mgr, const char *name);
340342

343+
int uc_mgr_duplicate_variables(struct list_head *dst, struct list_head *src);
344+
341345
int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr,
342346
char **_rvalue,
343347
const char *value);

src/ucm/utils.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,39 @@ int uc_mgr_delete_variable(snd_use_case_mgr_t *uc_mgr, const char *name)
733733
return -ENOENT;
734734
}
735735

736+
int uc_mgr_duplicate_variables(struct list_head *dst, struct list_head *src)
737+
{
738+
struct list_head *pos;
739+
struct ucm_value *var, *new_var;
740+
int err;
741+
742+
INIT_LIST_HEAD(dst);
743+
744+
list_for_each(pos, src) {
745+
var = list_entry(pos, struct ucm_value, list);
746+
new_var = calloc(1, sizeof(*new_var));
747+
if (new_var == NULL) {
748+
err = -ENOMEM;
749+
goto __error;
750+
}
751+
new_var->name = strdup(var->name);
752+
new_var->data = strdup(var->data);
753+
if (new_var->name == NULL || new_var->data == NULL) {
754+
free(new_var->name);
755+
free(new_var->data);
756+
free(new_var);
757+
err = -ENOMEM;
758+
goto __error;
759+
}
760+
list_add_tail(&new_var->list, dst);
761+
}
762+
return 0;
763+
764+
__error:
765+
uc_mgr_free_value(dst);
766+
return err;
767+
}
768+
736769
void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
737770
{
738771
struct list_head *pos, *npos;

0 commit comments

Comments
 (0)