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);
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)
*/
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;
}
/* 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;
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);
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); \
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) {
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;
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);