From: Jaroslav Kysela Date: Mon, 11 Jun 2001 08:07:48 +0000 (+0000) Subject: New syntax for the substituted variables - $(var). X-Git-Tag: v1.0.3~817 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=61bf03ce707c83115ade1cc6d7701d6b255a128a;p=alsa-lib.git New syntax for the substituted variables - $(var). Improved the variable substitution (all references in a string are replaced). Added special redirect loading code (to separate card dependant code to single files). --- diff --git a/configure.in b/configure.in index 36a85c80..7e9cc4cd 100644 --- a/configure.in +++ b/configure.in @@ -53,6 +53,6 @@ AC_OUTPUT(Makefile doc/Makefile include/Makefile src/Makefile \ src/control/Makefile src/mixer/Makefile src/pcm/Makefile \ src/rawmidi/Makefile src/timer/Makefile \ src/hwdep/Makefile src/seq/Makefile src/instr/Makefile \ - src/compat/Makefile aserver/Makefile \ + src/compat/Makefile src/cards/Makefile aserver/Makefile \ test/Makefile utils/Makefile \ utils/alsa-lib.spec) diff --git a/include/conf.h b/include/conf.h index 7b566bd6..69aa2df7 100644 --- a/include/conf.h +++ b/include/conf.h @@ -80,6 +80,10 @@ const char *snd_config_get_id(snd_config_t *config); extern snd_config_t *snd_config; int snd_config_update(void); +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/Makefile.am b/src/Makefile.am index 37076abc..d71cff0e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS=control mixer pcm rawmidi timer hwdep seq instr compat +SUBDIRS=control mixer pcm rawmidi timer hwdep seq instr compat cards COMPATNUM=@LIBTOOL_VERSION_INFO@ lib_LTLIBRARIES = libasound.la diff --git a/src/alsa.conf b/src/alsa.conf index 323bd66f..2dd02fd4 100644 --- a/src/alsa.conf +++ b/src/alsa.conf @@ -26,9 +26,9 @@ pcm.hw { default -1 } type hw - card $CARD - device $DEV - subdevice $SUBDEV + card $(CARD) + device $(DEV) + subdevice $(SUBDEV) } pcm.plughw { @@ -48,9 +48,9 @@ pcm.plughw { type plug slave.pcm { type hw - card $CARD - device $DEV - subdevice $SUBDEV + card $(CARD) + device $(DEV) + subdevice $(SUBDEV) } } @@ -60,7 +60,7 @@ pcm.plug { type string } type plug - slave.pcm $SLAVE + slave.pcm $(SLAVE) } pcm.shm { @@ -73,8 +73,8 @@ pcm.shm { type string } type shm - server $SOCKET - pcm $PCM + server $(SOCKET) + pcm $(PCM) } pcm.tee { @@ -92,9 +92,9 @@ pcm.tee { default raw } type file - slave.pcm $SLAVE - file $FILE - format $FORMAT + slave.pcm $(SLAVE) + file $(FILE) + format $(FORMAT) } pcm.file { @@ -109,8 +109,8 @@ pcm.file { } type file slave.pcm null - file $FILE - format $FORMAT + file $(FILE) + format $(FORMAT) } pcm.surround40 { @@ -125,9 +125,26 @@ pcm.surround40 { default <@ALSA_SURROUND40_DEVICE:0@> } type surround - card $CARD - device $DEVICE - stype 4.0 + card $(CARD) + device $(DEVICE) + stype "4.0" +} + +pcm.surround40_new { + $.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@> + } + redirect { + filename "&(datadir)/cards/&(card_id:$(CARD)).conf" + name "pcm.surround40_$(DEV)_&(pcm_id:$(CARD),$(DEV)):$(CARD),$(DEV)" + } } pcm.surround51 { @@ -142,9 +159,9 @@ pcm.surround51 { default <@ALSA_SURROUND51_DEVICE:0@> } type surround - card $CARD - device $DEVICE - stype 5.1 + card $(CARD) + device $(DEVICE) + stype "5.1" } pcm.null { @@ -162,7 +179,7 @@ ctl.hw { type integer } type hw - card $CARD + card $(CARD) } ctl.shm { @@ -175,8 +192,8 @@ ctl.shm { type string } type shm - server $SOCKET - ctl $PCM + server $(SOCKET) + ctl $(PCM) } rawmidi.default { @@ -200,9 +217,9 @@ rawmidi.hw { default -1 } type hw - card $CARD - device $DEV - subdevice $SUBDEV + card $(CARD) + device $(DEV) + subdevice $(SUBDEV) } seq.default { @@ -242,7 +259,7 @@ pcm.iec958 { default 0x00 } type hooks - slave.pcm $PCM + slave.pcm $(PCM) hooks.0 { type ctl_elems args.0 { @@ -250,10 +267,10 @@ pcm.iec958 { subdevice 0 preserve true lock true - value.0 $AES0 - value.1 $AES1 - value.2 $AES2 - value.3 $AES3 + value.0 $(AES0) + value.1 $(AES1) + value.2 $(AES2) + value.3 $(AES3) } } } diff --git a/src/cards/Makefile.am b/src/cards/Makefile.am new file mode 100644 index 00000000..46960667 --- /dev/null +++ b/src/cards/Makefile.am @@ -0,0 +1,5 @@ +alsadir = $(datadir)/alsa/cards +cfg_files = SI_7018.conf + +EXTRA_DIST = $(cfg_files) +alsa_DATA = $(cfg_files) diff --git a/src/cards/SI_7018.conf b/src/cards/SI_7018.conf new file mode 100644 index 00000000..1dce64d5 --- /dev/null +++ b/src/cards/SI_7018.conf @@ -0,0 +1,18 @@ +# +# Configuration for the SI7018 chip +# + +pcm.surround40_0_trident_dx_nx { + $.0 CARD + $.1 DEV + $.CARD { + type integer + } + $.DEV { + type integer + } + type hw + card $(CARD) + device $(DEV) + subdevice -1 +} diff --git a/src/conf.c b/src/conf.c index 8b27143d..e50bc065 100644 --- a/src/conf.c +++ b/src/conf.c @@ -63,6 +63,38 @@ typedef struct { } error; } input_t; +int safe_strtol(const char *str, long *val) +{ + char *end; + long v; + if (!*str) + return -EINVAL; + errno = 0; + v = strtol(str, &end, 0); + if (errno) + return -errno; + if (*end) + return -EINVAL; + *val = v; + return 0; +} + +static int safe_strtod(const char *str, double *val) +{ + char *end; + double v; + if (!*str) + return -EINVAL; + errno = 0; + v = strtod(str, &end); + if (errno) + return -errno; + if (*end) + return -EINVAL; + *val = v; + return 0; +} + static int get_char(input_t *input) { int c; @@ -721,7 +753,7 @@ static int _snd_config_save_leaf(snd_config_t *n, snd_output_t *out, snd_output_printf(out, "%ld", n->u.integer); break; case SND_CONFIG_TYPE_REAL: - snd_output_printf(out, "%16g", n->u.real); + snd_output_printf(out, "%-16g", n->u.real); break; case SND_CONFIG_TYPE_STRING: string_print(n->u.string, 0, out); @@ -882,7 +914,7 @@ int snd_config_load(snd_config_t *config, snd_input_t *in) assert(0); break; } - SNDERR("%s:%d:%d:%s", fd->name ? fd->name : "", + SNDERR("%s:%d:%d:%s", fd->name ? fd->name : "_toplevel_", fd->line, fd->column, str); } goto _end; @@ -1083,6 +1115,48 @@ int snd_config_set_string(snd_config_t *config, const char *value) return 0; } +/** + * \brief Change the value of a config node + * \param config Config node handle + * \param ascii Value in ASCII form + * \return 0 on success otherwise a negative error code + */ +int snd_config_set_ascii(snd_config_t *config, const char *ascii) +{ + assert(config && ascii); + switch (snd_enum_to_int(config->type)) { + case SND_CONFIG_TYPE_INTEGER: + { + long i; + int err = safe_strtol(ascii, &i); + if (err < 0) + return err; + config->u.integer = i; + } + break; + case SND_CONFIG_TYPE_REAL: + { + double d; + int err = safe_strtod(ascii, &d); + if (err < 0) + return err; + config->u.real = d; + break; + } + case SND_CONFIG_TYPE_STRING: + { + char *ptr = realloc(config->u.string, strlen(ascii) + 1); + if (ptr == NULL) + return -ENOMEM; + strcpy(config->u.string, ascii); + } + break; + default: + return -EINVAL; + } + return 0; +} + /** * \brief Get the value of an integer config node * \param config Config node handle @@ -1128,6 +1202,51 @@ int snd_config_get_string(snd_config_t *config, const char **ptr) return 0; } +/** + * \brief Get the value in ASCII form + * \param config Config node handle + * \param ascii Returned dynamically allocated ASCII string + * \return 0 on success otherwise a negative error code + */ +int snd_config_get_ascii(snd_config_t *config, char **ascii) +{ + assert(config && ascii); + switch (snd_enum_to_int(config->type)) { + case SND_CONFIG_TYPE_INTEGER: + { + char res[12]; + int err; + err = snprintf(res, sizeof(res), "%li", config->u.integer); + if (err < 0 || err == sizeof(res)) { + assert(0); + return -ENOMEM; + } + *ascii = strdup(res); + } + break; + case SND_CONFIG_TYPE_REAL: + { + char res[32]; + int err; + err = snprintf(res, sizeof(res), "%-16g", config->u.real); + if (err < 0 || err == sizeof(res)) { + assert(0); + return -ENOMEM; + } + *ascii = strdup(res); + } + break; + case SND_CONFIG_TYPE_STRING: + *ascii = strdup(config->u.string); + break; + default: + return -EINVAL; + } + if (*ascii == NULL) + return -ENOMEM; + return 0; +} + /** * \brief Dump a config tree contents * \param config Config node handle @@ -1526,12 +1645,97 @@ static int _snd_config_copy(snd_config_t *src, return 1; } +/** + * \brief Return the copy of configuration + * \param dst Destination configuration handle + * \return src Source configuration handle + */ int snd_config_copy(snd_config_t **dst, snd_config_t *src) { 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, + int (*callback)(const char *what, char **dst, void *private_data), + 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, @@ -1578,8 +1782,11 @@ static int _snd_config_expand(snd_config_t *src, snd_config_t *val; snd_config_t *vars = private_data; err = snd_config_get_string(src, &s); - if (s[0] == '$') { - if (snd_config_search(vars, s + 1, &val) < 0) + 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; + if (snd_config_search(vars, str, &val) < 0) return 0; err = snd_config_copy(dst, val); if (err < 0) @@ -1593,10 +1800,26 @@ static int _snd_config_expand(snd_config_t *src, err = snd_config_make(dst, id, type); if (err < 0) return err; - err = snd_config_set_string(*dst, s); - if (err < 0) { - snd_config_delete(*dst); - 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; + } + err = snd_config_set_string(*dst, str); + if (err < 0) { + snd_config_delete(*dst); + return err; + } + } else { + err = snd_config_set_string(*dst, s); + if (err < 0) { + snd_config_delete(*dst); + return err; + } } } break; @@ -1647,39 +1870,6 @@ static int load_defaults(snd_config_t *subs, snd_config_t *defs) return 0; } -int safe_strtol(const char *str, long *val) -{ - char *end; - long v; - if (!*str) - return -EINVAL; - errno = 0; - v = strtol(str, &end, 0); - if (errno) - return -errno; - if (*end) - return -EINVAL; - *val = v; - return 0; -} - -static int safe_strtod(const char *str, double *val) -{ - char *end; - double v; - if (!*str) - return -EINVAL; - errno = 0; - v = strtod(str, &end); - if (errno) - return -errno; - if (*end) - return -EINVAL; - *val = v; - return 0; -} - - static void skip_blank(const char **ptr) { while (1) { @@ -2062,3 +2252,183 @@ static void _snd_config_end(void) files_info_count = 0; } #endif + +static int _snd_config_redirect_load_replace(const char *what, char **dst, void *private_data ATTRIBUTE_UNUSED) +{ + enum { + CARD_ID, + PCM_ID, + RAWMIDI_ID + } id; + int len; + + 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); + } + 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); + } + break; + } + if (err < 0) + return err; + snd_ctl_close(ctl); + *dst = fstr ? fstr : (str ? strdup(str) : NULL); + if (*dst == NULL) + return 0; + return 0; + } + return 0; /* empty */ +} + +/** + * \brief Redirect the configuration block to an another + * \param root the root of all configurations + * \param config redirect configuration + * \param name the identifier of new configuration block + * \param dst_config new configuration block + * \param dst_dynamic new configuration block is dynamically allocated + */ +int snd_config_redirect_load(snd_config_t *root, + snd_config_t *config, + char **name, + snd_config_t **dst_config, + int *dst_dynamic) +{ + int err, dynamic; + snd_config_t *result, *c; + char *rname; + + assert(config); + assert(name); + assert(dst_config); + assert(dst_dynamic); + if (snd_config_get_type(config) == SND_CONFIG_TYPE_STRING) { + const char *str; + snd_config_get_string(config, &str); + *name = strdup(str); + if (*name == NULL) + return -ENOMEM; + *dst_config = root; + *dst_dynamic = 0; + return 0; + } + if (snd_config_get_type(config) != SND_CONFIG_TYPE_COMPOUND) + return -EINVAL; + result = root; + dynamic = 0; + rname = NULL; + if (snd_config_search(config, "filename", &c) >= 0) { + snd_config_t *rconfig; + 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; + } else { + __filename_error_einval: + err = -EINVAL; + __filename_error: + snd_config_delete(rconfig); + return err; + } + err = snd_input_stdio_open(&input, filename, "r"); + if (err < 0) { + SNDERR("Unable to open filename %s: %s", filename, snd_strerror(err)); + goto __filename_error; + } + err = snd_config_load(rconfig, input); + if (err < 0) { + snd_input_close(input); + goto __filename_error; + return err; + } + snd_input_close(input); + free(filename); + result = rconfig; + dynamic = 1; + } + if (snd_config_search(config, "name", &c) >= 0) { + 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) + goto __error; + } + if (rname == NULL) { + err = -EINVAL; + goto __error; + } + *dst_config = result; + *dst_dynamic = dynamic; + *name = rname; + return 0; + __error: + if (rname) + free(rname); + if (dynamic) + snd_config_delete(result); + return err; +} diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 44050d91..cf6d60b5 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -995,30 +995,68 @@ static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name, return 0; } -static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, const char *name, - snd_pcm_stream_t stream, int mode) +static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root, + const char *name, snd_pcm_stream_t stream, int mode) { int err; snd_config_t *pcm_conf; + char *key; const char *args = strchr(name, ':'); char *base; + snd_config_t *conf; if (args) { args++; base = alloca(args - name); memcpy(base, name, args - name - 1); - base[args - name - 1] = 0; - } else - base = (char *) name; - err = snd_config_search_alias(snd_config, "pcm", base, &pcm_conf); + base[args - name - 1] = '\0'; + key = strchr(base, '.'); + if (key) + *key++ = '\0'; + } else { + key = strchr(name, '.'); + if (key) { + key++; + base = alloca(key - name); + memcpy(base, name, key - name - 1); + base[key - name - 1] = '\0'; + } else + base = (char *) name; + } + if (key == NULL) { + key = base; + base = NULL; + } + err = snd_config_search_alias(root, base, key, &pcm_conf); if (err < 0) { - SNDERR("Unknown PCM %s", name); - return err; + (void)(base == NULL && (err = snd_config_search_alias(root, "pcm", key, &pcm_conf))); + if (err < 0) { + SNDERR("Unknown PCM %s", name); + 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; } + if (snd_config_search(pcm_conf, "redirect", &conf) >= 0) { + snd_config_t *tmp_conf; + int conf_free_tmp; + char *redir_name = NULL; + err = snd_config_redirect_load(root, conf, &redir_name, &tmp_conf, &conf_free_tmp); + if (args) + snd_config_delete(pcm_conf); + if (err < 0) + return err; + err = snd_pcm_open_noupdate(pcmp, tmp_conf, redir_name, stream, mode); + if (redir_name) + free(redir_name); + if (conf_free_tmp) + snd_config_delete(tmp_conf); + return err; + } err = snd_pcm_open_conf(pcmp, name, pcm_conf, stream, mode); if (args) snd_config_delete(pcm_conf); @@ -1041,7 +1079,7 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name, err = snd_config_update(); if (err < 0) return err; - return snd_pcm_open_noupdate(pcmp, name, stream, mode); + return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode); } #ifndef DOC_HIDDEN @@ -1050,7 +1088,7 @@ int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *conf, { const char *str; if (snd_config_get_string(conf, &str) >= 0) - return snd_pcm_open_noupdate(pcmp, str, stream, mode); + return snd_pcm_open_noupdate(pcmp, snd_config, str, stream, mode); return snd_pcm_open_conf(pcmp, NULL, conf, stream, mode); } #endif