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