From: Jaroslav Kysela Date: Wed, 13 Jun 2001 09:31:05 +0000 (+0000) Subject: Enhanced configuration syntax (added [ ] block for arrays). X-Git-Tag: android-x86-9.0-r1~2870 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=5c3075d32febcd03ce8b76f7aab8dbf78b3329fd;p=android-x86%2Fexternal-alsa-lib.git Enhanced configuration syntax (added [ ] block for arrays). The snd_config_expand functions expands the runtime contents (@func...). Removed the environment variable replace code from the configuration parser. Updated the alsa.conf configuration file. --- diff --git a/include/conf.h b/include/conf.h index 43b93e9a..1c5e91a6 100644 --- a/include/conf.h +++ b/include/conf.h @@ -39,7 +39,7 @@ int snd_config_search_alias(snd_config_t *config, snd_config_t **result); int snd_config_expand(snd_config_t *config, const char *args, - snd_config_t **result); + void *private_data, snd_config_t **result); int snd_config_add(snd_config_t *config, snd_config_t *leaf); int snd_config_delete(snd_config_t *config); @@ -96,11 +96,12 @@ int snd_config_string_replace(const char *src, char idchr, snd_config_string_replace_callback_t *callback, void *private_data, char **dst); -int snd_config_redirect_load(snd_config_t *root, snd_config_t *config, - char **name, snd_config_t **dst_config, +int snd_config_redirect_load(snd_config_t *root, + snd_config_t *config, + char **name, + snd_config_t **dst_config, int *dst_dynamic); - #ifdef __cplusplus } #endif diff --git a/src/alsa.conf b/src/alsa.conf index 52219200..fd74e10e 100644 --- a/src/alsa.conf +++ b/src/alsa.conf @@ -6,22 +6,36 @@ pcm.default { type plug slave.pcm { type hw - card <@ALSA_PCM_CARD,ALSA_CARD:0@> - device <@ALSA_PCM_DEVICE:0@> + card { + @func getenv + @type integer + envname [ + ALSA_PCM_CARD + ALSA_CARD + ] + default 0 + } + device { + @func getenv + @type integer + envname [ + ALSA_PCM_DEVICE + ] + default 0 + } + subdevice -1 } } pcm.hw { - $.0 CARD - $.1 DEV - $.2 SUBDEV - $.CARD { + args [ CARD DEV SUBDEV ] + args.CARD { type integer } - $.DEV { + args.DEV { type integer } - $.SUBDEV { + args.SUBDEV { type integer default -1 } @@ -32,16 +46,14 @@ pcm.hw { } pcm.plughw { - $.0 CARD - $.1 DEV - $.2 SUBDEV - $.CARD { + args [ CARD DEV SUBDEV ] + args.CARD { type integer } - $.DEV { + args.DEV { type integer } - $.SUBDEV { + args.SUBDEV { type integer default -1 } @@ -55,8 +67,8 @@ pcm.plughw { } pcm.plug { - $.0 SLAVE - $.SLAVE { + args [ SLAVE ] + args.SLAVE { type string } type plug @@ -64,12 +76,11 @@ pcm.plug { } pcm.shm { - $.0 SOCKET - $.1 PCM - $.SOCKET { + args [ SOCKET PCM ] + args.SOCKET { type string } - $.PCM { + args.PCM { type string } type shm @@ -78,16 +89,14 @@ pcm.shm { } pcm.tee { - $.0 SLAVE - $.1 FILE - $.2 FORMAT - $.SLAVE { + args [ SLAVE FILE FORMAT ] + args.SLAVE { type string } - $.FILE { + args.FILE { type string } - $.FORMAT { + args.FORMAT { type string default raw } @@ -98,12 +107,11 @@ pcm.tee { } pcm.file { - $.0 FILE - $.1 FORMAT - $.FILE { + args [ FILE FORMAT ] + args.FILE { type string } - $.FORMAT { + args.FORMAT { type string default raw } @@ -114,47 +122,77 @@ pcm.file { } pcm.surround40 { - $.0 CARD - $.1 DEV - $.CARD { - type integer - default <@ALSA_SURROUND40_CARD,ALSA_PCM_CARD,ALSA_CARD:0@> - } - $.DEV { - type integer - default <@ALSA_SURROUND40_DEVICE:0@> - } - type surround - card $(CARD) - device $(DEVICE) - stype "4.0" -} - -pcm.surround40_new { - $.0 CARD - $.1 DEV - $.CARD { + args [ CARD DEV ] + args.CARD { type integer - default <@ALSA_SURROUND40_CARD,ALSA_PCM_CARD,ALSA_CARD:0@> + default { + @func getenv + @type integer + envname [ + ALSA_SURROUND40_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default 0 + } } - $.DEV { + args.DEV { type integer - default <@ALSA_SURROUND40_DEVICE:0@> + default { + @func getenv + @type integer + envname [ + ALSA_SURROUND40_DEVICE + ] + default 0 + } } redirect { - filename "&(datadir)/cards/&(card_id:$(CARD)).conf" - name "pcm.surround40_$(DEV)_&(pcm_id:$(CARD),$(DEV)):$(CARD)" + filename { + @func concat + strings [ + { + @func datadir + } + "/cards/" + { + @func card_strtype + card $(CARD) + } + ".conf" + ] + } + name { + @func concat + strings [ + "pcm.surround40_" $(DEV) "_" + { + @func pcm_id + card $(CARD) + device 0 + } + ":" $(CARD) + ] + } } } pcm.surround51 { - $.0 CARD - $.1 DEV - $.CARD { + args [ CARD DEV ] + args.CARD { type integer - default <@ALSA_SURROUND51_CARD,ALSA_PCM_CARD,ALSA_CARD:0@> + default { + @func getenv + @type integer + envname [ + ALSA_SURROUND51_CARD + ALSA_PCM_CARD + ALSA_CARD + ] + default 0 + } } - $.DEV { + args.DEV { type integer default <@ALSA_SURROUND51_DEVICE:0@> } @@ -174,8 +212,8 @@ ctl.default { } ctl.hw { - $.0 CARD - $.CARD { + args[ CARD ] + args.CARD { type integer } type hw @@ -183,39 +221,51 @@ ctl.hw { } ctl.shm { - $.0 SOCKET - $.1 PCM - $.SOCKET { + args [ SOCKET CTL ] + args.SOCKET { type string } - $.PCM { + args.CTL { type string } type shm server $(SOCKET) - ctl $(PCM) + ctl $(CTL) } rawmidi.default { type hw - card <@ALSA_RAWMIDI_CARD,ALSA_CARD:0@> - device <@ALSA_RAWMIDI_DEVICE:0@> + card { + @func getenv + @type integer + envname [ + ALSA_RAWMIDI_CARD + ALSA_CARD + ] + default 0 + } + device { + @func getenv + @type integer + envname [ + ALSA_RAWMIDI_DEVICE + ] + default 0 + } } rawmidi.hw { - $.0 CARD - $.1 DEV - $.2 SUBDEV - $.CARD { + args [ CARD DEV SUBDEV ] + args.CARD { type integer } - $.DEV { + args.DEV { type integer } - $.SUBDEV { + args.SUBDEV { type integer default -1 - } + } type hw card $(CARD) device $(DEV) @@ -231,46 +281,44 @@ seq.hw { } pcm.iec958 { - $.0 PCM - $.1 AES0 - $.2 AES1 - $.3 AES2 - $.4 AES3 - $.PCM { + args [ PCM AES0 AES1 AES2 AES3 ] + args.PCM { type string default default } - $.AES0 { + args.AES0 { type integer # IEC958_AES0_PROFESSIONAL | IEC958_AES0_NONAUDIO | # IEC958_AES0_PRO_EMPHASIS_NONE | IEC958_AES0_PRO_FS_48000 default 0x87 } - $.AES1 { + args.AES1 { type integer default 0x00 } - $.AES2 { + args.AES2 { type integer default 0x00 } - $.AES3 { + args.AES3 { type integer default 0x00 } type hooks slave.pcm $(PCM) - hooks.0 { - type ctl_elems - args.0 { - name "IEC958 Playback PCM Stream" - subdevice 0 - preserve true - lock true - value.0 $(AES0) - value.1 $(AES1) - value.2 $(AES2) - value.3 $(AES3) + hooks [ + { + type ctl_elems + args [ + name "IEC958 Playback PCM Stream" + subdevice 0 + preserve true + lock true + value.0 $(AES0) + value.1 $(AES1) + value.2 $(AES2) + value.3 $(AES3) + ] } - } + ] } diff --git a/src/cards/SI_7018.conf b/src/cards/SI_7018.conf index b115f5b9..d22942ad 100644 --- a/src/cards/SI_7018.conf +++ b/src/cards/SI_7018.conf @@ -3,16 +3,14 @@ # pcm.front { - $.0 CARD - $.1 DEV - $.2 SUBDEV - $.CARD { + args [ CARD DEV SUBDEV ] + args.CARD { type integer } - $.DEV { + args.DEV { type integer } - $.SUBDEV { + args.SUBDEV { type integer default -1 } @@ -28,16 +26,14 @@ pcm_slave.front { } pcm.rear { - $.0 CARD - $.1 DEV - $.2 SUBDEV - $.CARD { + args [ CARD DEV SUBDEV ] + args.CARD { type integer } - $.DEV { + args.DEV { type integer } - $.SUBDEV { + args.SUBDEV { type integer default -1 } @@ -53,19 +49,29 @@ pcm_slave.rear { } pcm.surround40_0_trident_dx_nx { - $.0 CARD - $.CARD { + args [ CARD ] + args.CARD { type integer } type multi - slaves { - 0 "pcm_slave.front:$(CARD),0,-1" - 1 "pcm_slave.rear:$(CARD),0,-1" - } - bindings { - 0 { slave 0 channel 0 } - 1 { slave 0 channel 1 } - 2 { slave 1 channel 0 } - 3 { slave 1 channel 1 } - } + slaves [ + { + @func concat + strings [ + "pcm_slave.front:" $(CARD) ",0,-1" + ] + } + { + @func concat + strings [ + "pcm_slave.rear:" $(CARD) ",0,-1" + ] + } + ] + bindings [ + { slave 0 channel 0 } + { slave 0 channel 1 } + { slave 1 channel 0 } + { slave 1 channel 1 } + ] } diff --git a/src/conf.c b/src/conf.c index a5885ae6..8d8bc1f3 100644 --- a/src/conf.c +++ b/src/conf.c @@ -1,6 +1,7 @@ /* * Configuration helper functions - * Copyright (c) 2000 by Abramo Bagnara + * Copyright (c) 2000 by Abramo Bagnara , + * Jaroslav Kysela * * * This library is free software; you can redistribute it and/or modify @@ -22,6 +23,7 @@ #include #include #include +#include #include "local.h" #include "list.h" @@ -151,44 +153,9 @@ static int get_char_skip_comments(input_t *input) int err = get_delimstring(&str, '>', input); if (err < 0) return err; - if (strlen(str) < 3 || - str[0] != '@' || - str[strlen(str)-1] != '@' || - strchr(str, ':') == NULL) { - err = snd_input_stdio_open(&in, str, "r"); - if (err < 0) - return err; - } else { - char *envvar = str + 1; - char *envdef = strchr(str, ':'); - char *env, *end; - - str[strlen(str)-1] = '\0'; - *envdef++ = '\0'; - if (*envdef == '\0') { - free(str); - input->error = BAD_ENV_DEFAULT; - return -EINVAL; - } - while (1) { - end = strchr(envvar, ','); - if (end) - *end = '\0'; - env = getenv(envvar); - if (env != NULL && *env != '\0') - break; - if (end) { - *end = ','; /* repair for fd->name */ - envvar = end + 1; - } else { - env = envdef; - break; - } - } - err = snd_input_buffer_open(&in, env, strlen(env)); - if (err < 0) - return err; - } + err = snd_input_stdio_open(&in, str, "r"); + if (err < 0) + return err; fd = malloc(sizeof(*fd)); if (!fd) return -ENOMEM; @@ -272,7 +239,7 @@ static int get_quotedchar(input_t *input) static int get_freestring(char **string, int id, input_t *input) { - const size_t bufsize = 256; + const size_t bufsize = 64; char _buf[bufsize]; char *buf = _buf; size_t alloc = bufsize; @@ -295,6 +262,8 @@ static int get_freestring(char **string, int id, input_t *input) case ';': case '{': case '}': + case '[': + case ']': case '\'': case '"': case '\\': @@ -319,11 +288,17 @@ static int get_freestring(char **string, int id, input_t *input) alloc *= 2; if (old_alloc == bufsize) { buf = malloc(alloc); + if (buf == NULL) + return -ENOMEM; memcpy(buf, _buf, old_alloc); - } else - buf = realloc(buf, alloc); - if (!buf) - return -ENOMEM; + } else { + char *ptr = realloc(buf, alloc); + if (ptr == NULL) { + free(buf); + return -ENOMEM; + } + buf = ptr; + } } buf[idx++] = c; } @@ -332,7 +307,7 @@ static int get_freestring(char **string, int id, input_t *input) static int get_delimstring(char **string, int delim, input_t *input) { - const size_t bufsize = 256; + const size_t bufsize = 64; char _buf[bufsize]; char *buf = _buf; size_t alloc = bufsize; @@ -369,11 +344,17 @@ static int get_delimstring(char **string, int delim, input_t *input) alloc *= 2; if (old_alloc == bufsize) { buf = malloc(alloc); + if (buf == NULL) + return -ENOMEM; memcpy(buf, _buf, old_alloc); - } else - buf = realloc(buf, alloc); - if (!buf) - return -ENOMEM; + } else { + char *ptr = realloc(buf, alloc); + if (ptr == NULL) { + free(buf); + return -ENOMEM; + } + buf = ptr; + } } buf[idx++] = c; } @@ -394,6 +375,8 @@ static int get_string(char **string, int id, input_t *input) case '.': case '{': case '}': + case '[': + case ']': input->error = UNEXPECTED_CHAR; return -EINVAL; case '\'': @@ -411,17 +394,21 @@ static int get_string(char **string, int id, input_t *input) } } -static int _snd_config_make(snd_config_t **config, char *id, - snd_config_type_t type) +static int _snd_config_make(snd_config_t **config, char **id, snd_config_type_t type) { snd_config_t *n; n = calloc(1, sizeof(*n)); if (n == NULL) { - if (id) - free(id); + if (*id) { + free(*id); + *id = NULL; + } return -ENOMEM; } - n->id = id; + if (id) { + n->id = *id; + *id = NULL; + } n->type = type; if (type == SND_CONFIG_TYPE_COMPOUND) INIT_LIST_HEAD(&n->u.compound.fields); @@ -430,7 +417,7 @@ static int _snd_config_make(snd_config_t **config, char *id, } -static int _snd_config_make_add(snd_config_t **config, char *id, +static int _snd_config_make_add(snd_config_t **config, char **id, snd_config_type_t type, snd_config_t *father) { snd_config_t *n; @@ -457,38 +444,182 @@ static int _snd_config_search(snd_config_t *config, } else if (strlen(n->id) != (size_t) len || memcmp(n->id, id, (size_t) len) != 0) continue; - *result = n; + if (result) + *result = n; return 0; } return -ENOENT; } +static int parse_value(snd_config_t **_n, snd_config_t *father, input_t *input, char **id) +{ + snd_config_t *n = *_n; + char *s; + int err; + + err = get_string(&s, 0, input); + if (err < 0) + return err; + if ((s[0] >= '0' && s[0] <= '9') || s[0] == '-') { + long i; + errno = 0; + err = safe_strtol(s, &i); + if (err < 0) { + double r; + err = safe_strtod(s, &r); + if (err >= 0) { + free(s); + if (n) { + if (n->type != SND_CONFIG_TYPE_REAL) { + SNDERR("%s is not a real", id); + return -EINVAL; + } + } else { + err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_REAL, father); + if (err < 0) + return err; + } + n->u.real = r; + *_n = n; + return 0; + } + } else { + free(s); + if (n) { + if (n->type != SND_CONFIG_TYPE_INTEGER) { + SNDERR("%s is not an integer", id); + return -EINVAL; + } + } else { + err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER, father); + if (err < 0) + return err; + } + n->u.integer = i; + *_n = n; + return 0; + } + } + if (n) { + if (n->type != SND_CONFIG_TYPE_STRING) { + SNDERR("%s is not a string", id); + free(s); + return -EINVAL; + } + } else { + err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_STRING, father); + if (err < 0) + return err; + } + if (n->u.string) + free(n->u.string); + n->u.string = s; + *_n = n; + return 0; +} + static int parse_defs(snd_config_t *father, input_t *input); +static int parse_array_defs(snd_config_t *farther, input_t *input); + +static int parse_array_def(snd_config_t *father, input_t *input, int idx) +{ + char static_id[12], *id; + int c; + int err; + snd_config_t *n = NULL; + + snprintf(static_id, sizeof(static_id), "%i", idx); + static_id[sizeof(static_id)-1] = '\0'; + id = strdup(static_id); + if (id == NULL) + return -ENOMEM; + c = get_nonwhite(input); + switch (c) { + case '{': + case '[': + { + char endchr; + if (n) { + if (n->type != SND_CONFIG_TYPE_COMPOUND) { + SNDERR("%s is not a compound", id); + err = -EINVAL; + goto __end; + } + } else { + err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father); + if (err < 0) + goto __end; + } + if (c == '{') { + err = parse_defs(n, input); + endchr = '}'; + } else { + err = parse_array_defs(n, input); + endchr = ']'; + } + c = get_nonwhite(input); + if (c != endchr) { + snd_config_delete(n); + input->error = (c == EOF ? UNEXPECTED_EOF : UNEXPECTED_CHAR); + err = -EINVAL; + goto __end; + } + break; + } + default: + unget_char(c, input); + err = parse_value(&n, father, input, &id); + if (err < 0) + goto __end; + break; + } + err = 0; + __end: + if (id) + free(id); + return err; +} + +static int parse_array_defs(snd_config_t *father, input_t *input) +{ + int idx = 0; + while (1) { + int c = get_nonwhite(input); + int err; + if (c == EOF) + return 0; + unget_char(c, input); + if (c == ']') + return 0; + err = parse_array_def(father, input, idx++); + if (err < 0) + return err; + } + return 0; +} static int parse_def(snd_config_t *father, input_t *input) { - char *id; + char *id = NULL; int c; int err; snd_config_t *n; enum {MERGE, NOCREATE, REMOVE} mode; while (1) { -#if 0 c = get_nonwhite(input); switch (c) { +#if 0 case '?': mode = NOCREATE; break; case '!': mode = REMOVE; break; +#endif default: mode = MERGE; unget_char(c, input); } -#else - mode = MERGE; -#endif err = get_string(&id, 1, input); if (err < 0) return err; @@ -510,12 +641,12 @@ static int parse_def(snd_config_t *father, input_t *input) } if (mode == NOCREATE) { SNDERR("%s does not exists", id); - free(id); - return -ENOENT; + err = -ENOENT; + goto __end; } - err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_COMPOUND, father); + err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father); if (err < 0) - return err; + goto __end; n->u.compound.join = 1; father = n; } @@ -526,104 +657,52 @@ static int parse_def(snd_config_t *father, input_t *input) snd_config_delete(n); n = NULL; } - else - free(id); } else { n = NULL; if (mode == NOCREATE) { SNDERR("%s does not exists", id); - free(id); - return -ENOENT; + err = -ENOENT; + goto __end; } } switch (c) { case '{': + case '[': { + char endchr; if (n) { if (n->type != SND_CONFIG_TYPE_COMPOUND) { SNDERR("%s is not a compound", id); - return -EINVAL; + err = -EINVAL; + goto __end; } } else { - err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_COMPOUND, father); + err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father); if (err < 0) - return err; + goto __end; } - err = parse_defs(n, input); - if (err < 0) { - snd_config_delete(n); - return err; + if (c == '{') { + err = parse_defs(n, input); + endchr = '}'; + } else { + err = parse_array_defs(n, input); + endchr = ']'; } c = get_nonwhite(input); - if (c != '}') { + if (c != endchr) { snd_config_delete(n); input->error = (c == EOF ? UNEXPECTED_EOF : UNEXPECTED_CHAR); - return -EINVAL; + err = -EINVAL; + goto __end; } break; } default: - { - char *s; unget_char(c, input); - err = get_string(&s, 0, input); + err = parse_value(&n, father, input, &id); if (err < 0) - return err; - if (!err && ((s[0] >= '0' && s[0] <= '9') || s[0] == '-')) { - char *ptr; - long i; - errno = 0; - i = strtol(s, &ptr, 0); - if (*ptr == '.' || errno != 0) { - double r; - errno = 0; - r = strtod(s, &ptr); - if (errno == 0) { - free(s); - if (n) { - if (n->type != SND_CONFIG_TYPE_REAL) { - SNDERR("%s is not a real", id); - return -EINVAL; - } - } else { - err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_REAL, father); - if (err < 0) - return err; - } - n->u.real = r; - break; - } - } else if (*ptr == '\0') { - free(s); - if (n) { - if (n->type != SND_CONFIG_TYPE_INTEGER) { - SNDERR("%s is not an integer", id); - return -EINVAL; - } - } else { - err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER, father); - if (err < 0) - return err; - } - n->u.integer = i; - break; - } - } - if (n) { - if (n->type != SND_CONFIG_TYPE_STRING) { - SNDERR("%s is not a string", id); - free(s); - return -EINVAL; - } - } else { - err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_STRING, father); - if (err < 0) - return err; - } - if (n->u.string) - free(n->u.string); - n->u.string = s; - } + goto __end; + break; } c = get_nonwhite(input); switch (c) { @@ -633,6 +712,9 @@ static int parse_def(snd_config_t *father, input_t *input) default: unget_char(c, input); } + __end: + if (id) + free(id); return err; } @@ -821,6 +903,33 @@ static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsi /** + * \brief Return type of a config node from an ASCII string + * \param config Config node handle + * \return node type + */ +int snd_config_get_type_ascii(const char *ascii, snd_config_type_t *type) +{ + assert(ascii && type); + if (!strcmp(ascii, "integer")) { + *type = SND_CONFIG_TYPE_INTEGER; + return 0; + } + if (!strcmp(ascii, "real")) { + *type = SND_CONFIG_TYPE_REAL; + return 0; + } + if (!strcmp(ascii, "string")) { + *type = SND_CONFIG_TYPE_STRING; + return 0; + } + if (!strcmp(ascii, "compound")) { + *type = SND_CONFIG_TYPE_COMPOUND; + return 0; + } + return -EINVAL; +} + +/** * \brief Return type of a config node * \param config Config node handle * \return node type @@ -1012,7 +1121,7 @@ int snd_config_make(snd_config_t **config, const char *id, return -ENOMEM; } else id1 = NULL; - return _snd_config_make(config, id1, type); + return _snd_config_make(config, &id1, type); } /** @@ -1233,6 +1342,15 @@ int snd_config_get_ascii(snd_config_t *config, char **ascii) assert(0); return -ENOMEM; } + if (res[0]) { /* trim the string */ + char *ptr; + ptr = res + strlen(res) - 1; + while (ptr != res && *ptr == ' ') + ptr--; + if (*ptr != ' ') + ptr++; + *ptr = '\0'; + } *ascii = strdup(res); } break; @@ -1268,7 +1386,7 @@ int snd_config_save(snd_config_t *config, snd_output_t *out) */ int snd_config_search(snd_config_t *config, const char *key, snd_config_t **result) { - assert(config && key && result); + assert(config && key); while (1) { snd_config_t *n; int err; @@ -1544,7 +1662,8 @@ typedef enum _snd_config_walk_pass { } snd_config_walk_pass_t; -/* Return 1 if node need to be attached to father */ +/* Return 1 if node needs to be attached to father */ +/* Return 2 if compound is replaced with standard node */ typedef int (*snd_config_walk_callback_t)(snd_config_t *src, snd_config_t **dst, snd_config_walk_pass_t pass, @@ -1656,86 +1775,6 @@ int snd_config_copy(snd_config_t **dst, return snd_config_walk(src, dst, _snd_config_copy, NULL); } -/** - * \brief Expand the dynamic contents - * \param src Source string - * \param idchr Identification character - * \param callback Callback function - * \param private_data Private data for the given callback function - * \param dst Destination string - */ -int snd_config_string_replace(const char *src, char idchr, - snd_config_string_replace_callback_t *callback, - void *private_data, - char **dst) -{ - int len = 0, len1, err; - const char *ptr, *end; - char *tmp, *what, *fptr, *rdst = NULL; - - assert(src && idchr && dst); - while (*src != '\0') { - ptr = strchr(src, idchr); - end = NULL; - if (ptr == src && *(ptr + 1) == '(' && (end = strchr(ptr + 2, ')')) != NULL) { - src = end + 1; - if (callback == NULL) - continue; - len1 = end - (ptr + 2); - if (len1 == 0) /* empty */ - continue; - what = malloc(len1 + 1); - memcpy(what, ptr + 2, len1); - what[len1] = '\0'; - fptr = NULL; - err = callback(what, &fptr, private_data); - free(what); - if (err < 0) { - if (*dst != NULL) - free(*dst); - return err; - } - if (fptr == NULL) /* empty */ - continue; - len1 = strlen(ptr = fptr); - } else { - if (ptr == NULL) { - len1 = strlen(ptr = src); - } else { - len1 = ptr - src; - ptr = src; - } - src += len1; - fptr = NULL; - } - tmp = realloc(rdst, len + len1 + 1); - if (tmp == NULL) { - if (*dst != NULL) - free(*dst); - return -ENOMEM; - } - memcpy(tmp + len, ptr, len1); - tmp[len+=len1] = '\0'; - if (fptr) - free(fptr); - rdst = tmp; - } - *dst = rdst; - return 0; -} - -static int _snd_config_expand_replace(const char *what, char **dst, void *private_data) -{ - snd_config_t *vars = private_data; - snd_config_t *val; - - assert(dst); - if (snd_config_search(vars, what, &val) < 0) - return 0; /* empty */ - else - return snd_config_get_ascii(val, dst); -} - static int _snd_config_expand(snd_config_t *src, snd_config_t **dst, snd_config_walk_pass_t pass, @@ -1746,12 +1785,14 @@ static int _snd_config_expand(snd_config_t *src, snd_config_type_t type = snd_config_get_type(src); switch (pass) { case SND_CONFIG_WALK_PASS_PRE: - if (strcmp(id, "$") == 0) + { + if (strcmp(id, "args") == 0) return 0; err = snd_config_make_compound(dst, id, src->u.compound.join); if (err < 0) return err; break; + } case SND_CONFIG_WALK_PASS_LEAF: switch (type) { case SND_CONFIG_TYPE_INTEGER: @@ -1781,11 +1822,12 @@ static int _snd_config_expand(snd_config_t *src, const char *s; snd_config_t *val; snd_config_t *vars = private_data; - err = snd_config_get_string(src, &s); - if (strncmp(s, "$(", 2) == 0 && s[strlen(s) - 1] == ')') { - char *str = alloca((strlen(s) - 3) + 1); - memcpy(str, s + 2, strlen(s) - 3); - str[strlen(s) - 3] = 0; + snd_config_get_string(src, &s); + if (strncmp(s, "$(", 2) == 0 && s[strlen(s) - 1] == ')') { + int len = strlen(s) - 3; + char *str = alloca(len + 1); + memcpy(str, s + 2, len); + str[len] = '\0'; if (snd_config_search(vars, str, &val) < 0) return 0; err = snd_config_copy(dst, val); @@ -1800,22 +1842,10 @@ static int _snd_config_expand(snd_config_t *src, err = snd_config_make(dst, id, type); if (err < 0) return err; - if (strstr(s, "$(") != NULL) { - char *str = NULL; - err = snd_config_string_replace(s, '$', _snd_config_expand_replace, vars, &str); - if (err < 0) - return err; - if (str == NULL) { - snd_config_delete(*dst); - return 0; - } - (*dst)->u.string = str; - } else { - err = snd_config_set_string(*dst, s); - if (err < 0) { - snd_config_delete(*dst); - return err; - } + err = snd_config_set_string(*dst, s); + if (err < 0) { + snd_config_delete(*dst); + return err; } } break; @@ -1830,6 +1860,181 @@ static int _snd_config_expand(snd_config_t *src, return 1; } +static int evaluate_node(snd_config_t *father, snd_config_t *src, + void *private_data, snd_config_t **_dst) +{ + snd_config_iterator_t i, next; + const char *lib = NULL, *func = NULL, *type = NULL; + int err; + + assert(father && src && _dst); + + snd_config_for_each(i, next, src) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id; + if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND) { + snd_config_t *n1; + err = evaluate_node(src, n, private_data, &n1); + if (err < 0) { + SNDERR("Error in node %s", snd_config_get_id(n)); + goto __error; + } + if (n1) { /* replace node */ + snd_config_delete(n); + err = snd_config_add(src, n1); + if (err < 0) + goto __error; + } + } + id = snd_config_get_id(n); + if (*id++ != '@') /* quick look */ + continue; + if (!strcmp(id, "lib")) { + if ((err = snd_config_get_string(n, &lib)) < 0) { + _invalid_field: + SNDERR("Unknown type of field %s", id); + return err; + } + lib = strdup(lib); + if (lib == NULL) + goto __error; + snd_config_delete(n); + } else if (!strcmp(id, "func")) { + if ((err = snd_config_get_string(n, &func)) < 0) + goto _invalid_field; + func = strdup(func); + if (func == NULL) + goto __error; + snd_config_delete(n); + } else if (!strcmp(id, "type")) { + if ((err = snd_config_get_string(n, &type)) < 0) + goto _invalid_field; + type = strdup(type); + if (type == NULL) + goto __error; + snd_config_delete(n); + } + } + + if (func == NULL) { + *_dst = NULL; + return 0; + } + + { + char buf[64], *ptr; + snd_config_type_t t; + snd_config_t *dst = NULL; + char *evaluate_name = NULL; + int (*evaluate_func)(char **dst, snd_config_t *src, void *private_data); + void *h; + + if (evaluate_name == NULL) { + snprintf(buf, sizeof(buf), "snd_func_%s", func); + buf[sizeof(buf)-1] = '\0'; + evaluate_name = buf; + } + + h = dlopen(lib, RTLD_NOW); + if (!h) { + SNDERR("Cannot open shared library %s", lib); + return -ENOENT; + } + evaluate_func = dlsym(h, evaluate_name); + if (!evaluate_func) { + dlclose(h); + SNDERR("symbol %s is not defined inside %s", evaluate_name, lib ? lib : ALSA_LIB); + return -ENXIO; + } + err = evaluate_func(&ptr, src, private_data); + dlclose(h); + if (err < 0) { + SNDERR("function %s returned error: %s", evaluate_name, snd_strerror(err)); + return err; + } + if (type == NULL) { + t = SND_CONFIG_TYPE_STRING; + } else { + err = snd_config_get_type_ascii(type, &t); + if (err < 0 || t == SND_CONFIG_TYPE_COMPOUND) { + free(ptr); + return -EINVAL; + } + } + err = snd_config_make(&dst, snd_config_get_id(src), t); + if (err < 0) { + free(ptr); + return err; + } + switch (t) { + case SND_CONFIG_TYPE_INTEGER: + { + long v; + err = safe_strtol(ptr, &v); + if (err < 0) { + free(ptr); + snd_config_delete(dst); + return err; + } + snd_config_set_integer(dst, v); + } + break; + case SND_CONFIG_TYPE_REAL: + { + double r; + err = safe_strtod(ptr, &r); + if (err < 0) { + free(ptr); + snd_config_delete(dst); + return err; + } + snd_config_set_real(dst, r); + } + break; + default: + snd_config_set_string(dst, ptr); + break; + } + free(ptr); + *_dst = dst; + } + + err = 0; + __error: + if (func) + free((void *)func); + if (lib) + free((void *)lib); + if (type) + free((void *)type); + return err; +} + +int snd_config_evaluate(snd_config_t *conf, void *private_data) +{ + snd_config_iterator_t i, next; + + assert(conf); + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); + if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND) { + snd_config_t *n1; + int err = evaluate_node(conf, n, private_data, &n1); + if (err < 0) { + SNDERR("Error in node %s", snd_config_get_id(n)); + return err; + } + if (n1) { /* replace node */ + snd_config_delete(n); + err = snd_config_add(conf, n1); + if (err < 0) + return err; + } + } + } + return 0; +} + static int load_defaults(snd_config_t *subs, snd_config_t *defs) { snd_config_iterator_t d, dnext; @@ -2055,6 +2260,8 @@ static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs) { int err; int arg = 0; + if (str == NULL) + return 0; skip_blank(&str); if (!*str) return 0; @@ -2198,35 +2405,54 @@ static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs) } /** - * \brief Expand a node applying arguments + * \brief Expand a node applying arguments and functions * \param config Config node handle - * \param args Arguments string + * \param args Arguments string (optional) + * \param private_data Private data for functions * \param result Pointer to found node * \return 0 on success otherwise a negative error code */ int snd_config_expand(snd_config_t *config, const char *args, - snd_config_t **result) + void *private_data, snd_config_t **result) { int err; - snd_config_t *defs, *subs; - err = snd_config_search(config, "$", &defs); - if (err < 0) - return -EINVAL; - err = snd_config_top(&subs); - if (err < 0) - return err; - err = load_defaults(subs, defs); - if (err < 0) - goto _end; - err = parse_args(subs, args, defs); - if (err < 0) - goto _end; - err = snd_config_walk(config, result, _snd_config_expand, subs); - if (err < 0) + snd_config_t *defs, *subs = NULL, *res; + err = snd_config_search(config, "args", &defs); + if (err < 0) { + err = snd_config_copy(&res, config); + if (err < 0) + return err; + } else { + err = snd_config_top(&subs); + if (err < 0) + return err; + err = load_defaults(subs, defs); + if (err < 0) { + SNDERR("Load defaults error: %s", snd_strerror(err)); + goto _end; + } + err = parse_args(subs, args, defs); + if (err < 0) { + SNDERR("Parse arguments error: %s", snd_strerror(err)); + goto _end; + } + err = snd_config_walk(config, &res, _snd_config_expand, subs); + if (err < 0) { + SNDERR("Expand error (walk): %s", snd_strerror(err)); + goto _end; + } + } + err = snd_config_evaluate(res, private_data); + if (err < 0) { + SNDERR("Evaluate error: %s", snd_strerror(err)); + snd_config_delete(res); goto _end; + } + *result = res; err = 1; _end: - snd_config_delete(subs); + if (subs) + snd_config_delete(subs); return err; } diff --git a/src/confmisc.c b/src/confmisc.c index a656ec00..0babee84 100644 --- a/src/confmisc.c +++ b/src/confmisc.c @@ -139,88 +139,72 @@ int snd_config_get_ctl_iface(snd_config_t *conf) return err; } -static int _snd_config_redirect_load_replace(const char *what, char **dst, void *private_data ATTRIBUTE_UNUSED) +/** + * \brief Expand the dynamic contents + * \param src Source string + * \param idchr Identification character + * \param callback Callback function + * \param private_data Private data for the given callback function + * \param dst Destination string + */ +int snd_config_string_replace(const char *src, char idchr, + snd_config_string_replace_callback_t *callback, + void *private_data, + char **dst) { - enum { - CARD_ID, - PCM_ID, - RAWMIDI_ID - } id; - int len; + int len = 0, len1, err; + const char *ptr, *end; + char *tmp, *what, *fptr, *rdst = NULL; - if (!strcmp(what, "datadir")) { - *dst = strdup(DATADIR "/alsa"); - return *dst == NULL ? -ENOMEM : 0; - } - if (!strncmp(what, "card_id:", len = 8)) - id = CARD_ID; - else if (!strncmp(what, "pcm_id:", len = 7)) - id = PCM_ID; - else if (!strncmp(what, "rawmidi_id:", len = 11)) - id = RAWMIDI_ID; - else - return 0; - { - snd_ctl_t *ctl; - int err; - char name[12]; - const char *str = NULL; - char *fstr = NULL; - sprintf(name, "hw:%d", atoi(what + len)); - err = snd_ctl_open(&ctl, name, 0); - if (err < 0) - return err; - switch (id) { - case CARD_ID: - { - snd_ctl_card_info_t *info; - snd_ctl_card_info_alloca(&info); - err = snd_ctl_card_info(ctl, info); - if (err < 0) - return err; - err = snd_card_type_enum_to_string(snd_ctl_card_info_get_type(info), &fstr); + assert(src && idchr && dst); + while (*src != '\0') { + ptr = strchr(src, idchr); + end = NULL; + if (ptr == src && *(ptr + 1) == '(' && (end = strchr(ptr + 2, ')')) != NULL) { + src = end + 1; + if (callback == NULL) + continue; + len1 = end - (ptr + 2); + if (len1 == 0) /* empty */ + continue; + what = malloc(len1 + 1); + memcpy(what, ptr + 2, len1); + what[len1] = '\0'; + fptr = NULL; + err = callback(what, &fptr, private_data); + free(what); + if (err < 0) { + if (*dst != NULL) + free(*dst); + return err; } - break; - case PCM_ID: - { - char *ptr = strchr(what + len, ','); - int dev = atoi(what + len); - int subdev = ptr ? atoi(ptr + 1) : -1; - snd_pcm_info_t *info; - snd_pcm_info_alloca(&info); - snd_pcm_info_set_device(info, dev); - snd_pcm_info_set_subdevice(info, subdev); - err = snd_ctl_pcm_info(ctl, info); - if (err < 0) - return err; - str = snd_pcm_info_get_id(info); - } - break; - case RAWMIDI_ID: - { - char *ptr = strchr(what + len, ','); - int dev = atoi(what + len); - int subdev = ptr ? atoi(ptr + 1) : -1; - snd_rawmidi_info_t *info; - snd_rawmidi_info_alloca(&info); - snd_rawmidi_info_set_device(info, dev); - snd_rawmidi_info_set_subdevice(info, subdev); - err = snd_ctl_rawmidi_info(ctl, info); - if (err < 0) - return err; - str = snd_rawmidi_info_get_id(info); + if (fptr == NULL) /* empty */ + continue; + len1 = strlen(ptr = fptr); + } else { + if (ptr == NULL) { + len1 = strlen(ptr = src); + } else { + len1 = ptr - src; + ptr = src; } - break; + src += len1; + fptr = NULL; } - if (err < 0) - return err; - snd_ctl_close(ctl); - *dst = fstr ? fstr : (str ? strdup(str) : NULL); - if (*dst == NULL) - return 0; - return 0; + tmp = realloc(rdst, len + len1 + 1); + if (tmp == NULL) { + if (*dst != NULL) + free(*dst); + return -ENOMEM; + } + memcpy(tmp + len, ptr, len1); + tmp[len+=len1] = '\0'; + if (fptr) + free(fptr); + rdst = tmp; } - return 0; /* empty */ + *dst = rdst; + return 0; } /** @@ -262,19 +246,14 @@ int snd_config_redirect_load(snd_config_t *root, rname = NULL; if (snd_config_search(config, "filename", &c) >= 0) { snd_config_t *rconfig; - char *filename; + const char *filename; snd_input_t *input; err = snd_config_copy(&rconfig, root); if (err < 0) return err; if (snd_config_get_type(c) == SND_CONFIG_TYPE_STRING) { - snd_config_get_string(c, (const char **)&filename); - if ((err = snd_config_string_replace(filename, '&', _snd_config_redirect_load_replace, NULL, &filename)) < 0) - goto __filename_error; - if (filename == NULL) - goto __filename_error_einval; + snd_config_get_string(c, &filename); } else { - __filename_error_einval: err = -EINVAL; __filename_error: snd_config_delete(rconfig); @@ -289,10 +268,8 @@ int snd_config_redirect_load(snd_config_t *root, if (err < 0) { snd_input_close(input); goto __filename_error; - return err; } snd_input_close(input); - free(filename); result = rconfig; dynamic = 1; } @@ -300,8 +277,11 @@ int snd_config_redirect_load(snd_config_t *root, const char *ptr; if ((err = snd_config_get_string(c, &ptr)) < 0) goto __error; - if ((err = snd_config_string_replace(ptr, '&', _snd_config_redirect_load_replace, NULL, &rname)) < 0) + rname = strdup(ptr); + if (rname == NULL) { + err = -ENOMEM; goto __error; + } } if (rname == NULL) { err = -EINVAL; @@ -318,3 +298,320 @@ int snd_config_redirect_load(snd_config_t *root, snd_config_delete(result); return err; } + +/* + * Helper functions for the configuration file + */ + +int snd_func_getenv(char **dst, snd_config_t *src, void *private_data ATTRIBUTE_UNUSED) +{ + snd_config_t *n, *d, *e; + snd_config_iterator_t i, next; + const char *res; + char *def = NULL; + int idx = 0, err; + + err = snd_config_expand(src, NULL, NULL, &e); + if (err < 0) + return err; + err = snd_config_search(e, "envname", &n); + if (err < 0) { + SNDERR("field envname not found"); + goto __error; + } + err = snd_config_search(e, "default", &d); + if (err < 0) { + SNDERR("field default not found"); + goto __error; + } + err = snd_config_get_ascii(d, &def); + if (err < 0) { + SNDERR("error getting field default"); + goto __error; + } + __retry: + snd_config_for_each(i, next, n) { + snd_config_t *n = snd_config_iterator_entry(i); + const char *id = snd_config_get_id(n); + const char *ptr, *env; + long i; + if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) { + SNDERR("field %s is not a string", id); + err = -EINVAL; + goto __error; + } + err = safe_strtol(id, &i); + if (err < 0) { + SNDERR("id of field %s is not an integer", id); + err = -EINVAL; + goto __error; + } + if (i == idx) { + idx++; + snd_config_get_string(n, &ptr); + env = getenv(ptr); + if (env != NULL && *env != '\0') { + res = strdup(env); + goto __ok; + } + goto __retry; + } + } + res = def; + def = NULL; + __ok: + err = res == NULL ? -ENOMEM : 0; + *dst = (char *)res; + __error: + if (def) + free(def); + snd_config_delete(e); + return err; +} + +int snd_func_concat(char **dst, snd_config_t *src, void *private_data ATTRIBUTE_UNUSED) +{ + snd_config_t *n, *e; + snd_config_iterator_t i, next; + char *res = NULL, *tmp; + int idx = 0, len = 0, len1, err; + + err = snd_config_expand(src, NULL, NULL, &e); + if (err < 0) + return err; + err = snd_config_search(e, "strings", &n); + if (err < 0) { + SNDERR("field strings not found"); + goto __error; + } + __retry: + snd_config_for_each(i, next, n) { + snd_config_t *n = snd_config_iterator_entry(i); + char *ptr; + const char *id = snd_config_get_id(n); + long i; + err = safe_strtol(id, &i); + if (err < 0) { + SNDERR("id of field %s is not an integer", id); + err = -EINVAL; + goto __error; + } + if (i == idx) { + idx++; + snd_config_get_ascii(n, &ptr); + len1 = strlen(ptr); + tmp = realloc(res, len + len1 + 1); + if (tmp == NULL) { + free(ptr); + if (res) + free(res); + err = -ENOMEM; + goto __error; + } + memcpy(tmp + len, ptr, len1); + free(ptr); + len += len1; + tmp[len] = '\0'; + res = tmp; + goto __retry; + } + } + if (res == NULL) { + SNDERR("empty string is not accepted"); + err = -EINVAL; + goto __error; + } + err = 0; + *dst = res; + __error: + snd_config_delete(e); + return err; +} + +int snd_func_datadir(char **dst, snd_config_t *src ATTRIBUTE_UNUSED, void *private_data ATTRIBUTE_UNUSED) +{ + char *res = strdup(DATADIR "/alsa"); + if (res == NULL) + return -ENOMEM; + *dst = res; + return 0; +} + +static int open_ctl(long card, snd_ctl_t **ctl) +{ + char name[16]; + snprintf(name, sizeof(name), "hw:%li", card); + name[sizeof(name)-1] = '\0'; + return snd_ctl_open(ctl, name, 0); +} + +#if 0 +static int string_from_integer(char **dst, long v) +{ + char str[32]; + char *res; + sprintf(str, "%li", v); + res = strdup(str); + if (res == NULL) + return -ENOMEM; + *dst = res; + return 0; +} +#endif + +int snd_func_card_strtype(char **dst, snd_config_t *src, void *private_data ATTRIBUTE_UNUSED) +{ + snd_config_t *n, *e; + char *res = NULL; + snd_ctl_t *ctl = NULL; + snd_ctl_card_info_t *info; + long v; + int err; + + err = snd_config_expand(src, NULL, NULL, &e); + if (err < 0) + return err; + err = snd_config_search(e, "card", &n); + if (err < 0) { + SNDERR("field card not found"); + goto __error; + } + err = snd_config_get_integer(n, &v); + if (err < 0) { + SNDERR("field card is not an integer"); + goto __error; + } + err = open_ctl(v, &ctl); + if (err < 0) { + SNDERR("could not open control for card %li", v); + goto __error; + } + snd_ctl_card_info_alloca(&info); + err = snd_ctl_card_info(ctl, info); + if (err < 0) { + SNDERR("snd_ctl_card_info error: %s", snd_strerror(err)); + goto __error; + } + err = snd_card_type_enum_to_string(snd_ctl_card_info_get_type(info), &res); + if (err < 0) { + SNDERR("snd_card_type_enum_to_string failed for %i", (int)snd_ctl_card_info_get_type(info)); + goto __error; + } + *dst = res; + __error: + if (ctl) + snd_ctl_close(ctl); + snd_config_delete(e); + return err; +} + +int snd_func_card_id(char **dst, snd_config_t *src, void *private_data ATTRIBUTE_UNUSED) +{ + snd_config_t *n, *e; + char *res = NULL; + snd_ctl_t *ctl = NULL; + snd_ctl_card_info_t *info; + long v; + int err; + + err = snd_config_expand(src, NULL, NULL, &e); + if (err < 0) + return err; + err = snd_config_search(e, "card", &n); + if (err < 0) { + SNDERR("field card not found"); + goto __error; + } + err = snd_config_get_integer(n, &v); + if (err < 0) { + SNDERR("field card is not an integer"); + goto __error; + } + err = open_ctl(v, &ctl); + if (err < 0) { + SNDERR("could not open control for card %li", v); + goto __error; + } + snd_ctl_card_info_alloca(&info); + err = snd_ctl_card_info(ctl, info); + if (err < 0) { + SNDERR("snd_ctl_card_info error: %s", snd_strerror(err)); + goto __error; + } + res = strdup(snd_ctl_card_info_get_id(info)); + if (res == NULL) { + err = -ENOMEM; + goto __error; + } + *dst = res; + __error: + if (ctl) + snd_ctl_close(ctl); + snd_config_delete(e); + return err; +} + +int snd_func_pcm_id(char **dst, snd_config_t *src, void *private_data ATTRIBUTE_UNUSED) +{ + snd_config_t *n, *e; + char *res = NULL; + snd_ctl_t *ctl = NULL; + snd_pcm_info_t *info; + long card, device, subdevice = 0; + int err; + + err = snd_config_expand(src, NULL, NULL, &e); + if (err < 0) + return err; + err = snd_config_search(e, "card", &n); + if (err < 0) { + SNDERR("field card not found"); + goto __error; + } + err = snd_config_get_integer(n, &card); + if (err < 0) { + SNDERR("field card is not an integer"); + goto __error; + } + err = snd_config_search(e, "device", &n); + if (err < 0) { + SNDERR("field device not found"); + goto __error; + } + err = snd_config_get_integer(n, &device); + if (err < 0) { + SNDERR("field device is not an integer"); + goto __error; + } + if (snd_config_search(e, "subdevice", &n) >= 0) { + err = snd_config_get_integer(n, &subdevice); + if (err < 0) { + SNDERR("field subdevice is not an integer"); + goto __error; + } + } + err = open_ctl(card, &ctl); + if (err < 0) { + SNDERR("could not open control for card %li", card); + goto __error; + } + snd_pcm_info_alloca(&info); + snd_pcm_info_set_device(info, device); + snd_pcm_info_set_subdevice(info, subdevice); + err = snd_ctl_pcm_info(ctl, info); + if (err < 0) { + SNDERR("snd_ctl_pcm_info error: %s", snd_strerror(err)); + goto __error; + } + res = strdup(snd_pcm_info_get_id(info)); + if (res == NULL) { + err = -ENOMEM; + goto __error; + } + *dst = res; + __error: + if (ctl) + snd_ctl_close(ctl); + snd_config_delete(e); + return err; +} diff --git a/src/control/control.c b/src/control/control.c index 90482765..37d00f41 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -478,7 +478,7 @@ int snd_ctl_open_noupdate(snd_ctl_t **ctlp, const char *name, int mode) return err; } if (args) { - err = snd_config_expand(ctl_conf, args, &ctl_conf); + err = snd_config_expand(ctl_conf, args, NULL, &ctl_conf); if (err < 0) return err; } diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 5bb93b38..d4f8c35c 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -1035,12 +1035,10 @@ static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root, return err; } } - if (args == NULL && snd_config_search(pcm_conf, "$", &conf) >= 0) /* expand arguments */ - args = ""; - if (args) { - err = snd_config_expand(pcm_conf, args, &pcm_conf); - if (err < 0) - return err; + err = snd_config_expand(pcm_conf, args, NULL, &pcm_conf); + if (err < 0) { + SNDERR("Could not expand configuration: %s", snd_strerror(err)); + return err; } if (snd_config_search(pcm_conf, "redirect", &conf) >= 0) { snd_config_t *tmp_conf; @@ -1049,8 +1047,10 @@ static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root, err = snd_config_redirect_load(root, conf, &redir_name, &tmp_conf, &conf_free_tmp); if (args) snd_config_delete(pcm_conf); - if (err < 0) + if (err < 0) { + SNDERR("Redirect error: %s", snd_strerror(err)); return err; + } err = snd_pcm_open_noupdate(pcmp, tmp_conf, redir_name, stream, mode); if (redir_name) free(redir_name); @@ -1059,8 +1059,7 @@ static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root, return err; } err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode); - if (args) - snd_config_delete(pcm_conf); + snd_config_delete(pcm_conf); return err; } diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c index 4741750c..413aaf23 100644 --- a/src/rawmidi/rawmidi.c +++ b/src/rawmidi/rawmidi.c @@ -175,7 +175,7 @@ int snd_rawmidi_open_noupdate(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, return err; } if (args) { - err = snd_config_expand(rawmidi_conf, args, &rawmidi_conf); + err = snd_config_expand(rawmidi_conf, args, NULL, &rawmidi_conf); if (err < 0) return err; } diff --git a/src/seq/seq.c b/src/seq/seq.c index dd42b2af..198f9efd 100644 --- a/src/seq/seq.c +++ b/src/seq/seq.c @@ -161,7 +161,7 @@ static int snd_seq_open_noupdate(snd_seq_t **seqp, const char *name, return err; } if (args) { - err = snd_config_expand(seq_conf, args, &seq_conf); + err = snd_config_expand(seq_conf, args, NULL, &seq_conf); if (err < 0) return err; }