From 0dd89f389245af2cff3547224391bebd84c9bb89 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 4 Nov 2019 16:18:07 +0100 Subject: [PATCH] ucm: add the run-time variable substitution Those two variables are supported: ${ConfName} - configuration file name ${CardId} - card identification string (like PCH) ${CardName} - card name (driver) ${CardLongName} - card long name (driver) ${env:ENV_NAME} - returns the environment variable ENV_NAME Signed-off-by: Jaroslav Kysela --- src/ucm/main.c | 197 +++++++++++++++++++++++++++++++++++++++----- src/ucm/parser.c | 2 + src/ucm/ucm_local.h | 2 + 3 files changed, 179 insertions(+), 22 deletions(-) diff --git a/src/ucm/main.c b/src/ucm/main.c index 0c4e2dc3..cce4f0b3 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -41,9 +41,10 @@ * misc */ -static int get_value1(char **value, struct list_head *value_list, - const char *identifier); -static int get_value3(char **value, +static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value, + struct list_head *value_list, const char *identifier); +static int get_value3(snd_use_case_mgr_t *uc_mgr, + char **value, const char *identifier, struct list_head *value_list1, struct list_head *value_list2, @@ -359,7 +360,7 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr, char *playback_ctl = NULL; char *capture_ctl = NULL; - err = get_value3(&playback_ctl, "PlaybackCTL", + err = get_value3(uc_mgr, &playback_ctl, "PlaybackCTL", value_list1, value_list2, value_list3); @@ -367,7 +368,7 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr, uc_error("cdev is not defined!"); return err; } - err = get_value3(&capture_ctl, "CaptureCTL", + err = get_value3(uc_mgr, &capture_ctl, "CaptureCTL", value_list1, value_list2, value_list3); @@ -1351,8 +1352,156 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, return err; } -static int get_value1(char **value, struct list_head *value_list, - const char *identifier) +static char *rval_conf_name(snd_use_case_mgr_t *uc_mgr) +{ + if (uc_mgr->conf_file_name[0]) + return strdup(uc_mgr->conf_file_name); + return NULL; +} + +static char *rval_card_id(snd_use_case_mgr_t *uc_mgr) +{ + struct list_head *pos; + struct ctl_list *ctl_list = NULL; + + list_for_each(pos, &uc_mgr->ctl_list) { + if (ctl_list) { + uc_error("multiple control device names were found!"); + return NULL; + } + ctl_list = list_entry(pos, struct ctl_list, list); + } + + if (ctl_list == NULL) + return NULL; + + return strdup(ctl_list->ctl_id); +} + +static char *rval_card_name(snd_use_case_mgr_t *uc_mgr) +{ + if (uc_mgr->card_short_name) + return strdup(uc_mgr->card_short_name); + return NULL; +} + +static char *rval_card_longname(snd_use_case_mgr_t *uc_mgr) +{ + if (uc_mgr->card_long_name[0]) + return strdup(uc_mgr->card_long_name); + return NULL; +} + +static char *rval_env(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char *id) +{ + char *e; + + e = getenv(id); + if (e) + return strdup(e); + return NULL; +} + +#define MATCH_VARIABLE(name, id, fcn) \ + if (strncmp((name), (id), sizeof(id) - 1) == 0) { \ + rval = fcn(uc_mgr); \ + idsize = sizeof(id) - 1; \ + goto __rval; \ + } + +#define MATCH_VARIABLE2(name, id, fcn) \ + if (strncmp((name), (id), sizeof(id) - 1) == 0) { \ + idsize = sizeof(id) - 1; \ + tmp = strchr(value + idsize, '}'); \ + if (tmp) { \ + rvalsize = tmp - (value + idsize); \ + if (rvalsize > sizeof(v2)) { \ + err = -ENOMEM; \ + goto __error; \ + } \ + strncpy(v2, value + idsize, rvalsize); \ + v2[rvalsize] = '\0'; \ + idsize += rvalsize + 1; \ + rval = fcn(uc_mgr, v2); \ + goto __rval; \ + } \ + } + +static int get_substituted_value(snd_use_case_mgr_t *uc_mgr, + char **_rvalue, + const char *value) +{ + size_t size, nsize, idsize, rvalsize, dpos = 0; + const char *tmp; + char *r, *nr, *rval, v2[32]; + int err; + + if (value == NULL) + return -ENOENT; + + size = strlen(value) + 1; + r = malloc(size); + if (r == NULL) + return -ENOMEM; + + while (*value) { + if (*value == '$' && *(value+1) == '{') { + MATCH_VARIABLE(value, "${ConfName}", rval_conf_name); + MATCH_VARIABLE(value, "${CardId}", rval_card_id); + MATCH_VARIABLE(value, "${CardName}", rval_card_name); + MATCH_VARIABLE(value, "${CardLongName}", rval_card_longname); + MATCH_VARIABLE2(value, "${env:", rval_env); + err = -EINVAL; + tmp = strchr(value, '}'); + if (tmp) { + strncpy(r, value, tmp + 1 - value); + r[tmp + 1 - value] = '\0'; + uc_error("variable '%s' is not known!", r); + } else { + uc_error("variable reference '%s' is not complete", value); + } + goto __error; +__rval: + if (rval == NULL || rval[0] == '\0') { + free(rval); + strncpy(r, value, idsize); + r[idsize] = '\0'; + uc_error("variable '%s' is not defined in this context!", r); + err = -EINVAL; + goto __error; + } + value += idsize; + rvalsize = strlen(rval); + nsize = size + rvalsize - idsize; + if (nsize > size) { + nr = realloc(r, nsize); + if (nr == NULL) { + err = -ENOMEM; + goto __error; + } + size = nsize; + r = nr; + } + strcpy(r + dpos, rval); + dpos += rvalsize; + free(rval); + } else { + r[dpos++] = *value; + value++; + } + } + r[dpos] = '\0'; + + *_rvalue = r; + return 0; + +__error: + free(r); + return err; +} + +static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value, + struct list_head *value_list, const char *identifier) { struct ucm_value *val; struct list_head *pos; @@ -1361,18 +1510,22 @@ static int get_value1(char **value, struct list_head *value_list, return -ENOENT; list_for_each(pos, value_list) { - val = list_entry(pos, struct ucm_value, list); - if (check_identifier(identifier, val->name)) { - *value = strdup(val->data); - if (*value == NULL) - return -ENOMEM; - return 0; - } + val = list_entry(pos, struct ucm_value, list); + if (check_identifier(identifier, val->name)) { + if (uc_mgr->conf_format < 2) { + *value = strdup(val->data); + if (*value == NULL) + return -ENOMEM; + return 0; + } + return get_substituted_value(uc_mgr, value, val->data); + } } return -ENOENT; } -static int get_value3(char **value, +static int get_value3(snd_use_case_mgr_t *uc_mgr, + char **value, const char *identifier, struct list_head *value_list1, struct list_head *value_list2, @@ -1380,13 +1533,13 @@ static int get_value3(char **value, { int err; - err = get_value1(value, value_list1, identifier); + err = get_value1(uc_mgr, value, value_list1, identifier); if (err >= 0 || err != -ENOENT) return err; - err = get_value1(value, value_list2, identifier); + err = get_value1(uc_mgr, value, value_list2, identifier); if (err >= 0 || err != -ENOENT) return err; - err = get_value1(value, value_list3, identifier); + err = get_value1(uc_mgr, value, value_list3, identifier); if (err >= 0 || err != -ENOENT) return err; return -ENOENT; @@ -1423,7 +1576,7 @@ static int get_value(snd_use_case_mgr_t *uc_mgr, mod = find_modifier(uc_mgr, verb, mod_dev_name, 0); if (mod) { - err = get_value1(value, + err = get_value1(uc_mgr, value, &mod->value_list, identifier); if (err >= 0 || err != -ENOENT) @@ -1433,7 +1586,7 @@ static int get_value(snd_use_case_mgr_t *uc_mgr, dev = find_device(uc_mgr, verb, mod_dev_name, 0); if (dev) { - err = get_value1(value, + err = get_value1(uc_mgr, value, &dev->value_list, identifier); if (err >= 0 || err != -ENOENT) @@ -1444,7 +1597,7 @@ static int get_value(snd_use_case_mgr_t *uc_mgr, return -ENOENT; } - err = get_value1(value, &verb->value_list, identifier); + err = get_value1(uc_mgr, value, &verb->value_list, identifier); if (err >= 0 || err != -ENOENT) return err; } @@ -1453,7 +1606,7 @@ static int get_value(snd_use_case_mgr_t *uc_mgr, return -ENOENT; } - err = get_value1(value, &uc_mgr->value_list, identifier); + err = get_value1(uc_mgr, value, &uc_mgr->value_list, identifier); if (err >= 0 || err != -ENOENT) return err; diff --git a/src/ucm/parser.c b/src/ucm/parser.c index 04843197..3e50520d 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -1464,6 +1464,7 @@ static int get_card_long_name(snd_use_case_mgr_t *mgr) _long_name = snd_ctl_card_info_get_longname(info); if (!strcmp(card_name, _name) || !strcmp(card_name, _long_name)) { + snd_strlcpy(mgr->card_short_name, _name, sizeof(mgr->card_short_name)); snd_strlcpy(mgr->card_long_name, _long_name, sizeof(mgr->card_long_name)); return 0; } @@ -1495,6 +1496,7 @@ static int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name) _name = snd_ctl_card_info_get_name(info); _long_name = snd_ctl_card_info_get_longname(info); + snd_strlcpy(mgr->card_short_name, _name, sizeof(mgr->card_short_name)); snd_strlcpy(mgr->card_long_name, _long_name, sizeof(mgr->card_long_name)); snd_strlcpy(mgr->conf_file_name, _name, sizeof(mgr->conf_file_name)); diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h index 3da747e9..78ff2225 100644 --- a/src/ucm/ucm_local.h +++ b/src/ucm/ucm_local.h @@ -43,6 +43,7 @@ #define SYNTAX_VERSION_MAX 2 #define MAX_FILE 256 +#define MAX_CARD_SHORT_NAME 32 #define MAX_CARD_LONG_NAME 80 #define SEQUENCE_ELEMENT_TYPE_CDEV 1 @@ -204,6 +205,7 @@ struct use_case_verb { */ struct snd_use_case_mgr { char *card_name; + char card_short_name[MAX_CARD_SHORT_NAME]; char card_long_name[MAX_CARD_LONG_NAME]; char conf_file_name[MAX_CARD_LONG_NAME]; char *comment; -- 2.47.1