Home | History | Annotate | Download | only in src
      1 /**
      2  * \file confmisc.c
      3  * \ingroup Configuration
      4  * \brief Configuration helper functions
      5  * \author Abramo Bagnara <abramo (at) alsa-project.org>
      6  * \author Jaroslav Kysela <perex (at) perex.cz>
      7  * \date 2000-2001
      8  *
      9  * Configuration helper functions.
     10  *
     11  * See the \ref conffunc page for more details.
     12  */
     13 /*
     14  *  Miscellaneous configuration helper functions
     15  *  Copyright (c) 2000 by Abramo Bagnara <abramo (at) alsa-project.org>,
     16  *			  Jaroslav Kysela <perex (at) perex.cz>
     17  *
     18  *
     19  *   This library is free software; you can redistribute it and/or modify
     20  *   it under the terms of the GNU Lesser General Public License as
     21  *   published by the Free Software Foundation; either version 2.1 of
     22  *   the License, or (at your option) any later version.
     23  *
     24  *   This program is distributed in the hope that it will be useful,
     25  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     26  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     27  *   GNU Lesser General Public License for more details.
     28  *
     29  *   You should have received a copy of the GNU Lesser General Public
     30  *   License along with this library; if not, write to the Free Software
     31  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     32  *
     33  */
     34 
     35 /*! \page conffunc
     36 
     37 \section conffunc_ref Function reference
     38 
     39 <UL>
     40   <LI>The getenv function - snd_func_getenv() - obtains
     41       an environment value. The result is a string.
     42   <LI>The igetenv function - snd_func_igetenv() - obtains
     43       an environment value. The result is an integer.
     44   <LI>The concat function - snd_func_concat() - merges all specified
     45       strings. The result is a string.
     46   <LI>The iadd function - snd_func_iadd() - sum all specified integers.
     47       The result is an integer.
     48   <LI>The imul function - snd_func_imul() - multiply all specified integers.
     49       The result is an integer.
     50   <LI>The datadir function - snd_func_datadir() - returns the
     51       ALSA data directory. The result is a string.
     52   <LI>The refer function - snd_func_refer() - copies the referred
     53       configuration. The result has the same type as the referred node.
     54   <LI>The card_inum function - snd_func_card_inum() - returns
     55       a card number (integers).
     56   <LI>The card_driver function - snd_func_card_driver() - returns
     57       a driver identification. The result is a string.
     58   <LI>The card_id function - snd_func_card_id() - returns
     59       a card identification. The result is a string.
     60   <LI>The card_name function - snd_func_card_name() - returns
     61       a card's name. The result is a string.
     62   <LI>The pcm_id function - snd_func_pcm_id() - returns
     63       a pcm identification. The result is a string.
     64   <LI>The private_string function - snd_func_private_string() - returns the
     65       string from the private_data node.
     66   <LI>The private_card_driver function - snd_func_private_card_driver() -
     67       returns the driver identification from the private_data node.
     68       The result is a string.
     69   <LI>The private_pcm_subdevice function - snd_func_private_pcm_subdevice() -
     70       returns the PCM subdevice number from the private_data node.
     71       The result is a string.
     72 </UL>
     73 
     74 */
     75 
     76 
     77 #include <stdlib.h>
     78 #include <stdio.h>
     79 #include <string.h>
     80 #include <ctype.h>
     81 #include "local.h"
     82 
     83 /**
     84  * \brief Gets the boolean value from the given ASCII string.
     85  * \param ascii The string to be parsed.
     86  * \return 0 or 1 if successful, otherwise a negative error code.
     87  */
     88 int snd_config_get_bool_ascii(const char *ascii)
     89 {
     90 	unsigned int k;
     91 	static const struct {
     92 		const char str[8];
     93 		int val;
     94 	} b[] = {
     95 		{ "0", 0 },
     96 		{ "1", 1 },
     97 		{ "false", 0 },
     98 		{ "true", 1 },
     99 		{ "no", 0 },
    100 		{ "yes", 1 },
    101 		{ "off", 0 },
    102 		{ "on", 1 },
    103 	};
    104 	for (k = 0; k < sizeof(b) / sizeof(*b); k++) {
    105 		if (strcasecmp(b[k].str, ascii) == 0)
    106 			return b[k].val;
    107 	}
    108 	return -EINVAL;
    109 }
    110 
    111 /**
    112  * \brief Gets the boolean value from a configuration node.
    113  * \param conf Handle to the configuration node to be parsed.
    114  * \return 0 or 1 if successful, otherwise a negative error code.
    115  */
    116 int snd_config_get_bool(const snd_config_t *conf)
    117 {
    118 	long v;
    119 	const char *str, *id;
    120 	int err;
    121 
    122 	err = snd_config_get_id(conf, &id);
    123 	if (err < 0)
    124 		return err;
    125 	err = snd_config_get_integer(conf, &v);
    126 	if (err >= 0) {
    127 		if (v < 0 || v > 1) {
    128 		_invalid_value:
    129 			SNDERR("Invalid value for %s", id);
    130 			return -EINVAL;
    131 		}
    132 		return v;
    133 	}
    134 	err = snd_config_get_string(conf, &str);
    135 	if (err < 0) {
    136 		SNDERR("Invalid type for %s", id);
    137 		return -EINVAL;
    138 	}
    139 	err = snd_config_get_bool_ascii(str);
    140 	if (err < 0)
    141 		goto _invalid_value;
    142 	return err;
    143 }
    144 
    145 /**
    146  * \brief Gets the control interface index from the given ASCII string.
    147  * \param ascii The string to be parsed.
    148  * \return The control interface index if successful, otherwise a negative error code.
    149  */
    150 int snd_config_get_ctl_iface_ascii(const char *ascii)
    151 {
    152 	long v;
    153 	snd_ctl_elem_iface_t idx;
    154 	if (isdigit(ascii[0])) {
    155 		if (safe_strtol(ascii, &v) >= 0) {
    156 			if (v < 0 || v > SND_CTL_ELEM_IFACE_LAST)
    157 				return -EINVAL;
    158 			return v;
    159 		}
    160 	}
    161 	for (idx = 0; idx <= SND_CTL_ELEM_IFACE_LAST; idx++) {
    162 		if (strcasecmp(snd_ctl_elem_iface_name(idx), ascii) == 0)
    163 			return idx;
    164 	}
    165 	return -EINVAL;
    166 }
    167 
    168 /**
    169  * \brief Gets the control interface index from a configuration node.
    170  * \param conf Handle to the configuration node to be parsed.
    171  * \return The control interface index if successful, otherwise a negative error code.
    172  */
    173 int snd_config_get_ctl_iface(const snd_config_t *conf)
    174 {
    175 	long v;
    176 	const char *str, *id;
    177 	int err;
    178 
    179 	err = snd_config_get_id(conf, &id);
    180 	if (err < 0)
    181 		return err;
    182 	err = snd_config_get_integer(conf, &v);
    183 	if (err >= 0) {
    184 		if (v < 0 || v > SND_CTL_ELEM_IFACE_LAST) {
    185 		_invalid_value:
    186 			SNDERR("Invalid value for %s", id);
    187 			return -EINVAL;
    188 		}
    189 		return v;
    190 	}
    191 	err = snd_config_get_string(conf, &str);
    192 	if (err < 0) {
    193 		SNDERR("Invalid type for %s", id);
    194 		return -EINVAL;
    195 	}
    196 	err = snd_config_get_ctl_iface_ascii(str);
    197 	if (err < 0)
    198 		goto _invalid_value;
    199 	return err;
    200 }
    201 
    202 /*
    203  *  Helper functions for the configuration file
    204  */
    205 
    206 /**
    207  * \brief Returns an environment value.
    208  * \param dst The function puts the handle to the result configuration node
    209  *            (with type string) at the address specified by \p dst.
    210  * \param root Handle to the root source node.
    211  * \param src Handle to the source node, with definitions for \c vars and
    212  *            \c default.
    213  * \param private_data Handle to the \c private_data node.
    214  * \return Zero if successful, otherwise a negative error code.
    215  *
    216  * Example:
    217 \code
    218 	{
    219 		@func getenv
    220 		vars [ MY_CARD CARD C ]
    221 		default 0
    222 	}
    223 \endcode
    224  */
    225 int snd_func_getenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
    226 		    snd_config_t *private_data)
    227 {
    228 	snd_config_t *n, *d;
    229 	snd_config_iterator_t i, next;
    230 	const char *res, *id;
    231 	char *def = NULL;
    232 	int idx = 0, err, hit;
    233 
    234 	err = snd_config_search(src, "vars", &n);
    235 	if (err < 0) {
    236 		SNDERR("field vars not found");
    237 		goto __error;
    238 	}
    239 	err = snd_config_evaluate(n, root, private_data, NULL);
    240 	if (err < 0) {
    241 		SNDERR("error evaluating vars");
    242 		goto __error;
    243 	}
    244 	err = snd_config_search(src, "default", &d);
    245 	if (err < 0) {
    246 		SNDERR("field default not found");
    247 		goto __error;
    248 	}
    249 	err = snd_config_evaluate(d, root, private_data, NULL);
    250 	if (err < 0) {
    251 		SNDERR("error evaluating default");
    252 		goto __error;
    253 	}
    254 	err = snd_config_get_ascii(d, &def);
    255 	if (err < 0) {
    256 		SNDERR("error getting field default");
    257 		goto __error;
    258 	}
    259 	do {
    260 		hit = 0;
    261 		snd_config_for_each(i, next, n) {
    262 			snd_config_t *n = snd_config_iterator_entry(i);
    263 			const char *ptr;
    264 			long i;
    265 			if (snd_config_get_id(n, &id) < 0)
    266 				continue;
    267 			if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) {
    268 				SNDERR("field %s is not a string", id);
    269 				err = -EINVAL;
    270 				goto __error;
    271 			}
    272 			err = safe_strtol(id, &i);
    273 			if (err < 0) {
    274 				SNDERR("id of field %s is not an integer", id);
    275 				err = -EINVAL;
    276 				goto __error;
    277 			}
    278 			if (i == idx) {
    279 				idx++;
    280 				err = snd_config_get_string(n, &ptr);
    281 				if (err < 0) {
    282 					SNDERR("invalid string for id %s", id);
    283 					err = -EINVAL;
    284 					goto __error;
    285 				}
    286 				res = getenv(ptr);
    287 				if (res != NULL && *res != '\0')
    288 					goto __ok;
    289 				hit = 1;
    290 			}
    291 		}
    292 	} while (hit);
    293 	res = def;
    294       __ok:
    295 	err = snd_config_get_id(src, &id);
    296 	if (err >= 0)
    297 		err = snd_config_imake_string(dst, id, res);
    298       __error:
    299 	free(def);
    300 	return err;
    301 }
    302 #ifndef DOC_HIDDEN
    303 SND_DLSYM_BUILD_VERSION(snd_func_getenv, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    304 #endif
    305 
    306 /**
    307  * \brief Returns an integer environment value.
    308  * \param dst The function puts the handle to the result configuration node
    309  *            (with type integer) at the address specified by \p dst.
    310  * \param root Handle to the root source node.
    311  * \param src Handle to the source node, with definitions for \c vars and
    312  *            \c default.
    313  * \param private_data Handle to the \c private_data node.
    314  * \return Zero if successful, otherwise a negative error code.
    315  *
    316  * Example:
    317 \code
    318 	{
    319 		@func igetenv
    320 		vars [ MY_DEVICE DEVICE D ]
    321 		default 0
    322 	}
    323 \endcode
    324  */
    325 int snd_func_igetenv(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
    326 		     snd_config_t *private_data)
    327 {
    328 	snd_config_t *d;
    329 	const char *str, *id;
    330 	int err;
    331 	long v;
    332 
    333 	err = snd_func_getenv(&d, root, src, private_data);
    334 	if (err < 0)
    335 		return err;
    336 	err = snd_config_get_string(d, &str);
    337 	if (err < 0) {
    338 		snd_config_delete(d);
    339 		return err;
    340 	}
    341 	err = safe_strtol(str, &v);
    342 	if (err < 0) {
    343 		snd_config_delete(d);
    344 		return err;
    345 	}
    346 	snd_config_delete(d);
    347 	err = snd_config_get_id(src, &id);
    348 	if (err < 0)
    349 		return err;
    350 	err = snd_config_imake_integer(dst, id, v);
    351 	if (err < 0)
    352 		return err;
    353 	return 0;
    354 }
    355 #ifndef DOC_HIDDEN
    356 SND_DLSYM_BUILD_VERSION(snd_func_igetenv, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    357 #endif
    358 
    359 /**
    360  * \brief Merges the given strings.
    361  * \param dst The function puts the handle to the result configuration node
    362  *            (with type string) at the address specified by \p dst.
    363  * \param root Handle to the root source node.
    364  * \param src Handle to the source node, with a definition for \c strings.
    365  * \param private_data Handle to the \c private_data node.
    366  * \return A non-negative value if successful, otherwise a negative error code.
    367  *
    368  * Example (result is "a1b2c3"):
    369 \code
    370 	{
    371 		@func concat
    372 		strings [ "a1" "b2" "c3" ]
    373 	}
    374 \endcode
    375  */
    376 int snd_func_concat(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
    377 		    snd_config_t *private_data)
    378 {
    379 	snd_config_t *n;
    380 	snd_config_iterator_t i, next;
    381 	const char *id;
    382 	char *res = NULL, *tmp;
    383 	int idx = 0, len = 0, len1, err, hit;
    384 
    385 	err = snd_config_search(src, "strings", &n);
    386 	if (err < 0) {
    387 		SNDERR("field strings not found");
    388 		goto __error;
    389 	}
    390 	err = snd_config_evaluate(n, root, private_data, NULL);
    391 	if (err < 0) {
    392 		SNDERR("error evaluating strings");
    393 		goto __error;
    394 	}
    395 	do {
    396 		hit = 0;
    397 		snd_config_for_each(i, next, n) {
    398 			snd_config_t *n = snd_config_iterator_entry(i);
    399 			char *ptr;
    400 			const char *id;
    401 			long i;
    402 			if (snd_config_get_id(n, &id) < 0)
    403 				continue;
    404 			err = safe_strtol(id, &i);
    405 			if (err < 0) {
    406 				SNDERR("id of field %s is not an integer", id);
    407 				err = -EINVAL;
    408 				goto __error;
    409 			}
    410 			if (i == idx) {
    411 				idx++;
    412 				err = snd_config_get_ascii(n, &ptr);
    413 				if (err < 0) {
    414 					SNDERR("invalid ascii string for id %s", id);
    415 					err = -EINVAL;
    416 					goto __error;
    417 				}
    418 				len1 = strlen(ptr);
    419 				tmp = realloc(res, len + len1 + 1);
    420 				if (tmp == NULL) {
    421 					free(ptr);
    422 					free(res);
    423 					err = -ENOMEM;
    424 					goto __error;
    425 				}
    426 				memcpy(tmp + len, ptr, len1);
    427 				free(ptr);
    428 				len += len1;
    429 				tmp[len] = '\0';
    430 				res = tmp;
    431 				hit = 1;
    432 			}
    433 		}
    434 	} while (hit);
    435 	if (res == NULL) {
    436 		SNDERR("empty string is not accepted");
    437 		err = -EINVAL;
    438 		goto __error;
    439 	}
    440 	err = snd_config_get_id(src, &id);
    441 	if (err >= 0)
    442 		err = snd_config_imake_string(dst, id, res);
    443 	free(res);
    444       __error:
    445 	return err;
    446 }
    447 #ifndef DOC_HIDDEN
    448 SND_DLSYM_BUILD_VERSION(snd_func_concat, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    449 #endif
    450 
    451 
    452 static int snd_func_iops(snd_config_t **dst,
    453 			 snd_config_t *root,
    454 			 snd_config_t *src,
    455 			 snd_config_t *private_data,
    456 			 int op)
    457 {
    458 	snd_config_t *n;
    459 	snd_config_iterator_t i, next;
    460 	const char *id;
    461 	char *res = NULL;
    462 	long result = 0, val;
    463 	int idx = 0, err, hit;
    464 
    465 	err = snd_config_search(src, "integers", &n);
    466 	if (err < 0) {
    467 		SNDERR("field integers not found");
    468 		goto __error;
    469 	}
    470 	err = snd_config_evaluate(n, root, private_data, NULL);
    471 	if (err < 0) {
    472 		SNDERR("error evaluating integers");
    473 		goto __error;
    474 	}
    475 	do {
    476 		hit = 0;
    477 		snd_config_for_each(i, next, n) {
    478 			snd_config_t *n = snd_config_iterator_entry(i);
    479 			const char *id;
    480 			long i;
    481 			if (snd_config_get_id(n, &id) < 0)
    482 				continue;
    483 			err = safe_strtol(id, &i);
    484 			if (err < 0) {
    485 				SNDERR("id of field %s is not an integer", id);
    486 				err = -EINVAL;
    487 				goto __error;
    488 			}
    489 			if (i == idx) {
    490 				idx++;
    491 				err = snd_config_get_integer(n, &val);
    492 				if (err < 0) {
    493 					SNDERR("invalid integer for id %s", id);
    494 					err = -EINVAL;
    495 					goto __error;
    496 				}
    497 				switch (op) {
    498 				case 0: result += val; break;
    499 				case 1: result *= val; break;
    500 				}
    501 				hit = 1;
    502 			}
    503 		}
    504 	} while (hit);
    505 	err = snd_config_get_id(src, &id);
    506 	if (err >= 0)
    507 		err = snd_config_imake_integer(dst, id, result);
    508 	free(res);
    509       __error:
    510 	return err;
    511 }
    512 
    513 
    514 /**
    515  * \brief Sum the given integers.
    516  * \param dst The function puts the handle to the result configuration node
    517  *            (with type integer) at the address specified by \p dst.
    518  * \param root Handle to the root source node.
    519  * \param src Handle to the source node, with a definition for \c integers.
    520  * \param private_data Handle to the \c private_data node.
    521  * \return A non-negative value if successful, otherwise a negative error code.
    522  *
    523  * Example (result is 10):
    524 \code
    525 	{
    526 		@func iadd
    527 		integers [ 2 3 5 ]
    528 	}
    529 \endcode
    530  */
    531 int snd_func_iadd(snd_config_t **dst, snd_config_t *root,
    532 	          snd_config_t *src, snd_config_t *private_data)
    533 {
    534 	return snd_func_iops(dst, root, src, private_data, 0);
    535 }
    536 #ifndef DOC_HIDDEN
    537 SND_DLSYM_BUILD_VERSION(snd_func_iadd, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    538 #endif
    539 
    540 /**
    541  * \brief Multiply the given integers.
    542  * \param dst The function puts the handle to the result configuration node
    543  *            (with type integer) at the address specified by \p dst.
    544  * \param root Handle to the root source node.
    545  * \param src Handle to the source node, with a definition for \c integers.
    546  * \param private_data Handle to the \c private_data node.
    547  * \return A non-negative value if successful, otherwise a negative error code.
    548  *
    549  * Example (result is 12):
    550 \code
    551 	{
    552 		@func imul
    553 		integers [ 2 3 2 ]
    554 	}
    555 \endcode
    556  */
    557 int snd_func_imul(snd_config_t **dst, snd_config_t *root,
    558 		  snd_config_t *src, snd_config_t *private_data)
    559 {
    560 	return snd_func_iops(dst, root, src, private_data, 1);
    561 }
    562 #ifndef DOC_HIDDEN
    563 SND_DLSYM_BUILD_VERSION(snd_func_imul, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    564 #endif
    565 
    566 /**
    567  * \brief Returns the ALSA data directory.
    568  * \param dst The function puts the handle to the result configuration node
    569  *            (with type string) at the address specified by \p dst.
    570  * \param root Handle to the root source node.
    571  * \param src Handle to the source node.
    572  * \param private_data Handle to the \c private_data node. Not used.
    573  * \return A non-negative value if successful, otherwise a negative error code.
    574  *
    575  * Example (result is "/usr/share/alsa" using the default paths):
    576 \code
    577 	{
    578 		@func datadir
    579 	}
    580 \endcode
    581  */
    582 int snd_func_datadir(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED,
    583 		     snd_config_t *src, snd_config_t *private_data ATTRIBUTE_UNUSED)
    584 {
    585 	int err;
    586 	const char *id;
    587 
    588 	err = snd_config_get_id(src, &id);
    589 	if (err < 0)
    590 		return err;
    591 	return snd_config_imake_string(dst, id, ALSA_CONFIG_DIR);
    592 }
    593 #ifndef DOC_HIDDEN
    594 SND_DLSYM_BUILD_VERSION(snd_func_datadir, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    595 #endif
    596 
    597 static int open_ctl(long card, snd_ctl_t **ctl)
    598 {
    599 	char name[16];
    600 	snprintf(name, sizeof(name), "hw:%li", card);
    601 	name[sizeof(name)-1] = '\0';
    602 	return snd_ctl_open(ctl, name, 0);
    603 }
    604 
    605 #if 0
    606 static int string_from_integer(char **dst, long v)
    607 {
    608 	char str[32];
    609 	char *res;
    610 	sprintf(str, "%li", v);
    611 	res = strdup(str);
    612 	if (res == NULL)
    613 		return -ENOMEM;
    614 	*dst = res;
    615 	return 0;
    616 }
    617 #endif
    618 
    619 /**
    620  * \brief Returns the string from \c private_data.
    621  * \param dst The function puts the handle to the result configuration node
    622  *            (with type string) at the address specified by \p dst.
    623  * \param root Handle to the root source node.
    624  * \param src Handle to the source node.
    625  * \param private_data Handle to the \c private_data node (type string,
    626  *                     id "string").
    627  * \return A non-negative value if successful, otherwise a negative error code.
    628  *
    629  * Example:
    630 \code
    631 	{
    632 		@func private_string
    633 	}
    634 \endcode
    635  */
    636 int snd_func_private_string(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED,
    637 			    snd_config_t *src, snd_config_t *private_data)
    638 {
    639 	int err;
    640 	const char *str, *id;
    641 
    642 	if (private_data == NULL)
    643 		return snd_config_copy(dst, src);
    644 	err = snd_config_test_id(private_data, "string");
    645 	if (err) {
    646 		SNDERR("field string not found");
    647 		return -EINVAL;
    648 	}
    649 	err = snd_config_get_string(private_data, &str);
    650 	if (err < 0) {
    651 		SNDERR("field string is not a string");
    652 		return err;
    653 	}
    654 	err = snd_config_get_id(src, &id);
    655 	if (err >= 0)
    656 		err = snd_config_imake_string(dst, id, str);
    657 	return err;
    658 }
    659 #ifndef DOC_HIDDEN
    660 SND_DLSYM_BUILD_VERSION(snd_func_private_string, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    661 #endif
    662 
    663 #ifndef DOC_HIDDEN
    664 int snd_determine_driver(int card, char **driver)
    665 {
    666 	snd_ctl_t *ctl = NULL;
    667 	snd_ctl_card_info_t *info;
    668 	char *res = NULL;
    669 	int err;
    670 
    671 	assert(card >= 0 && card <= 32);
    672 	err = open_ctl(card, &ctl);
    673 	if (err < 0) {
    674 		SNDERR("could not open control for card %i", card);
    675 		goto __error;
    676 	}
    677 	snd_ctl_card_info_alloca(&info);
    678 	err = snd_ctl_card_info(ctl, info);
    679 	if (err < 0) {
    680 		SNDERR("snd_ctl_card_info error: %s", snd_strerror(err));
    681 		goto __error;
    682 	}
    683 	res = strdup(snd_ctl_card_info_get_driver(info));
    684 	if (res == NULL)
    685 		err = -ENOMEM;
    686 	else {
    687 		*driver = res;
    688 		err = 0;
    689 	}
    690       __error:
    691 	if (ctl)
    692 		snd_ctl_close(ctl);
    693 	return err;
    694 }
    695 #endif
    696 
    697 /**
    698  * \brief Returns the driver identification from \c private_data.
    699  * \param dst The function puts the handle to the result configuration node
    700  *            (with type string) at the address specified by \p dst.
    701  * \param root Handle to the root source node.
    702  * \param src Handle to the source node.
    703  * \param private_data Handle to the \c private_data node (type integer,
    704  *                     id "card").
    705  * \return A non-negative value if successful, otherwise a negative error code.
    706  *
    707  * Example:
    708 \code
    709 	{
    710 		@func private_card_driver
    711 	}
    712 \endcode
    713  */
    714 int snd_func_private_card_driver(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *src,
    715 				 snd_config_t *private_data)
    716 {
    717 	char *driver;
    718 	const char *id;
    719 	int err;
    720 	long card;
    721 
    722 	err = snd_config_test_id(private_data, "card");
    723 	if (err) {
    724 		SNDERR("field card not found");
    725 		return -EINVAL;
    726 	}
    727 	err = snd_config_get_integer(private_data, &card);
    728 	if (err < 0) {
    729 		SNDERR("field card is not an integer");
    730 		return err;
    731 	}
    732 	if ((err = snd_determine_driver(card, &driver)) < 0)
    733 		return err;
    734 	err = snd_config_get_id(src, &id);
    735 	if (err >= 0)
    736 		err = snd_config_imake_string(dst, id, driver);
    737 	free(driver);
    738 	return err;
    739 }
    740 #ifndef DOC_HIDDEN
    741 SND_DLSYM_BUILD_VERSION(snd_func_private_card_driver, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    742 #endif
    743 
    744 static int parse_card(snd_config_t *root, snd_config_t *src,
    745 		      snd_config_t *private_data)
    746 {
    747 	snd_config_t *n;
    748 	char *str;
    749 	int card, err;
    750 
    751 	err = snd_config_search(src, "card", &n);
    752 	if (err < 0) {
    753 		SNDERR("field card not found");
    754 		return err;
    755 	}
    756 	err = snd_config_evaluate(n, root, private_data, NULL);
    757 	if (err < 0) {
    758 		SNDERR("error evaluating card");
    759 		return err;
    760 	}
    761 	err = snd_config_get_ascii(n, &str);
    762 	if (err < 0) {
    763 		SNDERR("field card is not an integer or a string");
    764 		return err;
    765 	}
    766 	card = snd_card_get_index(str);
    767 	if (card < 0)
    768 		SNDERR("cannot find card '%s'", str);
    769 	free(str);
    770 	return card;
    771 }
    772 
    773 /**
    774  * \brief Returns the card number as integer.
    775  * \param dst The function puts the handle to the result configuration node
    776  *            (with type string) at the address specified by \p dst.
    777  * \param root Handle to the root source node.
    778  * \param src Handle to the source node, with a \c card definition.
    779  * \param private_data Handle to the \c private_data node.
    780  * \return A non-negative value if successful, otherwise a negative error code.
    781  *
    782  * Example:
    783 \code
    784 	{
    785 		@func card_inum
    786 		card '0'
    787 	}
    788 \endcode
    789  */
    790 int snd_func_card_inum(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
    791 		       snd_config_t *private_data)
    792 {
    793 	const char *id;
    794 	int card, err;
    795 
    796 	card = parse_card(root, src, private_data);
    797 	if (card < 0)
    798 		return card;
    799 	err = snd_config_get_id(src, &id);
    800 	if (err >= 0)
    801 		err = snd_config_imake_integer(dst, id, card);
    802 	return err;
    803 }
    804 #ifndef DOC_HIDDEN
    805 SND_DLSYM_BUILD_VERSION(snd_func_card_inum, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    806 #endif
    807 
    808 /**
    809  * \brief Returns the driver identification for a card.
    810  * \param dst The function puts the handle to the result configuration node
    811  *            (with type string) at the address specified by \p dst.
    812  * \param root Handle to the root source node.
    813  * \param src Handle to the source node, with a \c card definition.
    814  * \param private_data Handle to the \c private_data node.
    815  * \return A non-negative value if successful, otherwise a negative error code.
    816  *
    817  * Example:
    818 \code
    819 	{
    820 		@func card_driver
    821 		card 0
    822 	}
    823 \endcode
    824  */
    825 int snd_func_card_driver(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
    826 			 snd_config_t *private_data)
    827 {
    828 	snd_config_t *val;
    829 	int card, err;
    830 
    831 	card = parse_card(root, src, private_data);
    832 	if (card < 0)
    833 		return card;
    834 	err = snd_config_imake_integer(&val, "card", card);
    835 	if (err < 0)
    836 		return err;
    837 	err = snd_func_private_card_driver(dst, root, src, val);
    838 	snd_config_delete(val);
    839 	return err;
    840 }
    841 #ifndef DOC_HIDDEN
    842 SND_DLSYM_BUILD_VERSION(snd_func_card_driver, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    843 #endif
    844 
    845 /**
    846  * \brief Returns the identification of a card.
    847  * \param dst The function puts the handle to the result configuration node
    848  *            (with type string) at the address specified by \p dst.
    849  * \param root Handle to the root source node.
    850  * \param src Handle to the source node, with a \c card definition.
    851  * \param private_data Handle to the \c private_data node.
    852  * \return A non-negative value if successful, otherwise a negative error code.
    853  *
    854  * Example:
    855 \code
    856 	{
    857 		@func card_id
    858 		card 0
    859 	}
    860 \endcode
    861  */
    862 int snd_func_card_id(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
    863 		     snd_config_t *private_data)
    864 {
    865 	snd_ctl_t *ctl = NULL;
    866 	snd_ctl_card_info_t *info;
    867 	const char *id;
    868 	int card, err;
    869 
    870 	card = parse_card(root, src, private_data);
    871 	if (card < 0)
    872 		return card;
    873 	err = open_ctl(card, &ctl);
    874 	if (err < 0) {
    875 		SNDERR("could not open control for card %i", card);
    876 		goto __error;
    877 	}
    878 	snd_ctl_card_info_alloca(&info);
    879 	err = snd_ctl_card_info(ctl, info);
    880 	if (err < 0) {
    881 		SNDERR("snd_ctl_card_info error: %s", snd_strerror(err));
    882 		goto __error;
    883 	}
    884 	err = snd_config_get_id(src, &id);
    885 	if (err >= 0)
    886 		err = snd_config_imake_string(dst, id,
    887 					      snd_ctl_card_info_get_id(info));
    888       __error:
    889       	if (ctl)
    890       		snd_ctl_close(ctl);
    891 	return err;
    892 }
    893 #ifndef DOC_HIDDEN
    894 SND_DLSYM_BUILD_VERSION(snd_func_card_id, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    895 #endif
    896 
    897 /**
    898  * \brief Returns the name of a card.
    899  * \param dst The function puts the handle to the result configuration node
    900  *            (with type string) at the address specified by \p dst.
    901  * \param root Handle to the root source node.
    902  * \param src Handle to the source node, with a \c card definition.
    903  * \param private_data Handle to the \c private_data node.
    904  * \return A non-negative value if successful, otherwise a negative error code.
    905  *
    906  * Example:
    907 \code
    908 	{
    909 		@func card_name
    910 		card 0
    911 	}
    912 \endcode
    913  */
    914 int snd_func_card_name(snd_config_t **dst, snd_config_t *root,
    915 		       snd_config_t *src, snd_config_t *private_data)
    916 {
    917 	snd_ctl_t *ctl = NULL;
    918 	snd_ctl_card_info_t *info;
    919 	const char *id;
    920 	int card, err;
    921 
    922 	card = parse_card(root, src, private_data);
    923 	if (card < 0)
    924 		return card;
    925 	err = open_ctl(card, &ctl);
    926 	if (err < 0) {
    927 		SNDERR("could not open control for card %i", card);
    928 		goto __error;
    929 	}
    930 	snd_ctl_card_info_alloca(&info);
    931 	err = snd_ctl_card_info(ctl, info);
    932 	if (err < 0) {
    933 		SNDERR("snd_ctl_card_info error: %s", snd_strerror(err));
    934 		goto __error;
    935 	}
    936 	err = snd_config_get_id(src, &id);
    937 	if (err >= 0)
    938 		err = snd_config_imake_string(dst, id,
    939 					      snd_ctl_card_info_get_name(info));
    940       __error:
    941       	if (ctl)
    942       		snd_ctl_close(ctl);
    943 	return err;
    944 }
    945 #ifndef DOC_HIDDEN
    946 SND_DLSYM_BUILD_VERSION(snd_func_card_name, SND_CONFIG_DLSYM_VERSION_EVALUATE);
    947 #endif
    948 
    949 #ifdef BUILD_PCM
    950 
    951 /**
    952  * \brief Returns the pcm identification of a device.
    953  * \param dst The function puts the handle to the result configuration node
    954  *            (with type string) at the address specified by \p dst.
    955  * \param root Handle to the root source node.
    956  * \param src Handle to the source node, with definitions for \c card,
    957  *            \c device and (optionally) \c subdevice.
    958  * \param private_data Handle to the \c private_data node.
    959  * \return A non-negative value if successful, otherwise a negative error code.
    960  *
    961  * Example:
    962 \code
    963 	{
    964 		@func pcm_id
    965 		card 0
    966 		device 0
    967 		subdevice 0	# optional
    968 	}
    969 \endcode
    970  */
    971 int snd_func_pcm_id(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data)
    972 {
    973 	snd_config_t *n;
    974 	snd_ctl_t *ctl = NULL;
    975 	snd_pcm_info_t *info;
    976 	const char *id;
    977 	long card, device, subdevice = 0;
    978 	int err;
    979 
    980 	card = parse_card(root, src, private_data);
    981 	if (card < 0)
    982 		return card;
    983 	err = snd_config_search(src, "device", &n);
    984 	if (err < 0) {
    985 		SNDERR("field device not found");
    986 		goto __error;
    987 	}
    988 	err = snd_config_evaluate(n, root, private_data, NULL);
    989 	if (err < 0) {
    990 		SNDERR("error evaluating device");
    991 		goto __error;
    992 	}
    993 	err = snd_config_get_integer(n, &device);
    994 	if (err < 0) {
    995 		SNDERR("field device is not an integer");
    996 		goto __error;
    997 	}
    998 	if (snd_config_search(src, "subdevice", &n) >= 0) {
    999 		err = snd_config_evaluate(n, root, private_data, NULL);
   1000 		if (err < 0) {
   1001 			SNDERR("error evaluating subdevice");
   1002 			goto __error;
   1003 		}
   1004 		err = snd_config_get_integer(n, &subdevice);
   1005 		if (err < 0) {
   1006 			SNDERR("field subdevice is not an integer");
   1007 			goto __error;
   1008 		}
   1009 	}
   1010 	err = open_ctl(card, &ctl);
   1011 	if (err < 0) {
   1012 		SNDERR("could not open control for card %li", card);
   1013 		goto __error;
   1014 	}
   1015 	snd_pcm_info_alloca(&info);
   1016 	snd_pcm_info_set_device(info, device);
   1017 	snd_pcm_info_set_subdevice(info, subdevice);
   1018 	err = snd_ctl_pcm_info(ctl, info);
   1019 	if (err < 0) {
   1020 		SNDERR("snd_ctl_pcm_info error: %s", snd_strerror(err));
   1021 		goto __error;
   1022 	}
   1023 	err = snd_config_get_id(src, &id);
   1024 	if (err >= 0)
   1025 		err = snd_config_imake_string(dst, id, snd_pcm_info_get_id(info));
   1026       __error:
   1027       	if (ctl)
   1028       		snd_ctl_close(ctl);
   1029 	return err;
   1030 }
   1031 #ifndef DOC_HIDDEN
   1032 SND_DLSYM_BUILD_VERSION(snd_func_pcm_id, SND_CONFIG_DLSYM_VERSION_EVALUATE);
   1033 #endif
   1034 
   1035 /**
   1036  * \brief Returns the pcm card and device arguments (in form CARD=N,DEV=M)
   1037  *                for pcm specified by class and index.
   1038  * \param dst The function puts the handle to the result configuration node
   1039  *            (with type string) at the address specified by \p dst.
   1040  * \param root Handle to the root source node.
   1041  * \param src Handle to the source node, with definitions for \c class
   1042  *            and \c index.
   1043  * \param private_data Handle to the \c private_data node.
   1044  * \return A non-negative value if successful, otherwise a negative error code.
   1045  *
   1046  * Example:
   1047 \code
   1048 	{
   1049 		@func pcm_args_by_class
   1050 		class 0
   1051 		index 0
   1052 	}
   1053 \endcode
   1054  */
   1055 int snd_func_pcm_args_by_class(snd_config_t **dst, snd_config_t *root, snd_config_t *src, void *private_data)
   1056 {
   1057 	snd_config_t *n;
   1058 	snd_ctl_t *ctl = NULL;
   1059 	snd_pcm_info_t *info;
   1060 	const char *id;
   1061 	int card = -1, dev;
   1062 	long class, index;
   1063 	int idx = 0;
   1064 	int err;
   1065 
   1066 	err = snd_config_search(src, "class", &n);
   1067 	if (err < 0) {
   1068 		SNDERR("field class not found");
   1069 		goto __out;
   1070 	}
   1071 	err = snd_config_evaluate(n, root, private_data, NULL);
   1072 	if (err < 0) {
   1073 		SNDERR("error evaluating class");
   1074 		goto __out;
   1075 	}
   1076 	err = snd_config_get_integer(n, &class);
   1077 	if (err < 0) {
   1078 		SNDERR("field class is not an integer");
   1079 		goto __out;
   1080 	}
   1081 	err = snd_config_search(src, "index", &n);
   1082 	if (err < 0) {
   1083 		SNDERR("field index not found");
   1084 		goto __out;
   1085 	}
   1086 	err = snd_config_evaluate(n, root, private_data, NULL);
   1087 	if (err < 0) {
   1088 		SNDERR("error evaluating index");
   1089 		goto __out;
   1090 	}
   1091 	err = snd_config_get_integer(n, &index);
   1092 	if (err < 0) {
   1093 		SNDERR("field index is not an integer");
   1094 		goto __out;
   1095 	}
   1096 
   1097 	snd_pcm_info_alloca(&info);
   1098 	while(1) {
   1099 		err = snd_card_next(&card);
   1100 		if (err < 0) {
   1101 			SNDERR("could not get next card");
   1102 			goto __out;
   1103 		}
   1104 		if (card < 0)
   1105 			break;
   1106 		err = open_ctl(card, &ctl);
   1107 		if (err < 0) {
   1108 			SNDERR("could not open control for card %i", card);
   1109 			goto __out;
   1110 		}
   1111 		dev = -1;
   1112 		memset(info, 0, snd_pcm_info_sizeof());
   1113 		while(1) {
   1114 			err = snd_ctl_pcm_next_device(ctl, &dev);
   1115 			if (err < 0) {
   1116 				SNDERR("could not get next pcm for card %i", card);
   1117 				goto __out;
   1118 			}
   1119 			if (dev < 0)
   1120 				break;
   1121 			snd_pcm_info_set_device(info, dev);
   1122 			err = snd_ctl_pcm_info(ctl, info);
   1123 			if (err < 0)
   1124 				continue;
   1125 			if (snd_pcm_info_get_class(info) == (snd_pcm_class_t)class &&
   1126 					index == idx++)
   1127 				goto __out;
   1128 		}
   1129       		snd_ctl_close(ctl);
   1130 		ctl = NULL;
   1131 	}
   1132 	err = -ENODEV;
   1133 
   1134       __out:
   1135       	if (ctl)
   1136       		snd_ctl_close(ctl);
   1137 	if (err < 0)
   1138 		return err;
   1139 	if((err = snd_config_get_id(src, &id)) >= 0) {
   1140 		char name[32];
   1141 		snprintf(name, sizeof(name), "CARD=%i,DEV=%i", card, dev);
   1142 		err = snd_config_imake_string(dst, id, name);
   1143 	}
   1144 	return err;
   1145 }
   1146 #ifndef DOC_HIDDEN
   1147 SND_DLSYM_BUILD_VERSION(snd_func_pcm_args_by_class, SND_CONFIG_DLSYM_VERSION_EVALUATE);
   1148 #endif
   1149 
   1150 /**
   1151  * \brief Returns the PCM subdevice from \c private_data.
   1152  * \param dst The function puts the handle to the result configuration node
   1153  *            (with type integer) at the address specified by \p dst.
   1154  * \param root Handle to the root source node.
   1155  * \param src Handle to the source node.
   1156  * \param private_data Handle to the \c private_data node (type pointer,
   1157  *                     id "pcm_handle").
   1158  * \return A non-negative value if successful, otherwise a negative error code.
   1159  *
   1160  * Example:
   1161 \code
   1162 	{
   1163 		@func private_pcm_subdevice
   1164 	}
   1165 \endcode
   1166  */
   1167 int snd_func_private_pcm_subdevice(snd_config_t **dst, snd_config_t *root ATTRIBUTE_UNUSED,
   1168 				   snd_config_t *src, snd_config_t *private_data)
   1169 {
   1170 	snd_pcm_info_t *info;
   1171 	const char *id;
   1172 	const void *data;
   1173 	snd_pcm_t *pcm;
   1174 	int err;
   1175 
   1176 	if (private_data == NULL)
   1177 		return snd_config_copy(dst, src);
   1178 	err = snd_config_test_id(private_data, "pcm_handle");
   1179 	if (err) {
   1180 		SNDERR("field pcm_handle not found");
   1181 		return -EINVAL;
   1182 	}
   1183 	err = snd_config_get_pointer(private_data, &data);
   1184 	pcm = (snd_pcm_t *)data;
   1185 	if (err < 0) {
   1186 		SNDERR("field pcm_handle is not a pointer");
   1187 		return err;
   1188 	}
   1189 	snd_pcm_info_alloca(&info);
   1190 	err = snd_pcm_info(pcm, info);
   1191 	if (err < 0) {
   1192 		SNDERR("snd_ctl_pcm_info error: %s", snd_strerror(err));
   1193 		return err;
   1194 	}
   1195 	err = snd_config_get_id(src, &id);
   1196 	if (err >= 0)
   1197 		err = snd_config_imake_integer(dst, id, snd_pcm_info_get_subdevice(info));
   1198 	return err;
   1199 }
   1200 #ifndef DOC_HIDDEN
   1201 SND_DLSYM_BUILD_VERSION(snd_func_private_pcm_subdevice, SND_CONFIG_DLSYM_VERSION_EVALUATE);
   1202 #endif
   1203 
   1204 #endif /* BUILD_PCM */
   1205 
   1206 /**
   1207  * \brief Copies the specified configuration node.
   1208  * \param dst The function puts the handle to the result configuration node
   1209  *            (with the same type as the specified node) at the address
   1210  *            specified by \p dst.
   1211  * \param root Handle to the root source node.
   1212  * \param src Handle to the source node, with definitions for \c name and
   1213  *            (optionally) \c file.
   1214  * \param private_data Handle to the \c private_data node.
   1215  * \return A non-negative value if successful, otherwise a negative error code.
   1216  * \note The root source node can be modified!
   1217  *
   1218  * Example:
   1219 \code
   1220 	{
   1221 		@func refer
   1222 		file "/etc/myconf.conf"		# optional
   1223 		name "id1.id2.id3"
   1224 	}
   1225 \endcode
   1226  */
   1227 int snd_func_refer(snd_config_t **dst, snd_config_t *root, snd_config_t *src,
   1228 		   snd_config_t *private_data)
   1229 {
   1230 	snd_config_t *n;
   1231 	const char *file = NULL, *name = NULL;
   1232 	int err;
   1233 
   1234 	err = snd_config_search(src, "file", &n);
   1235 	if (err >= 0) {
   1236 		err = snd_config_evaluate(n, root, private_data, NULL);
   1237 		if (err < 0) {
   1238 			SNDERR("error evaluating file");
   1239 			goto _end;
   1240 		}
   1241 		err = snd_config_get_string(n, &file);
   1242 		if (err < 0) {
   1243 			SNDERR("file is not a string");
   1244 			goto _end;
   1245 		}
   1246 	}
   1247 	err = snd_config_search(src, "name", &n);
   1248 	if (err >= 0) {
   1249 		err = snd_config_evaluate(n, root, private_data, NULL);
   1250 		if (err < 0) {
   1251 			SNDERR("error evaluating name");
   1252 			goto _end;
   1253 		}
   1254 		err = snd_config_get_string(n, &name);
   1255 		if (err < 0) {
   1256 			SNDERR("name is not a string");
   1257 			goto _end;
   1258 		}
   1259 	}
   1260 	if (!name) {
   1261 		err = -EINVAL;
   1262 		SNDERR("name is not specified");
   1263 		goto _end;
   1264 	}
   1265 	if (file) {
   1266 		snd_input_t *input;
   1267 		err = snd_input_stdio_open(&input, file, "r");
   1268 		if (err < 0) {
   1269 			SNDERR("Unable to open file %s: %s", file, snd_strerror(err));
   1270 			goto _end;
   1271 		}
   1272 		err = snd_config_load(root, input);
   1273 		snd_input_close(input);
   1274 		if (err < 0)
   1275 			goto _end;
   1276 	}
   1277 	err = snd_config_search_definition(root, NULL, name, dst);
   1278 	if (err >= 0) {
   1279 		const char *id;
   1280 		err = snd_config_get_id(src, &id);
   1281 		if (err >= 0)
   1282 			err = snd_config_set_id(*dst, id);
   1283 	} else {
   1284 		err = snd_config_search(src, "default", &n);
   1285 		if (err < 0)
   1286 			SNDERR("Unable to find definition '%s'", name);
   1287 		else {
   1288 			const char *id;
   1289 			err = snd_config_evaluate(n, root, private_data, NULL);
   1290 			if (err < 0)
   1291 				return err;
   1292 			if ((err = snd_config_copy(dst, n)) >= 0) {
   1293 				if ((err = snd_config_get_id(src, &id)) < 0 ||
   1294 				    (err = snd_config_set_id(*dst, id)) < 0)
   1295 					snd_config_delete(*dst);
   1296 			}
   1297 		}
   1298 	}
   1299  _end:
   1300 	return err;
   1301 }
   1302 #ifndef DOC_HIDDEN
   1303 SND_DLSYM_BUILD_VERSION(snd_func_refer, SND_CONFIG_DLSYM_VERSION_EVALUATE);
   1304 #endif
   1305