• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * \file conf.c
3  * \ingroup Configuration
4  * \brief Configuration helper functions
5  * \author Abramo Bagnara <abramo@alsa-project.org>
6  * \author Jaroslav Kysela <perex@perex.cz>
7  * \date 2000-2001
8  *
9  * Tree based, full nesting configuration functions.
10  *
11  * See the \ref conf page for more details.
12  */
13 /*
14  *  Configuration helper functions
15  *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>,
16  *			  Jaroslav Kysela <perex@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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
32  *
33  */
34 
35 /*! \page conf Configuration files
36 
37 <P>Configuration files use a simple format allowing modern
38 data description like nesting and array assignments.</P>
39 
40 \section conf_whitespace Whitespace
41 
42 Whitespace is the collective name given to spaces (blanks), horizontal and
43 vertical tabs, newline characters, and comments. Whitespace can
44 indicate where configuration tokens start and end, but beyond this function,
45 any surplus whitespace is discarded. For example, the two sequences
46 
47 \code
48   a 1 b 2
49 \endcode
50 
51 and
52 
53 \code
54   a 1
55      b 2
56 \endcode
57 
58 are lexically equivalent and parse identically to give the four tokens:
59 
60 \code
61 a
62 1
63 b
64 2
65 \endcode
66 
67 The ASCII characters representing whitespace can occur within literal
68 strings, in which case they are protected from the normal parsing process
69 (they remain as part of the string). For example:
70 
71 \code
72   name "John Smith"
73 \endcode
74 
75 parses to two tokens, including the single literal-string token "John
76 Smith".
77 
78 \section conf_linesplicing Line continuation with \
79 
80 A special case occurs if a newline character in a string is preceded
81 by a backslash (\). The backslash and the new line are both discarded,
82 allowing two physical lines of text to be treated as one unit.
83 
84 \code
85 "John \
86 Smith"
87 \endcode
88 
89 is parsed as "John Smith".
90 
91 \section conf_comments Comments
92 
93 A single-line comment begins with the character #. The comment can start
94 at any position, and extends to the end of the line.
95 
96 \code
97   a 1  # this is a comment
98 \endcode
99 
100 \section conf_include Including configuration files
101 
102 To include another configuration file, write the file name in angle brackets.
103 The prefix \c confdir: will reference the global configuration directory.
104 
105 \code
106 </etc/alsa1.conf>
107 <confdir:pcm/surround.conf>
108 \endcode
109 
110 \section conf_punctuators Punctuators
111 
112 The configuration punctuators (also known as separators) are:
113 
114 \code
115   {} [] , ; = . ' " new-line form-feed carriage-return whitespace
116 \endcode
117 
118 \subsection conf_braces Braces
119 
120 Opening and closing braces { } indicate the start and end of a compound
121 statement:
122 
123 \code
124 a {
125   b 1
126 }
127 \endcode
128 
129 \subsection conf_brackets Brackets
130 
131 Opening and closing brackets indicate a single array definition. The
132 identifiers are automatically generated starting with zero.
133 
134 \code
135 a [
136   "first"
137   "second"
138 ]
139 \endcode
140 
141 The above code is equal to
142 
143 \code
144 a.0 "first"
145 a.1 "second"
146 \endcode
147 
148 \subsection conf_comma_semicolon Comma and semicolon
149 
150 The comma (,) or semicolon (;) can separate value assignments. It is not
151 strictly required to use these separators because whitespace suffices to
152 separate tokens.
153 
154 \code
155 a 1;
156 b 1,
157 \endcode
158 
159 \subsection conf_equal Equal sign
160 
161 The equal sign (=) can separate variable declarations from
162 initialization lists:
163 
164 \code
165 a=1
166 b=2
167 \endcode
168 
169 Using equal signs is not required because whitespace suffices to separate
170 tokens.
171 
172 \section conf_assigns Assignments
173 
174 The configuration file defines id (key) and value pairs. The id (key) can be
175 composed from ASCII digits, characters from a to z and A to Z, and the
176 underscore (_). The value can be either a string, an integer, a real number,
177 or a compound statement.
178 
179 \subsection conf_single Single assignments
180 
181 \code
182 a 1	# is equal to
183 a=1	# is equal to
184 a=1;	# is equal to
185 a 1,
186 \endcode
187 
188 \subsection conf_compound Compound assignments (definitions using braces)
189 
190 \code
191 a {
192   b = 1
193 }
194 a={
195   b 1,
196 }
197 \endcode
198 
199 \section conf_compound1 Compound assignments (one key definitions)
200 
201 \code
202 a.b 1
203 a.b=1
204 \endcode
205 
206 \subsection conf_array Array assignments (definitions using brackets)
207 
208 \code
209 a [
210   "first"
211   "second"
212 ]
213 \endcode
214 
215 \subsection conf_array1 Array assignments (one key definitions)
216 
217 \code
218 a.0 "first"
219 a.1 "second"
220 \endcode
221 
222 \section conf_mode Operation modes for parsing nodes
223 
224 By default, the node operation mode is 'merge+create', i.e., if
225 a configuration node is not present a new one is created, otherwise
226 the latest assignment is merged (if possible - type checking). The
227 'merge+create' operation mode is specified with the prefix character plus (+).
228 
229 The operation mode 'merge' merges the node with the old one (which must
230 exist). Type checking is done, so strings cannot be assigned to integers
231 and so on. This mode is specified with the prefix character minus (-).
232 
233 The operation mode 'do not override' ignores a new configuration node
234 if a configuration node with the same name exists. This mode is specified with
235 the prefix character question mark (?).
236 
237 The operation mode 'override' always overrides the old configuration node
238 with new contents. This mode is specified with the prefix character
239 exclamation mark (!).
240 
241 \code
242 defaults.pcm.!device 1
243 \endcode
244 
245 \section conf_syntax_summary Syntax summary
246 
247 \code
248 # Configuration file syntax
249 
250 # Include a new configuration file
251 <filename>
252 
253 # Simple assignment
254 name [=] value [,|;]
255 
256 # Compound assignment (first style)
257 name [=] {
258         name1 [=] value [,|;]
259         ...
260 }
261 
262 # Compound assignment (second style)
263 name.name1 [=] value [,|;]
264 
265 # Array assignment (first style)
266 name [
267         value0 [,|;]
268         value1 [,|;]
269         ...
270 ]
271 
272 # Array assignment (second style)
273 name.0 [=] value0 [,|;]
274 name.1 [=] value1 [,|;]
275 \endcode
276 
277 \section conf_syntax_ref References
278 
279 \ref confarg
280 \ref conffunc
281 \ref confhooks
282 
283 */
284 
285 /*! \page confarg Runtime arguments in configuration files
286 
287 <P>The ALSA library can accept runtime arguments for some configuration
288 blocks. This extension is built on top of the basic configuration file
289 syntax.<P>
290 
291 \section confarg_define Defining arguments
292 
293 Arguments are defined using the id (key) \c \@args and array values containing
294 the string names of the arguments:
295 
296 \code
297 @args [ CARD ]	# or
298 @args.0 CARD
299 \endcode
300 
301 \section confarg_type Defining argument types and default values
302 
303 An argument's type is specified with the id (key) \c \@args and the argument
304 name. The type and the default value are specified in the compound block:
305 
306 \code
307 @args.CARD {
308   type string
309   default "abcd"
310 }
311 \endcode
312 
313 \section confarg_refer Referring to arguments
314 
315 Arguments are referred to with a dollar-sign ($) and the name of the argument:
316 
317 \code
318   card $CARD
319 \endcode
320 
321 \section confarg_math simple math expressions
322 
323 The simple math expressions are identified using a unix shell like expression syntax
324 with a dollar-sign ($) and bracket ([):
325 
326 \code
327   card "$[$CARD + 1]"
328 \endcode
329 
330 \section confarg_usage Usage
331 
332 To use a block with arguments, write the argument values after the key,
333 separated with a colon (:). For example, all these names for PCM interfaces
334 give the same result:
335 
336 \code
337 hw:0,1
338 hw:CARD=0,DEV=1
339 hw:{CARD 0 DEV 1}
340 plug:"hw:0,1"
341 plug:{SLAVE="hw:{CARD 0 DEV 1}"}
342 \endcode
343 
344 As you see, arguments can be specified in their proper order or by name.
345 Note that arguments enclosed in braces are parsed in the same way as in
346 configuration files, but using the override method by default.
347 
348 \section confarg_example Example
349 
350 \code
351 pcm.demo {
352 	@args [ CARD DEVICE ]
353 	@args.CARD {
354 		type string
355 		default "supersonic"
356 	}
357 	@args.DEVICE {
358 		type integer
359 		default 0
360 	}
361 	type hw
362 	card $CARD
363 	device $DEVICE
364 }
365 \endcode
366 
367 
368 */
369 
370 /*! \page conffunc Runtime functions in configuration files
371 
372 <P>The ALSA library can modify the configuration at runtime.
373 Several built-in functions are available.</P>
374 
375 <P>A function is defined with the id \c \@func and the function name. All other
376 values in the current compound are used as configuration for the function.
377 If the compound func.\<function_name\> is defined in the root node, then the
378 library and function from this compound configuration are used, otherwise
379 'snd_func_' is prefixed to the string and code from the ALSA library is used.
380 The definition of a function looks like:</P>
381 
382 \code
383 func.remove_first_char {
384 	lib "/usr/lib/libasoundextend.so"
385 	func "extend_remove_first_char"
386 }
387 \endcode
388 
389 */
390 
391 /*! \page confhooks Hooks in configuration files
392 
393 <P>The hook extension in the ALSA library allows expansion of configuration
394 nodes at run-time. The existence of a hook is determined by the
395 presence of a \@hooks compound node.</P>
396 
397 <P>This example defines a hook which loads two configuration files at the
398 beginning:</P>
399 
400 \code
401 @hooks [
402 	{
403 		func load
404 		files [
405 			"/etc/asound.conf"
406 			"~/.asoundrc"
407 		]
408 		errors false
409 	}
410 ]
411 \endcode
412 
413 \section confhooks_ref Function reference
414 
415 <UL>
416   <LI>The function load - \c snd_config_hook_load() - loads and parses the
417       given configuration files.
418   <LI>The function load_for_all_cards - \c snd_config_hook_load_for_all_cards() -
419       loads and parses the given configuration files for each installed sound
420       card. The driver name (the type of the sound card) is passed in the
421       private configuration node.
422 </UL>
423 
424 */
425 
426 
427 #include "local.h"
428 #include <stdarg.h>
429 #include <stdbool.h>
430 #include <limits.h>
431 #include <sys/stat.h>
432 #include <dirent.h>
433 #include <locale.h>
434 #ifdef HAVE_LIBPTHREAD
435 #include <pthread.h>
436 #endif
437 
438 #ifndef DOC_HIDDEN
439 
440 #ifdef HAVE_LIBPTHREAD
441 static pthread_mutex_t snd_config_update_mutex;
442 static pthread_once_t snd_config_update_mutex_once = PTHREAD_ONCE_INIT;
443 #endif
444 
445 struct _snd_config {
446 	char *id;
447 	snd_config_type_t type;
448 	int refcount; /* default = 0 */
449 	union {
450 		long integer;
451 		long long integer64;
452 		char *string;
453 		double real;
454 		const void *ptr;
455 		struct {
456 			struct list_head fields;
457 			bool join;
458 		} compound;
459 	} u;
460 	struct list_head list;
461 	snd_config_t *parent;
462 	int hop;
463 };
464 
465 struct filedesc {
466 	char *name;
467 	snd_input_t *in;
468 	unsigned int line, column;
469 	struct filedesc *next;
470 
471 	/* list of the include paths (configuration directories),
472 	 * defined by <searchdir:relative-path/to/top-alsa-conf-dir>,
473 	 * for searching its included files.
474 	 */
475 	struct list_head include_paths;
476 };
477 
478 /* path to search included files */
479 struct include_path {
480 	char *dir;
481 	struct list_head list;
482 };
483 
484 #define LOCAL_ERROR			(-0x68000000)
485 
486 #define LOCAL_UNTERMINATED_STRING 	(LOCAL_ERROR - 0)
487 #define LOCAL_UNTERMINATED_QUOTE	(LOCAL_ERROR - 1)
488 #define LOCAL_UNEXPECTED_CHAR		(LOCAL_ERROR - 2)
489 #define LOCAL_UNEXPECTED_EOF		(LOCAL_ERROR - 3)
490 
491 typedef struct {
492 	struct filedesc *current;
493 	int unget;
494 	int ch;
495 } input_t;
496 
497 #ifdef HAVE_LIBPTHREAD
498 
snd_config_init_mutex(void)499 static void snd_config_init_mutex(void)
500 {
501 	pthread_mutexattr_t attr;
502 
503 	pthread_mutexattr_init(&attr);
504 #ifdef HAVE_PTHREAD_MUTEX_RECURSIVE
505 	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
506 #endif
507 	pthread_mutex_init(&snd_config_update_mutex, &attr);
508 	pthread_mutexattr_destroy(&attr);
509 }
510 
snd_config_lock(void)511 static inline void snd_config_lock(void)
512 {
513 	pthread_once(&snd_config_update_mutex_once, snd_config_init_mutex);
514 	pthread_mutex_lock(&snd_config_update_mutex);
515 }
516 
snd_config_unlock(void)517 static inline void snd_config_unlock(void)
518 {
519 	pthread_mutex_unlock(&snd_config_update_mutex);
520 }
521 
522 #else
523 
snd_config_lock(void)524 static inline void snd_config_lock(void) { }
snd_config_unlock(void)525 static inline void snd_config_unlock(void) { }
526 
527 #endif
528 
529 /*
530  * Add a diretory to the paths to search included files.
531  * param fd -  File object that owns these paths to search files included by it.
532  * param dir - Path of the directory to add. Allocated externally and need to
533 *              be freed manually later.
534  * return - Zero if successful, otherwise a negative error code.
535  *
536  * The direcotry should be a subdiretory of top configuration directory
537  * "/usr/share/alsa/".
538  */
add_include_path(struct filedesc * fd,const char * dir)539 static int add_include_path(struct filedesc *fd, const char *dir)
540 {
541 	struct include_path *path;
542 	struct filedesc *fd1;
543 	struct list_head *pos;
544 
545 	/* check, if dir is already registered (also in parents) */
546 	for (fd1 = fd; fd1; fd1 = fd1->next) {
547 		list_for_each(pos, &fd1->include_paths) {
548 			path = list_entry(pos, struct include_path, list);
549 			if (strcmp(path->dir, dir) == 0)
550 				return 0;
551 		}
552 	}
553 
554 	path = calloc(1, sizeof(*path));
555 	if (!path)
556 		return -ENOMEM;
557 
558 	path->dir = strdup(dir);
559 	if (path->dir == NULL) {
560 		free(path);
561 		return -ENOMEM;
562 	}
563 
564 	list_add_tail(&path->list, &fd->include_paths);
565 	return 0;
566 }
567 
568 /*
569  * Free all include paths of a file descriptor.
570  * param fd - File object that owns these paths to search files included by it.
571  */
free_include_paths(struct filedesc * fd)572 static void free_include_paths(struct filedesc *fd)
573 {
574 	struct list_head *pos, *npos, *base;
575 	struct include_path *path;
576 
577 	base = &fd->include_paths;
578 	list_for_each_safe(pos, npos, base) {
579 		path = list_entry(pos, struct include_path, list);
580 		list_del(&path->list);
581 		if (path->dir)
582 			free(path->dir);
583 		free(path);
584 	}
585 }
586 
587 /**
588  * \brief Returns the default top-level config directory
589  * \return The top-level config directory path string
590  *
591  * This function returns the string of the top-level config directory path.
592  * If the path is specified via the environment variable \c ALSA_CONFIG_DIR
593  * and the value is a valid path, it returns this value.  If unspecified, it
594  * returns the default value, "/usr/share/alsa".
595  */
snd_config_topdir(void)596 const char *snd_config_topdir(void)
597 {
598 	static char *topdir;
599 
600 	if (!topdir) {
601 		topdir = getenv("ALSA_CONFIG_DIR");
602 		if (!topdir || *topdir != '/' || strlen(topdir) >= PATH_MAX)
603 			topdir = ALSA_CONFIG_DIR;
604 	}
605 	return topdir;
606 }
607 
_snd_config_path(const char * name)608 static char *_snd_config_path(const char *name)
609 {
610 	const char *root = snd_config_topdir();
611 	char *path = malloc(strlen(root) + strlen(name) + 2);
612 	if (!path)
613 		return NULL;
614 	sprintf(path, "%s/%s", root, name);
615 	return path;
616 }
617 
618 /*
619  * Search and open a file, and creates a new input object reading from the file.
620  * param inputp - The functions puts the pointer to the new input object
621  *               at the address specified by \p inputp.
622  * param file - Name of the configuration file.
623  * param include_paths - Optional, addtional directories to search the file.
624  * return - Zero if successful, otherwise a negative error code.
625  *
626  * This function will search and open the file in the following order
627  * of priority:
628  * 1. directly open the file by its name (only if absolute)
629  * 2. search for the file name in in additional configuration directories
630  *    specified by users, via alsaconf syntax
631  *    <searchdir:relative-path/to/user/share/alsa>;
632  *    These directories should be subdirectories of /usr/share/alsa.
633  */
input_stdio_open(snd_input_t ** inputp,const char * file,struct filedesc * current)634 static int input_stdio_open(snd_input_t **inputp, const char *file,
635 			    struct filedesc *current)
636 {
637 	struct list_head *pos;
638 	struct include_path *path;
639 	char full_path[PATH_MAX];
640 	int err;
641 
642 	if (file[0] == '/')
643 		return snd_input_stdio_open(inputp, file, "r");
644 
645 	/* search file in user specified include paths. These directories
646 	 * are subdirectories of /usr/share/alsa.
647 	 */
648 	err = -ENOENT;
649 	while (current) {
650 		list_for_each(pos, &current->include_paths) {
651 			path = list_entry(pos, struct include_path, list);
652 			if (!path->dir)
653 				continue;
654 
655 			snprintf(full_path, PATH_MAX, "%s/%s", path->dir, file);
656 			err = snd_input_stdio_open(inputp, full_path, "r");
657 			if (err == 0)
658 				return 0;
659 		}
660 		current = current->next;
661 	}
662 
663 	return err;
664 }
665 
safe_strtoll_base(const char * str,long long * val,int base)666 int safe_strtoll_base(const char *str, long long *val, int base)
667 {
668 	char *end;
669 	long v;
670 	if (!*str)
671 		return -EINVAL;
672 	errno = 0;
673 	v = strtoll(str, &end, base);
674 	if (errno)
675 		return -errno;
676 	if (*end)
677 		return -EINVAL;
678 	*val = v;
679 	return 0;
680 }
681 
safe_strtol_base(const char * str,long * val,int base)682 int safe_strtol_base(const char *str, long *val, int base)
683 {
684 	char *end;
685 	long v;
686 	if (!*str)
687 		return -EINVAL;
688 	errno = 0;
689 	v = strtol(str, &end, base);
690 	if (errno)
691 		return -errno;
692 	if (*end)
693 		return -EINVAL;
694 	*val = v;
695 	return 0;
696 }
697 
safe_strtod(const char * str,double * val)698 static int safe_strtod(const char *str, double *val)
699 {
700 	char *end;
701 	double v;
702 #ifdef HAVE_USELOCALE
703 	locale_t saved_locale, c_locale;
704 #else
705 	char *saved_locale;
706 	char locstr[64]; /* enough? */
707 #endif
708 	int err;
709 
710 	if (!*str)
711 		return -EINVAL;
712 #ifdef HAVE_USELOCALE
713 	c_locale = newlocale(LC_NUMERIC_MASK, "C", 0);
714 	saved_locale = uselocale(c_locale);
715 #else
716 	saved_locale = setlocale(LC_NUMERIC, NULL);
717 	if (saved_locale) {
718 		snprintf(locstr, sizeof(locstr), "%s", saved_locale);
719 		setlocale(LC_NUMERIC, "C");
720 	}
721 #endif
722 	errno = 0;
723 	v = strtod(str, &end);
724 	err = -errno;
725 #ifdef HAVE_USELOCALE
726 	if (c_locale != (locale_t)0) {
727 		uselocale(saved_locale);
728 		freelocale(c_locale);
729 	}
730 #else
731 	if (saved_locale)
732 		setlocale(LC_NUMERIC, locstr);
733 #endif
734 	if (err)
735 		return err;
736 	if (*end)
737 		return -EINVAL;
738 	*val = v;
739 	return 0;
740 }
741 
get_char(input_t * input)742 static int get_char(input_t *input)
743 {
744 	int c;
745 	struct filedesc *fd;
746 	if (input->unget) {
747 		input->unget = 0;
748 		return input->ch;
749 	}
750  again:
751 	fd = input->current;
752 	c = snd_input_getc(fd->in);
753 	switch (c) {
754 	case '\n':
755 		fd->column = 0;
756 		fd->line++;
757 		break;
758 	case '\t':
759 		fd->column += 8 - fd->column % 8;
760 		break;
761 	case EOF:
762 		if (fd->next) {
763 			snd_input_close(fd->in);
764 			free(fd->name);
765 			input->current = fd->next;
766 			free(fd);
767 			goto again;
768 		}
769 		return LOCAL_UNEXPECTED_EOF;
770 	default:
771 		fd->column++;
772 		break;
773 	}
774 	return (unsigned char)c;
775 }
776 
unget_char(int c,input_t * input)777 static void unget_char(int c, input_t *input)
778 {
779 	assert(!input->unget);
780 	input->ch = c;
781 	input->unget = 1;
782 }
783 
784 static int get_delimstring(char **string, int delim, input_t *input);
785 
get_char_skip_comments(input_t * input)786 static int get_char_skip_comments(input_t *input)
787 {
788 	int c;
789 	while (1) {
790 		c = get_char(input);
791 		if (c == '<') {
792 			char *str;
793 			snd_input_t *in;
794 			struct filedesc *fd;
795 			DIR *dirp;
796 			int err = get_delimstring(&str, '>', input);
797 			if (err < 0)
798 				return err;
799 
800 			if (!strncmp(str, "searchdir:", 10)) {
801 				/* directory to search included files */
802 				char *tmp = _snd_config_path(str + 10);
803 				free(str);
804 				if (tmp == NULL)
805 					return -ENOMEM;
806 				str = tmp;
807 
808 				dirp = opendir(str);
809 				if (!dirp) {
810 					SNDERR("Invalid search dir %s", str);
811 					free(str);
812 					return -EINVAL;
813 				}
814 				closedir(dirp);
815 
816 				err = add_include_path(input->current, str);
817 				free(str);
818 				if (err < 0) {
819 					SNDERR("Cannot add search dir %s", str);
820 					return err;
821 				}
822 				continue;
823 			}
824 
825 			if (!strncmp(str, "confdir:", 8)) {
826 				/* file in the specified directory */
827 				char *tmp = _snd_config_path(str + 8);
828 				free(str);
829 				if (tmp == NULL)
830 					return -ENOMEM;
831 				str = tmp;
832 				err = snd_input_stdio_open(&in, str, "r");
833 			} else { /* absolute or relative file path */
834 				err = input_stdio_open(&in, str, input->current);
835 			}
836 
837 			if (err < 0) {
838 				SNDERR("Cannot access file %s", str);
839 				free(str);
840 				return err;
841 			}
842 			fd = malloc(sizeof(*fd));
843 			if (!fd) {
844 				free(str);
845 				return -ENOMEM;
846 			}
847 			fd->name = str;
848 			fd->in = in;
849 			fd->next = input->current;
850 			fd->line = 1;
851 			fd->column = 0;
852 			INIT_LIST_HEAD(&fd->include_paths);
853 			input->current = fd;
854 			continue;
855 		}
856 		if (c != '#')
857 			break;
858 		while (1) {
859 			c = get_char(input);
860 			if (c < 0)
861 				return c;
862 			if (c == '\n')
863 				break;
864 		}
865 	}
866 
867 	return c;
868 }
869 
870 
get_nonwhite(input_t * input)871 static int get_nonwhite(input_t *input)
872 {
873 	int c;
874 	while (1) {
875 		c = get_char_skip_comments(input);
876 		switch (c) {
877 		case ' ':
878 		case '\f':
879 		case '\t':
880 		case '\n':
881 		case '\r':
882 			break;
883 		default:
884 			return c;
885 		}
886 	}
887 }
888 
get_hexachar(input_t * input)889 static inline int get_hexachar(input_t *input)
890 {
891 	int c, num = 0;
892 
893 	c = get_char(input);
894 	if (c >= '0' && c <= '9') num |= (c - '0') << 4;
895 	else if (c >= 'a' && c <= 'f') num |= (c - 'a') << 4;
896 	else if (c >= 'A' && c <= 'F') num |= (c - 'A') << 4;
897 	c = get_char(input);
898 	if (c >= '0' && c <= '9') num |= (c - '0') << 0;
899 	else if (c >= 'a' && c <= 'f') num |= (c - 'a') << 0;
900 	else if (c >= 'A' && c <= 'F') num |= (c - 'A') << 0;
901 	return num;
902 }
903 
get_quotedchar(input_t * input)904 static int get_quotedchar(input_t *input)
905 {
906 	int c;
907 	c = get_char(input);
908 	switch (c) {
909 	case 'n':
910 		return '\n';
911 	case 't':
912 		return '\t';
913 	case 'v':
914 		return '\v';
915 	case 'b':
916 		return '\b';
917 	case 'r':
918 		return '\r';
919 	case 'f':
920 		return '\f';
921 	case 'x':
922 		return get_hexachar(input);
923 	case '0': case '1': case '2': case '3':
924 	case '4': case '5': case '6': case '7':
925 	{
926 		int num = c - '0';
927 		int i = 1;
928 		do {
929 			c = get_char(input);
930 			if (c < '0' || c > '7') {
931 				unget_char(c, input);
932 				break;
933 			}
934 			num = num * 8 + c - '0';
935 			i++;
936 		} while (i < 3);
937 		return num;
938 	}
939 	default:
940 		return c;
941 	}
942 }
943 
944 #define LOCAL_STR_BUFSIZE	64
945 struct local_string {
946 	char *buf;
947 	size_t alloc;
948 	size_t idx;
949 	char tmpbuf[LOCAL_STR_BUFSIZE];
950 };
951 
init_local_string(struct local_string * s)952 static void init_local_string(struct local_string *s)
953 {
954 	memset(s, 0, sizeof(*s));
955 	s->buf = s->tmpbuf;
956 	s->alloc = LOCAL_STR_BUFSIZE;
957 }
958 
free_local_string(struct local_string * s)959 static void free_local_string(struct local_string *s)
960 {
961 	if (s->buf != s->tmpbuf)
962 		free(s->buf);
963 }
964 
add_char_local_string(struct local_string * s,int c)965 static int add_char_local_string(struct local_string *s, int c)
966 {
967 	if (s->idx >= s->alloc) {
968 		size_t nalloc = s->alloc * 2;
969 		if (s->buf == s->tmpbuf) {
970 			s->buf = malloc(nalloc);
971 			if (s->buf == NULL)
972 				return -ENOMEM;
973 			memcpy(s->buf, s->tmpbuf, s->alloc);
974 		} else {
975 			char *ptr = realloc(s->buf, nalloc);
976 			if (ptr == NULL)
977 				return -ENOMEM;
978 			s->buf = ptr;
979 		}
980 		s->alloc = nalloc;
981 	}
982 	s->buf[s->idx++] = c;
983 	return 0;
984 }
985 
copy_local_string(struct local_string * s)986 static char *copy_local_string(struct local_string *s)
987 {
988 	char *dst = malloc(s->idx + 1);
989 	if (dst) {
990 		memcpy(dst, s->buf, s->idx);
991 		dst[s->idx] = '\0';
992 	}
993 	return dst;
994 }
995 
get_freestring(char ** string,int id,input_t * input)996 static int get_freestring(char **string, int id, input_t *input)
997 {
998 	struct local_string str;
999 	int c;
1000 
1001 	init_local_string(&str);
1002 	while (1) {
1003 		c = get_char(input);
1004 		if (c < 0) {
1005 			if (c == LOCAL_UNEXPECTED_EOF) {
1006 				*string = copy_local_string(&str);
1007 				if (! *string)
1008 					c = -ENOMEM;
1009 				else
1010 					c = 0;
1011 			}
1012 			break;
1013 		}
1014 		switch (c) {
1015 		case '.':
1016 			if (!id)
1017 				break;
1018 			/* fall through */
1019 		case ' ':
1020 		case '\f':
1021 		case '\t':
1022 		case '\n':
1023 		case '\r':
1024 		case '=':
1025 		case ',':
1026 		case ';':
1027 		case '{':
1028 		case '}':
1029 		case '[':
1030 		case ']':
1031 		case '\'':
1032 		case '"':
1033 		case '\\':
1034 		case '#':
1035 			*string = copy_local_string(&str);
1036 			if (! *string)
1037 				c = -ENOMEM;
1038 			else {
1039 				unget_char(c, input);
1040 				c = 0;
1041 			}
1042 			goto _out;
1043 		default:
1044 			break;
1045 		}
1046 		if (add_char_local_string(&str, c) < 0) {
1047 			c = -ENOMEM;
1048 			break;
1049 		}
1050 	}
1051  _out:
1052 	free_local_string(&str);
1053 	return c;
1054 }
1055 
get_delimstring(char ** string,int delim,input_t * input)1056 static int get_delimstring(char **string, int delim, input_t *input)
1057 {
1058 	struct local_string str;
1059 	int c;
1060 
1061 	init_local_string(&str);
1062 	while (1) {
1063 		c = get_char(input);
1064 		if (c < 0)
1065 			break;
1066 		if (c == '\\') {
1067 			c = get_quotedchar(input);
1068 			if (c < 0)
1069 				break;
1070 			if (c == '\n')
1071 				continue;
1072 		} else if (c == delim) {
1073 			*string = copy_local_string(&str);
1074 			if (! *string)
1075 				c = -ENOMEM;
1076 			else
1077 				c = 0;
1078 			break;
1079 		}
1080 		if (add_char_local_string(&str, c) < 0) {
1081 			c = -ENOMEM;
1082 			break;
1083 		}
1084 	}
1085 	 free_local_string(&str);
1086 	 return c;
1087 }
1088 
1089 /* Return 0 for free string, 1 for delimited string */
get_string(char ** string,int id,input_t * input)1090 static int get_string(char **string, int id, input_t *input)
1091 {
1092 	int c = get_nonwhite(input), err;
1093 	if (c < 0)
1094 		return c;
1095 	switch (c) {
1096 	case '=':
1097 	case ',':
1098 	case ';':
1099 	case '.':
1100 	case '{':
1101 	case '}':
1102 	case '[':
1103 	case ']':
1104 	case '\\':
1105 		return LOCAL_UNEXPECTED_CHAR;
1106 	case '\'':
1107 	case '"':
1108 		err = get_delimstring(string, c, input);
1109 		if (err < 0)
1110 			return err;
1111 		return 1;
1112 	default:
1113 		unget_char(c, input);
1114 		err = get_freestring(string, id, input);
1115 		if (err < 0)
1116 			return err;
1117 		return 0;
1118 	}
1119 }
1120 
_snd_config_make(snd_config_t ** config,char ** id,snd_config_type_t type)1121 static int _snd_config_make(snd_config_t **config, char **id, snd_config_type_t type)
1122 {
1123 	snd_config_t *n;
1124 	assert(config);
1125 	n = calloc(1, sizeof(*n));
1126 	if (n == NULL) {
1127 		if (*id) {
1128 			free(*id);
1129 			*id = NULL;
1130 		}
1131 		return -ENOMEM;
1132 	}
1133 	if (id) {
1134 		n->id = *id;
1135 		*id = NULL;
1136 	}
1137 	n->type = type;
1138 	if (type == SND_CONFIG_TYPE_COMPOUND)
1139 		INIT_LIST_HEAD(&n->u.compound.fields);
1140 	*config = n;
1141 	return 0;
1142 }
1143 
1144 
_snd_config_make_add(snd_config_t ** config,char ** id,snd_config_type_t type,snd_config_t * parent)1145 static int _snd_config_make_add(snd_config_t **config, char **id,
1146 				snd_config_type_t type, snd_config_t *parent)
1147 {
1148 	snd_config_t *n;
1149 	int err;
1150 	assert(parent->type == SND_CONFIG_TYPE_COMPOUND);
1151 	err = _snd_config_make(&n, id, type);
1152 	if (err < 0)
1153 		return err;
1154 	n->parent = parent;
1155 	list_add_tail(&n->list, &parent->u.compound.fields);
1156 	*config = n;
1157 	return 0;
1158 }
1159 
_snd_config_search(snd_config_t * config,const char * id,int len,snd_config_t ** result)1160 static int _snd_config_search(snd_config_t *config,
1161 			      const char *id, int len, snd_config_t **result)
1162 {
1163 	snd_config_iterator_t i, next;
1164 	snd_config_for_each(i, next, config) {
1165 		snd_config_t *n = snd_config_iterator_entry(i);
1166 		if (len < 0) {
1167 			if (strcmp(n->id, id) != 0)
1168 				continue;
1169 		} else if (strlen(n->id) != (size_t) len ||
1170 			   memcmp(n->id, id, (size_t) len) != 0)
1171 				continue;
1172 		if (result)
1173 			*result = n;
1174 		return 0;
1175 	}
1176 	return -ENOENT;
1177 }
1178 
parse_value(snd_config_t ** _n,snd_config_t * parent,input_t * input,char ** id,int skip)1179 static int parse_value(snd_config_t **_n, snd_config_t *parent, input_t *input, char **id, int skip)
1180 {
1181 	snd_config_t *n = *_n;
1182 	char *s;
1183 	int err;
1184 
1185 	err = get_string(&s, 0, input);
1186 	if (err < 0)
1187 		return err;
1188 	if (skip) {
1189 		free(s);
1190 		return 0;
1191 	}
1192 	if (err == 0 && ((s[0] >= '0' && s[0] <= '9') || s[0] == '-')) {
1193 		long long i;
1194 		errno = 0;
1195 		err = safe_strtoll(s, &i);
1196 		if (err < 0) {
1197 			double r;
1198 			err = safe_strtod(s, &r);
1199 			if (err >= 0) {
1200 				free(s);
1201 				if (n) {
1202 					if (n->type != SND_CONFIG_TYPE_REAL) {
1203 						SNDERR("%s is not a real", *id);
1204 						return -EINVAL;
1205 					}
1206 				} else {
1207 					err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_REAL, parent);
1208 					if (err < 0)
1209 						return err;
1210 				}
1211 				n->u.real = r;
1212 				*_n = n;
1213 				return 0;
1214 			}
1215 		} else {
1216 			free(s);
1217 			if (n) {
1218 				if (n->type != SND_CONFIG_TYPE_INTEGER && n->type != SND_CONFIG_TYPE_INTEGER64) {
1219 					SNDERR("%s is not an integer", *id);
1220 					return -EINVAL;
1221 				}
1222 			} else {
1223 				if (i <= INT_MAX)
1224 					err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER, parent);
1225 				else
1226 					err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER64, parent);
1227 				if (err < 0)
1228 					return err;
1229 			}
1230 			if (n->type == SND_CONFIG_TYPE_INTEGER)
1231 				n->u.integer = (long) i;
1232 			else
1233 				n->u.integer64 = i;
1234 			*_n = n;
1235 			return 0;
1236 		}
1237 	}
1238 	if (n) {
1239 		if (n->type != SND_CONFIG_TYPE_STRING) {
1240 			SNDERR("%s is not a string", *id);
1241 			free(s);
1242 			return -EINVAL;
1243 		}
1244 	} else {
1245 		err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_STRING, parent);
1246 		if (err < 0)
1247 			return err;
1248 	}
1249 	free(n->u.string);
1250 	n->u.string = s;
1251 	*_n = n;
1252 	return 0;
1253 }
1254 
1255 static int parse_defs(snd_config_t *parent, input_t *input, int skip, int override);
1256 static int parse_array_defs(snd_config_t *farther, input_t *input, int skip, int override);
1257 
parse_array_def(snd_config_t * parent,input_t * input,int * idx,int skip,int override)1258 static int parse_array_def(snd_config_t *parent, input_t *input, int *idx, int skip, int override)
1259 {
1260 	char *id = NULL;
1261 	int c;
1262 	int err;
1263 	snd_config_t *n = NULL;
1264 
1265 	if (!skip) {
1266 		snd_config_t *g;
1267 		char static_id[12];
1268 		while (1) {
1269 			snprintf(static_id, sizeof(static_id), "%i", *idx);
1270 			if (_snd_config_search(parent, static_id, -1, &g) == 0) {
1271 				if (override) {
1272 					snd_config_delete(n);
1273 				} else {
1274 					/* merge */
1275 					(*idx)++;
1276 					continue;
1277 				}
1278 			}
1279 			break;
1280 		}
1281 		id = strdup(static_id);
1282 		if (id == NULL)
1283 			return -ENOMEM;
1284 	}
1285 	c = get_nonwhite(input);
1286 	if (c < 0) {
1287 		err = c;
1288 		goto __end;
1289 	}
1290 	switch (c) {
1291 	case '{':
1292 	case '[':
1293 	{
1294 		char endchr;
1295 		if (!skip) {
1296 			if (n) {
1297 				if (n->type != SND_CONFIG_TYPE_COMPOUND) {
1298 					SNDERR("%s is not a compound", id);
1299 					err = -EINVAL;
1300 					goto __end;
1301 				}
1302 			} else {
1303 				err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent);
1304 				if (err < 0)
1305 					goto __end;
1306 			}
1307 		}
1308 		if (c == '{') {
1309 			err = parse_defs(n, input, skip, override);
1310 			endchr = '}';
1311 		} else {
1312 			err = parse_array_defs(n, input, skip, override);
1313 			endchr = ']';
1314 		}
1315 		c = get_nonwhite(input);
1316 		if (c < 0) {
1317 			err = c;
1318 			goto __end;
1319 		}
1320 		if (c != endchr) {
1321 			if (n)
1322 				snd_config_delete(n);
1323 			err = LOCAL_UNEXPECTED_CHAR;
1324 			goto __end;
1325 		}
1326 		break;
1327 	}
1328 	default:
1329 		unget_char(c, input);
1330 		err = parse_value(&n, parent, input, &id, skip);
1331 		if (err < 0)
1332 			goto __end;
1333 		break;
1334 	}
1335 	err = 0;
1336       __end:
1337 	free(id);
1338       	return err;
1339 }
1340 
parse_array_defs(snd_config_t * parent,input_t * input,int skip,int override)1341 static int parse_array_defs(snd_config_t *parent, input_t *input, int skip, int override)
1342 {
1343 	int idx = 0;
1344 	while (1) {
1345 		int c = get_nonwhite(input), err;
1346 		if (c < 0)
1347 			return c;
1348 		unget_char(c, input);
1349 		if (c == ']')
1350 			return 0;
1351 		err = parse_array_def(parent, input, &idx, skip, override);
1352 		if (err < 0)
1353 			return err;
1354 		idx++;
1355 	}
1356 	return 0;
1357 }
1358 
parse_def(snd_config_t * parent,input_t * input,int skip,int override)1359 static int parse_def(snd_config_t *parent, input_t *input, int skip, int override)
1360 {
1361 	char *id = NULL;
1362 	int c;
1363 	int err;
1364 	snd_config_t *n;
1365 	enum {MERGE_CREATE, MERGE, OVERRIDE, DONT_OVERRIDE} mode;
1366 	while (1) {
1367 		c = get_nonwhite(input);
1368 		if (c < 0)
1369 			return c;
1370 		switch (c) {
1371 		case '+':
1372 			mode = MERGE_CREATE;
1373 			break;
1374 		case '-':
1375 			mode = MERGE;
1376 			break;
1377 		case '?':
1378 			mode = DONT_OVERRIDE;
1379 			break;
1380 		case '!':
1381 			mode = OVERRIDE;
1382 			break;
1383 		default:
1384 			mode = !override ? MERGE_CREATE : OVERRIDE;
1385 			unget_char(c, input);
1386 		}
1387 		err = get_string(&id, 1, input);
1388 		if (err < 0)
1389 			return err;
1390 		c = get_nonwhite(input);
1391 		if (c != '.')
1392 			break;
1393 		if (skip) {
1394 			free(id);
1395 			continue;
1396 		}
1397 		if (_snd_config_search(parent, id, -1, &n) == 0) {
1398 			if (mode == DONT_OVERRIDE) {
1399 				skip = 1;
1400 				free(id);
1401 				continue;
1402 			}
1403 			if (mode != OVERRIDE) {
1404 				if (n->type != SND_CONFIG_TYPE_COMPOUND) {
1405 					SNDERR("%s is not a compound", id);
1406 					return -EINVAL;
1407 				}
1408 				n->u.compound.join = true;
1409 				parent = n;
1410 				free(id);
1411 				continue;
1412 			}
1413 			snd_config_delete(n);
1414 		}
1415 		if (mode == MERGE) {
1416 			SNDERR("%s does not exists", id);
1417 			err = -ENOENT;
1418 			goto __end;
1419 		}
1420 		err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent);
1421 		if (err < 0)
1422 			goto __end;
1423 		n->u.compound.join = true;
1424 		parent = n;
1425 	}
1426 	if (c == '=') {
1427 		c = get_nonwhite(input);
1428 		if (c < 0)
1429 			return c;
1430 	}
1431 	if (!skip) {
1432 		if (_snd_config_search(parent, id, -1, &n) == 0) {
1433 			if (mode == DONT_OVERRIDE) {
1434 				skip = 1;
1435 				n = NULL;
1436 			} else if (mode == OVERRIDE) {
1437 				snd_config_delete(n);
1438 				n = NULL;
1439 			}
1440 		} else {
1441 			n = NULL;
1442 			if (mode == MERGE) {
1443 				SNDERR("%s does not exists", id);
1444 				err = -ENOENT;
1445 				goto __end;
1446 			}
1447 		}
1448 	}
1449 	switch (c) {
1450 	case '{':
1451 	case '[':
1452 	{
1453 		char endchr;
1454 		if (!skip) {
1455 			if (n) {
1456 				if (n->type != SND_CONFIG_TYPE_COMPOUND) {
1457 					SNDERR("%s is not a compound", id);
1458 					err = -EINVAL;
1459 					goto __end;
1460 				}
1461 			} else {
1462 				err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent);
1463 				if (err < 0)
1464 					goto __end;
1465 			}
1466 		}
1467 		if (c == '{') {
1468 			err = parse_defs(n, input, skip, override);
1469 			endchr = '}';
1470 		} else {
1471 			err = parse_array_defs(n, input, skip, override);
1472 			endchr = ']';
1473 		}
1474 		c = get_nonwhite(input);
1475 		if (c != endchr) {
1476 			if (n)
1477 				snd_config_delete(n);
1478 			err = LOCAL_UNEXPECTED_CHAR;
1479 			goto __end;
1480 		}
1481 		break;
1482 	}
1483 	default:
1484 		unget_char(c, input);
1485 		err = parse_value(&n, parent, input, &id, skip);
1486 		if (err < 0)
1487 			goto __end;
1488 		break;
1489 	}
1490 	c = get_nonwhite(input);
1491 	switch (c) {
1492 	case ';':
1493 	case ',':
1494 		break;
1495 	default:
1496 		unget_char(c, input);
1497 	}
1498       __end:
1499 	free(id);
1500 	return err;
1501 }
1502 
parse_defs(snd_config_t * parent,input_t * input,int skip,int override)1503 static int parse_defs(snd_config_t *parent, input_t *input, int skip, int override)
1504 {
1505 	int c, err;
1506 	while (1) {
1507 		c = get_nonwhite(input);
1508 		if (c < 0)
1509 			return c == LOCAL_UNEXPECTED_EOF ? 0 : c;
1510 		unget_char(c, input);
1511 		if (c == '}')
1512 			return 0;
1513 		err = parse_def(parent, input, skip, override);
1514 		if (err < 0)
1515 			return err;
1516 	}
1517 	return 0;
1518 }
1519 
string_print(char * str,int id,snd_output_t * out)1520 static void string_print(char *str, int id, snd_output_t *out)
1521 {
1522 	int q;
1523 	unsigned char *p = (unsigned char *)str;
1524 	if (!p || !*p) {
1525 		snd_output_puts(out, "''");
1526 		return;
1527 	}
1528 	if (!id) {
1529 		switch (*p) {
1530 		case '0': case '1': case '2': case '3': case '4':
1531 		case '5': case '6': case '7': case '8': case '9':
1532 		case '-':
1533 			goto quoted;
1534 		}
1535 	}
1536  loop:
1537 	switch (*p) {
1538 	case 0:
1539 		goto nonquoted;
1540 	case ' ':
1541 	case '=':
1542 	case ';':
1543 	case ',':
1544 	case '.':
1545 	case '{':
1546 	case '}':
1547 	case '[':
1548 	case ']':
1549 	case '\'':
1550 	case '"':
1551 	case '*':
1552 	case '#':
1553 		goto quoted;
1554 	default:
1555 		if (*p <= 31 || *p >= 127)
1556 			goto quoted;
1557 		p++;
1558 		goto loop;
1559 	}
1560  nonquoted:
1561 	snd_output_puts(out, str);
1562 	return;
1563  quoted:
1564 	q = strchr(str, '\'') ? '"' : '\'';
1565 	snd_output_putc(out, q);
1566 	p = (unsigned char *)str;
1567 	while (*p) {
1568 		int c;
1569 		c = *p;
1570 		switch (c) {
1571 		case '\n':
1572 			snd_output_putc(out, '\\');
1573 			snd_output_putc(out, 'n');
1574 			break;
1575 		case '\t':
1576 			snd_output_putc(out, '\\');
1577 			snd_output_putc(out, 't');
1578 			break;
1579 		case '\v':
1580 			snd_output_putc(out, '\\');
1581 			snd_output_putc(out, 'v');
1582 			break;
1583 		case '\b':
1584 			snd_output_putc(out, '\\');
1585 			snd_output_putc(out, 'b');
1586 			break;
1587 		case '\r':
1588 			snd_output_putc(out, '\\');
1589 			snd_output_putc(out, 'r');
1590 			break;
1591 		case '\f':
1592 			snd_output_putc(out, '\\');
1593 			snd_output_putc(out, 'f');
1594 			break;
1595 		default:
1596 			if (c == q) {
1597 				snd_output_putc(out, '\\');
1598 				snd_output_putc(out, c);
1599 			} else {
1600 				if (c >= 32 && c <= 126)
1601 					snd_output_putc(out, c);
1602 				else
1603 					snd_output_printf(out, "\\%04o", c);
1604 			}
1605 			break;
1606 		}
1607 		p++;
1608 	}
1609 	snd_output_putc(out, q);
1610 }
1611 
level_print(snd_output_t * out,unsigned int level)1612 static void level_print(snd_output_t *out, unsigned int level)
1613 {
1614 	char a[level + 1];
1615 	memset(a, '\t', level);
1616 	a[level] = '\0';
1617 	snd_output_puts(out, a);
1618 }
1619 
1620 static int _snd_config_save_children(snd_config_t *config, snd_output_t *out,
1621 				     unsigned int level, unsigned int joins,
1622 				     int array);
1623 
_snd_config_save_node_value(snd_config_t * n,snd_output_t * out,unsigned int level)1624 int _snd_config_save_node_value(snd_config_t *n, snd_output_t *out,
1625 				unsigned int level)
1626 {
1627 	int err, array;
1628 	switch (n->type) {
1629 	case SND_CONFIG_TYPE_INTEGER:
1630 		snd_output_printf(out, "%ld", n->u.integer);
1631 		break;
1632 	case SND_CONFIG_TYPE_INTEGER64:
1633 		snd_output_printf(out, "%lld", n->u.integer64);
1634 		break;
1635 	case SND_CONFIG_TYPE_REAL:
1636 		snd_output_printf(out, "%-16g", n->u.real);
1637 		break;
1638 	case SND_CONFIG_TYPE_STRING:
1639 		string_print(n->u.string, 0, out);
1640 		break;
1641 	case SND_CONFIG_TYPE_POINTER:
1642 		SNDERR("cannot save runtime pointer type");
1643 		return -EINVAL;
1644 	case SND_CONFIG_TYPE_COMPOUND:
1645 		array = snd_config_is_array(n);
1646 		snd_output_putc(out, array ? '[' : '{');
1647 		snd_output_putc(out, '\n');
1648 		err = _snd_config_save_children(n, out, level + 1, 0, array);
1649 		if (err < 0)
1650 			return err;
1651 		level_print(out, level);
1652 		snd_output_putc(out, array ? ']' : '}');
1653 		break;
1654 	}
1655 	return 0;
1656 }
1657 
id_print(snd_config_t * n,snd_output_t * out,unsigned int joins)1658 static void id_print(snd_config_t *n, snd_output_t *out, unsigned int joins)
1659 {
1660 	if (joins > 0) {
1661 		assert(n->parent);
1662 		id_print(n->parent, out, joins - 1);
1663 		snd_output_putc(out, '.');
1664 	}
1665 	string_print(n->id, 1, out);
1666 }
1667 
_snd_config_save_children(snd_config_t * config,snd_output_t * out,unsigned int level,unsigned int joins,int array)1668 static int _snd_config_save_children(snd_config_t *config, snd_output_t *out,
1669 				     unsigned int level, unsigned int joins,
1670 				     int array)
1671 {
1672 	int err;
1673 	snd_config_iterator_t i, next;
1674 	assert(config && out);
1675 	snd_config_for_each(i, next, config) {
1676 		snd_config_t *n = snd_config_iterator_entry(i);
1677 		if (n->type == SND_CONFIG_TYPE_COMPOUND &&
1678 		    n->u.compound.join) {
1679 			err = _snd_config_save_children(n, out, level, joins + 1, 0);
1680 			if (err < 0)
1681 				return err;
1682 			continue;
1683 		}
1684 		level_print(out, level);
1685 		if (!array) {
1686 			id_print(n, out, joins);
1687 			snd_output_putc(out, ' ');
1688 #if 0
1689 			snd_output_putc(out, '=');
1690 #endif
1691 		}
1692 		err = _snd_config_save_node_value(n, out, level);
1693 		if (err < 0)
1694 			return err;
1695 #if 0
1696 		snd_output_putc(out, ';');
1697 #endif
1698 		snd_output_putc(out, '\n');
1699 	}
1700 	return 0;
1701 }
1702 #endif
1703 
1704 
1705 /**
1706  * \brief Substitutes one configuration node to another.
1707  * \param dst Handle to the destination node.
1708  * \param src Handle to the source node. Must not be the same as \a dst.
1709  * \return Zero if successful, otherwise a negative error code.
1710  *
1711  * If both nodes are compounds, the source compound node members will
1712  * be moved to the destination compound node. The original destination
1713  * compound node members will be deleted (overwritten).
1714  *
1715  * If the destination node is a compound and the source node is
1716  * an ordinary type, the compound members are deleted (including
1717  * their contents).
1718  *
1719  * Otherwise, the source node's value replaces the destination node's
1720  * value.
1721  *
1722  * In any case, a successful call to this function frees the source
1723  * node.
1724  */
snd_config_substitute(snd_config_t * dst,snd_config_t * src)1725 int snd_config_substitute(snd_config_t *dst, snd_config_t *src)
1726 {
1727 	assert(dst && src);
1728 	if (dst->type == SND_CONFIG_TYPE_COMPOUND) {
1729 		int err = snd_config_delete_compound_members(dst);
1730 		if (err < 0)
1731 			return err;
1732 	}
1733 	if (dst->type == SND_CONFIG_TYPE_COMPOUND &&
1734 	    src->type == SND_CONFIG_TYPE_COMPOUND) {	/* overwrite */
1735 		snd_config_iterator_t i, next;
1736 		snd_config_for_each(i, next, src) {
1737 			snd_config_t *n = snd_config_iterator_entry(i);
1738 			n->parent = dst;
1739 		}
1740 		src->u.compound.fields.next->prev = &dst->u.compound.fields;
1741 		src->u.compound.fields.prev->next = &dst->u.compound.fields;
1742 	}
1743 	free(dst->id);
1744 	dst->id = src->id;
1745 	dst->type = src->type;
1746 	dst->u = src->u;
1747 	free(src);
1748 	return 0;
1749 }
1750 
1751 /**
1752  * \brief Converts an ASCII string to a configuration node type.
1753  * \param[in] ascii A string containing a configuration node type.
1754  * \param[out] type The node type corresponding to \a ascii.
1755  * \return Zero if successful, otherwise a negative error code.
1756  *
1757  * This function recognizes at least the following node types:
1758  * <dl>
1759  * <dt>integer<dt>#SND_CONFIG_TYPE_INTEGER
1760  * <dt>integer64<dt>#SND_CONFIG_TYPE_INTEGER64
1761  * <dt>real<dt>#SND_CONFIG_TYPE_REAL
1762  * <dt>string<dt>#SND_CONFIG_TYPE_STRING
1763  * <dt>compound<dt>#SND_CONFIG_TYPE_COMPOUND
1764  * </dl>
1765  *
1766  * \par Errors:
1767  * <dl>
1768  * <dt>-EINVAL<dd>Unknown note type in \a type.
1769  * </dl>
1770  */
snd_config_get_type_ascii(const char * ascii,snd_config_type_t * type)1771 int snd_config_get_type_ascii(const char *ascii, snd_config_type_t *type)
1772 {
1773 	assert(ascii && type);
1774 	if (!strcmp(ascii, "integer")) {
1775 		*type = SND_CONFIG_TYPE_INTEGER;
1776 		return 0;
1777 	}
1778 	if (!strcmp(ascii, "integer64")) {
1779 		*type = SND_CONFIG_TYPE_INTEGER64;
1780 		return 0;
1781 	}
1782 	if (!strcmp(ascii, "real")) {
1783 		*type = SND_CONFIG_TYPE_REAL;
1784 		return 0;
1785 	}
1786 	if (!strcmp(ascii, "string")) {
1787 		*type = SND_CONFIG_TYPE_STRING;
1788 		return 0;
1789 	}
1790 	if (!strcmp(ascii, "compound")) {
1791 		*type = SND_CONFIG_TYPE_COMPOUND;
1792 		return 0;
1793 	}
1794 	return -EINVAL;
1795 }
1796 
1797 /**
1798  * \brief Returns the type of a configuration node.
1799  * \param config Handle to the configuration node.
1800  * \return The node's type.
1801  *
1802  * \par Conforming to:
1803  * LSB 3.2
1804  */
snd_config_get_type(const snd_config_t * config)1805 snd_config_type_t snd_config_get_type(const snd_config_t *config)
1806 {
1807 	return config->type;
1808 }
1809 
check_array_item(const char * id,int index)1810 static int check_array_item(const char *id, int index)
1811 {
1812 	const char *p;
1813 	long val;
1814 
1815 	for (p = id; *p; p++) {
1816 		if (*p < '0' || *p > '9')
1817 			return 0;
1818 	}
1819 
1820 	if (safe_strtol(id, &val))
1821 		return 0;
1822 	return val == index;
1823 }
1824 
1825 /**
1826  * \brief Returns if the compound is an array (and count of items).
1827  * \param config Handle to the configuration node.
1828  * \return A count of items in array, zero when the compound is not an array,
1829  *         otherwise a negative error code.
1830  */
snd_config_is_array(const snd_config_t * config)1831 int snd_config_is_array(const snd_config_t *config)
1832 {
1833 	int idx;
1834 	snd_config_iterator_t i, next;
1835 	snd_config_t *node;
1836 
1837 	assert(config);
1838 	if (config->type != SND_CONFIG_TYPE_COMPOUND)
1839 		return -EINVAL;
1840 	idx = 0;
1841 	snd_config_for_each(i, next, config) {
1842 		node = snd_config_iterator_entry(i);
1843 		if (!check_array_item(node->id, idx))
1844 			return 0;
1845 		idx++;
1846 	}
1847 	return idx;
1848 }
1849 
1850 /**
1851  * \brief Returns if the compound has no fields (is empty).
1852  * \param config Handle to the configuration node.
1853  * \return A positive value when true, zero when false, otherwise a negative error code.
1854  */
snd_config_is_empty(const snd_config_t * config)1855 int snd_config_is_empty(const snd_config_t *config)
1856 {
1857 	assert(config);
1858 	if (config->type != SND_CONFIG_TYPE_COMPOUND)
1859 		return -EINVAL;
1860 	return list_empty(&config->u.compound.fields);
1861 }
1862 
1863 /**
1864  * \brief Returns the id of a configuration node.
1865  * \param[in] config Handle to the configuration node.
1866  * \param[out] id The function puts the pointer to the id string at the
1867  *                address specified by \a id.
1868  * \return Zero if successful, otherwise a negative error code.
1869  *
1870  * The returned string is owned by the configuration node; the application
1871  * must not modify or delete it, and the string becomes invalid when the
1872  * node's id changes or when the node is freed.
1873  *
1874  * If the node does not have an id, \a *id is set to \c NULL.
1875  *
1876  * \par Conforming to:
1877  * LSB 3.2
1878  */
snd_config_get_id(const snd_config_t * config,const char ** id)1879 int snd_config_get_id(const snd_config_t *config, const char **id)
1880 {
1881 	assert(config && id);
1882 	*id = config->id;
1883 	return 0;
1884 }
1885 
1886 /**
1887  * \brief Sets the id of a configuration node.
1888  * \param config Handle to the configuration node.
1889  * \param id The new node id, must not be \c NULL.
1890  * \return Zero if successful, otherwise a negative error code.
1891  *
1892  * This function stores a copy of \a id in the node.
1893  *
1894  * \par Errors:
1895  * <dl>
1896  * <dt>-EEXIST<dd>One of \a config's siblings already has the id \a id.
1897  * <dt>-EINVAL<dd>The id of a node with a parent cannot be set to \c NULL.
1898  * <dt>-ENOMEM<dd>Out of memory.
1899  * </dl>
1900  */
snd_config_set_id(snd_config_t * config,const char * id)1901 int snd_config_set_id(snd_config_t *config, const char *id)
1902 {
1903 	snd_config_iterator_t i, next;
1904 	char *new_id;
1905 	assert(config);
1906 	if (id) {
1907 		if (config->parent) {
1908 			snd_config_for_each(i, next, config->parent) {
1909 				snd_config_t *n = snd_config_iterator_entry(i);
1910 				if (n != config && strcmp(id, n->id) == 0)
1911 					return -EEXIST;
1912 			}
1913 		}
1914 		new_id = strdup(id);
1915 		if (!new_id)
1916 			return -ENOMEM;
1917 	} else {
1918 		if (config->parent)
1919 			return -EINVAL;
1920 		new_id = NULL;
1921 	}
1922 	free(config->id);
1923 	config->id = new_id;
1924 	return 0;
1925 }
1926 
1927 /**
1928  * \brief Creates a top level configuration node.
1929  * \param[out] config Handle to the new node.
1930  * \return Zero if successful, otherwise a negative error code.
1931  *
1932  * The returned node is an empty compound node without a parent and
1933  * without an id.
1934  *
1935  * \par Errors:
1936  * <dl>
1937  * <dt>-ENOMEM<dd>Out of memory.
1938  * </dl>
1939  *
1940  * \par Conforming to:
1941  * LSB 3.2
1942  */
snd_config_top(snd_config_t ** config)1943 int snd_config_top(snd_config_t **config)
1944 {
1945 	assert(config);
1946 	return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND);
1947 }
1948 
1949 #ifndef DOC_HIDDEN
_snd_config_load_with_include(snd_config_t * config,snd_input_t * in,int override,const char * const * include_paths)1950 int _snd_config_load_with_include(snd_config_t *config, snd_input_t *in,
1951 				  int override, const char * const *include_paths)
1952 {
1953 	int err;
1954 	input_t input;
1955 	struct filedesc *fd, *fd_next;
1956 
1957 	assert(config && in);
1958 	fd = malloc(sizeof(*fd));
1959 	if (!fd)
1960 		return -ENOMEM;
1961 	fd->name = NULL;
1962 	fd->in = in;
1963 	fd->line = 1;
1964 	fd->column = 0;
1965 	fd->next = NULL;
1966 	INIT_LIST_HEAD(&fd->include_paths);
1967 	if (include_paths) {
1968 		for (; *include_paths; include_paths++) {
1969 			err = add_include_path(fd, *include_paths);
1970 			if (err < 0)
1971 				goto _end;
1972 		}
1973 	} else {
1974 		err = add_include_path(fd, snd_config_topdir());
1975 		if (err < 0)
1976 			goto _end;
1977 	}
1978 	input.current = fd;
1979 	input.unget = 0;
1980 	err = parse_defs(config, &input, 0, override);
1981 	fd = input.current;
1982 	if (err < 0) {
1983 		const char *str;
1984 		switch (err) {
1985 		case LOCAL_UNTERMINATED_STRING:
1986 			str = "Unterminated string";
1987 			err = -EINVAL;
1988 			break;
1989 		case LOCAL_UNTERMINATED_QUOTE:
1990 			str = "Unterminated quote";
1991 			err = -EINVAL;
1992 			break;
1993 		case LOCAL_UNEXPECTED_CHAR:
1994 			str = "Unexpected char";
1995 			err = -EINVAL;
1996 			break;
1997 		case LOCAL_UNEXPECTED_EOF:
1998 			str = "Unexpected end of file";
1999 			err = -EINVAL;
2000 			break;
2001 		default:
2002 			str = strerror(-err);
2003 			break;
2004 		}
2005 		SNDERR("%s:%d:%d:%s", fd->name ? fd->name : "_toplevel_", fd->line, fd->column, str);
2006 		goto _end;
2007 	}
2008 	err = get_char(&input);
2009 	fd = input.current;
2010 	if (err != LOCAL_UNEXPECTED_EOF) {
2011 		SNDERR("%s:%d:%d:Unexpected }", fd->name ? fd->name : "", fd->line, fd->column);
2012 		err = -EINVAL;
2013 		goto _end;
2014 	}
2015 	err = 0;
2016  _end:
2017 	while (fd->next) {
2018 		fd_next = fd->next;
2019 		snd_input_close(fd->in);
2020 		free(fd->name);
2021 		free_include_paths(fd);
2022 		free(fd);
2023 		fd = fd_next;
2024 	}
2025 
2026 	free_include_paths(fd);
2027 	free(fd);
2028 	return err;
2029 }
2030 #endif
2031 
2032 /**
2033  * \brief Loads a configuration tree.
2034  * \param config Handle to a top level configuration node.
2035  * \param in Input handle to read the configuration from.
2036  * \return Zero if successful, otherwise a negative error code.
2037  *
2038  * The definitions loaded from the input are added to \a config, which
2039  * must be a compound node.
2040  *
2041  * \par Errors:
2042  * Any errors encountered when parsing the input or returned by hooks or
2043  * functions.
2044  *
2045  * \par Conforming to:
2046  * LSB 3.2
2047  */
snd_config_load(snd_config_t * config,snd_input_t * in)2048 int snd_config_load(snd_config_t *config, snd_input_t *in)
2049 {
2050 	return _snd_config_load_with_include(config, in, 0, NULL);
2051 }
2052 
2053 /**
2054  * \brief Loads a configuration tree from a string.
2055  * \param[out] The function puts the handle to the configuration
2056  *	       node loaded from the file(s) at the address specified
2057  *             by \a config.
2058  * \param[in] s String with the ASCII configuration
2059  * \param[in] size String size, if zero, a C string is expected (with termination)
2060  * \return Zero if successful, otherwise a negative error code.
2061  *
2062  * The definitions loaded from the string are put to \a config, which
2063  * is created as a new top node.
2064  *
2065  * \par Errors:
2066  * Any errors encountered when parsing the input or returned by hooks or
2067  * functions.
2068  */
snd_config_load_string(snd_config_t ** config,const char * s,size_t size)2069 int snd_config_load_string(snd_config_t **config, const char *s, size_t size)
2070 {
2071 	snd_input_t *input;
2072 	snd_config_t *dst;
2073 	int err;
2074 
2075 	assert(config && s);
2076 	if (size == 0)
2077 		size = strlen(s);
2078 	err = snd_input_buffer_open(&input, s, size);
2079 	if (err < 0)
2080 		return err;
2081 	err = snd_config_top(&dst);
2082 	if (err < 0) {
2083 		snd_input_close(input);
2084 		return err;
2085 	}
2086 	err = snd_config_load(dst, input);
2087 	snd_input_close(input);
2088 	if (err < 0) {
2089 		snd_config_delete(dst);
2090 		return err;
2091 	}
2092 	*config = dst;
2093 	return 0;
2094 }
2095 
2096 /**
2097  * \brief Loads a configuration tree and overrides existing configuration nodes.
2098  * \param config Handle to a top level configuration node.
2099  * \param in Input handle to read the configuration from.
2100  * \return Zero if successful, otherwise a negative error code.
2101  *
2102  * This function loads definitions from \a in into \a config like
2103  * #snd_config_load, but the default mode for input nodes is 'override'
2104  * (!) instead of 'merge+create' (+).
2105  */
snd_config_load_override(snd_config_t * config,snd_input_t * in)2106 int snd_config_load_override(snd_config_t *config, snd_input_t *in)
2107 {
2108 	return _snd_config_load_with_include(config, in, 1, NULL);
2109 }
2110 
2111 /**
2112  * \brief Adds a child to a compound configuration node.
2113  * \param parent Handle to a compound configuration node.
2114  * \param child Handle to the configuration node to be added.
2115  * \return Zero if successful, otherwise a negative error code.
2116  *
2117  * This function makes the node \a child a child of the node \a parent.
2118  *
2119  * The parent node then owns the child node, i.e., the child node gets
2120  * deleted together with its parent.
2121  *
2122  * \a child must have an id.
2123  *
2124  * \par Errors:
2125  * <dl>
2126  * <dt>-EINVAL<dd>\a child does not have an id.
2127  * <dt>-EINVAL<dd>\a child already has a parent.
2128  * <dt>-EEXIST<dd>\a parent already contains a child node with the same
2129  *                id as \a child.
2130  * </dl>
2131  *
2132  * \par Conforming to:
2133  * LSB 3.2
2134  */
snd_config_add(snd_config_t * parent,snd_config_t * child)2135 int snd_config_add(snd_config_t *parent, snd_config_t *child)
2136 {
2137 	snd_config_iterator_t i, next;
2138 	assert(parent && child);
2139 	if (!child->id || child->parent)
2140 		return -EINVAL;
2141 	snd_config_for_each(i, next, parent) {
2142 		snd_config_t *n = snd_config_iterator_entry(i);
2143 		if (strcmp(child->id, n->id) == 0)
2144 			return -EEXIST;
2145 	}
2146 	child->parent = parent;
2147 	list_add_tail(&child->list, &parent->u.compound.fields);
2148 	return 0;
2149 }
2150 
2151 /**
2152  * \brief Adds a child after another child configuration node.
2153  * \param after Handle to the start configuration node.
2154  * \param child Handle to the configuration node to be added.
2155  * \return Zero if successful, otherwise a negative error code.
2156  *
2157  * This function makes the node \a child a child of the parent of
2158  * the node \a after.
2159  *
2160  * The parent node then owns the child node, i.e., the child node gets
2161  * deleted together with its parent.
2162  *
2163  * \a child must have an id.
2164  *
2165  * \par Errors:
2166  * <dl>
2167  * <dt>-EINVAL<dd>\a child does not have an id.
2168  * <dt>-EINVAL<dd>\a child already has a parent.
2169  * <dt>-EEXIST<dd>\a parent already contains a child node with the same
2170  *                id as \a child.
2171  * </dl>
2172  */
snd_config_add_after(snd_config_t * after,snd_config_t * child)2173 int snd_config_add_after(snd_config_t *after, snd_config_t *child)
2174 {
2175 	snd_config_iterator_t i, next;
2176 	snd_config_t *parent;
2177 	assert(after && child);
2178 	parent = after->parent;
2179 	assert(parent);
2180 	if (!child->id || child->parent)
2181 		return -EINVAL;
2182 	snd_config_for_each(i, next, parent) {
2183 		snd_config_t *n = snd_config_iterator_entry(i);
2184 		if (strcmp(child->id, n->id) == 0)
2185 			return -EEXIST;
2186 	}
2187 	child->parent = parent;
2188 	list_insert(&child->list, &after->list, after->list.next);
2189 	return 0;
2190 }
2191 
2192 /**
2193  * \brief Adds a child before another child configuration node.
2194  * \param before Handle to the start configuration node.
2195  * \param child Handle to the configuration node to be added.
2196  * \return Zero if successful, otherwise a negative error code.
2197  *
2198  * This function makes the node \a child a child of the parent of
2199  * the node \a before.
2200  *
2201  * The parent node then owns the child node, i.e., the child node gets
2202  * deleted together with its parent.
2203  *
2204  * \a child must have an id.
2205  *
2206  * \par Errors:
2207  * <dl>
2208  * <dt>-EINVAL<dd>\a child does not have an id.
2209  * <dt>-EINVAL<dd>\a child already has a parent.
2210  * <dt>-EEXIST<dd>\a parent already contains a child node with the same
2211  *                id as \a child.
2212  * </dl>
2213  */
snd_config_add_before(snd_config_t * before,snd_config_t * child)2214 int snd_config_add_before(snd_config_t *before, snd_config_t *child)
2215 {
2216 	snd_config_iterator_t i, next;
2217 	snd_config_t *parent;
2218 	assert(before && child);
2219 	parent = before->parent;
2220 	assert(parent);
2221 	if (!child->id || child->parent)
2222 		return -EINVAL;
2223 	snd_config_for_each(i, next, parent) {
2224 		snd_config_t *n = snd_config_iterator_entry(i);
2225 		if (strcmp(child->id, n->id) == 0)
2226 			return -EEXIST;
2227 	}
2228 	child->parent = parent;
2229 	list_insert(&child->list, before->list.prev, &before->list);
2230 	return 0;
2231 }
2232 
2233 /*
2234  * append all src items to the end of dst arrray
2235  */
_snd_config_array_merge(snd_config_t * dst,snd_config_t * src,int index)2236 static int _snd_config_array_merge(snd_config_t *dst, snd_config_t *src, int index)
2237 {
2238 	snd_config_iterator_t si, snext;
2239 	int err;
2240 
2241 	snd_config_for_each(si, snext, src) {
2242 		snd_config_t *sn = snd_config_iterator_entry(si);
2243 		char id[16];
2244 		snd_config_remove(sn);
2245 		snprintf(id, sizeof(id), "%d", index++);
2246 		err = snd_config_set_id(sn, id);
2247 		if (err < 0) {
2248 			snd_config_delete(sn);
2249 			return err;
2250 		}
2251 		sn->parent = dst;
2252 		list_add_tail(&sn->list, &dst->u.compound.fields);
2253 	}
2254 	snd_config_delete(src);
2255 	return 0;
2256 }
2257 
2258 /**
2259  * \brief In-place merge of two config handles
2260  * \param dst[out] Config handle for the merged contents
2261  * \param src[in] Config handle to merge into dst (may be NULL)
2262  * \param override[in] Override flag
2263  * \return Zero if successful, otherwise a negative error code.
2264  *
2265  * This function merges all fields from the source compound to the destination compound.
2266  * When the \a override flag is set, the related subtree in \a dst is replaced from \a src.
2267  *
2268  * When \a override is not set, the child compounds are traversed and merged.
2269  *
2270  * The configuration elements other than compounds are always substituted (overwritten)
2271  * from the \a src config handle.
2272  *
2273  * The src handle is deleted.
2274  *
2275  * Note: On error, config handles may be modified.
2276  *
2277  * \par Errors:
2278  * <dl>
2279  * <dt>-EEXIST<dd>identifier already exists (!overwrite)
2280  * <dt>-ENOMEM<dd>not enough memory
2281  * </dl>
2282  */
snd_config_merge(snd_config_t * dst,snd_config_t * src,int override)2283 int snd_config_merge(snd_config_t *dst, snd_config_t *src, int override)
2284 {
2285 	snd_config_iterator_t di, si, dnext, snext;
2286 	bool found;
2287 	int err, array;
2288 
2289 	assert(dst);
2290 	if (src == NULL)
2291 		return 0;
2292 	if (dst->type != SND_CONFIG_TYPE_COMPOUND || src->type != SND_CONFIG_TYPE_COMPOUND)
2293 		return snd_config_substitute(dst, src);
2294 	array = snd_config_is_array(dst);
2295 	if (array && snd_config_is_array(src))
2296 		return _snd_config_array_merge(dst, src, array);
2297 	snd_config_for_each(si, snext, src) {
2298 		snd_config_t *sn = snd_config_iterator_entry(si);
2299 		found = false;
2300 		snd_config_for_each(di, dnext, dst) {
2301 			snd_config_t *dn = snd_config_iterator_entry(di);
2302 			if (strcmp(sn->id, dn->id) == 0) {
2303 				if (override ||
2304 				    sn->type != SND_CONFIG_TYPE_COMPOUND ||
2305 				    dn->type != SND_CONFIG_TYPE_COMPOUND) {
2306 					snd_config_remove(sn);
2307 					err = snd_config_substitute(dn, sn);
2308 					if (err < 0)
2309 						return err;
2310 				} else {
2311 					err = snd_config_merge(dn, sn, 0);
2312 					if (err < 0)
2313 						return err;
2314 				}
2315 				found = true;
2316 				break;
2317 			}
2318 		}
2319 		if (!found) {
2320 			/* move config from src to dst */
2321 			snd_config_remove(sn);
2322 			sn->parent = dst;
2323 			list_add_tail(&sn->list, &dst->u.compound.fields);
2324 		}
2325 	}
2326 	snd_config_delete(src);
2327 	return 0;
2328 }
2329 
2330 /**
2331  * \brief Removes a configuration node from its tree.
2332  * \param config Handle to the configuration node to be removed.
2333  * \return Zero if successful, otherwise a negative error code.
2334  *
2335  * This function makes \a config a top-level node, i.e., if \a config
2336  * has a parent, then \a config is removed from the list of the parent's
2337  * children.
2338  *
2339  * This functions does \e not free the removed node.
2340  *
2341  * \sa snd_config_delete
2342  */
snd_config_remove(snd_config_t * config)2343 int snd_config_remove(snd_config_t *config)
2344 {
2345 	assert(config);
2346 	if (config->parent)
2347 		list_del(&config->list);
2348 	config->parent = NULL;
2349 	return 0;
2350 }
2351 
2352 /**
2353  * \brief Frees a configuration node.
2354  * \param config Handle to the configuration node to be deleted.
2355  * \return Zero if successful, otherwise a negative error code.
2356  *
2357  * This function frees a configuration node and all its resources.
2358  *
2359  * If the node is a child node, it is removed from the tree before being
2360  * deleted.
2361  *
2362  * If the node is a compound node, its descendants (the whole subtree)
2363  * are deleted recursively.
2364  *
2365  * The function is supposed to be called only for locally copied config
2366  * trees.  For the global tree, take the reference via #snd_config_update_ref
2367  * and free it via #snd_config_unref.
2368  *
2369  * \par Conforming to:
2370  * LSB 3.2
2371  *
2372  * \sa snd_config_remove
2373  */
snd_config_delete(snd_config_t * config)2374 int snd_config_delete(snd_config_t *config)
2375 {
2376 	assert(config);
2377 	if (config->refcount > 0) {
2378 		config->refcount--;
2379 		return 0;
2380 	}
2381 	switch (config->type) {
2382 	case SND_CONFIG_TYPE_COMPOUND:
2383 	{
2384 		int err;
2385 		struct list_head *i;
2386 		i = config->u.compound.fields.next;
2387 		while (i != &config->u.compound.fields) {
2388 			struct list_head *nexti = i->next;
2389 			snd_config_t *child = snd_config_iterator_entry(i);
2390 			err = snd_config_delete(child);
2391 			if (err < 0)
2392 				return err;
2393 			i = nexti;
2394 		}
2395 		break;
2396 	}
2397 	case SND_CONFIG_TYPE_STRING:
2398 		free(config->u.string);
2399 		break;
2400 	default:
2401 		break;
2402 	}
2403 	if (config->parent)
2404 		list_del(&config->list);
2405 	free(config->id);
2406 	free(config);
2407 	return 0;
2408 }
2409 
2410 /**
2411  * \brief Deletes the children of a node.
2412  * \param config Handle to the compound configuration node.
2413  * \return Zero if successful, otherwise a negative error code.
2414  *
2415  * This function removes and frees all children of a configuration node.
2416  *
2417  * Any compound nodes among the children of \a config are deleted
2418  * recursively.
2419  *
2420  * After a successful call to this function, \a config is an empty
2421  * compound node.
2422  *
2423  * \par Errors:
2424  * <dl>
2425  * <dt>-EINVAL<dd>\a config is not a compound node.
2426  * </dl>
2427  */
snd_config_delete_compound_members(const snd_config_t * config)2428 int snd_config_delete_compound_members(const snd_config_t *config)
2429 {
2430 	int err;
2431 	struct list_head *i;
2432 
2433 	assert(config);
2434 	if (config->type != SND_CONFIG_TYPE_COMPOUND)
2435 		return -EINVAL;
2436 	i = config->u.compound.fields.next;
2437 	while (i != &config->u.compound.fields) {
2438 		struct list_head *nexti = i->next;
2439 		snd_config_t *child = snd_config_iterator_entry(i);
2440 		err = snd_config_delete(child);
2441 		if (err < 0)
2442 			return err;
2443 		i = nexti;
2444 	}
2445 	return 0;
2446 }
2447 
2448 /**
2449  * \brief Creates a configuration node.
2450  * \param[out] config The function puts the handle to the new node at
2451  *                    the address specified by \a config.
2452  * \param[in] id The id of the new node.
2453  * \param[in] type The type of the new node.
2454  * \return Zero if successful, otherwise a negative error code.
2455  *
2456  * This functions creates a new node of the specified type.
2457  * The new node has id \a id, which may be \c NULL.
2458  *
2459  * The value of the new node is zero (for numbers), or \c NULL (for
2460  * strings and pointers), or empty (for compound nodes).
2461  *
2462  * \par Errors:
2463  * <dl>
2464  * <dt>-ENOMEM<dd>Out of memory.
2465  * </dl>
2466  */
snd_config_make(snd_config_t ** config,const char * id,snd_config_type_t type)2467 int snd_config_make(snd_config_t **config, const char *id,
2468 		    snd_config_type_t type)
2469 {
2470 	char *id1;
2471 	assert(config);
2472 	if (id) {
2473 		id1 = strdup(id);
2474 		if (!id1)
2475 			return -ENOMEM;
2476 	} else
2477 		id1 = NULL;
2478 	return _snd_config_make(config, &id1, type);
2479 }
2480 
2481 /**
2482  * \brief Creates an integer configuration node.
2483  * \param[out] config The function puts the handle to the new node at
2484  *                    the address specified by \a config.
2485  * \param[in] id The id of the new node.
2486  * \return Zero if successful, otherwise a negative error code.
2487  *
2488  * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER and
2489  * with value \c 0.
2490  *
2491  * \par Errors:
2492  * <dl>
2493  * <dt>-ENOMEM<dd>Out of memory.
2494  * </dl>
2495  *
2496  * \par Conforming to:
2497  * LSB 3.2
2498  *
2499  * \sa snd_config_imake_integer
2500  */
snd_config_make_integer(snd_config_t ** config,const char * id)2501 int snd_config_make_integer(snd_config_t **config, const char *id)
2502 {
2503 	return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER);
2504 }
2505 
2506 /**
2507  * \brief Creates a 64-bit-integer configuration node.
2508  * \param[out] config The function puts the handle to the new node at
2509  *                    the address specified by \a config.
2510  * \param[in] id The id of the new node.
2511  * \return Zero if successful, otherwise a negative error code.
2512  *
2513  * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER64
2514  * and with value \c 0.
2515  *
2516  * \par Errors:
2517  * <dl>
2518  * <dt>-ENOMEM<dd>Out of memory.
2519  * </dl>
2520  *
2521  * \par Conforming to:
2522  * LSB 3.2
2523  *
2524  * \sa snd_config_imake_integer64
2525  */
snd_config_make_integer64(snd_config_t ** config,const char * id)2526 int snd_config_make_integer64(snd_config_t **config, const char *id)
2527 {
2528 	return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64);
2529 }
2530 
2531 /**
2532  * \brief Creates a real number configuration node.
2533  * \param[out] config The function puts the handle to the new node at
2534  *                    the address specified by \a config.
2535  * \param[in] id The id of the new node.
2536  * \return Zero if successful, otherwise a negative error code.
2537  *
2538  * This function creates a new node of type #SND_CONFIG_TYPE_REAL and
2539  * with value \c 0.0.
2540  *
2541  * \par Errors:
2542  * <dl>
2543  * <dt>-ENOMEM<dd>Out of memory.
2544  * </dl>
2545  *
2546  * \sa snd_config_imake_real
2547  */
snd_config_make_real(snd_config_t ** config,const char * id)2548 int snd_config_make_real(snd_config_t **config, const char *id)
2549 {
2550 	return snd_config_make(config, id, SND_CONFIG_TYPE_REAL);
2551 }
2552 
2553 /**
2554  * \brief Creates a string configuration node.
2555  * \param[out] config The function puts the handle to the new node at
2556  *                    the address specified by \a config.
2557  * \param[in] id The id of the new node.
2558  * \return Zero if successful, otherwise a negative error code.
2559  *
2560  * This function creates a new node of type #SND_CONFIG_TYPE_STRING and
2561  * with value \c NULL.
2562  *
2563  * \par Errors:
2564  * <dl>
2565  * <dt>-ENOMEM<dd>Out of memory.
2566  * </dl>
2567  *
2568  * \par Conforming to:
2569  * LSB 3.2
2570  *
2571  * \sa snd_config_imake_string
2572  */
snd_config_make_string(snd_config_t ** config,const char * id)2573 int snd_config_make_string(snd_config_t **config, const char *id)
2574 {
2575 	return snd_config_make(config, id, SND_CONFIG_TYPE_STRING);
2576 }
2577 
2578 /**
2579  * \brief Creates a pointer configuration node.
2580  * \param[out] config The function puts the handle to the new node at
2581  *                    the address specified by \a config.
2582  * \param[in] id The id of the new node.
2583  * \return Zero if successful, otherwise a negative error code.
2584  *
2585  * This function creates a new node of type #SND_CONFIG_TYPE_POINTER and
2586  * with value \c NULL.
2587  *
2588  * \par Errors:
2589  * <dl>
2590  * <dt>-ENOMEM<dd>Out of memory.
2591  * </dl>
2592  *
2593  * \sa snd_config_imake_pointer
2594  */
snd_config_make_pointer(snd_config_t ** config,const char * id)2595 int snd_config_make_pointer(snd_config_t **config, const char *id)
2596 {
2597 	return snd_config_make(config, id, SND_CONFIG_TYPE_POINTER);
2598 }
2599 
2600 /**
2601  * \brief Creates an empty compound configuration node.
2602  * \param[out] config The function puts the handle to the new node at
2603  *                    the address specified by \a config.
2604  * \param[in] id The id of the new node.
2605  * \param[in] join Join flag.
2606  * \return Zero if successful, otherwise a negative error code.
2607  *
2608  * This function creates a new empty node of type
2609  * #SND_CONFIG_TYPE_COMPOUND.
2610  *
2611  * \a join determines how the compound node's id is printed when the
2612  * configuration is saved to a text file.  For example, if the join flag
2613  * of compound node \c a is zero, the output will look as follows:
2614  * \code
2615  * a {
2616  *     b "hello"
2617  *     c 42
2618  * }
2619  * \endcode
2620  * If, however, the join flag of \c a is nonzero, its id will be joined
2621  * with its children's ids, like this:
2622  * \code
2623  * a.b "hello"
2624  * a.c 42
2625  * \endcode
2626  * An \e empty compound node with its join flag set would result in no
2627  * output, i.e., after saving and reloading the configuration file, that
2628  * compound node would be lost.
2629  *
2630  * \par Errors:
2631  * <dl>
2632  * <dt>-ENOMEM<dd>Out of memory.
2633  * </dl>
2634  *
2635  * \par Conforming to:
2636  * LSB 3.2
2637  */
snd_config_make_compound(snd_config_t ** config,const char * id,int join)2638 int snd_config_make_compound(snd_config_t **config, const char *id,
2639 			     int join)
2640 {
2641 	int err;
2642 	err = snd_config_make(config, id, SND_CONFIG_TYPE_COMPOUND);
2643 	if (err < 0)
2644 		return err;
2645 	(*config)->u.compound.join = join;
2646 	return 0;
2647 }
2648 
2649 /**
2650  * \brief Creates an empty compound configuration node in the path.
2651  * \param[out] config The function puts the handle to the new or
2652  *		      existing compound node at the address specified
2653  *		      by \a config.
2654  * \param[in] root The id of the new node.
2655  * \param[in] key The id of the new node.
2656  * \param[in] join Join flag.
2657  * \param[in] override Override flag.
2658  * \return Zero if successful, otherwise a negative error code.
2659  *
2660  * This function creates a new empty node of type
2661  * #SND_CONFIG_TYPE_COMPOUND if the path does not exist. Otherwise,
2662  * the node from the current configuration tree is returned without
2663  * any modification. The \a join argument is ignored in this case.
2664  *
2665  * \a join determines how the compound node's id is printed when the
2666  * configuration is saved to a text file.  For example, if the join flag
2667  * of compound node \c a is zero, the output will look as follows:
2668  * \code
2669  * a {
2670  *     b "hello"
2671  *     c 42
2672  * }
2673  * \endcode
2674  * If, however, the join flag of \c a is nonzero, its id will be joined
2675  * with its children's ids, like this:
2676  * \code
2677  * a.b "hello"
2678  * a.c 42
2679  * \endcode
2680  * An \e empty compound node with its join flag set would result in no
2681  * output, i.e., after saving and reloading the configuration file, that
2682  * compound node would be lost.
2683  *
2684  * \par Errors:
2685  * <dl>
2686  * <dt>-ENOMEM<dd>Out of memory.
2687  * <dt>-EACCESS<dd>Path exists, but it's not a compound (!override)
2688  * </dl>
2689  */
snd_config_make_path(snd_config_t ** config,snd_config_t * root,const char * key,int join,int override)2690 int snd_config_make_path(snd_config_t **config, snd_config_t *root,
2691 			 const char *key, int join, int override)
2692 {
2693 	snd_config_t *n;
2694 	const char *p;
2695 	int err;
2696 
2697 	while (1) {
2698 		p = strchr(key, '.');
2699 		if (p) {
2700 			err = _snd_config_search(root, key, p - key, &n);
2701 			if (err < 0) {
2702 				size_t l = p - key;
2703 				char *s = malloc(l + 1);
2704 				if (s == NULL)
2705 					return -ENOMEM;
2706 				strncpy(s, key, l);
2707 				s[l] = '\0';
2708 				err = snd_config_make_compound(&n, s, join);
2709 				free(s);
2710 				if (err < 0)
2711 					return err;
2712 				err = snd_config_add(root, n);
2713 				if (err < 0)
2714 					return err;
2715 			}
2716 			root = n;
2717 			key = p + 1;
2718 		} else {
2719 			err = _snd_config_search(root, key, -1, config);
2720 			if (err == 0) {
2721 				if ((*config)->type != SND_CONFIG_TYPE_COMPOUND) {
2722 					if (override) {
2723 						err = snd_config_delete(*config);
2724 						if (err < 0)
2725 							return err;
2726 						goto __make;
2727 					} else {
2728 						return -EACCES;
2729 					}
2730 				}
2731 				return 0;
2732 			}
2733 __make:
2734 			err = snd_config_make_compound(&n, key, join);
2735 			if (err < 0)
2736 				return err;
2737 			err = snd_config_add(root, n);
2738 			if (err < 0)
2739 				return err;
2740 			*config = n;
2741 			return 0;
2742 		}
2743 	}
2744 }
2745 
2746 /**
2747  * \brief Creates an integer configuration node with the given initial value.
2748  * \param[out] config The function puts the handle to the new node at
2749  *                    the address specified by \a config.
2750  * \param[in] id The id of the new node.
2751  * \param[in] value The initial value of the new node.
2752  * \return Zero if successful, otherwise a negative error code.
2753  *
2754  * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER and
2755  * with value \a value.
2756  *
2757  * \par Errors:
2758  * <dl>
2759  * <dt>-ENOMEM<dd>Out of memory.
2760  * </dl>
2761  *
2762  * \par Conforming to:
2763  * LSB 3.2
2764  */
snd_config_imake_integer(snd_config_t ** config,const char * id,const long value)2765 int snd_config_imake_integer(snd_config_t **config, const char *id, const long value)
2766 {
2767 	int err;
2768 
2769 	err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER);
2770 	if (err < 0)
2771 		return err;
2772 	(*config)->u.integer = value;
2773 	return 0;
2774 }
2775 
2776 /**
2777  * \brief Creates a 64-bit-integer configuration node with the given initial value.
2778  * \param[out] config The function puts the handle to the new node at
2779  *                    the address specified by \a config.
2780  * \param[in] id The id of the new node.
2781  * \param[in] value The initial value of the new node.
2782  * \return Zero if successful, otherwise a negative error code.
2783  *
2784  * This function creates a new node of type #SND_CONFIG_TYPE_INTEGER64
2785  * and with value \a value.
2786  *
2787  * \par Errors:
2788  * <dl>
2789  * <dt>-ENOMEM<dd>Out of memory.
2790  * </dl>
2791  *
2792  * \par Conforming to:
2793  * LSB 3.2
2794  */
snd_config_imake_integer64(snd_config_t ** config,const char * id,const long long value)2795 int snd_config_imake_integer64(snd_config_t **config, const char *id, const long long value)
2796 {
2797 	int err;
2798 
2799 	err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64);
2800 	if (err < 0)
2801 		return err;
2802 	(*config)->u.integer64 = value;
2803 	return 0;
2804 }
2805 
2806 /**
2807  * \brief Creates a real number configuration node with the given initial value.
2808  * \param[out] config The function puts the handle to the new node at
2809  *                    the address specified by \a config.
2810  * \param[in] id The id of the new node.
2811  * \param[in] value The initial value of the new node.
2812  * \return Zero if successful, otherwise a negative error code.
2813  *
2814  * This function creates a new node of type #SND_CONFIG_TYPE_REAL and
2815  * with value \a value.
2816  *
2817  * \par Errors:
2818  * <dl>
2819  * <dt>-ENOMEM<dd>Out of memory.
2820  * </dl>
2821  */
snd_config_imake_real(snd_config_t ** config,const char * id,const double value)2822 int snd_config_imake_real(snd_config_t **config, const char *id, const double value)
2823 {
2824 	int err;
2825 
2826 	err = snd_config_make(config, id, SND_CONFIG_TYPE_REAL);
2827 	if (err < 0)
2828 		return err;
2829 	(*config)->u.real = value;
2830 	return 0;
2831 }
2832 
2833 /**
2834  * \brief Creates a string configuration node with the given initial value.
2835  * \param[out] config The function puts the handle to the new node at
2836  *                    the address specified by \a config.
2837  * \param[in] id The id of the new node.
2838  * \param[in] value The initial value of the new node.  May be \c NULL.
2839  * \return Zero if successful, otherwise a negative error code.
2840  *
2841  * This function creates a new node of type #SND_CONFIG_TYPE_STRING and
2842  * with a copy of the string \c value.
2843  *
2844  * \par Errors:
2845  * <dl>
2846  * <dt>-ENOMEM<dd>Out of memory.
2847  * </dl>
2848  *
2849  * \par Conforming to:
2850  * LSB 3.2
2851  */
snd_config_imake_string(snd_config_t ** config,const char * id,const char * value)2852 int snd_config_imake_string(snd_config_t **config, const char *id, const char *value)
2853 {
2854 	int err;
2855 	snd_config_t *tmp;
2856 
2857 	err = snd_config_make(&tmp, id, SND_CONFIG_TYPE_STRING);
2858 	if (err < 0)
2859 		return err;
2860 	if (value) {
2861 		tmp->u.string = strdup(value);
2862 		if (!tmp->u.string) {
2863 			snd_config_delete(tmp);
2864 			return -ENOMEM;
2865 		}
2866 	} else {
2867 		tmp->u.string = NULL;
2868 	}
2869 	*config = tmp;
2870 	return 0;
2871 }
2872 
snd_config_imake_safe_string(snd_config_t ** config,const char * id,const char * value)2873 int snd_config_imake_safe_string(snd_config_t **config, const char *id, const char *value)
2874 {
2875 	int err;
2876 	snd_config_t *tmp;
2877 	char *c;
2878 
2879 	err = snd_config_make(&tmp, id, SND_CONFIG_TYPE_STRING);
2880 	if (err < 0)
2881 		return err;
2882 	if (value) {
2883 		tmp->u.string = strdup(value);
2884 		if (!tmp->u.string) {
2885 			snd_config_delete(tmp);
2886 			return -ENOMEM;
2887 		}
2888 
2889 		for (c = tmp->u.string; *c; c++) {
2890 			if (*c == ' ' || *c == '-' || *c == '_' ||
2891 				(*c >= '0' && *c <= '9') ||
2892 				(*c >= 'a' && *c <= 'z') ||
2893 				(*c >= 'A' && *c <= 'Z'))
2894 					continue;
2895 			*c = '_';
2896 		}
2897 	} else {
2898 		tmp->u.string = NULL;
2899 	}
2900 	*config = tmp;
2901 	return 0;
2902 }
2903 
2904 
2905 /**
2906  * \brief Creates a pointer configuration node with the given initial value.
2907  * \param[out] config The function puts the handle to the new node at
2908  *                    the address specified by \a config.
2909  * \param[in] id The id of the new node.
2910  * \param[in] value The initial value of the new node.
2911  * \return Zero if successful, otherwise a negative error code.
2912  *
2913  * This function creates a new node of type #SND_CONFIG_TYPE_POINTER and
2914  * with value \c value.
2915  *
2916  * \par Errors:
2917  * <dl>
2918  * <dt>-ENOMEM<dd>Out of memory.
2919  * </dl>
2920  */
snd_config_imake_pointer(snd_config_t ** config,const char * id,const void * value)2921 int snd_config_imake_pointer(snd_config_t **config, const char *id, const void *value)
2922 {
2923 	int err;
2924 
2925 	err = snd_config_make(config, id, SND_CONFIG_TYPE_POINTER);
2926 	if (err < 0)
2927 		return err;
2928 	(*config)->u.ptr = value;
2929 	return 0;
2930 }
2931 
2932 /**
2933  * \brief Changes the value of an integer configuration node.
2934  * \param config Handle to the configuration node.
2935  * \param value The new value for the node.
2936  * \return Zero if successful, otherwise a negative error code.
2937  *
2938  * \par Errors:
2939  * <dl>
2940  * <dt>-EINVAL<dd>\a config is not an integer node.
2941  * </dl>
2942  *
2943  * \par Conforming to:
2944  * LSB 3.2
2945  */
snd_config_set_integer(snd_config_t * config,long value)2946 int snd_config_set_integer(snd_config_t *config, long value)
2947 {
2948 	assert(config);
2949 	if (config->type != SND_CONFIG_TYPE_INTEGER)
2950 		return -EINVAL;
2951 	config->u.integer = value;
2952 	return 0;
2953 }
2954 
2955 /**
2956  * \brief Changes the value of a 64-bit-integer configuration node.
2957  * \param config Handle to the configuration node.
2958  * \param value The new value for the node.
2959  * \return Zero if successful, otherwise a negative error code.
2960  *
2961  * \par Errors:
2962  * <dl>
2963  * <dt>-EINVAL<dd>\a config is not a 64-bit-integer node.
2964  * </dl>
2965  *
2966  * \par Conforming to:
2967  * LSB 3.2
2968  */
snd_config_set_integer64(snd_config_t * config,long long value)2969 int snd_config_set_integer64(snd_config_t *config, long long value)
2970 {
2971 	assert(config);
2972 	if (config->type != SND_CONFIG_TYPE_INTEGER64)
2973 		return -EINVAL;
2974 	config->u.integer64 = value;
2975 	return 0;
2976 }
2977 
2978 /**
2979  * \brief Changes the value of a real-number configuration node.
2980  * \param config Handle to the configuration node.
2981  * \param value The new value for the node.
2982  * \return Zero if successful, otherwise a negative error code.
2983  *
2984  * \par Errors:
2985  * <dl>
2986  * <dt>-EINVAL<dd>\a config is not a real-number node.
2987  * </dl>
2988  */
snd_config_set_real(snd_config_t * config,double value)2989 int snd_config_set_real(snd_config_t *config, double value)
2990 {
2991 	assert(config);
2992 	if (config->type != SND_CONFIG_TYPE_REAL)
2993 		return -EINVAL;
2994 	config->u.real = value;
2995 	return 0;
2996 }
2997 
2998 /**
2999  * \brief Changes the value of a string configuration node.
3000  * \param config Handle to the configuration node.
3001  * \param value The new value for the node.  May be \c NULL.
3002  * \return Zero if successful, otherwise a negative error code.
3003  *
3004  * This function deletes the old string in the node and stores a copy of
3005  * \a value string in the node.
3006  *
3007  * \par Errors:
3008  * <dl>
3009  * <dt>-EINVAL<dd>\a config is not a string node.
3010  * </dl>
3011  *
3012  * \par Conforming to:
3013  * LSB 3.2
3014  */
snd_config_set_string(snd_config_t * config,const char * value)3015 int snd_config_set_string(snd_config_t *config, const char *value)
3016 {
3017 	char *new_string;
3018 	assert(config);
3019 	if (config->type != SND_CONFIG_TYPE_STRING)
3020 		return -EINVAL;
3021 	if (value) {
3022 		new_string = strdup(value);
3023 		if (!new_string)
3024 			return -ENOMEM;
3025 	} else {
3026 		new_string = NULL;
3027 	}
3028 	free(config->u.string);
3029 	config->u.string = new_string;
3030 	return 0;
3031 }
3032 
3033 /**
3034  * \brief Changes the value of a pointer configuration node.
3035  * \param config Handle to the configuration node.
3036  * \param value The new value for the node.  May be \c NULL.
3037  * \return Zero if successful, otherwise a negative error code.
3038  *
3039  * This function does not free the old pointer in the node.
3040  *
3041  * \par Errors:
3042  * <dl>
3043  * <dt>-EINVAL<dd>\a config is not a pointer node.
3044  * </dl>
3045  */
snd_config_set_pointer(snd_config_t * config,const void * value)3046 int snd_config_set_pointer(snd_config_t *config, const void *value)
3047 {
3048 	assert(config);
3049 	if (config->type != SND_CONFIG_TYPE_POINTER)
3050 		return -EINVAL;
3051 	config->u.ptr = value;
3052 	return 0;
3053 }
3054 
3055 /**
3056  * \brief Changes the value of a configuration node.
3057  * \param config Handle to the configuration node.
3058  * \param ascii The new value for the node, as an ASCII string.
3059  * \return Zero if successful, otherwise a negative error code.
3060  *
3061  * This function changes the node's value to a new value that is parsed
3062  * from the string \a ascii.  \a ascii must not be \c NULL, not even for
3063  * a string node.
3064  *
3065  * The node's type does not change, i.e., the string must contain a
3066  * valid value with the same type as the node's type.  For a string
3067  * node, the node's new value is a copy of \a ascii.
3068  *
3069  * \par Errors:
3070  * <dl>
3071  * <dt>-EINVAL<dd>\a config is not a number or string node.
3072  * <dt>-EINVAL<dd>The value in \a ascii cannot be parsed.
3073  * <dt>-ERANGE<dd>The value in \a ascii is too big for the node's type.
3074  * <dt>-ENOMEM<dd>Out of memory.
3075  * </dl>
3076  *
3077  * \par Conforming to:
3078  * LSB 3.2
3079  */
snd_config_set_ascii(snd_config_t * config,const char * ascii)3080 int snd_config_set_ascii(snd_config_t *config, const char *ascii)
3081 {
3082 	assert(config && ascii);
3083 	switch (config->type) {
3084 	case SND_CONFIG_TYPE_INTEGER:
3085 		{
3086 			long i;
3087 			int err = safe_strtol(ascii, &i);
3088 			if (err < 0)
3089 				return err;
3090 			config->u.integer = i;
3091 		}
3092 		break;
3093 	case SND_CONFIG_TYPE_INTEGER64:
3094 		{
3095 			long long i;
3096 			int err = safe_strtoll(ascii, &i);
3097 			if (err < 0)
3098 				return err;
3099 			config->u.integer64 = i;
3100 		}
3101 		break;
3102 	case SND_CONFIG_TYPE_REAL:
3103 		{
3104 			double d;
3105 			int err = safe_strtod(ascii, &d);
3106 			if (err < 0)
3107 				return err;
3108 			config->u.real = d;
3109 			break;
3110 		}
3111 	case SND_CONFIG_TYPE_STRING:
3112 		{
3113 			char *ptr = strdup(ascii);
3114 			if (ptr == NULL)
3115 				return -ENOMEM;
3116 			free(config->u.string);
3117 			config->u.string = ptr;
3118 		}
3119 		break;
3120 	default:
3121 		return -EINVAL;
3122 	}
3123 	return 0;
3124 }
3125 
3126 /**
3127  * \brief Returns the value of an integer configuration node.
3128  * \param[in] config Handle to the configuration node.
3129  * \param[out] ptr The node's value.
3130  * \return Zero if successful, otherwise a negative error code.
3131  *
3132  * \par Errors:
3133  * <dl>
3134  * <dt>-EINVAL<dd>\a config is not an integer node.
3135  * </dl>
3136  *
3137  * \par Conforming to:
3138  * LSB 3.2
3139  */
snd_config_get_integer(const snd_config_t * config,long * ptr)3140 int snd_config_get_integer(const snd_config_t *config, long *ptr)
3141 {
3142 	assert(config && ptr);
3143 	if (config->type != SND_CONFIG_TYPE_INTEGER)
3144 		return -EINVAL;
3145 	*ptr = config->u.integer;
3146 	return 0;
3147 }
3148 
3149 /**
3150  * \brief Returns the value of a 64-bit-integer configuration node.
3151  * \param[in] config Handle to the configuration node.
3152  * \param[out] ptr The node's value.
3153  * \return Zero if successful, otherwise a negative error code.
3154  *
3155  * \par Errors:
3156  * <dl>
3157  * <dt>-EINVAL<dd>\a config is not a 64-bit-integer node.
3158  * </dl>
3159  *
3160  * \par Conforming to:
3161  * LSB 3.2
3162  */
snd_config_get_integer64(const snd_config_t * config,long long * ptr)3163 int snd_config_get_integer64(const snd_config_t *config, long long *ptr)
3164 {
3165 	assert(config && ptr);
3166 	if (config->type != SND_CONFIG_TYPE_INTEGER64)
3167 		return -EINVAL;
3168 	*ptr = config->u.integer64;
3169 	return 0;
3170 }
3171 
3172 /**
3173  * \brief Returns the value of a real-number configuration node.
3174  * \param[in] config Handle to the configuration node.
3175  * \param[out] ptr The node's value.
3176  * \return Zero if successful, otherwise a negative error code.
3177  *
3178  * \par Errors:
3179  * <dl>
3180  * <dt>-EINVAL<dd>\a config is not a real-number node.
3181  * </dl>
3182  */
snd_config_get_real(const snd_config_t * config,double * ptr)3183 int snd_config_get_real(const snd_config_t *config, double *ptr)
3184 {
3185 	assert(config && ptr);
3186 	if (config->type != SND_CONFIG_TYPE_REAL)
3187 		return -EINVAL;
3188 	*ptr = config->u.real;
3189 	return 0;
3190 }
3191 
3192 /**
3193  * \brief Returns the value of a real or integer configuration node.
3194  * \param[in] config Handle to the configuration node.
3195  * \param[out] ptr The node's value.
3196  * \return Zero if successful, otherwise a negative error code.
3197  *
3198  * If the node's type is integer or integer64, the value is converted
3199  * to the \c double type on the fly.
3200  *
3201  * \par Errors:
3202  * <dl>
3203  * <dt>-EINVAL<dd>\a config is not a number node.
3204  * </dl>
3205  */
snd_config_get_ireal(const snd_config_t * config,double * ptr)3206 int snd_config_get_ireal(const snd_config_t *config, double *ptr)
3207 {
3208 	assert(config && ptr);
3209 	if (config->type == SND_CONFIG_TYPE_REAL)
3210 		*ptr = config->u.real;
3211 	else if (config->type == SND_CONFIG_TYPE_INTEGER)
3212 		*ptr = config->u.integer;
3213 	else if (config->type == SND_CONFIG_TYPE_INTEGER64)
3214 		*ptr = config->u.integer64;
3215 	else
3216 		return -EINVAL;
3217 	return 0;
3218 }
3219 
3220 /**
3221  * \brief Returns the value of a string configuration node.
3222  * \param[in] config Handle to the configuration node.
3223  * \param[out] ptr The function puts the node's value at the address
3224  *                 specified by \a ptr.
3225  * \return Zero if successful, otherwise a negative error code.
3226  *
3227  * The returned string is owned by the configuration node; the
3228  * application must not modify or delete it, and the string becomes
3229  * invalid when the node's value changes or when the node is freed.
3230  *
3231  * The string may be \c NULL.
3232  *
3233  * \par Errors:
3234  * <dl>
3235  * <dt>-EINVAL<dd>\a config is not a string node.
3236  * </dl>
3237  *
3238  * \par Conforming to:
3239  * LSB 3.2
3240  */
snd_config_get_string(const snd_config_t * config,const char ** ptr)3241 int snd_config_get_string(const snd_config_t *config, const char **ptr)
3242 {
3243 	assert(config && ptr);
3244 	if (config->type != SND_CONFIG_TYPE_STRING)
3245 		return -EINVAL;
3246 	*ptr = config->u.string;
3247 	return 0;
3248 }
3249 
3250 /**
3251  * \brief Returns the value of a pointer configuration node.
3252  * \param[in] config Handle to the configuration node.
3253  * \param[out] ptr The function puts the node's value at the address
3254  *                 specified by \a ptr.
3255  * \return Zero if successful, otherwise a negative error code.
3256  *
3257  * \par Errors:
3258  * <dl>
3259  * <dt>-EINVAL<dd>\a config is not a string node.
3260  * </dl>
3261  */
snd_config_get_pointer(const snd_config_t * config,const void ** ptr)3262 int snd_config_get_pointer(const snd_config_t *config, const void **ptr)
3263 {
3264 	assert(config && ptr);
3265 	if (config->type != SND_CONFIG_TYPE_POINTER)
3266 		return -EINVAL;
3267 	*ptr = config->u.ptr;
3268 	return 0;
3269 }
3270 
3271 /**
3272  * \brief Returns the value of a configuration node as a string.
3273  * \param[in] config Handle to the configuration node.
3274  * \param[out] ascii The function puts the pointer to the returned
3275  *                   string at the address specified by \a ascii.
3276  * \return Zero if successful, otherwise a negative error code.
3277  *
3278  * This function dynamically allocates the returned string.  The
3279  * application is responsible for deleting it with \c free() when it is
3280  * no longer used.
3281  *
3282  * For a string node with \c NULL value, the returned string is \c NULL.
3283  *
3284  * Supported node types are #SND_CONFIG_TYPE_INTEGER,
3285  * #SND_CONFIG_TYPE_INTEGER64, #SND_CONFIG_TYPE_REAL, and
3286  * #SND_CONFIG_TYPE_STRING.
3287  *
3288  * \par Errors:
3289  * <dl>
3290  * <dt>-EINVAL<dd>\a config is not a (64-bit) integer or real number or
3291  *                string node.
3292  * <dt>-ENOMEM<dd>Out of memory.
3293  * </dl>
3294  *
3295  * \par Conforming to:
3296  * LSB 3.2
3297  */
snd_config_get_ascii(const snd_config_t * config,char ** ascii)3298 int snd_config_get_ascii(const snd_config_t *config, char **ascii)
3299 {
3300 	assert(config && ascii);
3301 	switch (config->type) {
3302 	case SND_CONFIG_TYPE_INTEGER:
3303 		{
3304 			char res[12];
3305 			int err;
3306 			err = snprintf(res, sizeof(res), "%li", config->u.integer);
3307 			if (err < 0 || err == sizeof(res)) {
3308 				assert(0);
3309 				return -ENOMEM;
3310 			}
3311 			*ascii = strdup(res);
3312 		}
3313 		break;
3314 	case SND_CONFIG_TYPE_INTEGER64:
3315 		{
3316 			char res[32];
3317 			int err;
3318 			err = snprintf(res, sizeof(res), "%lli", config->u.integer64);
3319 			if (err < 0 || err == sizeof(res)) {
3320 				assert(0);
3321 				return -ENOMEM;
3322 			}
3323 			*ascii = strdup(res);
3324 		}
3325 		break;
3326 	case SND_CONFIG_TYPE_REAL:
3327 		{
3328 			char res[32];
3329 			int err;
3330 			err = snprintf(res, sizeof(res), "%-16g", config->u.real);
3331 			if (err < 0 || err == sizeof(res)) {
3332 				assert(0);
3333 				return -ENOMEM;
3334 			}
3335 			if (res[0]) {		/* trim the string */
3336 				char *ptr;
3337 				ptr = res + strlen(res) - 1;
3338 				while (ptr != res && *ptr == ' ')
3339 					ptr--;
3340 				if (*ptr != ' ')
3341 					ptr++;
3342 				*ptr = '\0';
3343 			}
3344 			*ascii = strdup(res);
3345 		}
3346 		break;
3347 	case SND_CONFIG_TYPE_STRING:
3348 		if (config->u.string)
3349 			*ascii = strdup(config->u.string);
3350 		else {
3351 			*ascii = NULL;
3352 			return 0;
3353 		}
3354 		break;
3355 	default:
3356 		return -EINVAL;
3357 	}
3358 	if (*ascii == NULL)
3359 		return -ENOMEM;
3360 	return 0;
3361 }
3362 
3363 /**
3364  * \brief Compares the id of a configuration node to a given string.
3365  * \param config Handle to the configuration node.
3366  * \param id ASCII id.
3367  * \return The same value as the result of the \c strcmp function, i.e.,
3368  *         less than zero if \a config's id is lexicographically less
3369  *         than \a id, zero if \a config's id is equal to id, greater
3370  *         than zero otherwise.
3371  */
snd_config_test_id(const snd_config_t * config,const char * id)3372 int snd_config_test_id(const snd_config_t *config, const char *id)
3373 {
3374 	assert(config && id);
3375 	if (config->id)
3376 		return strcmp(config->id, id);
3377 	else
3378 		return -1;
3379 }
3380 
3381 /**
3382  * \brief Dumps the contents of a configuration node or tree.
3383  * \param config Handle to the (root) configuration node.
3384  * \param out Output handle.
3385  * \return Zero if successful, otherwise a negative error code.
3386  *
3387  * This function writes a textual representation of \a config's value to
3388  * the output \a out.
3389  *
3390  * \par Errors:
3391  * <dl>
3392  * <dt>-EINVAL<dd>A node in the tree has a type that cannot be printed,
3393  *                i.e., #SND_CONFIG_TYPE_POINTER.
3394  * </dl>
3395  *
3396  * \par Conforming to:
3397  * LSB 3.2
3398  */
snd_config_save(snd_config_t * config,snd_output_t * out)3399 int snd_config_save(snd_config_t *config, snd_output_t *out)
3400 {
3401 	assert(config && out);
3402 	if (config->type == SND_CONFIG_TYPE_COMPOUND) {
3403 		int array = snd_config_is_array(config);
3404 		return _snd_config_save_children(config, out, 0, 0, array);
3405 	} else {
3406 		return _snd_config_save_node_value(config, out, 0);
3407 	}
3408 }
3409 
3410 /*
3411  *  *** search macros ***
3412  */
3413 
3414 #ifndef DOC_HIDDEN
3415 
3416 #define SND_CONFIG_SEARCH(config, key, result, extra_code) \
3417 { \
3418 	snd_config_t *n; \
3419 	int err; \
3420 	const char *p; \
3421 	assert(config && key); \
3422 	while (1) { \
3423 		if (config->type != SND_CONFIG_TYPE_COMPOUND) \
3424 			return -ENOENT; \
3425 		{ extra_code ; } \
3426 		p = strchr(key, '.'); \
3427 		if (p) { \
3428 			err = _snd_config_search(config, key, p - key, &n); \
3429 			if (err < 0) \
3430 				return err; \
3431 			config = n; \
3432 			key = p + 1; \
3433 		} else \
3434 			return _snd_config_search(config, key, -1, result); \
3435 	} \
3436 }
3437 
3438 #define SND_CONFIG_SEARCHA(root, config, key, result, fcn, extra_code) \
3439 { \
3440 	snd_config_t *n; \
3441 	int err; \
3442 	const char *p; \
3443 	assert(config && key); \
3444 	while (1) { \
3445 		if (config->type != SND_CONFIG_TYPE_COMPOUND) { \
3446 			if (snd_config_get_string(config, &p) < 0) \
3447 				return -ENOENT; \
3448 			err = fcn(root, root, p, &config); \
3449 			if (err < 0) \
3450 				return err; \
3451 		} \
3452 		{ extra_code ; } \
3453 		p = strchr(key, '.'); \
3454 		if (p) { \
3455 			err = _snd_config_search(config, key, p - key, &n); \
3456 			if (err < 0) \
3457 				return err; \
3458 			config = n; \
3459 			key = p + 1; \
3460 		} else \
3461 			return _snd_config_search(config, key, -1, result); \
3462 	} \
3463 }
3464 
3465 #define SND_CONFIG_SEARCHV(config, result, fcn) \
3466 { \
3467 	snd_config_t *n; \
3468 	va_list arg; \
3469 	assert(config); \
3470 	va_start(arg, result); \
3471 	while (1) { \
3472 		const char *k = va_arg(arg, const char *); \
3473 		int err; \
3474 		if (!k) \
3475 			break; \
3476 		err = fcn(config, k, &n); \
3477 		if (err < 0) { \
3478 			va_end(arg); \
3479 			return err; \
3480 		} \
3481 		config = n; \
3482 	} \
3483 	va_end(arg); \
3484 	if (result) \
3485 		*result = n; \
3486 	return 0; \
3487 }
3488 
3489 #define SND_CONFIG_SEARCHVA(root, config, result, fcn) \
3490 { \
3491 	snd_config_t *n; \
3492 	va_list arg; \
3493 	assert(config); \
3494 	va_start(arg, result); \
3495 	while (1) { \
3496 		const char *k = va_arg(arg, const char *); \
3497 		int err; \
3498 		if (!k) \
3499 			break; \
3500 		err = fcn(root, config, k, &n); \
3501 		if (err < 0) { \
3502 			va_end(arg); \
3503 			return err; \
3504 		} \
3505 		config = n; \
3506 	} \
3507 	va_end(arg); \
3508 	if (result) \
3509 		*result = n; \
3510 	return 0; \
3511 }
3512 
3513 #define SND_CONFIG_SEARCH_ALIAS(config, base, key, result, fcn1, fcn2) \
3514 { \
3515 	snd_config_t *res = NULL; \
3516 	char *old_key; \
3517 	int err, first = 1, maxloop = 1000; \
3518 	assert(config && key); \
3519 	while (1) { \
3520 		old_key = strdup(key); \
3521 		if (old_key == NULL) { \
3522 			err = -ENOMEM; \
3523 			res = NULL; \
3524 			break; \
3525 		} \
3526 		err = first && base ? -EIO : fcn1(config, config, key, &res); \
3527 		if (err < 0) { \
3528 			if (!base) \
3529 				break; \
3530 			err = fcn2(config, config, &res, base, key, NULL); \
3531 			if (err < 0) \
3532 				break; \
3533 		} \
3534 		if (snd_config_get_string(res, &key) < 0) \
3535 			break; \
3536 		assert(key); \
3537 		if (!first && (strcmp(key, old_key) == 0 || maxloop <= 0)) { \
3538 			if (maxloop == 0) \
3539 				SNDERR("maximum loop count reached (circular configuration?)"); \
3540 			else \
3541 				SNDERR("key %s refers to itself", key); \
3542 			err = -EINVAL; \
3543 			res = NULL; \
3544 			break; \
3545 		} \
3546 		free(old_key); \
3547 		first = 0; \
3548 		maxloop--; \
3549 	} \
3550 	free(old_key); \
3551 	if (!res) \
3552 		return err; \
3553 	if (result) \
3554 		*result = res; \
3555 	return 0; \
3556 }
3557 
3558 #endif /* DOC_HIDDEN */
3559 
3560 /**
3561  * \brief Searches for a node in a configuration tree.
3562  * \param[in] config Handle to the root of the configuration (sub)tree to search.
3563  * \param[in] key Search key: one or more node ids, separated with dots.
3564  * \param[out] result When \a result != \c NULL, the function puts the
3565  *                    handle to the node found at the address specified
3566  *                    by \a result.
3567  * \return Zero if successful, otherwise a negative error code.
3568  *
3569  * This function searches for a child node of \a config that is
3570  * identified by \a key, which contains either the id of a direct child
3571  * node of \a config, or a series of ids, separated with dots, where
3572  * each id specifies a node that is contained in the previous compound
3573  * node.
3574  *
3575  * In the following example, the comment after each node shows the
3576  * search key to find that node, assuming that \a config is a handle to
3577  * the compound node with id \c config:
3578  * \code
3579  * config {
3580  *     a 42               # "a"
3581  *     b {                # "b"
3582  *         c "cee"        # "b.c"
3583  *         d {            # "b.d"
3584  *             e 2.71828  # "b.d.e"
3585  *         }
3586  *     }
3587  * }
3588  * \endcode
3589  *
3590  * \par Errors:
3591  * <dl>
3592  * <dt>-ENOENT<dd>An id in \a key does not exist.
3593  * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3594  *                not a compound node.
3595  * </dl>
3596  *
3597  * \par Conforming to:
3598  * LSB 3.2
3599  */
snd_config_search(snd_config_t * config,const char * key,snd_config_t ** result)3600 int snd_config_search(snd_config_t *config, const char *key, snd_config_t **result)
3601 {
3602 	SND_CONFIG_SEARCH(config, key, result, );
3603 }
3604 
3605 /**
3606  * \brief Searches for a node in a configuration tree, expanding aliases.
3607  * \param[in] root Handle to the root configuration node containing
3608  *                 alias definitions.
3609  * \param[in] config Handle to the root of the configuration (sub)tree to search.
3610  * \param[in] key Search key: one or more node keys, separated with dots.
3611  * \param[out] result When \a result != \c NULL, the function puts the
3612  *                    handle to the node found at the address specified
3613  *                    by \a result.
3614  * \return Zero if successful, otherwise a negative error code.
3615  *
3616  * This functions searches for a child node of \a config like
3617  * #snd_config_search.  However, any compound node can also be
3618  * identified by an alias, which is a string node whose value is taken
3619  * as the id of a compound node below \a root.
3620  *
3621  * \a root must be a compound node.
3622  * \a root and \a config may be the same node.
3623  *
3624  * For example, with the following configuration, the call
3625  * \code
3626  * snd_config_searcha(root, config, "a.b.c.d", &result);
3627  * \endcode
3628  * would return the node with id \c d:
3629  * \code
3630  * config {
3631  *     a {
3632  *         b bb
3633  *     }
3634  * }
3635  * root {
3636  *     bb {
3637  *         c cc
3638  *     }
3639  *     cc ccc
3640  *     ccc {
3641  *         d {
3642  *             x "icks"
3643  *         }
3644  *     }
3645  * }
3646  * \endcode
3647  *
3648  * \par Errors:
3649  * <dl>
3650  * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
3651  * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3652  *                not a compound or string node.
3653  * </dl>
3654  */
snd_config_searcha(snd_config_t * root,snd_config_t * config,const char * key,snd_config_t ** result)3655 int snd_config_searcha(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result)
3656 {
3657 	SND_CONFIG_SEARCHA(root, config, key, result, snd_config_searcha, );
3658 }
3659 
3660 /**
3661  * \brief Searches for a node in a configuration tree.
3662  * \param[in] config Handle to the root of the configuration (sub)tree to search.
3663  * \param[out] result When \a result != \c NULL, the function puts the
3664  *                    handle to the node found at the address specified
3665  *                    by \a result.
3666  * \param[in] ... One or more concatenated dot-separated search keys,
3667  *                terminated with \c NULL.
3668  * \return Zero if successful, otherwise a negative error code.
3669  *
3670  * This functions searches for a child node of \a config like
3671  * #snd_config_search, but the search key is the concatenation of all
3672  * passed search key strings.  For example, the call
3673  * \code
3674  * snd_config_searchv(cfg, &res, "a", "b.c", "d.e", NULL);
3675  * \endcode
3676  * is equivalent to the call
3677  * \code
3678  * snd_config_search(cfg, "a.b.c.d.e", &res);
3679  * \endcode
3680  *
3681  * \par Errors:
3682  * <dl>
3683  * <dt>-ENOENT<dd>An id in a search key does not exist.
3684  * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3685  *                not a compound node.
3686  * </dl>
3687  *
3688  * \par Conforming to:
3689  * LSB 3.2
3690  */
snd_config_searchv(snd_config_t * config,snd_config_t ** result,...)3691 int snd_config_searchv(snd_config_t *config, snd_config_t **result, ...)
3692 {
3693 	SND_CONFIG_SEARCHV(config, result, snd_config_search);
3694 }
3695 
3696 /**
3697  * \brief Searches for a node in a configuration tree, expanding aliases.
3698  * \param[in] root Handle to the root configuration node containing
3699  *                 alias definitions.
3700  * \param[in] config Handle to the root of the configuration (sub)tree to search.
3701  * \param[out] result When \a result != \c NULL, the function puts the
3702  *                    handle to the node found at the address specified
3703  *                    by \a result.
3704  * \param[in] ... One or more concatenated dot separated search keys,
3705  *                terminated with \c NULL.
3706  * \return Zero if successful, otherwise a negative error code.
3707  *
3708  * This function searches for a child node of \a config, allowing
3709  * aliases, like #snd_config_searcha, but the search key is the
3710  * concatenation of all passed seach key strings, like with
3711  * #snd_config_searchv.
3712  *
3713  * \par Errors:
3714  * <dl>
3715  * <dt>-ENOENT<dd>An id in a search key does not exist.
3716  * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3717  *                not a compound or string node.
3718  * </dl>
3719  */
snd_config_searchva(snd_config_t * root,snd_config_t * config,snd_config_t ** result,...)3720 int snd_config_searchva(snd_config_t *root, snd_config_t *config, snd_config_t **result, ...)
3721 {
3722 	SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha);
3723 }
3724 
3725 /**
3726  * \brief Searches for a node in a configuration tree, expanding aliases.
3727  * \param[in] config Handle to the root of the configuration (sub)tree to search.
3728  * \param[in] base Search key base, or \c NULL.
3729  * \param[in] key Search key suffix.
3730  * \param[out] result When \a result != \c NULL, the function puts the
3731  *                    handle to the node found at the address specified
3732  *                    by \a result.
3733  * \return Zero if successful, otherwise a negative error code.
3734  *
3735  * This functions searches for a child node of \a config, allowing
3736  * aliases, like #snd_config_searcha.  However, alias definitions are
3737  * searched below \a config (there is no separate \a root parameter),
3738  * and \a base specifies a seach key that identifies a compound node
3739  * that is used to search for an alias definitions that is not found
3740  * directly below \a config and that does not contain a period.  In
3741  * other words, when \c "id" is not found in \a config, this function
3742  * also tries \c "base.id".
3743  *
3744  * \par Errors:
3745  * <dl>
3746  * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
3747  * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3748  *                not a compound or string node.
3749  * </dl>
3750  */
snd_config_search_alias(snd_config_t * config,const char * base,const char * key,snd_config_t ** result)3751 int snd_config_search_alias(snd_config_t *config,
3752 			    const char *base, const char *key,
3753 			    snd_config_t **result)
3754 {
3755 	SND_CONFIG_SEARCH_ALIAS(config, base, key, result,
3756 				snd_config_searcha, snd_config_searchva);
3757 }
3758 
3759 static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data);
3760 
3761 /**
3762  * \brief Searches for a node in a configuration tree and expands hooks.
3763  * \param[in,out] config Handle to the root of the configuration
3764  *                       (sub)tree to search.
3765  * \param[in] key Search key: one or more node keys, separated with dots.
3766  * \param[out] result The function puts the handle to the node found at
3767  *                    the address specified by \a result.
3768  * \return Zero if successful, otherwise a negative error code.
3769  *
3770  * This functions searches for a child node of \a config like
3771  * #snd_config_search, but any compound nodes to be searched that
3772  * contain hooks are modified by the respective hook functions.
3773  *
3774  * \par Errors:
3775  * <dl>
3776  * <dt>-ENOENT<dd>An id in \a key does not exist.
3777  * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3778  *                not a compound node.
3779  * </dl>
3780  * Additionally, any errors encountered when parsing the hook
3781  * definitions or returned by the hook functions.
3782  */
snd_config_search_hooks(snd_config_t * config,const char * key,snd_config_t ** result)3783 int snd_config_search_hooks(snd_config_t *config, const char *key, snd_config_t **result)
3784 {
3785 	SND_CONFIG_SEARCH(config, key, result, \
3786 					err = snd_config_hooks(config, NULL); \
3787 					if (err < 0) \
3788 						return err; \
3789 			 );
3790 }
3791 
3792 /**
3793  * \brief Searches for a node in a configuration tree, expanding aliases and hooks.
3794  * \param[in] root Handle to the root configuration node containing
3795  *                 alias definitions.
3796  * \param[in,out] config Handle to the root of the configuration
3797  *                       (sub)tree to search.
3798  * \param[in] key Search key: one or more node keys, separated with dots.
3799  * \param[out] result The function puts the handle to the node found at
3800  *                    the address specified by \a result.
3801  * \return Zero if successful, otherwise a negative error code.
3802  *
3803  * This function searches for a child node of \a config, allowing
3804  * aliases, like #snd_config_searcha, and expanding hooks, like
3805  * #snd_config_search_hooks.
3806  *
3807  * \par Errors:
3808  * <dl>
3809  * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
3810  * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3811  *                not a compound node.
3812  * </dl>
3813  * Additionally, any errors encountered when parsing the hook
3814  * definitions or returned by the hook functions.
3815  */
snd_config_searcha_hooks(snd_config_t * root,snd_config_t * config,const char * key,snd_config_t ** result)3816 int snd_config_searcha_hooks(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result)
3817 {
3818 	SND_CONFIG_SEARCHA(root, config, key, result,
3819 					snd_config_searcha_hooks,
3820 					err = snd_config_hooks(config, NULL); \
3821 					if (err < 0) \
3822 						return err; \
3823 			 );
3824 }
3825 
3826 /**
3827  * \brief Searches for a node in a configuration tree, expanding aliases and hooks.
3828  * \param[in] root Handle to the root configuration node containing
3829  *                 alias definitions.
3830  * \param[in,out] config Handle to the root of the configuration
3831  *                       (sub)tree to search.
3832  * \param[out] result The function puts the handle to the node found at
3833  *                    the address specified by \a result.
3834  * \param[in] ... One or more concatenated dot separated search keys,
3835  *                terminated with \c NULL.
3836  * \return Zero if successful, otherwise a negative error code.
3837  *
3838  * This function searches for a child node of \a config, allowing
3839  * aliases and expanding hooks like #snd_config_searcha_hooks, but the
3840  * search key is the concatenation of all passed seach key strings, like
3841  * with #snd_config_searchv.
3842  *
3843  * \par Errors:
3844  * <dl>
3845  * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
3846  * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3847  *                not a compound node.
3848  * </dl>
3849  * Additionally, any errors encountered when parsing the hook
3850  * definitions or returned by the hook functions.
3851  */
snd_config_searchva_hooks(snd_config_t * root,snd_config_t * config,snd_config_t ** result,...)3852 int snd_config_searchva_hooks(snd_config_t *root, snd_config_t *config,
3853 			      snd_config_t **result, ...)
3854 {
3855 	SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha_hooks);
3856 }
3857 
3858 /**
3859  * \brief Searches for a node in a configuration tree, using an alias and expanding hooks.
3860  * \param[in] config Handle to the root of the configuration (sub)tree
3861  *                   to search.
3862  * \param[in] base Search key base, or \c NULL.
3863  * \param[in] key Search key suffix.
3864  * \param[out] result The function puts the handle to the node found at
3865  *                    the address specified by \a result.
3866  * \return Zero if successful, otherwise a negative error code.
3867  *
3868  * This functions searches for a child node of \a config, allowing
3869  * aliases, like #snd_config_search_alias, and expanding hooks, like
3870  * #snd_config_search_hooks.
3871  *
3872  * \par Errors:
3873  * <dl>
3874  * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
3875  * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
3876  *                not a compound node.
3877  * </dl>
3878  * Additionally, any errors encountered when parsing the hook
3879  * definitions or returned by the hook functions.
3880  */
snd_config_search_alias_hooks(snd_config_t * config,const char * base,const char * key,snd_config_t ** result)3881 int snd_config_search_alias_hooks(snd_config_t *config,
3882 				  const char *base, const char *key,
3883 				  snd_config_t **result)
3884 {
3885 	SND_CONFIG_SEARCH_ALIAS(config, base, key, result,
3886 				snd_config_searcha_hooks,
3887 				snd_config_searchva_hooks);
3888 }
3889 
3890 /** The name of the environment variable containing the files list for #snd_config_update. */
3891 #define ALSA_CONFIG_PATH_VAR "ALSA_CONFIG_PATH"
3892 
3893 /**
3894  * \ingroup Config
3895  * \brief Configuration top-level node (the global configuration).
3896  *
3897  * This variable contains a handle to the top-level configuration node,
3898  * as loaded from global configuration file.
3899  *
3900  * This variable is initialized or updated by #snd_config_update.
3901  * Functions like #snd_pcm_open (that use a device name from the global
3902  * configuration) automatically call #snd_config_update.  Before the
3903  * first call to #snd_config_update, this variable is \c NULL.
3904  *
3905  * The global configuration files are specified in the environment
3906  * variable \c ALSA_CONFIG_PATH.  If this is not set, the default value
3907  * is "/usr/share/alsa/alsa.conf".
3908  *
3909  * \warning Whenever the configuration tree is updated, all string
3910  * pointers and configuration node handles previously obtained from this
3911  * variable may become invalid.
3912  *
3913  * \par Conforming to:
3914  * LSB 3.2
3915  */
3916 snd_config_t *snd_config = NULL;
3917 
3918 #ifndef DOC_HIDDEN
3919 struct finfo {
3920 	char *name;
3921 	dev_t dev;
3922 	ino_t ino;
3923 	time_t mtime;
3924 };
3925 
3926 struct _snd_config_update {
3927 	unsigned int count;
3928 	struct finfo *finfo;
3929 };
3930 #endif /* DOC_HIDDEN */
3931 
3932 static snd_config_update_t *snd_config_global_update = NULL;
3933 
snd_config_hooks_call(snd_config_t * root,snd_config_t * config,snd_config_t * private_data)3934 static int snd_config_hooks_call(snd_config_t *root, snd_config_t *config, snd_config_t *private_data)
3935 {
3936 	void *h = NULL;
3937 	snd_config_t *c, *func_conf = NULL;
3938 	char *buf = NULL, errbuf[256];
3939 	const char *lib = NULL, *func_name = NULL;
3940 	const char *str;
3941 	int (*func)(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data) = NULL;
3942 	int err;
3943 
3944 	err = snd_config_search(config, "func", &c);
3945 	if (err < 0) {
3946 		SNDERR("Field func is missing");
3947 		return err;
3948 	}
3949 	err = snd_config_get_string(c, &str);
3950 	if (err < 0) {
3951 		SNDERR("Invalid type for field func");
3952 		return err;
3953 	}
3954 	assert(str);
3955 	err = snd_config_search_definition(root, "hook_func", str, &func_conf);
3956 	if (err >= 0) {
3957 		snd_config_iterator_t i, next;
3958 		if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) {
3959 			SNDERR("Invalid type for func %s definition", str);
3960 			err = -EINVAL;
3961 			goto _err;
3962 		}
3963 		snd_config_for_each(i, next, func_conf) {
3964 			snd_config_t *n = snd_config_iterator_entry(i);
3965 			const char *id = n->id;
3966 			if (strcmp(id, "comment") == 0)
3967 				continue;
3968 			if (strcmp(id, "lib") == 0) {
3969 				err = snd_config_get_string(n, &lib);
3970 				if (err < 0) {
3971 					SNDERR("Invalid type for %s", id);
3972 					goto _err;
3973 				}
3974 				continue;
3975 			}
3976 			if (strcmp(id, "func") == 0) {
3977 				err = snd_config_get_string(n, &func_name);
3978 				if (err < 0) {
3979 					SNDERR("Invalid type for %s", id);
3980 					goto _err;
3981 				}
3982 				continue;
3983 			}
3984 			SNDERR("Unknown field %s", id);
3985 		}
3986 	}
3987 	if (!func_name) {
3988 		int len = 16 + strlen(str) + 1;
3989 		buf = malloc(len);
3990 		if (! buf) {
3991 			err = -ENOMEM;
3992 			goto _err;
3993 		}
3994 		snprintf(buf, len, "snd_config_hook_%s", str);
3995 		buf[len-1] = '\0';
3996 		func_name = buf;
3997 	}
3998 	h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf));
3999 	func = h ? snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_HOOK)) : NULL;
4000 	err = 0;
4001 	if (!h) {
4002 		SNDERR("Cannot open shared library %s (%s)", lib, errbuf);
4003 		err = -ENOENT;
4004 	} else if (!func) {
4005 		SNDERR("symbol %s is not defined inside %s", func_name, lib);
4006 		snd_dlclose(h);
4007 		err = -ENXIO;
4008 	}
4009 	_err:
4010 	if (func_conf)
4011 		snd_config_delete(func_conf);
4012 	if (err >= 0) {
4013 		snd_config_t *nroot;
4014 		err = func(root, config, &nroot, private_data);
4015 		if (err < 0)
4016 			SNDERR("function %s returned error: %s", func_name, snd_strerror(err));
4017 		snd_dlclose(h);
4018 		if (err >= 0 && nroot)
4019 			err = snd_config_substitute(root, nroot);
4020 	}
4021 	free(buf);
4022 	if (err < 0)
4023 		return err;
4024 	return 0;
4025 }
4026 
snd_config_hooks(snd_config_t * config,snd_config_t * private_data)4027 static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data)
4028 {
4029 	snd_config_t *n;
4030 	snd_config_iterator_t i, next;
4031 	int err, hit, idx = 0;
4032 
4033 	if ((err = snd_config_search(config, "@hooks", &n)) < 0)
4034 		return 0;
4035 	snd_config_lock();
4036 	snd_config_remove(n);
4037 	do {
4038 		hit = 0;
4039 		snd_config_for_each(i, next, n) {
4040 			snd_config_t *n = snd_config_iterator_entry(i);
4041 			const char *id = n->id;
4042 			long i;
4043 			err = safe_strtol(id, &i);
4044 			if (err < 0) {
4045 				SNDERR("id of field %s is not and integer", id);
4046 				err = -EINVAL;
4047 				goto _err;
4048 			}
4049 			if (i == idx) {
4050 				err = snd_config_hooks_call(config, n, private_data);
4051 				if (err < 0)
4052 					goto _err;
4053 				idx++;
4054 				hit = 1;
4055 			}
4056 		}
4057 	} while (hit);
4058 	err = 0;
4059        _err:
4060 	snd_config_delete(n);
4061 	snd_config_unlock();
4062 	return err;
4063 }
4064 
config_filename_filter(const struct dirent * dirent)4065 static int config_filename_filter(const struct dirent *dirent)
4066 {
4067 	size_t flen;
4068 
4069 	if (dirent == NULL)
4070 		return 0;
4071 	if (dirent->d_type == DT_DIR)
4072 		return 0;
4073 
4074 	flen = strlen(dirent->d_name);
4075 	if (flen <= 5)
4076 		return 0;
4077 
4078 	if (strncmp(&dirent->d_name[flen-5], ".conf", 5) == 0)
4079 		return 1;
4080 
4081 	return 0;
4082 }
4083 
config_file_open(snd_config_t * root,const char * filename)4084 static int config_file_open(snd_config_t *root, const char *filename)
4085 {
4086 	snd_input_t *in;
4087 	int err;
4088 
4089 	err = snd_input_stdio_open(&in, filename, "r");
4090 	if (err >= 0) {
4091 		err = snd_config_load(root, in);
4092 		snd_input_close(in);
4093 		if (err < 0)
4094 			SNDERR("%s may be old or corrupted: consider to remove or fix it", filename);
4095 	} else
4096 		SNDERR("cannot access file %s", filename);
4097 
4098 	return err;
4099 }
4100 
config_file_load(snd_config_t * root,const char * fn,int errors)4101 static int config_file_load(snd_config_t *root, const char *fn, int errors)
4102 {
4103 	struct stat st;
4104 	struct dirent **namelist;
4105 	int err, n;
4106 
4107 	if (!errors && access(fn, R_OK) < 0)
4108 		return 1;
4109 	if (stat(fn, &st) < 0) {
4110 		SNDERR("cannot stat file/directory %s", fn);
4111 		return 1;
4112 	}
4113 	if (!S_ISDIR(st.st_mode))
4114 		return config_file_open(root, fn);
4115 #ifndef DOC_HIDDEN
4116 #if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__sun) && !defined(ANDROID)
4117 #define SORTFUNC	versionsort
4118 #else
4119 #define SORTFUNC	alphasort
4120 #endif
4121 #endif
4122 	n = scandir(fn, &namelist, config_filename_filter, SORTFUNC);
4123 	if (n > 0) {
4124 		int j;
4125 		err = 0;
4126 		for (j = 0; j < n; ++j) {
4127 			if (err >= 0) {
4128 				int sl = strlen(fn) + strlen(namelist[j]->d_name) + 2;
4129 				char *filename = malloc(sl);
4130 				snprintf(filename, sl, "%s/%s", fn, namelist[j]->d_name);
4131 				filename[sl-1] = '\0';
4132 
4133 				err = config_file_open(root, filename);
4134 				free(filename);
4135 			}
4136 			free(namelist[j]);
4137 		}
4138 		free(namelist);
4139 		if (err < 0)
4140 			return err;
4141 	}
4142 	return 0;
4143 }
4144 
config_file_load_user(snd_config_t * root,const char * fn,int errors)4145 static int config_file_load_user(snd_config_t *root, const char *fn, int errors)
4146 {
4147 	char *fn2;
4148 	int err;
4149 
4150 	err = snd_user_file(fn, &fn2);
4151 	if (err < 0)
4152 		return config_file_load(root, fn, errors);
4153 	err = config_file_load(root, fn2, errors);
4154 	free(fn2);
4155 	return err;
4156 }
4157 
config_file_load_user_all(snd_config_t * _root,snd_config_t * _file,int errors)4158 static int config_file_load_user_all(snd_config_t *_root, snd_config_t *_file, int errors)
4159 {
4160 	snd_config_t *file = _file, *root = _root, *n;
4161 	char *name, *name2, *remain, *rname = NULL;
4162 	int err;
4163 
4164 	if (snd_config_get_type(_file) == SND_CONFIG_TYPE_COMPOUND) {
4165 		if ((err = snd_config_search(_file, "file", &file)) < 0) {
4166 			SNDERR("Field file not found");
4167 			return err;
4168 		}
4169 		if ((err = snd_config_search(_file, "root", &root)) >= 0) {
4170 			err = snd_config_get_ascii(root, &rname);
4171 			if (err < 0) {
4172 				SNDERR("Field root is bad");
4173 				return err;
4174 			}
4175 			err = snd_config_make_compound(&root, rname, 0);
4176 			if (err < 0)
4177 				return err;
4178 		}
4179 	}
4180 	if ((err = snd_config_get_ascii(file, &name)) < 0)
4181 		goto _err;
4182 	name2 = name;
4183 	remain = strstr(name, "|||");
4184 	while (1) {
4185 		if (remain) {
4186 			*remain = '\0';
4187 			remain += 3;
4188 		}
4189 		err = config_file_load_user(root, name2, errors);
4190 		if (err < 0)
4191 			goto _err;
4192 		if (err == 0)	/* first hit wins */
4193 			break;
4194 		if (!remain)
4195 			break;
4196 		name2 = remain;
4197 		remain = strstr(remain, "|||");
4198 	}
4199 _err:
4200 	if (root != _root) {
4201 		if (err == 0) {
4202 			if (snd_config_get_type(root) == SND_CONFIG_TYPE_COMPOUND) {
4203 				if (snd_config_is_empty(root))
4204 					goto _del;
4205 			}
4206 			err = snd_config_make_path(&n, _root, rname, 0, 1);
4207 			if (err < 0)
4208 				goto _del;
4209 			err = snd_config_substitute(n, root);
4210 			if (err == 0)
4211 				goto _fin;
4212 		}
4213 _del:
4214 		snd_config_delete(root);
4215 	}
4216 _fin:
4217 	free(name);
4218 	free(rname);
4219 	return err;
4220 }
4221 
4222 /**
4223  * \brief Loads and parses the given configurations files.
4224  * \param[in] root Handle to the root configuration node.
4225  * \param[in] config Handle to the configuration node for this hook.
4226  * \param[out] dst The function puts the handle to the configuration
4227  *                 node loaded from the file(s) at the address specified
4228  *                 by \a dst.
4229  * \param[in] private_data Handle to the private data configuration node.
4230  * \return Zero if successful, otherwise a negative error code.
4231  *
4232  * See \ref confhooks for an example.
4233  */
snd_config_hook_load(snd_config_t * root,snd_config_t * config,snd_config_t ** dst,snd_config_t * private_data)4234 int snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data)
4235 {
4236 	snd_config_t *n;
4237 	snd_config_iterator_t i, next;
4238 	int err, idx = 0, errors = 1, hit;
4239 
4240 	assert(root && dst);
4241 	if ((err = snd_config_search(config, "errors", &n)) >= 0) {
4242 		errors = snd_config_get_bool(n);
4243 		if (errors < 0) {
4244 			SNDERR("Invalid bool value in field errors");
4245 			return errors;
4246 		}
4247 	}
4248 	if ((err = snd_config_search(config, "files", &n)) < 0) {
4249 		SNDERR("Unable to find field files in the pre-load section");
4250 		return -EINVAL;
4251 	}
4252 	if ((err = snd_config_expand(n, root, NULL, private_data, &n)) < 0) {
4253 		SNDERR("Unable to expand filenames in the pre-load section");
4254 		return err;
4255 	}
4256 	if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
4257 		SNDERR("Invalid type for field filenames");
4258 		goto _err;
4259 	}
4260 	do {
4261 		hit = 0;
4262 		snd_config_for_each(i, next, n) {
4263 			snd_config_t *n = snd_config_iterator_entry(i);
4264 			const char *id = n->id;
4265 			long i;
4266 			err = safe_strtol(id, &i);
4267 			if (err < 0) {
4268 				SNDERR("id of field %s is not and integer", id);
4269 				err = -EINVAL;
4270 				goto _err;
4271 			}
4272 			if (i == idx) {
4273 				err = config_file_load_user_all(root, n, errors);
4274 				if (err < 0)
4275 					goto _err;
4276 				idx++;
4277 				hit = 1;
4278 			}
4279 		}
4280 	} while (hit);
4281 	*dst = NULL;
4282 	err = 0;
4283        _err:
4284 	snd_config_delete(n);
4285 	return err;
4286 }
4287 #ifndef DOC_HIDDEN
4288 SND_DLSYM_BUILD_VERSION(snd_config_hook_load, SND_CONFIG_DLSYM_VERSION_HOOK);
4289 #endif
4290 
4291 #ifndef DOC_HIDDEN
4292 int snd_determine_driver(int card, char **driver);
4293 #endif
4294 
_snd_config_hook_private_data(int card,const char * driver)4295 snd_config_t *_snd_config_hook_private_data(int card, const char *driver)
4296 {
4297 	snd_config_t *private_data, *v;
4298 	int err;
4299 
4300 	err = snd_config_make_compound(&private_data, NULL, 0);
4301 	if (err < 0)
4302 		goto __err;
4303 	err = snd_config_imake_integer(&v, "integer", card);
4304 	if (err < 0)
4305 		goto __err;
4306 	err = snd_config_add(private_data, v);
4307 	if (err < 0) {
4308 		snd_config_delete(v);
4309 		goto __err;
4310 	}
4311 	err = snd_config_imake_string(&v, "string", driver);
4312 	if (err < 0)
4313 		goto __err;
4314 	err = snd_config_add(private_data, v);
4315 	if (err < 0) {
4316 		snd_config_delete(v);
4317 		goto __err;
4318 	}
4319 	return private_data;
4320 
4321 __err:
4322 	snd_config_delete(private_data);
4323 	return NULL;
4324 }
4325 
_snd_config_hook_table(snd_config_t * root,snd_config_t * config,snd_config_t * private_data)4326 static int _snd_config_hook_table(snd_config_t *root, snd_config_t *config, snd_config_t *private_data)
4327 {
4328 	snd_config_t *n, *tn;
4329 	const char *id;
4330 	int err;
4331 
4332 	if (snd_config_search(config, "table", &n) < 0)
4333 		return 0;
4334 	if ((err = snd_config_expand(n, root, NULL, private_data, &n)) < 0) {
4335 		SNDERR("Unable to expand table compound");
4336 		return err;
4337 	}
4338 	if (snd_config_search(n, "id", &tn) < 0 ||
4339 	    snd_config_get_string(tn, &id) < 0) {
4340 		SNDERR("Unable to find field table.id");
4341 		snd_config_delete(n);
4342 		return -EINVAL;
4343 	}
4344 	if (snd_config_search(n, "value", &tn) < 0 ||
4345 	    snd_config_get_type(tn) != SND_CONFIG_TYPE_STRING) {
4346 		SNDERR("Unable to find field table.value");
4347 		snd_config_delete(n);
4348 		return -EINVAL;
4349 	}
4350 	snd_config_remove(tn);
4351 	if ((err = snd_config_set_id(tn, id)) < 0) {
4352 		snd_config_delete(tn);
4353 		snd_config_delete(n);
4354 		return err;
4355 	}
4356 	snd_config_delete(n);
4357 	if ((err = snd_config_add(root, tn)) < 0) {
4358 		snd_config_delete(tn);
4359 		return err;
4360 	}
4361 	return 0;
4362 }
4363 
4364 /**
4365  * \brief Loads and parses the given configurations files for each
4366  *        installed sound card.
4367  * \param[in] root Handle to the root configuration node.
4368  * \param[in] config Handle to the configuration node for this hook.
4369  * \param[out] dst The function puts the handle to the configuration
4370  *                 node loaded from the file(s) at the address specified
4371  *                 by \a dst.
4372  * \param[in] private_data Handle to the private data configuration node.
4373  * \return Zero if successful, otherwise a negative error code.
4374  *
4375  * This function works like #snd_config_hook_load, but the files are
4376  * loaded once for each sound card.  The driver name is available with
4377  * the \c private_string function to customize the file name.
4378  */
snd_config_hook_load_for_all_cards(snd_config_t * root,snd_config_t * config,snd_config_t ** dst,snd_config_t * private_data ATTRIBUTE_UNUSED)4379 int snd_config_hook_load_for_all_cards(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data ATTRIBUTE_UNUSED)
4380 {
4381 	int card = -1, err;
4382 	snd_config_t *loaded;	// trace loaded cards
4383 
4384 	err = snd_config_top(&loaded);
4385 	if (err < 0)
4386 		return err;
4387 	do {
4388 		err = snd_card_next(&card);
4389 		if (err < 0)
4390 			goto __fin_err;
4391 		if (card >= 0) {
4392 			snd_config_t *n, *m, *private_data = NULL;
4393 			const char *driver;
4394 			char *fdriver = NULL;
4395 			bool load;
4396 			err = snd_determine_driver(card, &fdriver);
4397 			if (err < 0)
4398 				goto __fin_err;
4399 			if (snd_config_search(root, fdriver, &n) >= 0) {
4400 				if (snd_config_get_string(n, &driver) < 0) {
4401 					if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND) {
4402 						snd_config_get_id(n, &driver);
4403 						goto __std;
4404 					}
4405 					goto __err;
4406 				}
4407 				while (1) {
4408 					char *s = strchr(driver, '.');
4409 					if (s == NULL)
4410 						break;
4411 					driver = s + 1;
4412 				}
4413 				if (snd_config_search(root, driver, &n) >= 0)
4414 					goto __err;
4415 			} else {
4416 				driver = fdriver;
4417 			}
4418 		      __std:
4419 			load = true;
4420 			err = snd_config_imake_integer(&m, driver, 1);
4421 			if (err < 0)
4422 				goto __err;
4423 			err = snd_config_add(loaded, m);
4424 			if (err < 0) {
4425 				if (err == -EEXIST) {
4426 					snd_config_delete(m);
4427 					load = false;
4428 				} else {
4429 					goto __err;
4430 				}
4431 			}
4432 			private_data = _snd_config_hook_private_data(card, driver);
4433 			if (!private_data) {
4434 				err = -ENOMEM;
4435 				goto __err;
4436 			}
4437 			err = _snd_config_hook_table(root, config, private_data);
4438 			if (err < 0)
4439 				goto __err;
4440 			if (load)
4441 				err = snd_config_hook_load(root, config, &n, private_data);
4442 		      __err:
4443 			if (private_data)
4444 				snd_config_delete(private_data);
4445 			free(fdriver);
4446 			if (err < 0)
4447 				goto __fin_err;
4448 		}
4449 	} while (card >= 0);
4450 	snd_config_delete(loaded);
4451 	*dst = NULL;
4452 	return 0;
4453 __fin_err:
4454 	snd_config_delete(loaded);
4455 	return err;
4456 }
4457 #ifndef DOC_HIDDEN
4458 SND_DLSYM_BUILD_VERSION(snd_config_hook_load_for_all_cards, SND_CONFIG_DLSYM_VERSION_HOOK);
4459 #endif
4460 
4461 /**
4462  * \brief Updates a configuration tree by rereading the configuration files (if needed).
4463  * \param[in,out] _top Address of the handle to the top-level node.
4464  * \param[in,out] _update Address of a pointer to private update information.
4465  * \param[in] cfgs A list of configuration file names, delimited with ':'.
4466  *                 If \p cfgs is \c NULL, the default global
4467  *                 configuration file is used.
4468  * \return 0 if \a _top was up to date, 1 if the configuration files
4469  *         have been reread, otherwise a negative error code.
4470  *
4471  * The variables pointed to by \a _top and \a _update can be initialized
4472  * to \c NULL before the first call to this function.  The private
4473  * update information holds information about all used configuration
4474  * files that allows this function to detects changes to them; this data
4475  * can be freed with #snd_config_update_free.
4476  *
4477  * The global configuration files are specified in the environment variable
4478  * \c ALSA_CONFIG_PATH.
4479  *
4480  * \warning If the configuration tree is reread, all string pointers and
4481  * configuration node handles previously obtained from this tree become
4482  * invalid.
4483  *
4484  * \par Errors:
4485  * Any errors encountered when parsing the input or returned by hooks or
4486  * functions.
4487  */
snd_config_update_r(snd_config_t ** _top,snd_config_update_t ** _update,const char * cfgs)4488 int snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, const char *cfgs)
4489 {
4490 	int err;
4491 	const char *configs, *c;
4492 	unsigned int k;
4493 	size_t l;
4494 	snd_config_update_t *local;
4495 	snd_config_update_t *update;
4496 	snd_config_t *top;
4497 
4498 	assert(_top && _update);
4499 	top = *_top;
4500 	update = *_update;
4501 	configs = cfgs;
4502 	if (!configs) {
4503 		configs = getenv(ALSA_CONFIG_PATH_VAR);
4504 		if (!configs || !*configs) {
4505 			const char *topdir = snd_config_topdir();
4506 			char *s = alloca(strlen(topdir) +
4507 					 strlen("alsa.conf") + 2);
4508 			sprintf(s, "%s/alsa.conf", topdir);
4509 			configs = s;
4510 		}
4511 	}
4512 	for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) {
4513 		c += l;
4514 		k++;
4515 		if (!*c)
4516 			break;
4517 		c++;
4518 	}
4519 	if (k == 0) {
4520 		local = NULL;
4521 		goto _reread;
4522 	}
4523 	local = (snd_config_update_t *)calloc(1, sizeof(snd_config_update_t));
4524 	if (!local)
4525 		return -ENOMEM;
4526 	local->count = k;
4527 	local->finfo = calloc(local->count, sizeof(struct finfo));
4528 	if (!local->finfo) {
4529 		free(local);
4530 		return -ENOMEM;
4531 	}
4532 	for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) {
4533 		char name[l + 1];
4534 		memcpy(name, c, l);
4535 		name[l] = 0;
4536 		err = snd_user_file(name, &local->finfo[k].name);
4537 		if (err < 0)
4538 			goto _end;
4539 		c += l;
4540 		k++;
4541 		if (!*c)
4542 			break;
4543 		c++;
4544 	}
4545 	for (k = 0; k < local->count; ++k) {
4546 		struct stat st;
4547 		struct finfo *lf = &local->finfo[k];
4548 		if (stat(lf->name, &st) >= 0) {
4549 			lf->dev = st.st_dev;
4550 			lf->ino = st.st_ino;
4551 			lf->mtime = st.st_mtime;
4552 		} else {
4553 			SNDERR("Cannot access file %s", lf->name);
4554 			free(lf->name);
4555 			memmove(&local->finfo[k], &local->finfo[k+1], sizeof(struct finfo) * (local->count - k - 1));
4556 			k--;
4557 			local->count--;
4558 		}
4559 	}
4560 	if (!update)
4561 		goto _reread;
4562 	if (local->count != update->count)
4563 		goto _reread;
4564 	for (k = 0; k < local->count; ++k) {
4565 		struct finfo *lf = &local->finfo[k];
4566 		struct finfo *uf = &update->finfo[k];
4567 		if (strcmp(lf->name, uf->name) != 0 ||
4568 		    lf->dev != uf->dev ||
4569 		    lf->ino != uf->ino ||
4570 		    lf->mtime != uf->mtime)
4571 			goto _reread;
4572 	}
4573 	err = 0;
4574 
4575  _end:
4576 	if (err < 0) {
4577 		if (top) {
4578 			snd_config_delete(top);
4579 			*_top = NULL;
4580 		}
4581 		if (update) {
4582 			snd_config_update_free(update);
4583 			*_update = NULL;
4584 		}
4585 	}
4586 	if (local)
4587 		snd_config_update_free(local);
4588 	return err;
4589 
4590  _reread:
4591  	*_top = NULL;
4592  	*_update = NULL;
4593  	if (update) {
4594  		snd_config_update_free(update);
4595  		update = NULL;
4596  	}
4597 	if (top) {
4598 		snd_config_delete(top);
4599 		top = NULL;
4600 	}
4601 	err = snd_config_top(&top);
4602 	if (err < 0)
4603 		goto _end;
4604 	if (!local)
4605 		goto _skip;
4606 	for (k = 0; k < local->count; ++k) {
4607 		snd_input_t *in;
4608 		err = snd_input_stdio_open(&in, local->finfo[k].name, "r");
4609 		if (err >= 0) {
4610 			err = snd_config_load(top, in);
4611 			snd_input_close(in);
4612 			if (err < 0) {
4613 				SNDERR("%s may be old or corrupted: consider to remove or fix it", local->finfo[k].name);
4614 				goto _end;
4615 			}
4616 		} else {
4617 			SNDERR("cannot access file %s", local->finfo[k].name);
4618 		}
4619 	}
4620  _skip:
4621 	err = snd_config_hooks(top, NULL);
4622 	if (err < 0) {
4623 		SNDERR("hooks failed, removing configuration");
4624 		goto _end;
4625 	}
4626 	*_top = top;
4627 	*_update = local;
4628 	return 1;
4629 }
4630 
4631 /**
4632  * \brief Updates #snd_config by rereading the global configuration files (if needed).
4633  * \return 0 if #snd_config was up to date, 1 if #snd_config was
4634  *         updated, otherwise a negative error code.
4635  *
4636  * \warning Whenever #snd_config is updated, all string pointers and
4637  * configuration node handles previously obtained from it may become
4638  * invalid.
4639  * For safer operations, use #snd_config_update_ref and release the config
4640  * via #snd_config_unref.
4641  *
4642  * \par Errors:
4643  * Any errors encountered when parsing the input or returned by hooks or
4644  * functions.
4645  *
4646  * \par Conforming to:
4647  * LSB 3.2
4648  */
snd_config_update(void)4649 int snd_config_update(void)
4650 {
4651 	int err;
4652 
4653 	snd_config_lock();
4654 	err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL);
4655 	snd_config_unlock();
4656 	return err;
4657 }
4658 
4659 /**
4660  * \brief Updates #snd_config and takes its reference.
4661  * \return 0 if #snd_config was up to date, 1 if #snd_config was
4662  *         updated, otherwise a negative error code.
4663  *
4664  * Unlike #snd_config_update, this function increases a reference counter
4665  * so that the obtained tree won't be deleted until unreferenced by
4666  * #snd_config_unref.
4667  *
4668  * This function is supposed to be thread-safe.
4669  */
snd_config_update_ref(snd_config_t ** top)4670 int snd_config_update_ref(snd_config_t **top)
4671 {
4672 	int err;
4673 
4674 	if (top)
4675 		*top = NULL;
4676 	snd_config_lock();
4677 	err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL);
4678 	if (err >= 0) {
4679 		if (snd_config) {
4680 			if (top) {
4681 				snd_config->refcount++;
4682 				*top = snd_config;
4683 			}
4684 		} else {
4685 			err = -ENODEV;
4686 		}
4687 	}
4688 	snd_config_unlock();
4689 	return err;
4690 }
4691 
4692 /**
4693  * \brief Take the reference of the config tree.
4694  *
4695  * Increases a reference counter of the given config tree.
4696  *
4697  * This function is supposed to be thread-safe.
4698  */
snd_config_ref(snd_config_t * cfg)4699 void snd_config_ref(snd_config_t *cfg)
4700 {
4701 	snd_config_lock();
4702 	if (cfg)
4703 		cfg->refcount++;
4704 	snd_config_unlock();
4705 }
4706 
4707 /**
4708  * \brief Unreference the config tree.
4709  *
4710  * Decreases a reference counter of the given config tree, and eventually
4711  * deletes the tree if all references are gone.  This is the counterpart of
4712  * #snd_config_unref.
4713  *
4714  * Also, the config taken via #snd_config_update_ref must be unreferenced
4715  * by this function, too.
4716  *
4717  * This function is supposed to be thread-safe.
4718  */
snd_config_unref(snd_config_t * cfg)4719 void snd_config_unref(snd_config_t *cfg)
4720 {
4721 	snd_config_lock();
4722 	if (cfg)
4723 		snd_config_delete(cfg);
4724 	snd_config_unlock();
4725 }
4726 
4727 /**
4728  * \brief Frees a private update structure.
4729  * \param[in] update The private update structure to free.
4730  * \return Zero if successful, otherwise a negative error code.
4731  */
snd_config_update_free(snd_config_update_t * update)4732 int snd_config_update_free(snd_config_update_t *update)
4733 {
4734 	unsigned int k;
4735 
4736 	assert(update);
4737 	for (k = 0; k < update->count; k++)
4738 		free(update->finfo[k].name);
4739 	free(update->finfo);
4740 	free(update);
4741 	return 0;
4742 }
4743 
4744 /**
4745  * \brief Frees the global configuration tree in #snd_config.
4746  * \return Zero if successful, otherwise a negative error code.
4747  *
4748  * This functions releases all resources of the global configuration
4749  * tree, and sets #snd_config to \c NULL.
4750  *
4751  * \par Conforming to:
4752  * LSB 3.2
4753  */
snd_config_update_free_global(void)4754 int snd_config_update_free_global(void)
4755 {
4756 	snd_config_lock();
4757 	if (snd_config)
4758 		snd_config_delete(snd_config);
4759 	snd_config = NULL;
4760 	if (snd_config_global_update)
4761 		snd_config_update_free(snd_config_global_update);
4762 	snd_config_global_update = NULL;
4763 	snd_config_unlock();
4764 	/* FIXME: better to place this in another place... */
4765 	snd_dlobj_cache_cleanup();
4766 
4767 	return 0;
4768 }
4769 
4770 /**
4771  * \brief Returns an iterator pointing to a node's first child.
4772  * \param[in] config Handle to a configuration node.
4773  * \return An iterator pointing to \a config's first child.
4774  *
4775  * \a config must be a compound node.
4776  *
4777  * The returned iterator is valid if it is not equal to the return value
4778  * of #snd_config_iterator_end on \a config.
4779  *
4780  * Use #snd_config_iterator_entry to get the handle of the node pointed
4781  * to.
4782  *
4783  * \par Conforming to:
4784  * LSB 3.2
4785  */
snd_config_iterator_first(const snd_config_t * config)4786 snd_config_iterator_t snd_config_iterator_first(const snd_config_t *config)
4787 {
4788 	assert(config->type == SND_CONFIG_TYPE_COMPOUND);
4789 	return config->u.compound.fields.next;
4790 }
4791 
4792 /**
4793  * \brief Returns an iterator pointing to the next sibling.
4794  * \param[in] iterator An iterator pointing to a child configuration node.
4795  * \return An iterator pointing to the next sibling of \a iterator.
4796  *
4797  * The returned iterator is valid if it is not equal to the return value
4798  * of #snd_config_iterator_end on the node's parent.
4799  *
4800  * Use #snd_config_iterator_entry to get the handle of the node pointed
4801  * to.
4802  *
4803  * \par Conforming to:
4804  * LSB 3.2
4805  */
snd_config_iterator_next(const snd_config_iterator_t iterator)4806 snd_config_iterator_t snd_config_iterator_next(const snd_config_iterator_t iterator)
4807 {
4808 	return iterator->next;
4809 }
4810 
4811 /**
4812  * \brief Returns an iterator that ends a node's children list.
4813  * \param[in] config Handle to a configuration node.
4814  * \return An iterator that indicates the end of \a config's children list.
4815  *
4816  * \a config must be a compound node.
4817  *
4818  * The return value can be understood as pointing past the last child of
4819  * \a config.
4820  *
4821  * \par Conforming to:
4822  * LSB 3.2
4823  */
snd_config_iterator_end(const snd_config_t * config)4824 snd_config_iterator_t snd_config_iterator_end(const snd_config_t *config)
4825 {
4826 	assert(config->type == SND_CONFIG_TYPE_COMPOUND);
4827 	return (const snd_config_iterator_t)&config->u.compound.fields;
4828 }
4829 
4830 /**
4831  * \brief Returns the configuration node handle pointed to by an iterator.
4832  * \param[in] iterator A configuration node iterator.
4833  * \return The configuration node handle pointed to by \a iterator.
4834  *
4835  * \par Conforming to:
4836  * LSB 3.2
4837  */
snd_config_iterator_entry(const snd_config_iterator_t iterator)4838 snd_config_t *snd_config_iterator_entry(const snd_config_iterator_t iterator)
4839 {
4840 	return list_entry(iterator, snd_config_t, list);
4841 }
4842 
4843 #ifndef DOC_HIDDEN
4844 typedef enum _snd_config_walk_pass {
4845 	SND_CONFIG_WALK_PASS_PRE,
4846 	SND_CONFIG_WALK_PASS_POST,
4847 	SND_CONFIG_WALK_PASS_LEAF,
4848 } snd_config_walk_pass_t;
4849 #endif
4850 
4851 /* Return 1 if node needs to be attached to parent */
4852 /* Return 2 if compound is replaced with standard node */
4853 #ifndef DOC_HIDDEN
4854 typedef int (*snd_config_walk_callback_t)(snd_config_t *src,
4855 					  snd_config_t *root,
4856 					  snd_config_t **dst,
4857 					  snd_config_walk_pass_t pass,
4858 					  snd_config_expand_fcn_t fcn,
4859 					  void *private_data);
4860 #endif
4861 
snd_config_walk(snd_config_t * src,snd_config_t * root,snd_config_t ** dst,snd_config_walk_callback_t callback,snd_config_expand_fcn_t fcn,void * private_data)4862 static int snd_config_walk(snd_config_t *src,
4863 			   snd_config_t *root,
4864 			   snd_config_t **dst,
4865 			   snd_config_walk_callback_t callback,
4866 			   snd_config_expand_fcn_t fcn,
4867 			   void *private_data)
4868 {
4869 	int err;
4870 	snd_config_iterator_t i, next;
4871 
4872 	switch (snd_config_get_type(src)) {
4873 	case SND_CONFIG_TYPE_COMPOUND:
4874 		err = callback(src, root, dst, SND_CONFIG_WALK_PASS_PRE, fcn, private_data);
4875 		if (err <= 0)
4876 			return err;
4877 		snd_config_for_each(i, next, src) {
4878 			snd_config_t *s = snd_config_iterator_entry(i);
4879 			snd_config_t *d = NULL;
4880 
4881 			err = snd_config_walk(s, root, (dst && *dst) ? &d : NULL,
4882 					      callback, fcn, private_data);
4883 			if (err < 0)
4884 				goto _error;
4885 			if (err && d) {
4886 				err = snd_config_add(*dst, d);
4887 				if (err < 0)
4888 					goto _error;
4889 			}
4890 		}
4891 		err = callback(src, root, dst, SND_CONFIG_WALK_PASS_POST, fcn, private_data);
4892 		if (err <= 0) {
4893 		_error:
4894 			if (dst && *dst)
4895 				snd_config_delete(*dst);
4896 		}
4897 		break;
4898 	default:
4899 		err = callback(src, root, dst, SND_CONFIG_WALK_PASS_LEAF, fcn, private_data);
4900 		break;
4901 	}
4902 	return err;
4903 }
4904 
_snd_config_copy(snd_config_t * src,snd_config_t * root ATTRIBUTE_UNUSED,snd_config_t ** dst,snd_config_walk_pass_t pass,snd_config_expand_fcn_t fcn ATTRIBUTE_UNUSED,void * private_data ATTRIBUTE_UNUSED)4905 static int _snd_config_copy(snd_config_t *src,
4906 			    snd_config_t *root ATTRIBUTE_UNUSED,
4907 			    snd_config_t **dst,
4908 			    snd_config_walk_pass_t pass,
4909 			    snd_config_expand_fcn_t fcn ATTRIBUTE_UNUSED,
4910 			    void *private_data ATTRIBUTE_UNUSED)
4911 {
4912 	int err;
4913 	const char *id = src->id;
4914 	snd_config_type_t type = snd_config_get_type(src);
4915 	switch (pass) {
4916 	case SND_CONFIG_WALK_PASS_PRE:
4917 		err = snd_config_make_compound(dst, id, src->u.compound.join);
4918 		if (err < 0)
4919 			return err;
4920 		break;
4921 	case SND_CONFIG_WALK_PASS_LEAF:
4922 		err = snd_config_make(dst, id, type);
4923 		if (err < 0)
4924 			return err;
4925 		switch (type) {
4926 		case SND_CONFIG_TYPE_INTEGER:
4927 		{
4928 			long v;
4929 			err = snd_config_get_integer(src, &v);
4930 			assert(err >= 0);
4931 			snd_config_set_integer(*dst, v);
4932 			break;
4933 		}
4934 		case SND_CONFIG_TYPE_INTEGER64:
4935 		{
4936 			long long v;
4937 			err = snd_config_get_integer64(src, &v);
4938 			assert(err >= 0);
4939 			snd_config_set_integer64(*dst, v);
4940 			break;
4941 		}
4942 		case SND_CONFIG_TYPE_REAL:
4943 		{
4944 			double v;
4945 			err = snd_config_get_real(src, &v);
4946 			assert(err >= 0);
4947 			snd_config_set_real(*dst, v);
4948 			break;
4949 		}
4950 		case SND_CONFIG_TYPE_STRING:
4951 		{
4952 			const char *s;
4953 			err = snd_config_get_string(src, &s);
4954 			assert(err >= 0);
4955 			err = snd_config_set_string(*dst, s);
4956 			if (err < 0)
4957 				return err;
4958 			break;
4959 		}
4960 		default:
4961 			assert(0);
4962 		}
4963 		break;
4964 	default:
4965 		break;
4966 	}
4967 	return 1;
4968 }
4969 
4970 /**
4971  * \brief Creates a copy of a configuration node.
4972  * \param[out] dst The function puts the handle to the new configuration
4973  *                 node at the address specified by \a dst.
4974  * \param[in] src Handle to the source configuration node.
4975  * \return A non-negative value if successful, otherwise a negative error code.
4976  *
4977  * This function creates a deep copy, i.e., if \a src is a compound
4978  * node, all children are copied recursively.
4979  *
4980  * \par Errors:
4981  * <dl>
4982  * <dt>-ENOMEM<dd>Out of memory.
4983  * </dl>
4984  *
4985  * \par Conforming to:
4986  * LSB 3.2
4987  */
snd_config_copy(snd_config_t ** dst,snd_config_t * src)4988 int snd_config_copy(snd_config_t **dst,
4989 		    snd_config_t *src)
4990 {
4991 	return snd_config_walk(src, NULL, dst, _snd_config_copy, NULL, NULL);
4992 }
4993 
_snd_config_expand_vars(snd_config_t ** dst,const char * s,void * private_data)4994 static int _snd_config_expand_vars(snd_config_t **dst, const char *s, void *private_data)
4995 {
4996 	snd_config_t *val, *vars = private_data;
4997 	if (snd_config_search(vars, s, &val) < 0)
4998 		return snd_config_make_string(dst, "");
4999 	return snd_config_copy(dst, val);
5000 }
5001 
_snd_config_expand(snd_config_t * src,snd_config_t * root ATTRIBUTE_UNUSED,snd_config_t ** dst,snd_config_walk_pass_t pass,snd_config_expand_fcn_t fcn,void * private_data)5002 static int _snd_config_expand(snd_config_t *src,
5003 			      snd_config_t *root ATTRIBUTE_UNUSED,
5004 			      snd_config_t **dst,
5005 			      snd_config_walk_pass_t pass,
5006 			      snd_config_expand_fcn_t fcn,
5007 			      void *private_data)
5008 {
5009 	int err;
5010 	const char *id = src->id;
5011 	snd_config_type_t type = snd_config_get_type(src);
5012 	switch (pass) {
5013 	case SND_CONFIG_WALK_PASS_PRE:
5014 	{
5015 		if (id && strcmp(id, "@args") == 0)
5016 			return 0;
5017 		err = snd_config_make_compound(dst, id, src->u.compound.join);
5018 		if (err < 0)
5019 			return err;
5020 		break;
5021 	}
5022 	case SND_CONFIG_WALK_PASS_LEAF:
5023 		switch (type) {
5024 		case SND_CONFIG_TYPE_INTEGER:
5025 		{
5026 			long v;
5027 			err = snd_config_get_integer(src, &v);
5028 			assert(err >= 0);
5029 			err = snd_config_imake_integer(dst, id, v);
5030 			if (err < 0)
5031 				return err;
5032 			break;
5033 		}
5034 		case SND_CONFIG_TYPE_INTEGER64:
5035 		{
5036 			long long v;
5037 			err = snd_config_get_integer64(src, &v);
5038 			assert(err >= 0);
5039 			err = snd_config_imake_integer64(dst, id, v);
5040 			if (err < 0)
5041 				return err;
5042 			break;
5043 		}
5044 		case SND_CONFIG_TYPE_REAL:
5045 		{
5046 			double v;
5047 			err = snd_config_get_real(src, &v);
5048 			assert(err >= 0);
5049 			err = snd_config_imake_real(dst, id, v);
5050 			if (err < 0)
5051 				return err;
5052 			break;
5053 		}
5054 		case SND_CONFIG_TYPE_STRING:
5055 		{
5056 			const char *s;
5057 			snd_config_t *vars = private_data;
5058 			snd_config_get_string(src, &s);
5059 			if (s && *s == '$') {
5060 				err = snd_config_evaluate_string(dst, s, fcn, vars);
5061 				if (err < 0)
5062 					return err;
5063 				err = snd_config_set_id(*dst, id);
5064 				if (err < 0) {
5065 					snd_config_delete(*dst);
5066 					return err;
5067 				}
5068 			} else {
5069 				err = snd_config_imake_string(dst, id, s);
5070 				if (err < 0)
5071 					return err;
5072 			}
5073 			break;
5074 		}
5075 		default:
5076 			assert(0);
5077 		}
5078 		break;
5079 	default:
5080 		break;
5081 	}
5082 	return 1;
5083 }
5084 
_snd_config_evaluate(snd_config_t * src,snd_config_t * root,snd_config_t ** dst ATTRIBUTE_UNUSED,snd_config_walk_pass_t pass,snd_config_expand_fcn_t fcn ATTRIBUTE_UNUSED,void * private_data)5085 static int _snd_config_evaluate(snd_config_t *src,
5086 				snd_config_t *root,
5087 				snd_config_t **dst ATTRIBUTE_UNUSED,
5088 				snd_config_walk_pass_t pass,
5089 				snd_config_expand_fcn_t fcn ATTRIBUTE_UNUSED,
5090 				void *private_data)
5091 {
5092 	int err;
5093 	if (pass == SND_CONFIG_WALK_PASS_PRE) {
5094 		char *buf = NULL, errbuf[256];
5095 		const char *lib = NULL, *func_name = NULL;
5096 		const char *str;
5097 		int (*func)(snd_config_t **dst, snd_config_t *root,
5098 			    snd_config_t *src, snd_config_t *private_data) = NULL;
5099 		void *h = NULL;
5100 		snd_config_t *c, *func_conf = NULL;
5101 		err = snd_config_search(src, "@func", &c);
5102 		if (err < 0)
5103 			return 1;
5104 		err = snd_config_get_string(c, &str);
5105 		if (err < 0) {
5106 			SNDERR("Invalid type for @func");
5107 			return err;
5108 		}
5109 		assert(str);
5110 		err = snd_config_search_definition(root, "func", str, &func_conf);
5111 		if (err >= 0) {
5112 			snd_config_iterator_t i, next;
5113 			if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) {
5114 				SNDERR("Invalid type for func %s definition", str);
5115 				err = -EINVAL;
5116 				goto _err;
5117 			}
5118 			snd_config_for_each(i, next, func_conf) {
5119 				snd_config_t *n = snd_config_iterator_entry(i);
5120 				const char *id = n->id;
5121 				if (strcmp(id, "comment") == 0)
5122 					continue;
5123 				if (strcmp(id, "lib") == 0) {
5124 					err = snd_config_get_string(n, &lib);
5125 					if (err < 0) {
5126 						SNDERR("Invalid type for %s", id);
5127 						goto _err;
5128 					}
5129 					continue;
5130 				}
5131 				if (strcmp(id, "func") == 0) {
5132 					err = snd_config_get_string(n, &func_name);
5133 					if (err < 0) {
5134 						SNDERR("Invalid type for %s", id);
5135 						goto _err;
5136 					}
5137 					continue;
5138 				}
5139 				SNDERR("Unknown field %s", id);
5140 			}
5141 		}
5142 		if (!func_name) {
5143 			int len = 9 + strlen(str) + 1;
5144 			buf = malloc(len);
5145 			if (! buf) {
5146 				err = -ENOMEM;
5147 				goto _err;
5148 			}
5149 			snprintf(buf, len, "snd_func_%s", str);
5150 			buf[len-1] = '\0';
5151 			func_name = buf;
5152 		}
5153 		h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf));
5154 		if (h)
5155 			func = snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_EVALUATE));
5156 		err = 0;
5157 		if (!h) {
5158 			SNDERR("Cannot open shared library %s (%s)", lib, errbuf);
5159 			err = -ENOENT;
5160 			goto _errbuf;
5161 		} else if (!func) {
5162 			SNDERR("symbol %s is not defined inside %s", func_name, lib);
5163 			snd_dlclose(h);
5164 			err = -ENXIO;
5165 			goto _errbuf;
5166 		}
5167 	       _err:
5168 		if (func_conf)
5169 			snd_config_delete(func_conf);
5170 		if (err >= 0) {
5171 			snd_config_t *eval;
5172 			err = func(&eval, root, src, private_data);
5173 			if (err < 0)
5174 				SNDERR("function %s returned error: %s", func_name, snd_strerror(err));
5175 			snd_dlclose(h);
5176 			if (err >= 0 && eval)
5177 				err = snd_config_substitute(src, eval);
5178 		}
5179 	       _errbuf:
5180 		free(buf);
5181 		if (err < 0)
5182 			return err;
5183 		return 0;
5184 	}
5185 	return 1;
5186 }
5187 
5188 /**
5189  * \brief Evaluates a configuration node at runtime.
5190  * \param[in,out] config Handle to the source configuration node.
5191  * \param[in] root Handle to the root of the source configuration.
5192  * \param[in] private_data Handle to the private data node for runtime evaluation.
5193  * \param result Must be \c NULL.
5194  * \return A non-negative value if successful, otherwise a negative error code.
5195  *
5196  * This function evaluates any functions (\c \@func) in \a config and
5197  * replaces those nodes with the respective function results.
5198  */
snd_config_evaluate(snd_config_t * config,snd_config_t * root,snd_config_t * private_data,snd_config_t ** result)5199 int snd_config_evaluate(snd_config_t *config, snd_config_t *root,
5200 		        snd_config_t *private_data, snd_config_t **result)
5201 {
5202 	/* FIXME: Only in place evaluation is currently implemented */
5203 	assert(result == NULL);
5204 	return snd_config_walk(config, root, result, _snd_config_evaluate, NULL, private_data);
5205 }
5206 
load_defaults(snd_config_t * subs,snd_config_t * defs)5207 static int load_defaults(snd_config_t *subs, snd_config_t *defs)
5208 {
5209 	snd_config_iterator_t d, dnext;
5210 	snd_config_for_each(d, dnext, defs) {
5211 		snd_config_t *def = snd_config_iterator_entry(d);
5212 		snd_config_iterator_t f, fnext;
5213 		if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND)
5214 			continue;
5215 		snd_config_for_each(f, fnext, def) {
5216 			snd_config_t *fld = snd_config_iterator_entry(f);
5217 			const char *id = fld->id;
5218 			if (strcmp(id, "type") == 0)
5219 				continue;
5220 			if (strcmp(id, "default") == 0) {
5221 				snd_config_t *deflt;
5222 				int err;
5223 				err = snd_config_copy(&deflt, fld);
5224 				if (err < 0)
5225 					return err;
5226 				err = snd_config_set_id(deflt, def->id);
5227 				if (err < 0) {
5228 					snd_config_delete(deflt);
5229 					return err;
5230 				}
5231 				err = snd_config_add(subs, deflt);
5232 				if (err < 0) {
5233 					snd_config_delete(deflt);
5234 					return err;
5235 				}
5236 				continue;
5237 			}
5238 			SNDERR("Unknown field %s", id);
5239 			return -EINVAL;
5240 		}
5241 	}
5242 	return 0;
5243 }
5244 
skip_blank(const char ** ptr)5245 static void skip_blank(const char **ptr)
5246 {
5247 	while (1) {
5248 		switch (**ptr) {
5249 		case ' ':
5250 		case '\f':
5251 		case '\t':
5252 		case '\n':
5253 		case '\r':
5254 			break;
5255 		default:
5256 			return;
5257 		}
5258 		(*ptr)++;
5259 	}
5260 }
5261 
parse_char(const char ** ptr)5262 static int parse_char(const char **ptr)
5263 {
5264 	int c;
5265 	assert(**ptr == '\\');
5266 	(*ptr)++;
5267 	c = **ptr;
5268 	switch (c) {
5269 	case 'n':
5270 		c = '\n';
5271 		break;
5272 	case 't':
5273 		c = '\t';
5274 		break;
5275 	case 'v':
5276 		c = '\v';
5277 		break;
5278 	case 'b':
5279 		c = '\b';
5280 		break;
5281 	case 'r':
5282 		c = '\r';
5283 		break;
5284 	case 'f':
5285 		c = '\f';
5286 		break;
5287 	case '0': case '1': case '2': case '3':
5288 	case '4': case '5': case '6': case '7':
5289 	{
5290 		int num = c - '0';
5291 		int i = 1;
5292 		(*ptr)++;
5293 		do {
5294 			c = **ptr;
5295 			if (c < '0' || c > '7')
5296 				break;
5297 			num = num * 8 + c - '0';
5298 			i++;
5299 			(*ptr)++;
5300 		} while (i < 3);
5301 		return num;
5302 	}
5303 	default:
5304 		break;
5305 	}
5306 	(*ptr)++;
5307 	return c;
5308 }
5309 
parse_id(const char ** ptr)5310 static int parse_id(const char **ptr)
5311 {
5312 	if (!**ptr)
5313 		return -EINVAL;
5314 	while (1) {
5315 		switch (**ptr) {
5316 		case '\f':
5317 		case '\t':
5318 		case '\n':
5319 		case '\r':
5320 		case ',':
5321 		case '=':
5322 		case '\0':
5323 			return 0;
5324 		default:
5325 			break;
5326 		}
5327 		(*ptr)++;
5328 	}
5329 }
5330 
parse_string(const char ** ptr,char ** val)5331 static int parse_string(const char **ptr, char **val)
5332 {
5333 	const size_t bufsize = 256;
5334 	char _buf[bufsize];
5335 	char *buf = _buf;
5336 	size_t alloc = bufsize;
5337 	char delim = **ptr;
5338 	size_t idx = 0;
5339 	(*ptr)++;
5340 	while (1) {
5341 		int c = **ptr;
5342 		switch (c) {
5343 		case '\0':
5344 			SNDERR("Unterminated string");
5345 			return -EINVAL;
5346 		case '\\':
5347 			c = parse_char(ptr);
5348 			if (c < 0) {
5349 				if (alloc > bufsize)
5350 					free(buf);
5351 				return c;
5352 			}
5353 			break;
5354 		default:
5355 			(*ptr)++;
5356 			if (c == delim) {
5357 				*val = malloc(idx + 1);
5358 				if (!*val)
5359 					return -ENOMEM;
5360 				memcpy(*val, buf, idx);
5361 				(*val)[idx] = 0;
5362 				if (alloc > bufsize)
5363 					free(buf);
5364 				return 0;
5365 			}
5366 		}
5367 		if (idx >= alloc) {
5368 			size_t old_alloc = alloc;
5369 			alloc *= 2;
5370 			if (old_alloc == bufsize) {
5371 				buf = malloc(alloc);
5372 				if (!buf)
5373 					return -ENOMEM;
5374 				memcpy(buf, _buf, old_alloc);
5375 			} else {
5376 				char *buf2 = realloc(buf, alloc);
5377 				if (!buf2) {
5378 					free(buf);
5379 					return -ENOMEM;
5380 				}
5381 				buf = buf2;
5382 			}
5383 		}
5384 		buf[idx++] = c;
5385 	}
5386 }
5387 
5388 
5389 /* Parse var=val or val */
parse_arg(const char ** ptr,unsigned int * varlen,char ** val)5390 static int parse_arg(const char **ptr, unsigned int *varlen, char **val)
5391 {
5392 	const char *str;
5393 	int err, vallen;
5394 	skip_blank(ptr);
5395 	str = *ptr;
5396 	if (*str == '"' || *str == '\'') {
5397 		err = parse_string(ptr, val);
5398 		if (err < 0)
5399 			return err;
5400 		*varlen = 0;
5401 		return 0;
5402 	}
5403 	err = parse_id(ptr);
5404 	if (err < 0)
5405 		return err;
5406 	vallen = *ptr - str;
5407 	skip_blank(ptr);
5408 	if (**ptr != '=') {
5409 		*varlen = 0;
5410 		goto _value;
5411 	}
5412 	*varlen = vallen;
5413 	(*ptr)++;
5414 	skip_blank(ptr);
5415 	str = *ptr;
5416 	if (*str == '"' || *str == '\'') {
5417 		err = parse_string(ptr, val);
5418 		if (err < 0)
5419 			return err;
5420 		return 0;
5421 	}
5422 	err = parse_id(ptr);
5423 	if (err < 0)
5424 		return err;
5425 	vallen = *ptr - str;
5426  _value:
5427 	*val = malloc(vallen + 1);
5428 	if (!*val)
5429 		return -ENOMEM;
5430 	memcpy(*val, str, vallen);
5431 	(*val)[vallen] = 0;
5432 	return 0;
5433 }
5434 
5435 
5436 /* val1, val2, ...
5437  * var1=val1,var2=val2,...
5438  * { conf syntax }
5439  */
parse_args(snd_config_t * subs,const char * str,snd_config_t * defs)5440 static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs)
5441 {
5442 	int err;
5443 	int arg = 0;
5444 	if (str == NULL)
5445 		return 0;
5446 	skip_blank(&str);
5447 	if (!*str)
5448 		return 0;
5449 	if (*str == '{') {
5450 		int len = strlen(str);
5451 		snd_input_t *input;
5452 		snd_config_iterator_t i, next;
5453 		while (1) {
5454 			switch (str[--len]) {
5455 			case ' ':
5456 			case '\f':
5457 			case '\t':
5458 			case '\n':
5459 			case '\r':
5460 				continue;
5461 			default:
5462 				break;
5463 			}
5464 			break;
5465 		}
5466 		if (str[len] != '}')
5467 			return -EINVAL;
5468 		err = snd_input_buffer_open(&input, str + 1, len - 1);
5469 		if (err < 0)
5470 			return err;
5471 		err = snd_config_load_override(subs, input);
5472 		snd_input_close(input);
5473 		if (err < 0)
5474 			return err;
5475 		snd_config_for_each(i, next, subs) {
5476 			snd_config_t *n = snd_config_iterator_entry(i);
5477 			snd_config_t *d;
5478 			const char *id = n->id;
5479 			err = snd_config_search(defs, id, &d);
5480 			if (err < 0) {
5481 				SNDERR("Unknown parameter %s", id);
5482 				return err;
5483 			}
5484 		}
5485 		return 0;
5486 	}
5487 
5488 	while (1) {
5489 		char buf[256];
5490 		const char *var = buf;
5491 		unsigned int varlen;
5492 		snd_config_t *def, *sub, *typ;
5493 		const char *new = str;
5494 		const char *tmp;
5495 		char *val = NULL;
5496 
5497 		sub = NULL;
5498 		err = parse_arg(&new, &varlen, &val);
5499 		if (err < 0)
5500 			goto _err;
5501 		if (varlen > 0) {
5502 			assert(varlen < sizeof(buf));
5503 			memcpy(buf, str, varlen);
5504 			buf[varlen] = 0;
5505 		} else {
5506 			sprintf(buf, "%d", arg);
5507 		}
5508 		err = snd_config_search_alias(defs, NULL, var, &def);
5509 		if (err < 0) {
5510 			SNDERR("Unknown parameter %s", var);
5511 			goto _err;
5512 		}
5513 		if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND) {
5514 			SNDERR("Parameter %s definition is not correct", var);
5515 			err = -EINVAL;
5516 			goto _err;
5517 		}
5518 		var = def->id;
5519 		err = snd_config_search(subs, var, &sub);
5520 		if (err >= 0)
5521 			snd_config_delete(sub);
5522 		sub = NULL;
5523 		err = snd_config_search(def, "type", &typ);
5524 		if (err < 0) {
5525 		_invalid_type:
5526 			SNDERR("Parameter %s definition is missing a valid type info", var);
5527 			goto _err;
5528 		}
5529 		err = snd_config_get_string(typ, &tmp);
5530 		if (err < 0 || !tmp)
5531 			goto _invalid_type;
5532 		if (strcmp(tmp, "integer") == 0) {
5533 			long v;
5534 			err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER);
5535 			if (err < 0)
5536 				goto _err;
5537 			err = safe_strtol(val, &v);
5538 			if (err < 0) {
5539 				SNDERR("Parameter %s must be an integer", var);
5540 				goto _err;
5541 			}
5542 			err = snd_config_set_integer(sub, v);
5543 			if (err < 0)
5544 				goto _err;
5545 		} else if (strcmp(tmp, "integer64") == 0) {
5546 			long long v;
5547 			err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER64);
5548 			if (err < 0)
5549 				goto _err;
5550 			err = safe_strtoll(val, &v);
5551 			if (err < 0) {
5552 				SNDERR("Parameter %s must be an integer", var);
5553 				goto _err;
5554 			}
5555 			err = snd_config_set_integer64(sub, v);
5556 			if (err < 0)
5557 				goto _err;
5558 		} else if (strcmp(tmp, "real") == 0) {
5559 			double v;
5560 			err = snd_config_make(&sub, var, SND_CONFIG_TYPE_REAL);
5561 			if (err < 0)
5562 				goto _err;
5563 			err = safe_strtod(val, &v);
5564 			if (err < 0) {
5565 				SNDERR("Parameter %s must be a real", var);
5566 				goto _err;
5567 			}
5568 			err = snd_config_set_real(sub, v);
5569 			if (err < 0)
5570 				goto _err;
5571 		} else if (strcmp(tmp, "string") == 0) {
5572 			err = snd_config_make(&sub, var, SND_CONFIG_TYPE_STRING);
5573 			if (err < 0)
5574 				goto _err;
5575 			err = snd_config_set_string(sub, val);
5576 			if (err < 0)
5577 				goto _err;
5578 		} else {
5579 			err = -EINVAL;
5580 			goto _invalid_type;
5581 		}
5582 		err = snd_config_set_id(sub, var);
5583 		if (err < 0)
5584 			goto _err;
5585 		err = snd_config_add(subs, sub);
5586 		if (err < 0) {
5587 		_err:
5588 			if (sub)
5589 				snd_config_delete(sub);
5590 			free(val);
5591 			return err;
5592 		}
5593 		free(val);
5594 		if (!*new)
5595 			break;
5596 		if (*new != ',')
5597 			return -EINVAL;
5598 		str = new + 1;
5599 		arg++;
5600 	}
5601 	return 0;
5602 }
5603 
5604 /**
5605  * \brief Expands a configuration node, applying arguments and functions.
5606  * \param[in] config Handle to the configuration node.
5607  * \param[in] root Handle to the root configuration node.
5608  * \param[in] fcn Custom function to obtain the referred variable name
5609  * \param[in] private_data Private data node for the custom function
5610  * \param[out] result The function puts the handle to the result
5611  *                    configuration node at the address specified by
5612  *                    \a result.
5613  * \return A non-negative value if successful, otherwise a negative error code.
5614  *
5615  * If \a config has arguments (defined by a child with id \c \@args),
5616  * this function replaces any string node beginning with $ with the
5617  * respective argument value, or the default argument value, or nothing.
5618  * Furthermore, any functions are evaluated (see #snd_config_evaluate).
5619  * The resulting copy of \a config is returned in \a result.
5620  *
5621  * The new tree is not evaluated (\ref snd_config_evaluate).
5622  */
snd_config_expand_custom(snd_config_t * config,snd_config_t * root,snd_config_expand_fcn_t fcn,void * private_data,snd_config_t ** result)5623 int snd_config_expand_custom(snd_config_t *config, snd_config_t *root,
5624 			     snd_config_expand_fcn_t fcn, void *private_data,
5625 			     snd_config_t **result)
5626 {
5627 	snd_config_t *res;
5628 	int err;
5629 
5630 	err = snd_config_walk(config, root, &res, _snd_config_expand, fcn, private_data);
5631 	if (err < 0) {
5632 		SNDERR("Expand error (walk): %s", snd_strerror(err));
5633 		return err;
5634 	}
5635 	*result = res;
5636 	return 1;
5637 }
5638 
5639 /**
5640  * \brief Expands a configuration node, applying arguments and functions.
5641  * \param[in] config Handle to the configuration node.
5642  * \param[in] root Handle to the root configuration node.
5643  * \param[in] args Arguments string, can be \c NULL.
5644  * \param[in] private_data Handle to the private data node for functions.
5645  * \param[out] result The function puts the handle to the result
5646  *                    configuration node at the address specified by
5647  *                    \a result.
5648  * \return A non-negative value if successful, otherwise a negative error code.
5649  *
5650  * If \a config has arguments (defined by a child with id \c \@args),
5651  * this function replaces any string node beginning with $ with the
5652  * respective argument value, or the default argument value, or nothing.
5653  * Furthermore, any functions are evaluated (see #snd_config_evaluate).
5654  * The resulting copy of \a config is returned in \a result.
5655  */
snd_config_expand(snd_config_t * config,snd_config_t * root,const char * args,snd_config_t * private_data,snd_config_t ** result)5656 int snd_config_expand(snd_config_t *config, snd_config_t *root, const char *args,
5657 		      snd_config_t *private_data, snd_config_t **result)
5658 {
5659 	int err;
5660 	snd_config_t *defs, *subs = NULL, *res;
5661 	err = snd_config_search(config, "@args", &defs);
5662 	if (err < 0) {
5663 		if (args != NULL) {
5664 			SNDERR("Unknown parameters %s", args);
5665 			return -EINVAL;
5666 		}
5667 		err = snd_config_copy(&res, config);
5668 		if (err < 0)
5669 			return err;
5670 	} else {
5671 		err = snd_config_top(&subs);
5672 		if (err < 0)
5673 			return err;
5674 		err = load_defaults(subs, defs);
5675 		if (err < 0) {
5676 			SNDERR("Load defaults error: %s", snd_strerror(err));
5677 			goto _end;
5678 		}
5679 		err = parse_args(subs, args, defs);
5680 		if (err < 0) {
5681 			SNDERR("Parse arguments error: %s", snd_strerror(err));
5682 			goto _end;
5683 		}
5684 		err = snd_config_evaluate(subs, root, private_data, NULL);
5685 		if (err < 0) {
5686 			SNDERR("Args evaluate error: %s", snd_strerror(err));
5687 			goto _end;
5688 		}
5689 		err = snd_config_walk(config, root, &res, _snd_config_expand, _snd_config_expand_vars, subs);
5690 		if (err < 0) {
5691 			SNDERR("Expand error (walk): %s", snd_strerror(err));
5692 			goto _end;
5693 		}
5694 	}
5695 	err = snd_config_evaluate(res, root, private_data, NULL);
5696 	if (err < 0) {
5697 		SNDERR("Evaluate error: %s", snd_strerror(err));
5698 		snd_config_delete(res);
5699 		goto _end;
5700 	}
5701 	*result = res;
5702 	err = 1;
5703  _end:
5704  	if (subs)
5705 		snd_config_delete(subs);
5706 	return err;
5707 }
5708 
5709 /**
5710  * \brief Searches for a definition in a configuration tree, using
5711  *        aliases and expanding hooks and arguments.
5712  * \param[in] config Handle to the configuration (sub)tree to search.
5713  * \param[in] base Implicit key base, or \c NULL for none.
5714  * \param[in] name Key suffix, optionally with arguments.
5715  * \param[out] result The function puts the handle to the expanded found
5716  *                    node at the address specified by \a result.
5717  * \return A non-negative value if successful, otherwise a negative error code.
5718  *
5719  * This functions searches for a child node of \a config, allowing
5720  * aliases and expanding hooks, like #snd_config_search_alias_hooks.
5721  *
5722  * If \a name contains a colon (:), the rest of the string after the
5723  * colon contains arguments that are expanded as with
5724  * #snd_config_expand.
5725  *
5726  * In any case, \a result is a new node that must be freed by the
5727  * caller.
5728  *
5729  * \par Errors:
5730  * <dl>
5731  * <dt>-ENOENT<dd>An id in \a key or an alias id does not exist.
5732  * <dt>-ENOENT<dd>\a config or one of its child nodes to be searched is
5733  *                not a compound node.
5734  * </dl>
5735  * Additionally, any errors encountered when parsing the hook
5736  * definitions or arguments, or returned by (hook) functions.
5737  */
snd_config_search_definition(snd_config_t * config,const char * base,const char * name,snd_config_t ** result)5738 int snd_config_search_definition(snd_config_t *config,
5739 				 const char *base, const char *name,
5740 				 snd_config_t **result)
5741 {
5742 	snd_config_t *conf;
5743 	char *key;
5744 	const char *args = strchr(name, ':');
5745 	int err;
5746 	if (args) {
5747 		args++;
5748 		key = alloca(args - name);
5749 		memcpy(key, name, args - name - 1);
5750 		key[args - name - 1] = '\0';
5751 	} else {
5752 		key = (char *) name;
5753 	}
5754 	/*
5755 	 *  if key contains dot (.), the implicit base is ignored
5756 	 *  and the key starts from root given by the 'config' parameter
5757 	 */
5758 	snd_config_lock();
5759 	err = snd_config_search_alias_hooks(config, strchr(key, '.') ? NULL : base, key, &conf);
5760 	if (err < 0) {
5761 		snd_config_unlock();
5762 		return err;
5763 	}
5764 	err = snd_config_expand(conf, config, args, NULL, result);
5765 	snd_config_unlock();
5766 	return err;
5767 }
5768 
5769 #ifndef DOC_HIDDEN
snd_config_set_hop(snd_config_t * conf,int hop)5770 void snd_config_set_hop(snd_config_t *conf, int hop)
5771 {
5772 	conf->hop = hop;
5773 }
5774 
snd_config_check_hop(snd_config_t * conf)5775 int snd_config_check_hop(snd_config_t *conf)
5776 {
5777 	if (conf) {
5778 		if (conf->hop >= SND_CONF_MAX_HOPS) {
5779 			SYSERR("Too many definition levels (looped?)\n");
5780 			return -EINVAL;
5781 		}
5782 		return conf->hop;
5783 	}
5784 	return 0;
5785 }
5786 #endif
5787 
5788 #if 0
5789 /* Not strictly needed, but useful to check for memory leaks */
5790 void _snd_config_end(void) __attribute__ ((destructor));
5791 
5792 static void _snd_config_end(void)
5793 {
5794 	int k;
5795 	if (snd_config)
5796 		snd_config_delete(snd_config);
5797 	snd_config = 0;
5798 	for (k = 0; k < files_info_count; ++k)
5799 		free(files_info[k].name);
5800 	free(files_info);
5801 	files_info = NULL;
5802 	files_info_count = 0;
5803 }
5804 #endif
5805 
page_size(void)5806 size_t page_size(void)
5807 {
5808 	long s = sysconf(_SC_PAGE_SIZE);
5809 	assert(s > 0);
5810 	return s;
5811 }
5812 
page_align(size_t size)5813 size_t page_align(size_t size)
5814 {
5815 	size_t r;
5816 	long psz = page_size();
5817 	r = size % psz;
5818 	if (r)
5819 		return size + psz - r;
5820 	return size;
5821 }
5822 
page_ptr(size_t object_offset,size_t object_size,size_t * offset,size_t * mmap_offset)5823 size_t page_ptr(size_t object_offset, size_t object_size, size_t *offset, size_t *mmap_offset)
5824 {
5825 	size_t r;
5826 	long psz = page_size();
5827 	assert(offset);
5828 	assert(mmap_offset);
5829 	*mmap_offset = object_offset;
5830 	object_offset %= psz;
5831 	*mmap_offset -= object_offset;
5832 	object_size += object_offset;
5833 	r = object_size % psz;
5834 	if (r)
5835 		r = object_size + psz - r;
5836 	else
5837 		r = object_size;
5838 	*offset = object_offset;
5839 	return r;
5840 }
5841