]> git.alsa-project.org Git - alsa-lib.git/commitdiff
ucm: configuration - allow to define the configuration variables
authorJaroslav Kysela <perex@perex.cz>
Wed, 20 May 2020 17:04:36 +0000 (19:04 +0200)
committerJaroslav Kysela <perex@perex.cz>
Mon, 25 May 2020 17:20:53 +0000 (19:20 +0200)
It may be useful for the library files to use the runtime configuration
variables.

Example:

 Define.Var1 "hw:${CardId},2"
 Value.PlaybackPCM "${var:Var1}"

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
src/ucm/main.c
src/ucm/parser.c
src/ucm/ucm_local.h
src/ucm/ucm_subs.c
src/ucm/utils.c

index 9c85462b869d94531c71f63f29419af3ae39c9db..4fdd9c70d6748d2136992294ade9103394fffad7 100644 (file)
@@ -966,6 +966,7 @@ int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr,
        INIT_LIST_HEAD(&mgr->active_modifiers);
        INIT_LIST_HEAD(&mgr->active_devices);
        INIT_LIST_HEAD(&mgr->ctl_list);
+       INIT_LIST_HEAD(&mgr->variable_list);
        pthread_mutex_init(&mgr->mutex, NULL);
 
        mgr->card_name = strdup(card_name);
index a6fa0d6c0aed7b33d333bc4af8277f7b00f18a18..7cc09379386e1630bd19f4fbd77052f8e561280f 100644 (file)
@@ -193,6 +193,49 @@ int parse_get_safe_id(snd_config_t *n, const char **id)
        return 0;
 }
 
+/*
+ * Evaluate variable definitions (in-place delete)
+ */
+static int evaluate_define(snd_use_case_mgr_t *uc_mgr,
+                          snd_config_t *cfg)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *d, *n;
+       const char *id;
+       char *var, *s;
+       int err;
+
+       err = snd_config_search(cfg, "Define", &d);
+       if (err == -ENOENT)
+               return 1;
+       if (err < 0)
+               return err;
+
+       if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
+               uc_error("compound type expected for Define");
+               return -EINVAL;
+       }
+
+       snd_config_for_each(i, next, d) {
+               n = snd_config_iterator_entry(i);
+               err = snd_config_get_id(n, &id);
+               if (err < 0)
+                       return err;
+               err = snd_config_get_ascii(n, &var);
+               if (err < 0)
+                       return err;
+               err = uc_mgr_get_substituted_value(uc_mgr, &s, var);
+               free(var);
+               if (err < 0)
+                       return err;
+               uc_mgr_set_variable(uc_mgr, id, s);
+               free(s);
+       }
+
+       snd_config_delete(d);
+       return 0;
+}
+
 /*
  * Evaluate include (in-place)
  */
@@ -239,16 +282,20 @@ static int evaluate_condition(snd_use_case_mgr_t *uc_mgr,
 int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
                            snd_config_t *cfg)
 {
-       int err1 = 0, err2 = 0;
+       int err1 = 0, err2 = 0, err3 = 0;
 
-       while (err1 == 0 || err2 == 0) {
-               /* include at first */
-               err1 = evaluate_include(uc_mgr, cfg);
+       while (err1 == 0 || err2 == 0 || err3 == 0) {
+               /* variables at first */
+               err1 = evaluate_define(uc_mgr, cfg);
                if (err1 < 0)
                        return err1;
-               err2 = evaluate_condition(uc_mgr, cfg);
+               /* include at second */
+               err2 = evaluate_include(uc_mgr, cfg);
                if (err2 < 0)
                        return err2;
+               err3 = evaluate_condition(uc_mgr, cfg);
+               if (err3 < 0)
+                       return err3;
        }
        return 0;
 }
index a9948704c7d03685b52b3f80f3832e354db03bfa..2aea43e47e089abb9106c3f6b60b71883329fad7 100644 (file)
@@ -239,6 +239,9 @@ struct snd_use_case_mgr {
        /* locking */
        pthread_mutex_t mutex;
 
+       /* UCM internal variables defined in configuration files */
+       struct list_head variable_list;
+
        /* list of opened control devices */
        struct list_head ctl_list;
 
@@ -289,6 +292,13 @@ void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr);
 
 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,
+                               const char *name);
+
+int uc_mgr_set_variable(snd_use_case_mgr_t *uc_mgr,
+                       const char *name,
+                       const char *val);
+
 int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr,
                                 char **_rvalue,
                                 const char *value);
index 944a8ceb02f499ea61b4de0a2c740c04510dcda5..9efa461fb3e146317c47faa03fba074259c9d751 100644 (file)
@@ -167,6 +167,21 @@ static char *rval_sysfs(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char
        return strdup(path);
 }
 
+static char *rval_var(snd_use_case_mgr_t *uc_mgr, const char *id)
+{
+       const char *v;
+
+       if (uc_mgr->conf_format < 3) {
+               uc_error("variable substitution is supported in v3+ syntax");
+               return NULL;
+       }
+
+       v = uc_mgr_get_variable(uc_mgr, id);
+       if (v)
+               return strdup(v);
+       return NULL;
+}
+
 #define MATCH_VARIABLE(name, id, fcn, empty_ok)                                \
        if (strncmp((name), (id), sizeof(id) - 1) == 0) {               \
                rval = fcn(uc_mgr);                                     \
@@ -224,6 +239,7 @@ int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr,
                        MATCH_VARIABLE(value, "${CardComponents}", rval_card_components, true);
                        MATCH_VARIABLE2(value, "${env:", rval_env);
                        MATCH_VARIABLE2(value, "${sys:", rval_sysfs);
+                       MATCH_VARIABLE2(value, "${var:", rval_var);
                        err = -EINVAL;
                        tmp = strchr(value, '}');
                        if (tmp) {
index 050ca4c0d90d94acb85ef52a64819ca0d564813e..77b9004393e8aac01c7cf50ba7b4991e43384bcc 100644 (file)
@@ -552,6 +552,56 @@ int uc_mgr_remove_device(struct use_case_verb *verb, const char *name)
        return found == 0 ? -ENODEV : 0;
 }
 
+const char *uc_mgr_get_variable(snd_use_case_mgr_t *uc_mgr, const char *name)
+{
+       struct list_head *pos;
+       struct ucm_value *value;
+
+       list_for_each(pos, &uc_mgr->variable_list) {
+               value = list_entry(pos, struct ucm_value, list);
+               if (strcmp(value->name, name) == 0)
+                       return value->data;
+       }
+       return NULL;
+}
+
+int uc_mgr_set_variable(snd_use_case_mgr_t *uc_mgr, const char *name,
+                       const char *val)
+{
+       struct list_head *pos;
+       struct ucm_value *curr;
+       char *val2;
+
+       list_for_each(pos, &uc_mgr->variable_list) {
+               curr = list_entry(pos, struct ucm_value, list);
+               if (strcmp(curr->name, name) == 0) {
+                       val2 = strdup(val);
+                       if (val2 == NULL)
+                               return -ENOMEM;
+                       free(curr->data);
+                       curr->data = val2;
+                       return 0;
+               }
+       }
+
+       curr = calloc(1, sizeof(struct ucm_value));
+       if (curr == NULL)
+               return -ENOMEM;
+       curr->name = strdup(name);
+       if (curr->name == NULL) {
+               free(curr);
+               return -ENOMEM;
+       }
+       curr->data = strdup(val);
+       if (curr->data == NULL) {
+               free(curr->name);
+               free(curr);
+               return -ENOMEM;
+       }
+       list_add_tail(&curr->list, &uc_mgr->variable_list);
+       return 0;
+}
+
 void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
 {
        struct list_head *pos, *npos;
@@ -576,6 +626,7 @@ void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
        uc_mgr_free_sequence(&uc_mgr->once_list);
        uc_mgr_free_sequence(&uc_mgr->default_list);
        uc_mgr_free_value(&uc_mgr->value_list);
+       uc_mgr_free_value(&uc_mgr->variable_list);
        free(uc_mgr->comment);
        free(uc_mgr->conf_dir_name);
        free(uc_mgr->conf_file_name);