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