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, ¤t->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