From ebdd2b6cdb8119cf75f0dd0a3b283d271b3a547e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sat, 30 Nov 2019 20:31:55 +0100 Subject: [PATCH 03/30] ucm: add _identifiers list Signed-off-by: Jaroslav Kysela --- include/use-case.h | 1 + src/ucm/main.c | 268 +++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 208 insertions(+), 61 deletions(-) diff --git a/include/use-case.h b/include/use-case.h index 8e7e838c9cb9..85c58ac0614a 100644 --- a/include/use-case.h +++ b/include/use-case.h @@ -206,6 +206,7 @@ int snd_use_case_free_list(const char *list[], int items); * - _enadevs - get list of enabled devices * - _enamods - get list of enabled modifiers * + * - _identifiers/{modifier}|{device}[/{verb}] - list of value identifiers * - _supporteddevs/{modifier}|{device}[/{verb}] - list of supported devices * - _conflictingdevs/{modifier}|{device}[/{verb}] - list of conflicting devices * diff --git a/src/ucm/main.c b/src/ucm/main.c index b80db65fa93b..d2078a2381d3 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -1072,7 +1072,6 @@ int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr) /** * \brief Get list of verbs in pair verbname+comment * \param list Returned list - * \param verbname For verb (NULL = current) * \return Number of list entries if success, otherwise a negative error code */ static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[]) @@ -1181,7 +1180,6 @@ static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr, } return -ENOENT; - } /** @@ -1210,41 +1208,201 @@ static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr, #ifndef DOC_HIDDEN struct myvalue { - struct list_head list; - char *value; + struct list_head list; + const char *text; }; #endif +/** + * \brief Convert myvalue list string list + * \param list myvalue list + * \param res string list + * \retval Number of list entries if success, otherwise a negativer error code + */ +static int myvalue_to_str_list(struct list_head *list, char ***res) +{ + struct list_head *pos; + struct myvalue *value; + char **p; + int cnt; + + cnt = alloc_str_list(list, 1, res); + if (cnt < 0) + return cnt; + p = *res; + list_for_each(pos, list) { + value = list_entry(pos, struct myvalue, list); + *p = strdup(value->text); + if (*p == NULL) { + snd_use_case_free_list((const char **)p, cnt); + return -ENOMEM; + } + p++; + } + return cnt; +} + +/** + * \brief Free myvalue list + * \param list myvalue list + */ +static void myvalue_list_free(struct list_head *list) +{ + struct list_head *pos, *npos; + struct myvalue *value; + + list_for_each_safe(pos, npos, list) { + value = list_entry(pos, struct myvalue, list); + list_del(&value->list); + free(value); + } +} + +/** + * \brief Merge one value to the myvalue list + * \param list The list with values + * \param value The value to be merged (without duplicates) + * \return 1 if dup, 0 if success, otherwise a negative error code + */ +static int merge_value(struct list_head *list, const char *text) +{ + struct list_head *pos; + struct myvalue *value; + + list_for_each(pos, list) { + value = list_entry(pos, struct myvalue, list); + if (strcmp(value->text, text) == 0) + return 1; + } + value = malloc(sizeof(*value)); + if (value == NULL) + return -ENOMEM; + value->text = text; + list_add_tail(&value->list, list); + return 0; +} + +/** + * \brief Find all values for given identifier + * \param list Returned list + * \param source Source list with ucm_value structures + * \return Zero if success, otherwise a negative error code + */ +static int add_identifiers(struct list_head *list, + struct list_head *source) +{ + struct ucm_value *v; + struct list_head *pos; + int err; + + list_for_each(pos, source) { + v = list_entry(pos, struct ucm_value, list); + err = merge_value(list, v->name); + if (err < 0) + return err; + } + return 0; +} + +/** + * \brief Find all values for given identifier + * \param list Returned list + * \param identifier Identifier + * \param source Source list with ucm_value structures + */ static int add_values(struct list_head *list, const char *identifier, struct list_head *source) { - struct ucm_value *v; - struct myvalue *val; - struct list_head *pos, *pos1; - int match; + struct ucm_value *v; + struct list_head *pos; + int err; - list_for_each(pos, source) { - v = list_entry(pos, struct ucm_value, list); - if (check_identifier(identifier, v->name)) { - match = 0; - list_for_each(pos1, list) { - val = list_entry(pos1, struct myvalue, list); - if (strcmp(val->value, v->data) == 0) { - match = 1; - break; - } - } - if (!match) { - val = malloc(sizeof(struct myvalue)); - if (val == NULL) - return -ENOMEM; - val->value = v->data; - list_add_tail(&val->list, list); - } - } - } - return 0; + list_for_each(pos, source) { + v = list_entry(pos, struct ucm_value, list); + if (check_identifier(identifier, v->name)) { + err = merge_value(list, v->data); + if (err < 0) + return err; + } + } + return 0; +} + +/** + * \brief compare two identifiers + */ +static int identifier_cmp(const void *_a, const void *_b) +{ + const char * const *a = _a; + const char * const *b = _b; + return strcmp(*a, *b); +} + +/** + * \brief Get list of available identifiers + * \param list Returned list + * \param name Name of verb or modifier to query + * \return Number of list entries if success, otherwise a negative error code + */ +static int get_identifiers_list(snd_use_case_mgr_t *uc_mgr, + const char **list[], char *name) +{ + struct use_case_verb *verb; + struct use_case_modifier *modifier; + struct use_case_device *device; + struct list_head mylist; + struct list_head *value_list; + char *str, **res; + int err; + + if (!name) + return -ENOENT; + + str = strchr(name, '/'); + if (str) { + *str = '\0'; + verb = find_verb(uc_mgr, str + 1); + } + else { + verb = uc_mgr->active_verb; + } + if (!verb) + return -ENOENT; + + value_list = NULL; + modifier = find_modifier(uc_mgr, verb, name, 0); + if (modifier) { + value_list = &modifier->value_list; + } else { + device = find_device(uc_mgr, verb, name, 0); + if (device) + value_list = &device->value_list; + } + if (value_list == NULL) + return -ENOENT; + + INIT_LIST_HEAD(&mylist); + err = add_identifiers(&mylist, &uc_mgr->value_list); + if (err < 0) + goto __fail; + err = add_identifiers(&mylist, &verb->value_list); + if (err < 0) + goto __fail; + err = add_identifiers(&mylist, value_list); + if (err < 0) + goto __fail; + err = myvalue_to_str_list(&mylist, &res); + if (err > 0) + *list = (const char **)res; + else if (err == 0) + *list = NULL; +__fail: + myvalue_list_free(&mylist); + if (err <= 0) + return err; + qsort(*list, err, sizeof(char *), identifier_cmp); + return err; } /** @@ -1258,8 +1416,7 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr, const char **list[], char *verbname) { - struct list_head mylist, *pos, *npos; - struct myvalue *val; + struct list_head mylist, *pos; struct use_case_verb *verb; struct use_case_device *dev; struct use_case_modifier *mod; @@ -1292,26 +1449,13 @@ static int get_value_list(snd_use_case_mgr_t *uc_mgr, if (err < 0) goto __fail; } - err = alloc_str_list(&mylist, 1, &res); - if (err >= 0) { + err = myvalue_to_str_list(&mylist, &res); + if (err > 0) *list = (const char **)res; - list_for_each(pos, &mylist) { - val = list_entry(pos, struct myvalue, list); - *res = strdup(val->value); - if (*res == NULL) { - snd_use_case_free_list((const char **)res, err); - err = -ENOMEM; - goto __fail; - } - res++; - } - } + else if (err == 0) + *list = NULL; __fail: - list_for_each_safe(pos, npos, &mylist) { - val = list_entry(pos, struct myvalue, list); - list_del(&val->list); - free(val); - } + myvalue_list_free(&mylist); return err; } @@ -1381,21 +1525,23 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, } else { str = NULL; } - if (check_identifier(identifier, "_devices")) - err = get_device_list(uc_mgr, list, str); + if (check_identifier(identifier, "_devices")) + err = get_device_list(uc_mgr, list, str); else if (check_identifier(identifier, "_modifiers")) - err = get_modifier_list(uc_mgr, list, str); - else if (check_identifier(identifier, "_supporteddevs")) - err = get_supported_device_list(uc_mgr, list, str); - else if (check_identifier(identifier, "_conflictingdevs")) - err = get_conflicting_device_list(uc_mgr, list, str); + err = get_modifier_list(uc_mgr, list, str); + else if (check_identifier(identifier, "_identifiers")) + err = get_identifiers_list(uc_mgr, list, str); + else if (check_identifier(identifier, "_supporteddevs")) + err = get_supported_device_list(uc_mgr, list, str); + else if (check_identifier(identifier, "_conflictingdevs")) + err = get_conflicting_device_list(uc_mgr, list, str); else if (identifier[0] == '_') err = -ENOENT; - else - err = get_value_list(uc_mgr, identifier, list, str); - if (str) - free(str); - } + else + err = get_value_list(uc_mgr, identifier, list, str); + if (str) + free(str); + } __end: pthread_mutex_unlock(&uc_mgr->mutex); return err; -- 2.16.4