1 /** 2 * \file conf.c 3 * \ingroup Configuration 4 * \brief Configuration helper functions 5 * \author Abramo Bagnara <abramo (at) alsa-project.org> 6 * \author Jaroslav Kysela <perex (at) perex.cz> 7 * \date 2000-2001 8 * 9 * 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 (at) alsa-project.org>, 16 * Jaroslav Kysela <perex (at) perex.cz> 17 * 18 * 19 * This library is free software; you can redistribute it and/or modify 20 * it under the terms of the GNU Lesser General Public License as 21 * published by the Free Software Foundation; either version 2.1 of 22 * the License, or (at your option) any later version. 23 * 24 * This program is distributed in the hope that it will be useful, 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * GNU Lesser General Public License for more details. 28 * 29 * You should have received a copy of the GNU Lesser General Public 30 * License along with this library; if not, write to the Free Software 31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 32 * 33 */ 34 35 /*! \page 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_usage Usage 322 323 To use a block with arguments, write the argument values after the key, 324 separated with a colon (:). For example, all these names for PCM interfaces 325 give the same result: 326 327 \code 328 hw:0,1 329 hw:CARD=0,DEV=1 330 hw:{CARD 0 DEV 1} 331 plug:"hw:0,1" 332 plug:{SLAVE="hw:{CARD 0 DEV 1}"} 333 \endcode 334 335 As you see, arguments can be specified in their proper order or by name. 336 Note that arguments enclosed in braces are parsed in the same way as in 337 configuration files, but using the override method by default. 338 339 \section confarg_example Example 340 341 \code 342 pcm.demo { 343 @args [ CARD DEVICE ] 344 @args.CARD { 345 type string 346 default "supersonic" 347 } 348 @args.DEVICE { 349 type integer 350 default 0 351 } 352 type hw 353 card $CARD 354 device $DEVICE 355 } 356 \endcode 357 358 */ 359 360 /*! \page conffunc Runtime functions in configuration files 361 362 <P>The ALSA library can modify the configuration at runtime. 363 Several built-in functions are available.</P> 364 365 <P>A function is defined with the id \c \@func and the function name. All other 366 values in the current compound are used as configuration for the function. 367 If the compound func.\<function_name\> is defined in the root node, then the 368 library and function from this compound configuration are used, otherwise 369 'snd_func_' is prefixed to the string and code from the ALSA library is used. 370 The definition of a function looks like:</P> 371 372 \code 373 func.remove_first_char { 374 lib "/usr/lib/libasoundextend.so" 375 func "extend_remove_first_char" 376 } 377 \endcode 378 379 */ 380 381 /*! \page confhooks Hooks in configuration files 382 383 <P>The hook extension in the ALSA library allows expansion of configuration 384 nodes at run-time. The existence of a hook is determined by the 385 presence of a \@hooks compound node.</P> 386 387 <P>This example defines a hook which loads two configuration files at the 388 beginning:</P> 389 390 \code 391 @hooks [ 392 { 393 func load 394 files [ 395 "/etc/asound.conf" 396 "~/.asoundrc" 397 ] 398 errors false 399 } 400 ] 401 \endcode 402 403 \section confhooks_ref Function reference 404 405 <UL> 406 <LI>The function load - \c snd_config_hook_load() - loads and parses the 407 given configuration files. 408 <LI>The function load_for_all_cards - \c snd_config_hook_load_for_all_cards() - 409 loads and parses the given configuration files for each installed sound 410 card. The driver name (the type of the sound card) is passed in the 411 private configuration node. 412 </UL> 413 414 */ 415 416 417 #include <stdarg.h> 418 #include <limits.h> 419 #include <sys/stat.h> 420 #include <locale.h> 421 #include "local.h" 422 #ifdef HAVE_LIBPTHREAD 423 #include <pthread.h> 424 #endif 425 426 #ifndef DOC_HIDDEN 427 428 struct _snd_config { 429 char *id; 430 snd_config_type_t type; 431 union { 432 long integer; 433 long long integer64; 434 char *string; 435 double real; 436 const void *ptr; 437 struct { 438 struct list_head fields; 439 int join; 440 } compound; 441 } u; 442 struct list_head list; 443 snd_config_t *father; 444 int hop; 445 }; 446 447 struct filedesc { 448 char *name; 449 snd_input_t *in; 450 unsigned int line, column; 451 struct filedesc *next; 452 }; 453 454 #define LOCAL_ERROR (-0x68000000) 455 456 #define LOCAL_UNTERMINATED_STRING (LOCAL_ERROR - 0) 457 #define LOCAL_UNTERMINATED_QUOTE (LOCAL_ERROR - 1) 458 #define LOCAL_UNEXPECTED_CHAR (LOCAL_ERROR - 2) 459 #define LOCAL_UNEXPECTED_EOF (LOCAL_ERROR - 3) 460 461 typedef struct { 462 struct filedesc *current; 463 int unget; 464 int ch; 465 } input_t; 466 467 static int safe_strtoll(const char *str, long long *val) 468 { 469 long long v; 470 int endidx; 471 if (!*str) 472 return -EINVAL; 473 errno = 0; 474 if (sscanf(str, "%Li%n", &v, &endidx) < 1) 475 return -EINVAL; 476 if (str[endidx]) 477 return -EINVAL; 478 *val = v; 479 return 0; 480 } 481 482 int safe_strtol(const char *str, long *val) 483 { 484 char *end; 485 long v; 486 if (!*str) 487 return -EINVAL; 488 errno = 0; 489 v = strtol(str, &end, 0); 490 if (errno) 491 return -errno; 492 if (*end) 493 return -EINVAL; 494 *val = v; 495 return 0; 496 } 497 498 static int safe_strtod(const char *str, double *val) 499 { 500 char *end; 501 double v; 502 char *saved_locale; 503 char locstr[64]; /* enough? */ 504 int err; 505 506 if (!*str) 507 return -EINVAL; 508 saved_locale = setlocale(LC_NUMERIC, NULL); 509 if (saved_locale) { 510 snprintf(locstr, sizeof(locstr), "%s", saved_locale); 511 setlocale(LC_NUMERIC, "C"); 512 } 513 errno = 0; 514 v = strtod(str, &end); 515 err = -errno; 516 if (saved_locale) 517 setlocale(LC_NUMERIC, locstr); 518 if (err) 519 return err; 520 if (*end) 521 return -EINVAL; 522 *val = v; 523 return 0; 524 } 525 526 static int get_char(input_t *input) 527 { 528 int c; 529 struct filedesc *fd; 530 if (input->unget) { 531 input->unget = 0; 532 return input->ch; 533 } 534 again: 535 fd = input->current; 536 c = snd_input_getc(fd->in); 537 switch (c) { 538 case '\n': 539 fd->column = 0; 540 fd->line++; 541 break; 542 case '\t': 543 fd->column += 8 - fd->column % 8; 544 break; 545 case EOF: 546 if (fd->next) { 547 snd_input_close(fd->in); 548 free(fd->name); 549 input->current = fd->next; 550 free(fd); 551 goto again; 552 } 553 return LOCAL_UNEXPECTED_EOF; 554 default: 555 fd->column++; 556 break; 557 } 558 return (unsigned char)c; 559 } 560 561 static void unget_char(int c, input_t *input) 562 { 563 assert(!input->unget); 564 input->ch = c; 565 input->unget = 1; 566 } 567 568 static int get_delimstring(char **string, int delim, input_t *input); 569 570 static int get_char_skip_comments(input_t *input) 571 { 572 int c; 573 while (1) { 574 c = get_char(input); 575 if (c == '<') { 576 char *str; 577 snd_input_t *in; 578 struct filedesc *fd; 579 int err = get_delimstring(&str, '>', input); 580 if (err < 0) 581 return err; 582 if (!strncmp(str, "confdir:", 8)) { 583 char *tmp = malloc(strlen(ALSA_CONFIG_DIR) + 1 + strlen(str + 8) + 1); 584 if (tmp == NULL) { 585 free(str); 586 return -ENOMEM; 587 } 588 sprintf(tmp, ALSA_CONFIG_DIR "/%s", str + 8); 589 free(str); 590 str = tmp; 591 } 592 err = snd_input_stdio_open(&in, str, "r"); 593 if (err < 0) { 594 SNDERR("Cannot access file %s", str); 595 free(str); 596 return err; 597 } 598 fd = malloc(sizeof(*fd)); 599 if (!fd) { 600 free(str); 601 return -ENOMEM; 602 } 603 fd->name = str; 604 fd->in = in; 605 fd->next = input->current; 606 fd->line = 1; 607 fd->column = 0; 608 input->current = fd; 609 continue; 610 } 611 if (c != '#') 612 break; 613 while (1) { 614 c = get_char(input); 615 if (c < 0) 616 return c; 617 if (c == '\n') 618 break; 619 } 620 } 621 622 return c; 623 } 624 625 626 static int get_nonwhite(input_t *input) 627 { 628 int c; 629 while (1) { 630 c = get_char_skip_comments(input); 631 switch (c) { 632 case ' ': 633 case '\f': 634 case '\t': 635 case '\n': 636 case '\r': 637 break; 638 default: 639 return c; 640 } 641 } 642 } 643 644 static int get_quotedchar(input_t *input) 645 { 646 int c; 647 c = get_char(input); 648 switch (c) { 649 case 'n': 650 return '\n'; 651 case 't': 652 return '\t'; 653 case 'v': 654 return '\v'; 655 case 'b': 656 return '\b'; 657 case 'r': 658 return '\r'; 659 case 'f': 660 return '\f'; 661 case '0' ... '7': 662 { 663 int num = c - '0'; 664 int i = 1; 665 do { 666 c = get_char(input); 667 if (c < '0' || c > '7') { 668 unget_char(c, input); 669 break; 670 } 671 num = num * 8 + c - '0'; 672 i++; 673 } while (i < 3); 674 return num; 675 } 676 default: 677 return c; 678 } 679 } 680 681 #define LOCAL_STR_BUFSIZE 64 682 struct local_string { 683 char *buf; 684 size_t alloc; 685 size_t idx; 686 char tmpbuf[LOCAL_STR_BUFSIZE]; 687 }; 688 689 static void init_local_string(struct local_string *s) 690 { 691 memset(s, 0, sizeof(*s)); 692 s->buf = s->tmpbuf; 693 s->alloc = LOCAL_STR_BUFSIZE; 694 } 695 696 static void free_local_string(struct local_string *s) 697 { 698 if (s->buf != s->tmpbuf) 699 free(s->buf); 700 } 701 702 static int add_char_local_string(struct local_string *s, int c) 703 { 704 if (s->idx >= s->alloc) { 705 size_t nalloc = s->alloc * 2; 706 if (s->buf == s->tmpbuf) { 707 s->buf = malloc(nalloc); 708 if (s->buf == NULL) 709 return -ENOMEM; 710 memcpy(s->buf, s->tmpbuf, s->alloc); 711 } else { 712 char *ptr = realloc(s->buf, nalloc); 713 if (ptr == NULL) 714 return -ENOMEM; 715 s->buf = ptr; 716 } 717 s->alloc = nalloc; 718 } 719 s->buf[s->idx++] = c; 720 return 0; 721 } 722 723 static char *copy_local_string(struct local_string *s) 724 { 725 char *dst = malloc(s->idx + 1); 726 if (dst) { 727 memcpy(dst, s->buf, s->idx); 728 dst[s->idx] = '\0'; 729 } 730 return dst; 731 } 732 733 static int get_freestring(char **string, int id, input_t *input) 734 { 735 struct local_string str; 736 int c; 737 738 init_local_string(&str); 739 while (1) { 740 c = get_char(input); 741 if (c < 0) { 742 if (c == LOCAL_UNEXPECTED_EOF) { 743 *string = copy_local_string(&str); 744 if (! *string) 745 c = -ENOMEM; 746 else 747 c = 0; 748 } 749 break; 750 } 751 switch (c) { 752 case '.': 753 if (!id) 754 break; 755 case ' ': 756 case '\f': 757 case '\t': 758 case '\n': 759 case '\r': 760 case '=': 761 case ',': 762 case ';': 763 case '{': 764 case '}': 765 case '[': 766 case ']': 767 case '\'': 768 case '"': 769 case '\\': 770 case '#': 771 *string = copy_local_string(&str); 772 if (! *string) 773 c = -ENOMEM; 774 else { 775 unget_char(c, input); 776 c = 0; 777 } 778 goto _out; 779 default: 780 break; 781 } 782 if (add_char_local_string(&str, c) < 0) { 783 c = -ENOMEM; 784 break; 785 } 786 } 787 _out: 788 free_local_string(&str); 789 return c; 790 } 791 792 static int get_delimstring(char **string, int delim, input_t *input) 793 { 794 struct local_string str; 795 int c; 796 797 init_local_string(&str); 798 while (1) { 799 c = get_char(input); 800 if (c < 0) 801 break; 802 if (c == '\\') { 803 c = get_quotedchar(input); 804 if (c < 0) 805 break; 806 if (c == '\n') 807 continue; 808 } else if (c == delim) { 809 *string = copy_local_string(&str); 810 if (! *string) 811 c = -ENOMEM; 812 else 813 c = 0; 814 break; 815 } 816 if (add_char_local_string(&str, c) < 0) { 817 c = -ENOMEM; 818 break; 819 } 820 } 821 free_local_string(&str); 822 return c; 823 } 824 825 /* Return 0 for free string, 1 for delimited string */ 826 static int get_string(char **string, int id, input_t *input) 827 { 828 int c = get_nonwhite(input), err; 829 if (c < 0) 830 return c; 831 switch (c) { 832 case '=': 833 case ',': 834 case ';': 835 case '.': 836 case '{': 837 case '}': 838 case '[': 839 case ']': 840 case '\\': 841 return LOCAL_UNEXPECTED_CHAR; 842 case '\'': 843 case '"': 844 err = get_delimstring(string, c, input); 845 if (err < 0) 846 return err; 847 return 1; 848 default: 849 unget_char(c, input); 850 err = get_freestring(string, id, input); 851 if (err < 0) 852 return err; 853 return 0; 854 } 855 } 856 857 static int _snd_config_make(snd_config_t **config, char **id, snd_config_type_t type) 858 { 859 snd_config_t *n; 860 assert(config); 861 n = calloc(1, sizeof(*n)); 862 if (n == NULL) { 863 if (*id) { 864 free(*id); 865 *id = NULL; 866 } 867 return -ENOMEM; 868 } 869 if (id) { 870 n->id = *id; 871 *id = NULL; 872 } 873 n->type = type; 874 if (type == SND_CONFIG_TYPE_COMPOUND) 875 INIT_LIST_HEAD(&n->u.compound.fields); 876 *config = n; 877 return 0; 878 } 879 880 881 static int _snd_config_make_add(snd_config_t **config, char **id, 882 snd_config_type_t type, snd_config_t *father) 883 { 884 snd_config_t *n; 885 int err; 886 assert(father->type == SND_CONFIG_TYPE_COMPOUND); 887 err = _snd_config_make(&n, id, type); 888 if (err < 0) 889 return err; 890 n->father = father; 891 list_add_tail(&n->list, &father->u.compound.fields); 892 *config = n; 893 return 0; 894 } 895 896 static int _snd_config_search(snd_config_t *config, 897 const char *id, int len, snd_config_t **result) 898 { 899 snd_config_iterator_t i, next; 900 snd_config_for_each(i, next, config) { 901 snd_config_t *n = snd_config_iterator_entry(i); 902 if (len < 0) { 903 if (strcmp(n->id, id) != 0) 904 continue; 905 } else if (strlen(n->id) != (size_t) len || 906 memcmp(n->id, id, (size_t) len) != 0) 907 continue; 908 if (result) 909 *result = n; 910 return 0; 911 } 912 return -ENOENT; 913 } 914 915 static int parse_value(snd_config_t **_n, snd_config_t *father, input_t *input, char **id, int skip) 916 { 917 snd_config_t *n = *_n; 918 char *s; 919 int err; 920 921 err = get_string(&s, 0, input); 922 if (err < 0) 923 return err; 924 if (skip) { 925 free(s); 926 return 0; 927 } 928 if (err == 0 && ((s[0] >= '0' && s[0] <= '9') || s[0] == '-')) { 929 long long i; 930 errno = 0; 931 err = safe_strtoll(s, &i); 932 if (err < 0) { 933 double r; 934 err = safe_strtod(s, &r); 935 if (err >= 0) { 936 free(s); 937 if (n) { 938 if (n->type != SND_CONFIG_TYPE_REAL) { 939 SNDERR("%s is not a real", *id); 940 return -EINVAL; 941 } 942 } else { 943 err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_REAL, father); 944 if (err < 0) 945 return err; 946 } 947 n->u.real = r; 948 *_n = n; 949 return 0; 950 } 951 } else { 952 free(s); 953 if (n) { 954 if (n->type != SND_CONFIG_TYPE_INTEGER && n->type != SND_CONFIG_TYPE_INTEGER64) { 955 SNDERR("%s is not an integer", *id); 956 return -EINVAL; 957 } 958 } else { 959 if (i <= INT_MAX) 960 err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER, father); 961 else 962 err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER64, father); 963 if (err < 0) 964 return err; 965 } 966 if (n->type == SND_CONFIG_TYPE_INTEGER) 967 n->u.integer = (long) i; 968 else 969 n->u.integer64 = i; 970 *_n = n; 971 return 0; 972 } 973 } 974 if (n) { 975 if (n->type != SND_CONFIG_TYPE_STRING) { 976 SNDERR("%s is not a string", *id); 977 free(s); 978 return -EINVAL; 979 } 980 } else { 981 err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_STRING, father); 982 if (err < 0) 983 return err; 984 } 985 free(n->u.string); 986 n->u.string = s; 987 *_n = n; 988 return 0; 989 } 990 991 static int parse_defs(snd_config_t *father, input_t *input, int skip, int override); 992 static int parse_array_defs(snd_config_t *farther, input_t *input, int skip, int override); 993 994 static int parse_array_def(snd_config_t *father, input_t *input, int idx, int skip, int override) 995 { 996 char *id = NULL; 997 int c; 998 int err; 999 snd_config_t *n = NULL; 1000 1001 if (!skip) { 1002 char static_id[12]; 1003 snprintf(static_id, sizeof(static_id), "%i", idx); 1004 id = strdup(static_id); 1005 if (id == NULL) 1006 return -ENOMEM; 1007 } 1008 c = get_nonwhite(input); 1009 if (c < 0) { 1010 err = c; 1011 goto __end; 1012 } 1013 switch (c) { 1014 case '{': 1015 case '[': 1016 { 1017 char endchr; 1018 if (!skip) { 1019 if (n) { 1020 if (n->type != SND_CONFIG_TYPE_COMPOUND) { 1021 SNDERR("%s is not a compound", id); 1022 err = -EINVAL; 1023 goto __end; 1024 } 1025 } else { 1026 err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father); 1027 if (err < 0) 1028 goto __end; 1029 } 1030 } 1031 if (c == '{') { 1032 err = parse_defs(n, input, skip, override); 1033 endchr = '}'; 1034 } else { 1035 err = parse_array_defs(n, input, skip, override); 1036 endchr = ']'; 1037 } 1038 c = get_nonwhite(input); 1039 if (c < 0) { 1040 err = c; 1041 goto __end; 1042 } 1043 if (c != endchr) { 1044 if (n) 1045 snd_config_delete(n); 1046 err = LOCAL_UNEXPECTED_CHAR; 1047 goto __end; 1048 } 1049 break; 1050 } 1051 default: 1052 unget_char(c, input); 1053 err = parse_value(&n, father, input, &id, skip); 1054 if (err < 0) 1055 goto __end; 1056 break; 1057 } 1058 err = 0; 1059 __end: 1060 free(id); 1061 return err; 1062 } 1063 1064 static int parse_array_defs(snd_config_t *father, input_t *input, int skip, int override) 1065 { 1066 int idx = 0; 1067 while (1) { 1068 int c = get_nonwhite(input), err; 1069 if (c < 0) 1070 return c; 1071 unget_char(c, input); 1072 if (c == ']') 1073 return 0; 1074 err = parse_array_def(father, input, idx++, skip, override); 1075 if (err < 0) 1076 return err; 1077 } 1078 return 0; 1079 } 1080 1081 static int parse_def(snd_config_t *father, input_t *input, int skip, int override) 1082 { 1083 char *id = NULL; 1084 int c; 1085 int err; 1086 snd_config_t *n; 1087 enum {MERGE_CREATE, MERGE, OVERRIDE, DONT_OVERRIDE} mode; 1088 while (1) { 1089 c = get_nonwhite(input); 1090 if (c < 0) 1091 return c; 1092 switch (c) { 1093 case '+': 1094 mode = MERGE_CREATE; 1095 break; 1096 case '-': 1097 mode = MERGE; 1098 break; 1099 case '?': 1100 mode = DONT_OVERRIDE; 1101 break; 1102 case '!': 1103 mode = OVERRIDE; 1104 break; 1105 default: 1106 mode = !override ? MERGE_CREATE : OVERRIDE; 1107 unget_char(c, input); 1108 } 1109 err = get_string(&id, 1, input); 1110 if (err < 0) 1111 return err; 1112 c = get_nonwhite(input); 1113 if (c != '.') 1114 break; 1115 if (skip) { 1116 free(id); 1117 continue; 1118 } 1119 if (_snd_config_search(father, id, -1, &n) == 0) { 1120 if (mode == DONT_OVERRIDE) { 1121 skip = 1; 1122 free(id); 1123 continue; 1124 } 1125 if (mode != OVERRIDE) { 1126 if (n->type != SND_CONFIG_TYPE_COMPOUND) { 1127 SNDERR("%s is not a compound", id); 1128 return -EINVAL; 1129 } 1130 n->u.compound.join = 1; 1131 father = n; 1132 free(id); 1133 continue; 1134 } 1135 snd_config_delete(n); 1136 } 1137 if (mode == MERGE) { 1138 SNDERR("%s does not exists", id); 1139 err = -ENOENT; 1140 goto __end; 1141 } 1142 err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father); 1143 if (err < 0) 1144 goto __end; 1145 n->u.compound.join = 1; 1146 father = n; 1147 } 1148 if (c == '=') { 1149 c = get_nonwhite(input); 1150 if (c < 0) 1151 return c; 1152 } 1153 if (!skip) { 1154 if (_snd_config_search(father, id, -1, &n) == 0) { 1155 if (mode == DONT_OVERRIDE) { 1156 skip = 1; 1157 n = NULL; 1158 } else if (mode == OVERRIDE) { 1159 snd_config_delete(n); 1160 n = NULL; 1161 } 1162 } else { 1163 n = NULL; 1164 if (mode == MERGE) { 1165 SNDERR("%s does not exists", id); 1166 err = -ENOENT; 1167 goto __end; 1168 } 1169 } 1170 } 1171 switch (c) { 1172 case '{': 1173 case '[': 1174 { 1175 char endchr; 1176 if (!skip) { 1177 if (n) { 1178 if (n->type != SND_CONFIG_TYPE_COMPOUND) { 1179 SNDERR("%s is not a compound", id); 1180 err = -EINVAL; 1181 goto __end; 1182 } 1183 } else { 1184 err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father); 1185 if (err < 0) 1186 goto __end; 1187 } 1188 } 1189 if (c == '{') { 1190 err = parse_defs(n, input, skip, override); 1191 endchr = '}'; 1192 } else { 1193 err = parse_array_defs(n, input, skip, override); 1194 endchr = ']'; 1195 } 1196 c = get_nonwhite(input); 1197 if (c != endchr) { 1198 if (n) 1199 snd_config_delete(n); 1200 err = LOCAL_UNEXPECTED_CHAR; 1201 goto __end; 1202 } 1203 break; 1204 } 1205 default: 1206 unget_char(c, input); 1207 err = parse_value(&n, father, input, &id, skip); 1208 if (err < 0) 1209 goto __end; 1210 break; 1211 } 1212 c = get_nonwhite(input); 1213 switch (c) { 1214 case ';': 1215 case ',': 1216 break; 1217 default: 1218 unget_char(c, input); 1219 } 1220 __end: 1221 free(id); 1222 return err; 1223 } 1224 1225 static int parse_defs(snd_config_t *father, input_t *input, int skip, int override) 1226 { 1227 int c, err; 1228 while (1) { 1229 c = get_nonwhite(input); 1230 if (c < 0) 1231 return c == LOCAL_UNEXPECTED_EOF ? 0 : c; 1232 unget_char(c, input); 1233 if (c == '}') 1234 return 0; 1235 err = parse_def(father, input, skip, override); 1236 if (err < 0) 1237 return err; 1238 } 1239 return 0; 1240 } 1241 1242 static void string_print(char *str, int id, snd_output_t *out) 1243 { 1244 unsigned char *p = (unsigned char *)str; 1245 if (!id) { 1246 switch (*p) { 1247 case 0: 1248 assert(0); 1249 break; 1250 case '0' ... '9': 1251 case '-': 1252 goto quoted; 1253 } 1254 } 1255 if (!*p) { 1256 snd_output_puts(out, "''"); 1257 return; 1258 } 1259 loop: 1260 switch (*p) { 1261 case 0: 1262 goto nonquoted; 1263 case 1 ... 31: 1264 case 127 ... 255: 1265 case ' ': 1266 case '=': 1267 case ';': 1268 case ',': 1269 case '.': 1270 case '{': 1271 case '}': 1272 case '\'': 1273 case '"': 1274 goto quoted; 1275 default: 1276 p++; 1277 goto loop; 1278 } 1279 nonquoted: 1280 snd_output_puts(out, str); 1281 return; 1282 quoted: 1283 snd_output_putc(out, '\''); 1284 p = (unsigned char *)str; 1285 while (*p) { 1286 int c; 1287 c = *p; 1288 switch (c) { 1289 case '\n': 1290 snd_output_putc(out, '\\'); 1291 snd_output_putc(out, 'n'); 1292 break; 1293 case '\t': 1294 snd_output_putc(out, '\\'); 1295 snd_output_putc(out, 't'); 1296 break; 1297 case '\v': 1298 snd_output_putc(out, '\\'); 1299 snd_output_putc(out, 'v'); 1300 break; 1301 case '\b': 1302 snd_output_putc(out, '\\'); 1303 snd_output_putc(out, 'b'); 1304 break; 1305 case '\r': 1306 snd_output_putc(out, '\\'); 1307 snd_output_putc(out, 'r'); 1308 break; 1309 case '\f': 1310 snd_output_putc(out, '\\'); 1311 snd_output_putc(out, 'f'); 1312 break; 1313 case '\'': 1314 snd_output_putc(out, '\\'); 1315 snd_output_putc(out, c); 1316 break; 1317 case 32 ... '\'' - 1: 1318 case '\'' + 1 ... 126: 1319 snd_output_putc(out, c); 1320 break; 1321 default: 1322 snd_output_printf(out, "\\%04o", c); 1323 break; 1324 } 1325 p++; 1326 } 1327 snd_output_putc(out, '\''); 1328 } 1329 1330 static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsigned int level, unsigned int joins); 1331 1332 static int _snd_config_save_leaf(snd_config_t *n, snd_output_t *out, 1333 unsigned int level) 1334 { 1335 int err; 1336 unsigned int k; 1337 switch (n->type) { 1338 case SND_CONFIG_TYPE_INTEGER: 1339 snd_output_printf(out, "%ld", n->u.integer); 1340 break; 1341 case SND_CONFIG_TYPE_INTEGER64: 1342 snd_output_printf(out, "%Ld", n->u.integer64); 1343 break; 1344 case SND_CONFIG_TYPE_REAL: 1345 snd_output_printf(out, "%-16g", n->u.real); 1346 break; 1347 case SND_CONFIG_TYPE_STRING: 1348 string_print(n->u.string, 0, out); 1349 break; 1350 case SND_CONFIG_TYPE_POINTER: 1351 SNDERR("cannot save runtime pointer type"); 1352 return -EINVAL; 1353 case SND_CONFIG_TYPE_COMPOUND: 1354 snd_output_putc(out, '{'); 1355 snd_output_putc(out, '\n'); 1356 err = _snd_config_save_leaves(n, out, level + 1, 0); 1357 if (err < 0) 1358 return err; 1359 for (k = 0; k < level; ++k) { 1360 snd_output_putc(out, '\t'); 1361 } 1362 snd_output_putc(out, '}'); 1363 break; 1364 } 1365 return 0; 1366 } 1367 1368 static void id_print(snd_config_t *n, snd_output_t *out, unsigned int joins) 1369 { 1370 if (joins > 0) { 1371 assert(n->father); 1372 id_print(n->father, out, joins - 1); 1373 snd_output_putc(out, '.'); 1374 } 1375 string_print(n->id, 1, out); 1376 } 1377 1378 static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsigned int level, unsigned int joins) 1379 { 1380 unsigned int k; 1381 int err; 1382 snd_config_iterator_t i, next; 1383 assert(config && out); 1384 snd_config_for_each(i, next, config) { 1385 snd_config_t *n = snd_config_iterator_entry(i); 1386 if (n->type == SND_CONFIG_TYPE_COMPOUND && 1387 n->u.compound.join) { 1388 err = _snd_config_save_leaves(n, out, level, joins + 1); 1389 if (err < 0) 1390 return err; 1391 continue; 1392 } 1393 for (k = 0; k < level; ++k) { 1394 snd_output_putc(out, '\t'); 1395 } 1396 id_print(n, out, joins); 1397 #if 0 1398 snd_output_putc(out, ' '); 1399 snd_output_putc(out, '='); 1400 #endif 1401 snd_output_putc(out, ' '); 1402 err = _snd_config_save_leaf(n, out, level); 1403 if (err < 0) 1404 return err; 1405 #if 0 1406 snd_output_putc(out, ';'); 1407 #endif 1408 snd_output_putc(out, '\n'); 1409 } 1410 return 0; 1411 } 1412 #endif 1413 1414 1415 /** 1416 * \brief Substitutes one configuration node to another. 1417 * \param dst Handle to the destination node. 1418 * \param src Handle to the source node. Must not be the same as \p dst. 1419 * \return Zero if successful, otherwise a negative error code. 1420 * 1421 * If both nodes are compounds, the source compound node members are 1422 * appended to the destination compound node. 1423 * 1424 * If the destination node is a compound and the source node is 1425 * an ordinary type, the compound members are deleted (including 1426 * their contents). 1427 * 1428 * A successful call to this function invalidates the source node. 1429 */ 1430 int snd_config_substitute(snd_config_t *dst, snd_config_t *src) 1431 { 1432 assert(dst && src); 1433 if (dst->type == SND_CONFIG_TYPE_COMPOUND && 1434 src->type == SND_CONFIG_TYPE_COMPOUND) { /* append */ 1435 snd_config_iterator_t i, next; 1436 snd_config_for_each(i, next, src) { 1437 snd_config_t *n = snd_config_iterator_entry(i); 1438 n->father = dst; 1439 } 1440 src->u.compound.fields.next->prev = &dst->u.compound.fields; 1441 src->u.compound.fields.prev->next = &dst->u.compound.fields; 1442 } else if (dst->type == SND_CONFIG_TYPE_COMPOUND) { 1443 int err; 1444 err = snd_config_delete_compound_members(dst); 1445 if (err < 0) 1446 return err; 1447 } 1448 free(dst->id); 1449 dst->id = src->id; 1450 dst->type = src->type; 1451 dst->u = src->u; 1452 free(src); 1453 return 0; 1454 } 1455 1456 /** 1457 * \brief Converts an ASCII string to a configuration node type. 1458 * \param ascii A string containing a configuration node type. 1459 * \param type The function puts the node type at the address specified 1460 * by \p type. 1461 * \return Zero if successgul, otherwise a negative error code. 1462 */ 1463 int snd_config_get_type_ascii(const char *ascii, snd_config_type_t *type) 1464 { 1465 assert(ascii && type); 1466 if (!strcmp(ascii, "integer")) { 1467 *type = SND_CONFIG_TYPE_INTEGER; 1468 return 0; 1469 } 1470 if (!strcmp(ascii, "integer64")) { 1471 *type = SND_CONFIG_TYPE_INTEGER64; 1472 return 0; 1473 } 1474 if (!strcmp(ascii, "real")) { 1475 *type = SND_CONFIG_TYPE_REAL; 1476 return 0; 1477 } 1478 if (!strcmp(ascii, "string")) { 1479 *type = SND_CONFIG_TYPE_STRING; 1480 return 0; 1481 } 1482 if (!strcmp(ascii, "compound")) { 1483 *type = SND_CONFIG_TYPE_COMPOUND; 1484 return 0; 1485 } 1486 return -EINVAL; 1487 } 1488 1489 /** 1490 * \brief Returns the type of a configuration node. 1491 * \param config Handle to the configuration node. 1492 * \return The node's type. 1493 */ 1494 snd_config_type_t snd_config_get_type(const snd_config_t *config) 1495 { 1496 return config->type; 1497 } 1498 1499 /** 1500 * \brief Returns the id of a configuration node. 1501 * \param config Handle to the configuration node. 1502 * \param id The function puts the pointer to the id string at the address 1503 * specified by \p id. 1504 * \return Zero if successful, otherwise a negative error code. 1505 * 1506 * The returned string is owned by the configuration node; the application 1507 * must not modify or delete it. 1508 */ 1509 int snd_config_get_id(const snd_config_t *config, const char **id) 1510 { 1511 assert(config && id); 1512 *id = config->id; 1513 return 0; 1514 } 1515 1516 /** 1517 * \brief Sets the id of a configuration node. 1518 * \param config Handle to the configuration node. 1519 * \param id The new node id. 1520 * \return Zero if successful, otherwise a negative error code. 1521 */ 1522 int snd_config_set_id(snd_config_t *config, const char *id) 1523 { 1524 char *new_id; 1525 assert(config && id); 1526 new_id = strdup(id); 1527 if (!new_id) 1528 return -ENOMEM; 1529 free(config->id); 1530 config->id = new_id; 1531 return 0; 1532 } 1533 1534 /** 1535 * \brief Creates a top level configuration node. 1536 * \param config The function puts the handle to the new node at the address 1537 * specified by \p config. 1538 * \return Zero if successful, otherwise a negative error code. 1539 * 1540 * The returned node is a compound node. 1541 */ 1542 int snd_config_top(snd_config_t **config) 1543 { 1544 assert(config); 1545 return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND); 1546 } 1547 1548 static int snd_config_load1(snd_config_t *config, snd_input_t *in, int override) 1549 { 1550 int err; 1551 input_t input; 1552 struct filedesc *fd, *fd_next; 1553 assert(config && in); 1554 fd = malloc(sizeof(*fd)); 1555 if (!fd) 1556 return -ENOMEM; 1557 fd->name = NULL; 1558 fd->in = in; 1559 fd->line = 1; 1560 fd->column = 0; 1561 fd->next = NULL; 1562 input.current = fd; 1563 input.unget = 0; 1564 err = parse_defs(config, &input, 0, override); 1565 fd = input.current; 1566 if (err < 0) { 1567 const char *str; 1568 switch (err) { 1569 case LOCAL_UNTERMINATED_STRING: 1570 str = "Unterminated string"; 1571 err = -EINVAL; 1572 break; 1573 case LOCAL_UNTERMINATED_QUOTE: 1574 str = "Unterminated quote"; 1575 err = -EINVAL; 1576 break; 1577 case LOCAL_UNEXPECTED_CHAR: 1578 str = "Unexpected char"; 1579 err = -EINVAL; 1580 break; 1581 case LOCAL_UNEXPECTED_EOF: 1582 str = "Unexpected end of file"; 1583 err = -EINVAL; 1584 break; 1585 default: 1586 str = strerror(-err); 1587 break; 1588 } 1589 SNDERR("%s:%d:%d:%s", fd->name ? fd->name : "_toplevel_", fd->line, fd->column, str); 1590 goto _end; 1591 } 1592 if (get_char(&input) != LOCAL_UNEXPECTED_EOF) { 1593 SNDERR("%s:%d:%d:Unexpected }", fd->name ? fd->name : "", fd->line, fd->column); 1594 err = -EINVAL; 1595 goto _end; 1596 } 1597 _end: 1598 while (fd->next) { 1599 fd_next = fd->next; 1600 snd_input_close(fd->in); 1601 free(fd->name); 1602 free(fd); 1603 fd = fd_next; 1604 } 1605 free(fd); 1606 return err; 1607 } 1608 1609 /** 1610 * \brief Loads a configuration tree. 1611 * \param config Handle to a top level configuration node. 1612 * \param in Input handle to read the configuration from. 1613 * \return Zero if successful, otherwise a negative error code. 1614 */ 1615 int snd_config_load(snd_config_t *config, snd_input_t *in) 1616 { 1617 return snd_config_load1(config, in, 0); 1618 } 1619 1620 /** 1621 * \brief Loads a configuration tree and overrides existing configuration nodes. 1622 * \param config Handle to a top level configuration node. 1623 * \param in Input handle to read the configuration from. 1624 * \return Zero if successful, otherwise a negative error code. 1625 */ 1626 int snd_config_load_override(snd_config_t *config, snd_input_t *in) 1627 { 1628 return snd_config_load1(config, in, 1); 1629 } 1630 1631 /** 1632 * \brief Adds a child to a compound configuration node. 1633 * \param father Handle to the compound configuration node. 1634 * \param leaf Handle to the configuration node to be added to \p father. 1635 * \return Zero if successful, otherwise a negative error code. 1636 */ 1637 int snd_config_add(snd_config_t *father, snd_config_t *leaf) 1638 { 1639 snd_config_iterator_t i, next; 1640 assert(father && leaf); 1641 snd_config_for_each(i, next, father) { 1642 snd_config_t *n = snd_config_iterator_entry(i); 1643 if (strcmp(leaf->id, n->id) == 0) 1644 return -EEXIST; 1645 } 1646 leaf->father = father; 1647 list_add_tail(&leaf->list, &father->u.compound.fields); 1648 return 0; 1649 } 1650 1651 /** 1652 * \brief Removes a configuration node from its tree. 1653 * \param config Handle to the configuration node to be removed. 1654 * \return Zero if successful, otherwise a negative error code. 1655 * 1656 * This functions does \e not delete the removed node. 1657 */ 1658 int snd_config_remove(snd_config_t *config) 1659 { 1660 assert(config); 1661 if (config->father) 1662 list_del(&config->list); 1663 config->father = NULL; 1664 return 0; 1665 } 1666 1667 /** 1668 * \brief Deletes a configuration node (freeing all its related resources). 1669 * \param config Handle to the configuration node to be deleted. 1670 * \return Zero if successful, otherwise a negative error code. 1671 * 1672 * If the node is a child node, it is removed from the tree before being 1673 * deleted. If the node is a compound node, all children are deleted 1674 * recursively. 1675 */ 1676 int snd_config_delete(snd_config_t *config) 1677 { 1678 assert(config); 1679 switch (config->type) { 1680 case SND_CONFIG_TYPE_COMPOUND: 1681 { 1682 int err; 1683 struct list_head *i; 1684 i = config->u.compound.fields.next; 1685 while (i != &config->u.compound.fields) { 1686 struct list_head *nexti = i->next; 1687 snd_config_t *leaf = snd_config_iterator_entry(i); 1688 err = snd_config_delete(leaf); 1689 if (err < 0) 1690 return err; 1691 i = nexti; 1692 } 1693 break; 1694 } 1695 case SND_CONFIG_TYPE_STRING: 1696 free(config->u.string); 1697 break; 1698 default: 1699 break; 1700 } 1701 if (config->father) 1702 list_del(&config->list); 1703 free(config->id); 1704 free(config); 1705 return 0; 1706 } 1707 1708 /** 1709 * \brief Deletes the children of a compound configuration node (freeing all its related resources) 1710 * \param config Handle to the compound configuration node. 1711 * \return Zero if successful, otherwise a negative error code. 1712 * 1713 * Any compound nodes among the children of \p config are deleted recursively. 1714 */ 1715 int snd_config_delete_compound_members(const snd_config_t *config) 1716 { 1717 int err; 1718 struct list_head *i; 1719 1720 assert(config); 1721 if (config->type != SND_CONFIG_TYPE_COMPOUND) 1722 return -EINVAL; 1723 i = config->u.compound.fields.next; 1724 while (i != &config->u.compound.fields) { 1725 struct list_head *nexti = i->next; 1726 snd_config_t *leaf = snd_config_iterator_entry(i); 1727 err = snd_config_delete(leaf); 1728 if (err < 0) 1729 return err; 1730 i = nexti; 1731 } 1732 return 0; 1733 } 1734 1735 /** 1736 * \brief Creates a configuration node. 1737 * \param config The function puts the handle to the new node at the address 1738 * specified by \p config. 1739 * \param id The id of the new node. 1740 * \param type The type of the new node. 1741 * \return Zero if successful, otherwise a negative error code. 1742 */ 1743 int snd_config_make(snd_config_t **config, const char *id, 1744 snd_config_type_t type) 1745 { 1746 char *id1; 1747 assert(config); 1748 if (id) { 1749 id1 = strdup(id); 1750 if (!id1) 1751 return -ENOMEM; 1752 } else 1753 id1 = NULL; 1754 return _snd_config_make(config, &id1, type); 1755 } 1756 1757 /** 1758 * \brief Creates an integer configuration node. 1759 * \param config The function puts the handle to the new node at the address 1760 * specified by \p config. 1761 * \param id The id of the new node. 1762 * \return Zero if successful, otherwise a negative error code. 1763 * 1764 * The value of the new node is 0. 1765 */ 1766 int snd_config_make_integer(snd_config_t **config, const char *id) 1767 { 1768 return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER); 1769 } 1770 1771 /** 1772 * \brief Creates an integer64 configuration node. 1773 * \param config The function puts the handle to the new node at the address 1774 * specified by \p config. 1775 * \param id The id of the new node. 1776 * \return Zero if successful, otherwise a negative error code. 1777 * 1778 * The value of the new node is 0. 1779 */ 1780 int snd_config_make_integer64(snd_config_t **config, const char *id) 1781 { 1782 return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64); 1783 } 1784 1785 /** 1786 * \brief Creates a real configuration node. 1787 * \param config The function puts the handle to the new node at the address 1788 * specified by \p config. 1789 * \param id The id of the new node. 1790 * \return Zero if successful, otherwise a negative error code. 1791 * 1792 * The value of the new node is 0.0. 1793 */ 1794 int snd_config_make_real(snd_config_t **config, const char *id) 1795 { 1796 return snd_config_make(config, id, SND_CONFIG_TYPE_REAL); 1797 } 1798 1799 /** 1800 * \brief Creates a string configuration node. 1801 * \param config The function puts the handle to the new node at the address 1802 * specified by \p config. 1803 * \param id The id of the new node. 1804 * \return Zero if successful, otherwise a negative error code. 1805 * 1806 * The value of the new node is \c NULL. 1807 */ 1808 int snd_config_make_string(snd_config_t **config, const char *id) 1809 { 1810 return snd_config_make(config, id, SND_CONFIG_TYPE_STRING); 1811 } 1812 1813 /** 1814 * \brief Creates a pointer configuration node. 1815 * \param config The function puts the handle to the new node at the address 1816 * specified by \p config. 1817 * \param id The id of the new node. 1818 * \return Zero if successful, otherwise a negative error code. 1819 * 1820 * The value of the new node is \c NULL. 1821 */ 1822 int snd_config_make_pointer(snd_config_t **config, const char *id) 1823 { 1824 return snd_config_make(config, id, SND_CONFIG_TYPE_POINTER); 1825 } 1826 1827 /** 1828 * \brief Creates an empty compound configuration node. 1829 * \param config The function puts the handle to the new node at the address 1830 * specified by \p config. 1831 * \param id The id of the new node. 1832 * \param join Join flag. 1833 * This is checked in #snd_config_save to change look. (Huh?) 1834 * \return Zero if successful, otherwise a negative error code. 1835 */ 1836 int snd_config_make_compound(snd_config_t **config, const char *id, 1837 int join) 1838 { 1839 int err; 1840 err = snd_config_make(config, id, SND_CONFIG_TYPE_COMPOUND); 1841 if (err < 0) 1842 return err; 1843 (*config)->u.compound.join = join; 1844 return 0; 1845 } 1846 1847 /** 1848 * \brief Creates an integer configuration node with the given initial value. 1849 * \param config The function puts the handle to the new node at the address 1850 * specified by \p config. 1851 * \param id The id of the new node. 1852 * \param value The initial value of the new node. 1853 * \return Zero if successful, otherwise a negative error code. 1854 */ 1855 int snd_config_imake_integer(snd_config_t **config, const char *id, const long value) 1856 { 1857 int err; 1858 1859 err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER); 1860 if (err < 0) 1861 return err; 1862 (*config)->u.integer = value; 1863 return 0; 1864 } 1865 1866 /** 1867 * \brief Creates an integer configuration node with the given initial value. 1868 * \param config The function puts the handle to the new node at the address 1869 * specified by \p config. 1870 * \param id The id of the new node. 1871 * \param value The initial value of the new node. 1872 * \return Zero if successful, otherwise a negative error code. 1873 */ 1874 int snd_config_imake_integer64(snd_config_t **config, const char *id, const long long value) 1875 { 1876 int err; 1877 1878 err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64); 1879 if (err < 0) 1880 return err; 1881 (*config)->u.integer64 = value; 1882 return 0; 1883 } 1884 1885 /** 1886 * \brief Creates a real configuration node with the given initial value. 1887 * \param config The function puts the handle to the new node at the address 1888 * specified by \p config. 1889 * \param id The id of the new node. 1890 * \param value The initial value of the new node. 1891 * \return Zero if successful, otherwise a negative error code. 1892 */ 1893 int snd_config_imake_real(snd_config_t **config, const char *id, const double value) 1894 { 1895 int err; 1896 1897 err = snd_config_make(config, id, SND_CONFIG_TYPE_REAL); 1898 if (err < 0) 1899 return err; 1900 (*config)->u.real = value; 1901 return 0; 1902 } 1903 1904 /** 1905 * \brief Creates a string configuration node with the given initial value. 1906 * \param config The function puts the handle to the new node at the address 1907 * specified by \p config. 1908 * \param id The id of the new node. 1909 * \param value The initial value of the new node. May be \c NULL. 1910 * \return Zero if successful, otherwise a negative error code. 1911 * 1912 * This function creates the new node with its own copy of the passed string. 1913 */ 1914 int snd_config_imake_string(snd_config_t **config, const char *id, const char *value) 1915 { 1916 int err; 1917 snd_config_t *tmp; 1918 1919 err = snd_config_make(&tmp, id, SND_CONFIG_TYPE_STRING); 1920 if (err < 0) 1921 return err; 1922 if (value) { 1923 tmp->u.string = strdup(value); 1924 if (!tmp->u.string) { 1925 snd_config_delete(tmp); 1926 return -ENOMEM; 1927 } 1928 } else { 1929 tmp->u.string = NULL; 1930 } 1931 *config = tmp; 1932 return 0; 1933 } 1934 1935 /** 1936 * \brief Creates a pointer configuration node with the given initial value. 1937 * \param config The function puts the handle to the new node at the address 1938 * specified by \p config. 1939 * \param id The id of the new node. 1940 * \param value The initial value of the new node. May be \c NULL. 1941 * \return Zero if successful, otherwise a negative error code. 1942 */ 1943 int snd_config_imake_pointer(snd_config_t **config, const char *id, const void *value) 1944 { 1945 int err; 1946 1947 err = snd_config_make(config, id, SND_CONFIG_TYPE_POINTER); 1948 if (err < 0) 1949 return err; 1950 (*config)->u.ptr = value; 1951 return 0; 1952 } 1953 1954 /** 1955 * \brief Changes the value of an integer configuration node. 1956 * \param config Handle to the configuration node. 1957 * \param value The new value for the node. 1958 * \return Zero if successful, otherwise a negative error code. 1959 */ 1960 int snd_config_set_integer(snd_config_t *config, long value) 1961 { 1962 assert(config); 1963 if (config->type != SND_CONFIG_TYPE_INTEGER) 1964 return -EINVAL; 1965 config->u.integer = value; 1966 return 0; 1967 } 1968 1969 /** 1970 * \brief Changes the value of an integer64 configuration node. 1971 * \param config Handle to the configuration node. 1972 * \param value The new value for the node. 1973 * \return Zero if successful, otherwise a negative error code. 1974 */ 1975 int snd_config_set_integer64(snd_config_t *config, long long value) 1976 { 1977 assert(config); 1978 if (config->type != SND_CONFIG_TYPE_INTEGER64) 1979 return -EINVAL; 1980 config->u.integer64 = value; 1981 return 0; 1982 } 1983 1984 /** 1985 * \brief Changes the value of a real configuration node. 1986 * \param config Handle to the configuration node. 1987 * \param value The new value for the node. 1988 * \return Zero if successful, otherwise a negative error code. 1989 */ 1990 int snd_config_set_real(snd_config_t *config, double value) 1991 { 1992 assert(config); 1993 if (config->type != SND_CONFIG_TYPE_REAL) 1994 return -EINVAL; 1995 config->u.real = value; 1996 return 0; 1997 } 1998 1999 /** 2000 * \brief Changes the value of a string configuration node. 2001 * \param config Handle to the configuration node. 2002 * \param value The new value for the node. May be \c NULL. 2003 * \return Zero if successful, otherwise a negative error code. 2004 * 2005 * This function deletes the old string in the node and stores a copy of 2006 * the passed string in the node. 2007 */ 2008 int snd_config_set_string(snd_config_t *config, const char *value) 2009 { 2010 char *new_string; 2011 assert(config); 2012 if (config->type != SND_CONFIG_TYPE_STRING) 2013 return -EINVAL; 2014 if (value) { 2015 new_string = strdup(value); 2016 if (!new_string) 2017 return -ENOMEM; 2018 } else { 2019 new_string = NULL; 2020 } 2021 free(config->u.string); 2022 config->u.string = new_string; 2023 return 0; 2024 } 2025 2026 /** 2027 * \brief Changes the value of a pointer configuration node. 2028 * \param config Handle to the configuration node. 2029 * \param value The new value for the node. May be \c NULL. 2030 * \return Zero if successful, otherwise a negative error code. 2031 * 2032 * This function does not free the old pointer in the node. 2033 */ 2034 int snd_config_set_pointer(snd_config_t *config, const void *value) 2035 { 2036 assert(config); 2037 if (config->type != SND_CONFIG_TYPE_POINTER) 2038 return -EINVAL; 2039 config->u.ptr = value; 2040 return 0; 2041 } 2042 2043 /** 2044 * \brief Changes the value of a configuration node. 2045 * \param config Handle to the configuration node. 2046 * \param ascii The new value for the node as an ASCII string. \p ascii must 2047 * not be \c NULL, not even for a string node. 2048 * \return Zero if successful, otherwise a negative error code. 2049 * 2050 * The node must have a simple type, and the new value must have the same type. 2051 */ 2052 int snd_config_set_ascii(snd_config_t *config, const char *ascii) 2053 { 2054 assert(config && ascii); 2055 switch (config->type) { 2056 case SND_CONFIG_TYPE_INTEGER: 2057 { 2058 long i; 2059 int err = safe_strtol(ascii, &i); 2060 if (err < 0) 2061 return err; 2062 config->u.integer = i; 2063 } 2064 break; 2065 case SND_CONFIG_TYPE_INTEGER64: 2066 { 2067 long long i; 2068 int err = safe_strtoll(ascii, &i); 2069 if (err < 0) 2070 return err; 2071 config->u.integer64 = i; 2072 } 2073 break; 2074 case SND_CONFIG_TYPE_REAL: 2075 { 2076 double d; 2077 int err = safe_strtod(ascii, &d); 2078 if (err < 0) 2079 return err; 2080 config->u.real = d; 2081 break; 2082 } 2083 case SND_CONFIG_TYPE_STRING: 2084 { 2085 char *ptr = strdup(ascii); 2086 if (ptr == NULL) 2087 return -ENOMEM; 2088 free(config->u.string); 2089 config->u.string = ptr; 2090 } 2091 break; 2092 default: 2093 return -EINVAL; 2094 } 2095 return 0; 2096 } 2097 2098 /** 2099 * \brief Returns the value of an integer configuration node. 2100 * \param config Handle to the configuration node. 2101 * \param ptr The function puts the node's value at the address specified 2102 * by \p ptr. 2103 * \return Zero if successful, otherwise a negative error code. 2104 */ 2105 int snd_config_get_integer(const snd_config_t *config, long *ptr) 2106 { 2107 assert(config && ptr); 2108 if (config->type != SND_CONFIG_TYPE_INTEGER) 2109 return -EINVAL; 2110 *ptr = config->u.integer; 2111 return 0; 2112 } 2113 2114 /** 2115 * \brief Returns the value of an integer64 configuration node. 2116 * \param config Handle to the configuration node. 2117 * \param ptr The function puts the node's value at the address specified 2118 * by \p ptr. 2119 * \return Zero if successful, otherwise a negative error code. 2120 */ 2121 int snd_config_get_integer64(const snd_config_t *config, long long *ptr) 2122 { 2123 assert(config && ptr); 2124 if (config->type != SND_CONFIG_TYPE_INTEGER64) 2125 return -EINVAL; 2126 *ptr = config->u.integer64; 2127 return 0; 2128 } 2129 2130 /** 2131 * \brief Returns the value of a real configuration node. 2132 * \param config Handle to the configuration node. 2133 * \param ptr The function puts the node's value at the address specified 2134 * by \p ptr. 2135 * \return Zero if successful, otherwise a negative error code. 2136 */ 2137 int snd_config_get_real(const snd_config_t *config, double *ptr) 2138 { 2139 assert(config && ptr); 2140 if (config->type != SND_CONFIG_TYPE_REAL) 2141 return -EINVAL; 2142 *ptr = config->u.real; 2143 return 0; 2144 } 2145 2146 /** 2147 * \brief Returns the value of a real or integer configuration node. 2148 * \param config Handle to the configuration node. 2149 * \param ptr The function puts the node's value at the address specified 2150 * by \p ptr. 2151 * \return Zero if successful, otherwise a negative error code. 2152 * 2153 * If the node's type is integer or integer64, the value is converted 2154 * to the \c double type on the fly. 2155 */ 2156 int snd_config_get_ireal(const snd_config_t *config, double *ptr) 2157 { 2158 assert(config && ptr); 2159 if (config->type == SND_CONFIG_TYPE_REAL) 2160 *ptr = config->u.real; 2161 else if (config->type == SND_CONFIG_TYPE_INTEGER) 2162 *ptr = config->u.integer; 2163 else if (config->type == SND_CONFIG_TYPE_INTEGER64) 2164 *ptr = config->u.integer64; 2165 else 2166 return -EINVAL; 2167 return 0; 2168 } 2169 2170 /** 2171 * \brief Returns the value of a string configuration node. 2172 * \param config Handle to the configuration node. 2173 * \param ptr The function puts the node's value at the address specified 2174 * by \p ptr. 2175 * \return Zero if successful, otherwise a negative error code. 2176 * 2177 * The returned string is owned by the configuration node; the application 2178 * must not modify or delete it. 2179 */ 2180 int snd_config_get_string(const snd_config_t *config, const char **ptr) 2181 { 2182 assert(config && ptr); 2183 if (config->type != SND_CONFIG_TYPE_STRING) 2184 return -EINVAL; 2185 *ptr = config->u.string; 2186 return 0; 2187 } 2188 2189 /** 2190 * \brief Returns the value of a pointer configuration node. 2191 * \param config Handle to the configuration node. 2192 * \param ptr The function puts the node's value at the address specified 2193 * by \p ptr. 2194 * \return Zero if successful, otherwise a negative error code. 2195 */ 2196 int snd_config_get_pointer(const snd_config_t *config, const void **ptr) 2197 { 2198 assert(config && ptr); 2199 if (config->type != SND_CONFIG_TYPE_POINTER) 2200 return -EINVAL; 2201 *ptr = config->u.ptr; 2202 return 0; 2203 } 2204 2205 /** 2206 * \brief Returns the value of a configuration node as a string. 2207 * \param config Handle to the configuration node. 2208 * \param ascii The function puts the pointer to the returned string at the 2209 * address specified by \p ascii. 2210 * \return Zero if successful, otherwise a negative error code. 2211 * 2212 * This function dynamically allocates the returned string. The application 2213 * is responsible for deleting it with \c free() when it is no longer used. 2214 */ 2215 int snd_config_get_ascii(const snd_config_t *config, char **ascii) 2216 { 2217 assert(config && ascii); 2218 switch (config->type) { 2219 case SND_CONFIG_TYPE_INTEGER: 2220 { 2221 char res[12]; 2222 int err; 2223 err = snprintf(res, sizeof(res), "%li", config->u.integer); 2224 if (err < 0 || err == sizeof(res)) { 2225 assert(0); 2226 return -ENOMEM; 2227 } 2228 *ascii = strdup(res); 2229 } 2230 break; 2231 case SND_CONFIG_TYPE_INTEGER64: 2232 { 2233 char res[32]; 2234 int err; 2235 err = snprintf(res, sizeof(res), "%Li", config->u.integer64); 2236 if (err < 0 || err == sizeof(res)) { 2237 assert(0); 2238 return -ENOMEM; 2239 } 2240 *ascii = strdup(res); 2241 } 2242 break; 2243 case SND_CONFIG_TYPE_REAL: 2244 { 2245 char res[32]; 2246 int err; 2247 err = snprintf(res, sizeof(res), "%-16g", config->u.real); 2248 if (err < 0 || err == sizeof(res)) { 2249 assert(0); 2250 return -ENOMEM; 2251 } 2252 if (res[0]) { /* trim the string */ 2253 char *ptr; 2254 ptr = res + strlen(res) - 1; 2255 while (ptr != res && *ptr == ' ') 2256 ptr--; 2257 if (*ptr != ' ') 2258 ptr++; 2259 *ptr = '\0'; 2260 } 2261 *ascii = strdup(res); 2262 } 2263 break; 2264 case SND_CONFIG_TYPE_STRING: 2265 if (config->u.string) 2266 *ascii = strdup(config->u.string); 2267 else { 2268 *ascii = NULL; 2269 return 0; 2270 } 2271 break; 2272 default: 2273 return -EINVAL; 2274 } 2275 if (*ascii == NULL) 2276 return -ENOMEM; 2277 return 0; 2278 } 2279 2280 /** 2281 * \brief Compares the id of a configuration node to a given string. 2282 * \param config Handle to the configuration node. 2283 * \param id ASCII id. 2284 * \return The same value as the result of the \c strcmp function. 2285 */ 2286 int snd_config_test_id(const snd_config_t *config, const char *id) 2287 { 2288 assert(config && id); 2289 return strcmp(config->id, id); 2290 } 2291 2292 /** 2293 * \brief Dumps the contents of a configuration node or tree. 2294 * \param config Handle to the (root) configuration node. 2295 * \param out Output handle. 2296 * \return Zero if successful, otherwise a negative error code. 2297 */ 2298 int snd_config_save(snd_config_t *config, snd_output_t *out) 2299 { 2300 assert(config && out); 2301 if (config->type == SND_CONFIG_TYPE_COMPOUND) 2302 return _snd_config_save_leaves(config, out, 0, 0); 2303 else 2304 return _snd_config_save_leaf(config, out, 0); 2305 } 2306 2307 /* 2308 * *** search macros *** 2309 */ 2310 2311 #ifndef DOC_HIDDEN 2312 2313 #define SND_CONFIG_SEARCH(config, key, result, extra_code) \ 2314 { \ 2315 snd_config_t *n; \ 2316 int err; \ 2317 const char *p; \ 2318 assert(config && key); \ 2319 while (1) { \ 2320 if (config->type != SND_CONFIG_TYPE_COMPOUND) \ 2321 return -ENOENT; \ 2322 { extra_code ; } \ 2323 p = strchr(key, '.'); \ 2324 if (p) { \ 2325 err = _snd_config_search(config, key, p - key, &n); \ 2326 if (err < 0) \ 2327 return err; \ 2328 config = n; \ 2329 key = p + 1; \ 2330 } else \ 2331 return _snd_config_search(config, key, -1, result); \ 2332 } \ 2333 } 2334 2335 #define SND_CONFIG_SEARCHA(root, config, key, result, fcn, extra_code) \ 2336 { \ 2337 snd_config_t *n; \ 2338 int err; \ 2339 const char *p; \ 2340 assert(config && key); \ 2341 while (1) { \ 2342 if (config->type != SND_CONFIG_TYPE_COMPOUND) { \ 2343 if (snd_config_get_string(config, &p) < 0) \ 2344 return -ENOENT; \ 2345 err = fcn(root, root, p, &config); \ 2346 if (err < 0) \ 2347 return err; \ 2348 } \ 2349 { extra_code ; } \ 2350 p = strchr(key, '.'); \ 2351 if (p) { \ 2352 err = _snd_config_search(config, key, p - key, &n); \ 2353 if (err < 0) \ 2354 return err; \ 2355 config = n; \ 2356 key = p + 1; \ 2357 } else \ 2358 return _snd_config_search(config, key, -1, result); \ 2359 } \ 2360 } 2361 2362 #define SND_CONFIG_SEARCHV(config, result, fcn) \ 2363 { \ 2364 snd_config_t *n; \ 2365 va_list arg; \ 2366 assert(config); \ 2367 va_start(arg, result); \ 2368 while (1) { \ 2369 const char *k = va_arg(arg, const char *); \ 2370 int err; \ 2371 if (!k) \ 2372 break; \ 2373 err = fcn(config, k, &n); \ 2374 if (err < 0) \ 2375 return err; \ 2376 config = n; \ 2377 } \ 2378 va_end(arg); \ 2379 if (result) \ 2380 *result = n; \ 2381 return 0; \ 2382 } 2383 2384 #define SND_CONFIG_SEARCHVA(root, config, result, fcn) \ 2385 { \ 2386 snd_config_t *n; \ 2387 va_list arg; \ 2388 assert(config); \ 2389 va_start(arg, result); \ 2390 while (1) { \ 2391 const char *k = va_arg(arg, const char *); \ 2392 int err; \ 2393 if (!k) \ 2394 break; \ 2395 err = fcn(root, config, k, &n); \ 2396 if (err < 0) \ 2397 return err; \ 2398 config = n; \ 2399 } \ 2400 va_end(arg); \ 2401 if (result) \ 2402 *result = n; \ 2403 return 0; \ 2404 } 2405 2406 #define SND_CONFIG_SEARCH_ALIAS(config, base, key, result, fcn1, fcn2) \ 2407 { \ 2408 snd_config_t *res = NULL; \ 2409 char *old_key; \ 2410 int err, first = 1, maxloop = 1000; \ 2411 assert(config && key); \ 2412 while (1) { \ 2413 old_key = strdup(key); \ 2414 if (old_key == NULL) { \ 2415 err = -ENOMEM; \ 2416 res = NULL; \ 2417 break; \ 2418 } \ 2419 err = first && base ? -EIO : fcn1(config, config, key, &res); \ 2420 if (err < 0) { \ 2421 if (!base) \ 2422 break; \ 2423 err = fcn2(config, config, &res, base, key, NULL); \ 2424 if (err < 0) \ 2425 break; \ 2426 } \ 2427 if (snd_config_get_string(res, &key) < 0) \ 2428 break; \ 2429 if (!first && (strcmp(key, old_key) == 0 || maxloop <= 0)) { \ 2430 if (maxloop == 0) \ 2431 SNDERR("maximum loop count reached (circular configuration?)"); \ 2432 else \ 2433 SNDERR("key %s refers to itself", key); \ 2434 err = -EINVAL; \ 2435 res = NULL; \ 2436 break; \ 2437 } \ 2438 free(old_key); \ 2439 first = 0; \ 2440 maxloop--; \ 2441 } \ 2442 free(old_key); \ 2443 if (!res) \ 2444 return err; \ 2445 if (result) \ 2446 *result = res; \ 2447 return 0; \ 2448 } 2449 2450 #endif /* DOC_HIDDEN */ 2451 2452 /** 2453 * \brief Searches for a node in a configuration tree. 2454 * \param config Handle to the root of the configuration (sub)tree to search. 2455 * \param key Search key: one or more node keys, separated with dots. 2456 * \param result The function puts the handle to the node found at the address 2457 * specified by \p result. 2458 * \return Zero if successful, otherwise a negative error code. 2459 */ 2460 int snd_config_search(snd_config_t *config, const char *key, snd_config_t **result) 2461 { 2462 SND_CONFIG_SEARCH(config, key, result, ); 2463 } 2464 2465 /** 2466 * \brief Searches for a node in a configuration tree, expanding aliases. 2467 * \param root Handle to the root configuration node containing alias 2468 * definitions. 2469 * \param config Handle to the root of the configuration (sub)tree to search. 2470 * \param key Search key: one or more node keys, separated with dots. 2471 * \param result The function puts the handle to the node found at the address 2472 * specified by \p result. 2473 * \return Zero if successful, otherwise a negative error code. 2474 */ 2475 int snd_config_searcha(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result) 2476 { 2477 SND_CONFIG_SEARCHA(root, config, key, result, snd_config_searcha, ); 2478 } 2479 2480 /** 2481 * \brief Searches for a node in a configuration tree. 2482 * \param config Handle to the root of the configuration (sub)tree to search. 2483 * \param result The function puts the handle to the node found at the address 2484 * specified by \p result. 2485 * \param ... One or more concatenated dot separated search keys, terminated with \c NULL. 2486 * \return Zero if successful, otherwise a negative error code. 2487 */ 2488 int snd_config_searchv(snd_config_t *config, snd_config_t **result, ...) 2489 { 2490 SND_CONFIG_SEARCHV(config, result, snd_config_search); 2491 } 2492 2493 /** 2494 * \brief Searches for a node in a configuration tree, expanding aliases. 2495 * \param root Handle to the root configuration node containing alias 2496 * definitions. 2497 * \param config Handle to the root of the configuration (sub)tree to search. 2498 * \param result The function puts the handle to the node found at the address 2499 * specified by \p result. 2500 * \param ... One or more concatenated dot separated search keys, terminated with \c NULL. 2501 * \return Zero if successful, otherwise a negative error code. 2502 */ 2503 int snd_config_searchva(snd_config_t *root, snd_config_t *config, snd_config_t **result, ...) 2504 { 2505 SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha); 2506 } 2507 2508 /** 2509 * \brief Searches for a node in a configuration tree, using an alias. 2510 * \param config Handle to the root of the configuration (sub)tree to search. 2511 * \param base Search key base, or \c NULL. 2512 * \param key Search key suffix. 2513 * \param result The function puts the handle to the node found at the address 2514 * specified by \p result. 2515 * \return Zero if successful, otherwise a negative error code. 2516 * 2517 * First \c key is tried, then, if nothing is found, \c base.key is tried. 2518 * If the value found is a string, this is recursively tried in the 2519 * same way. 2520 */ 2521 int snd_config_search_alias(snd_config_t *config, 2522 const char *base, const char *key, 2523 snd_config_t **result) 2524 { 2525 SND_CONFIG_SEARCH_ALIAS(config, base, key, result, 2526 snd_config_searcha, snd_config_searchva); 2527 } 2528 2529 static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data); 2530 2531 /** 2532 * \brief Searches for a node in a configuration tree and expands hooks. 2533 * \param config Handle to the root of the configuration (sub)tree to search. 2534 * \param key Search key: one or more node keys, separated with dots. 2535 * \param result The function puts the handle to the node found at the address 2536 * specified by \p result. 2537 * \return Zero if successful, otherwise a negative error code. 2538 */ 2539 int snd_config_search_hooks(snd_config_t *config, const char *key, snd_config_t **result) 2540 { 2541 SND_CONFIG_SEARCH(config, key, result, \ 2542 err = snd_config_hooks(config, NULL); \ 2543 if (err < 0) \ 2544 return err; \ 2545 ); 2546 } 2547 2548 /** 2549 * \brief Searches for a node in a configuration tree, expanding aliases and hooks. 2550 * \param root Handle to the root configuration node containing alias 2551 * definitions. 2552 * \param config Handle to the root of the configuration (sub)tree to search. 2553 * \param key Search key: one or more node keys, separated with dots. 2554 * \param result The function puts the handle to the node found at the address 2555 * specified by \p result. 2556 * \return Zero if successful, otherwise a negative error code. 2557 */ 2558 int snd_config_searcha_hooks(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result) 2559 { 2560 SND_CONFIG_SEARCHA(root, config, key, result, 2561 snd_config_searcha_hooks, 2562 err = snd_config_hooks(config, NULL); \ 2563 if (err < 0) \ 2564 return err; \ 2565 ); 2566 } 2567 2568 /** 2569 * \brief Searches for a node in a configuration tree, expanding aliases and hooks. 2570 * \param root Handle to the root configuration node containing alias 2571 * definitions. 2572 * \param config Handle to the root of the configuration (sub)tree to search. 2573 * \param result The function puts the handle to the node found at the address 2574 * specified by \p result. 2575 * \param ... One or more concatenated dot separated search keys, terminated with \c NULL. 2576 * \return Zero if successful, otherwise a negative error code. 2577 */ 2578 int snd_config_searchva_hooks(snd_config_t *root, snd_config_t *config, 2579 snd_config_t **result, ...) 2580 { 2581 SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha_hooks); 2582 } 2583 2584 /** 2585 * \brief Searches for a node in a configuration tree, using an alias and expanding hooks. 2586 * \param config Handle to the root of the configuration (sub)tree to search. 2587 * \param base Search key base, or \c NULL. 2588 * \param key Search key suffix. 2589 * \param result The function puts the handle to the node found at the address 2590 * specified by \p result. 2591 * \return Zero if successful, otherwise a negative error code. 2592 * 2593 * First \c key is tried, then, if nothing is found, \c base.key is tried. 2594 * If the value found is a string, this is recursively tried in the 2595 * same way. 2596 */ 2597 int snd_config_search_alias_hooks(snd_config_t *config, 2598 const char *base, const char *key, 2599 snd_config_t **result) 2600 { 2601 SND_CONFIG_SEARCH_ALIAS(config, base, key, result, 2602 snd_config_searcha_hooks, 2603 snd_config_searchva_hooks); 2604 } 2605 2606 /** The name of the environment variable containing the files list for #snd_config_update. */ 2607 #define ALSA_CONFIG_PATH_VAR "ALSA_CONFIG_PATH" 2608 2609 /** The name of the default files used by #snd_config_update. */ 2610 #define ALSA_CONFIG_PATH_DEFAULT ALSA_CONFIG_DIR "/alsa.conf" 2611 2612 /** 2613 * \ingroup Config 2614 * Configuration top level node (the global configuration). 2615 */ 2616 snd_config_t *snd_config = NULL; 2617 2618 #ifndef DOC_HIDDEN 2619 struct finfo { 2620 char *name; 2621 dev_t dev; 2622 ino_t ino; 2623 time_t mtime; 2624 }; 2625 2626 struct _snd_config_update { 2627 unsigned int count; 2628 struct finfo *finfo; 2629 }; 2630 #endif /* DOC_HIDDEN */ 2631 2632 static snd_config_update_t *snd_config_global_update = NULL; 2633 2634 static int snd_config_hooks_call(snd_config_t *root, snd_config_t *config, snd_config_t *private_data) 2635 { 2636 void *h = NULL; 2637 snd_config_t *c, *func_conf = NULL; 2638 char *buf = NULL; 2639 const char *lib = NULL, *func_name = NULL; 2640 const char *str; 2641 int (*func)(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data) = NULL; 2642 int err; 2643 2644 err = snd_config_search(config, "func", &c); 2645 if (err < 0) { 2646 SNDERR("Field func is missing"); 2647 return err; 2648 } 2649 err = snd_config_get_string(c, &str); 2650 if (err < 0) { 2651 SNDERR("Invalid type for field func"); 2652 return err; 2653 } 2654 err = snd_config_search_definition(root, "hook_func", str, &func_conf); 2655 if (err >= 0) { 2656 snd_config_iterator_t i, next; 2657 if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) { 2658 SNDERR("Invalid type for func %s definition", str); 2659 goto _err; 2660 } 2661 snd_config_for_each(i, next, func_conf) { 2662 snd_config_t *n = snd_config_iterator_entry(i); 2663 const char *id = n->id; 2664 if (strcmp(id, "comment") == 0) 2665 continue; 2666 if (strcmp(id, "lib") == 0) { 2667 err = snd_config_get_string(n, &lib); 2668 if (err < 0) { 2669 SNDERR("Invalid type for %s", id); 2670 goto _err; 2671 } 2672 continue; 2673 } 2674 if (strcmp(id, "func") == 0) { 2675 err = snd_config_get_string(n, &func_name); 2676 if (err < 0) { 2677 SNDERR("Invalid type for %s", id); 2678 goto _err; 2679 } 2680 continue; 2681 } 2682 SNDERR("Unknown field %s", id); 2683 } 2684 } 2685 if (!func_name) { 2686 int len = 16 + strlen(str) + 1; 2687 buf = malloc(len); 2688 if (! buf) { 2689 err = -ENOMEM; 2690 goto _err; 2691 } 2692 snprintf(buf, len, "snd_config_hook_%s", str); 2693 buf[len-1] = '\0'; 2694 func_name = buf; 2695 } 2696 h = snd_dlopen(lib, RTLD_NOW); 2697 func = h ? snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_HOOK)) : NULL; 2698 err = 0; 2699 if (!h) { 2700 SNDERR("Cannot open shared library %s", lib); 2701 err = -ENOENT; 2702 } else if (!func) { 2703 SNDERR("symbol %s is not defined inside %s", func_name, lib); 2704 snd_dlclose(h); 2705 err = -ENXIO; 2706 } 2707 _err: 2708 if (func_conf) 2709 snd_config_delete(func_conf); 2710 if (err >= 0) { 2711 snd_config_t *nroot; 2712 err = func(root, config, &nroot, private_data); 2713 if (err < 0) 2714 SNDERR("function %s returned error: %s", func_name, snd_strerror(err)); 2715 snd_dlclose(h); 2716 if (err >= 0 && nroot) 2717 err = snd_config_substitute(root, nroot); 2718 } 2719 free(buf); 2720 if (err < 0) 2721 return err; 2722 return 0; 2723 } 2724 2725 static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data) 2726 { 2727 snd_config_t *n; 2728 snd_config_iterator_t i, next; 2729 int err, hit, idx = 0; 2730 2731 if ((err = snd_config_search(config, "@hooks", &n)) < 0) 2732 return 0; 2733 snd_config_remove(n); 2734 do { 2735 hit = 0; 2736 snd_config_for_each(i, next, n) { 2737 snd_config_t *n = snd_config_iterator_entry(i); 2738 const char *id = n->id; 2739 long i; 2740 err = safe_strtol(id, &i); 2741 if (err < 0) { 2742 SNDERR("id of field %s is not and integer", id); 2743 err = -EINVAL; 2744 goto _err; 2745 } 2746 if (i == idx) { 2747 err = snd_config_hooks_call(config, n, private_data); 2748 if (err < 0) 2749 return err; 2750 idx++; 2751 hit = 1; 2752 } 2753 } 2754 } while (hit); 2755 err = 0; 2756 _err: 2757 snd_config_delete(n); 2758 return err; 2759 } 2760 2761 /** 2762 * \brief Loads and parses the given configurations files. 2763 * \param root Handle to the root configuration node. 2764 * \param config Handle to the configuration node for this hook. 2765 * \param dst The function puts the handle to the configuration node loaded 2766 * from the file(s) at the address specified by \p dst. 2767 * \param private_data Handle to the private data configuration node. 2768 * \return Zero if successful, otherwise a negative error code. 2769 */ 2770 int snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data) 2771 { 2772 snd_config_t *n; 2773 snd_config_iterator_t i, next; 2774 struct finfo *fi = NULL; 2775 int err, idx = 0, fi_count = 0, errors = 1, hit; 2776 2777 assert(root && dst); 2778 if ((err = snd_config_search(config, "errors", &n)) >= 0) { 2779 char *tmp; 2780 err = snd_config_get_ascii(n, &tmp); 2781 if (err < 0) 2782 return err; 2783 errors = snd_config_get_bool_ascii(tmp); 2784 free(tmp); 2785 if (errors < 0) { 2786 SNDERR("Invalid bool value in field errors"); 2787 return errors; 2788 } 2789 } 2790 if ((err = snd_config_search(config, "files", &n)) < 0) { 2791 SNDERR("Unable to find field files in the pre-load section"); 2792 return -EINVAL; 2793 } 2794 if ((err = snd_config_expand(n, root, NULL, private_data, &n)) < 0) { 2795 SNDERR("Unable to expand filenames in the pre-load section"); 2796 return err; 2797 } 2798 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 2799 SNDERR("Invalid type for field filenames"); 2800 goto _err; 2801 } 2802 snd_config_for_each(i, next, n) { 2803 snd_config_t *c = snd_config_iterator_entry(i); 2804 const char *str; 2805 if ((err = snd_config_get_string(c, &str)) < 0) { 2806 SNDERR("Field %s is not a string", c->id); 2807 goto _err; 2808 } 2809 fi_count++; 2810 } 2811 fi = calloc(fi_count, sizeof(*fi)); 2812 if (fi == NULL) { 2813 err = -ENOMEM; 2814 goto _err; 2815 } 2816 do { 2817 hit = 0; 2818 snd_config_for_each(i, next, n) { 2819 snd_config_t *n = snd_config_iterator_entry(i); 2820 const char *id = n->id; 2821 long i; 2822 err = safe_strtol(id, &i); 2823 if (err < 0) { 2824 SNDERR("id of field %s is not and integer", id); 2825 err = -EINVAL; 2826 goto _err; 2827 } 2828 if (i == idx) { 2829 char *name; 2830 if ((err = snd_config_get_ascii(n, &name)) < 0) 2831 goto _err; 2832 if ((err = snd_user_file(name, &fi[idx].name)) < 0) 2833 fi[idx].name = name; 2834 else 2835 free(name); 2836 idx++; 2837 hit = 1; 2838 } 2839 } 2840 } while (hit); 2841 for (idx = 0; idx < fi_count; idx++) { 2842 snd_input_t *in; 2843 if (!errors && access(fi[idx].name, R_OK) < 0) 2844 continue; 2845 err = snd_input_stdio_open(&in, fi[idx].name, "r"); 2846 if (err >= 0) { 2847 err = snd_config_load(root, in); 2848 snd_input_close(in); 2849 if (err < 0) { 2850 SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[idx].name); 2851 goto _err; 2852 } 2853 } else { 2854 SNDERR("cannot access file %s", fi[idx].name); 2855 } 2856 } 2857 *dst = NULL; 2858 err = 0; 2859 _err: 2860 if (fi) 2861 for (idx = 0; idx < fi_count; idx++) 2862 free(fi[idx].name); 2863 free(fi); 2864 snd_config_delete(n); 2865 return err; 2866 } 2867 #ifndef DOC_HIDDEN 2868 SND_DLSYM_BUILD_VERSION(snd_config_hook_load, SND_CONFIG_DLSYM_VERSION_HOOK); 2869 #endif 2870 2871 #ifndef DOC_HIDDEN 2872 int snd_determine_driver(int card, char **driver); 2873 #endif 2874 2875 /** 2876 * \brief Loads and parses the given configurations files for each installed sound card. 2877 * \param root Handle to the root configuration node. 2878 * \param config Handle to the configuration node for this hook. 2879 * \param dst The function puts the handle to the configuration node loaded 2880 * from the file(s) at the address specified by \p dst. 2881 * \param private_data Handle to the private data configuration node. 2882 * \return Zero if successful, otherwise a negative error code. 2883 */ 2884 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) 2885 { 2886 int card = -1, err; 2887 2888 do { 2889 err = snd_card_next(&card); 2890 if (err < 0) 2891 return err; 2892 if (card >= 0) { 2893 snd_config_t *n, *private_data = NULL; 2894 const char *driver; 2895 char *fdriver = NULL; 2896 err = snd_determine_driver(card, &fdriver); 2897 if (err < 0) 2898 return err; 2899 if (snd_config_search(root, fdriver, &n) >= 0) { 2900 if (snd_config_get_string(n, &driver) < 0) 2901 goto __err; 2902 while (1) { 2903 char *s = strchr(driver, '.'); 2904 if (s == NULL) 2905 break; 2906 driver = s + 1; 2907 } 2908 if (snd_config_search(root, driver, &n) >= 0) 2909 goto __err; 2910 } else { 2911 driver = fdriver; 2912 } 2913 err = snd_config_imake_string(&private_data, "string", driver); 2914 if (err < 0) 2915 goto __err; 2916 err = snd_config_hook_load(root, config, &n, private_data); 2917 __err: 2918 if (private_data) 2919 snd_config_delete(private_data); 2920 free(fdriver); 2921 if (err < 0) 2922 return err; 2923 } 2924 } while (card >= 0); 2925 *dst = NULL; 2926 return 0; 2927 } 2928 #ifndef DOC_HIDDEN 2929 SND_DLSYM_BUILD_VERSION(snd_config_hook_load_for_all_cards, SND_CONFIG_DLSYM_VERSION_HOOK); 2930 #endif 2931 2932 /** 2933 * \brief Updates a configuration tree by rereading the configuration files (if needed). 2934 * \param _top Address of the handle to the top level node. 2935 * \param _update Address of a pointer to private update information. 2936 * \param cfgs A list of configuration file names, delimited with ':'. 2937 * If \p cfgs is set to \c NULL, the default global configuration 2938 * file is used ("/usr/share/alsa/alsa.conf"). 2939 * \return A non-negative value if successful, otherwise a negative error code. 2940 * \retval 0 No action is needed. 2941 * \retval 1 The configuration tree has been rebuilt. 2942 * 2943 * The global configuration files are specified in the environment variable 2944 * \c ALSA_CONFIG_PATH. 2945 * 2946 * \warning If the configuration tree is reread, all string pointers and 2947 * configuration node handles previously obtained from this tree become invalid. 2948 */ 2949 int snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, const char *cfgs) 2950 { 2951 int err; 2952 const char *configs, *c; 2953 unsigned int k; 2954 size_t l; 2955 snd_config_update_t *local; 2956 snd_config_update_t *update; 2957 snd_config_t *top; 2958 2959 assert(_top && _update); 2960 top = *_top; 2961 update = *_update; 2962 configs = cfgs; 2963 if (!configs) { 2964 configs = getenv(ALSA_CONFIG_PATH_VAR); 2965 if (!configs || !*configs) 2966 configs = ALSA_CONFIG_PATH_DEFAULT; 2967 } 2968 for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) { 2969 c += l; 2970 k++; 2971 if (!*c) 2972 break; 2973 c++; 2974 } 2975 if (k == 0) { 2976 local = NULL; 2977 goto _reread; 2978 } 2979 local = (snd_config_update_t *)calloc(1, sizeof(snd_config_update_t)); 2980 if (!local) 2981 return -ENOMEM; 2982 local->count = k; 2983 local->finfo = calloc(local->count, sizeof(struct finfo)); 2984 if (!local->finfo) { 2985 free(local); 2986 return -ENOMEM; 2987 } 2988 for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) { 2989 char name[l + 1]; 2990 memcpy(name, c, l); 2991 name[l] = 0; 2992 err = snd_user_file(name, &local->finfo[k].name); 2993 if (err < 0) 2994 goto _end; 2995 c += l; 2996 k++; 2997 if (!*c) 2998 break; 2999 c++; 3000 } 3001 for (k = 0; k < local->count; ++k) { 3002 struct stat st; 3003 struct finfo *lf = &local->finfo[k]; 3004 if (stat(lf->name, &st) >= 0) { 3005 lf->dev = st.st_dev; 3006 lf->ino = st.st_ino; 3007 lf->mtime = st.st_mtime; 3008 } else { 3009 SNDERR("Cannot access file %s", lf->name); 3010 free(lf->name); 3011 memmove(&local->finfo[k], &local->finfo[k+1], sizeof(struct finfo) * (local->count - k - 1)); 3012 k--; 3013 local->count--; 3014 } 3015 } 3016 if (!update) 3017 goto _reread; 3018 if (local->count != update->count) 3019 goto _reread; 3020 for (k = 0; k < local->count; ++k) { 3021 struct finfo *lf = &local->finfo[k]; 3022 struct finfo *uf = &update->finfo[k]; 3023 if (strcmp(lf->name, uf->name) != 0 || 3024 lf->dev != uf->dev || 3025 lf->ino != uf->ino || 3026 lf->mtime != uf->mtime) 3027 goto _reread; 3028 } 3029 err = 0; 3030 3031 _end: 3032 if (err < 0) { 3033 if (top) { 3034 snd_config_delete(top); 3035 *_top = NULL; 3036 } 3037 if (update) { 3038 snd_config_update_free(update); 3039 *_update = NULL; 3040 } 3041 } 3042 if (local) 3043 snd_config_update_free(local); 3044 return err; 3045 3046 _reread: 3047 *_top = NULL; 3048 *_update = NULL; 3049 if (update) { 3050 snd_config_update_free(update); 3051 update = NULL; 3052 } 3053 if (top) { 3054 snd_config_delete(top); 3055 top = NULL; 3056 } 3057 err = snd_config_top(&top); 3058 if (err < 0) 3059 goto _end; 3060 if (!local) 3061 goto _skip; 3062 for (k = 0; k < local->count; ++k) { 3063 snd_input_t *in; 3064 err = snd_input_stdio_open(&in, local->finfo[k].name, "r"); 3065 if (err >= 0) { 3066 err = snd_config_load(top, in); 3067 snd_input_close(in); 3068 if (err < 0) { 3069 SNDERR("%s may be old or corrupted: consider to remove or fix it", local->finfo[k].name); 3070 goto _end; 3071 } 3072 } else { 3073 SNDERR("cannot access file %s", local->finfo[k].name); 3074 } 3075 } 3076 _skip: 3077 err = snd_config_hooks(top, NULL); 3078 if (err < 0) { 3079 SNDERR("hooks failed, removing configuration"); 3080 goto _end; 3081 } 3082 *_top = top; 3083 *_update = local; 3084 return 1; 3085 } 3086 3087 #ifdef HAVE_LIBPTHREAD 3088 static pthread_mutex_t snd_config_update_mutex = PTHREAD_MUTEX_INITIALIZER; 3089 #endif 3090 3091 /** 3092 * \brief Updates #snd_config by rereading the global configuration files (if needed). 3093 * \return A non-negative value if successful, otherwise a negative error code. 3094 * \retval 0 No action is needed. 3095 * \retval 1 The configuration tree has been rebuilt. 3096 * 3097 * The global configuration files are specified in the environment variable 3098 * \c ALSA_CONFIG_PATH. If this is not set, the default value is 3099 * "/usr/share/alsa/alsa.conf". 3100 * 3101 * \warning If the configuration tree is reread, all string pointers and 3102 * configuration node handles previously obtained from this tree become invalid. 3103 */ 3104 int snd_config_update(void) 3105 { 3106 int err; 3107 3108 #ifdef HAVE_LIBPTHREAD 3109 pthread_mutex_lock(&snd_config_update_mutex); 3110 #endif 3111 err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL); 3112 #ifdef HAVE_LIBPTHREAD 3113 pthread_mutex_unlock(&snd_config_update_mutex); 3114 #endif 3115 return err; 3116 } 3117 3118 /** 3119 * \brief Frees a private update structure. 3120 * \param update The private update structure to free. 3121 * \return Zero if successful, otherwise a negative error code. 3122 */ 3123 int snd_config_update_free(snd_config_update_t *update) 3124 { 3125 unsigned int k; 3126 3127 assert(update); 3128 for (k = 0; k < update->count; k++) 3129 free(update->finfo[k].name); 3130 free(update->finfo); 3131 free(update); 3132 return 0; 3133 } 3134 3135 /** 3136 * \brief Frees the global configuration tree in #snd_config. 3137 * \return Zero if successful, otherwise a negative error code. 3138 */ 3139 int snd_config_update_free_global(void) 3140 { 3141 #ifdef HAVE_LIBPTHREAD 3142 pthread_mutex_lock(&snd_config_update_mutex); 3143 #endif 3144 if (snd_config) 3145 snd_config_delete(snd_config); 3146 snd_config = NULL; 3147 if (snd_config_global_update) 3148 snd_config_update_free(snd_config_global_update); 3149 snd_config_global_update = NULL; 3150 #ifdef HAVE_LIBPTHREAD 3151 pthread_mutex_unlock(&snd_config_update_mutex); 3152 #endif 3153 /* FIXME: better to place this in another place... */ 3154 snd_dlobj_cache_cleanup(); 3155 3156 return 0; 3157 } 3158 3159 /** 3160 * \brief Returns an iterator pointing to the first child of a compound configuration node. 3161 * \param node Handle to the compound configuration node. 3162 * \return An iterator pointing to the first child. 3163 */ 3164 snd_config_iterator_t snd_config_iterator_first(const snd_config_t *node) 3165 { 3166 assert(node->type == SND_CONFIG_TYPE_COMPOUND); 3167 return node->u.compound.fields.next; 3168 } 3169 3170 /** 3171 * \brief Returns an iterator pointing to the next sibling. 3172 * \param iterator An iterator pointing to a child configuration node. 3173 * \return An iterator pointing to the next sibling of \p iterator. 3174 * If \p iterator is the last sibling, the returned value is the same 3175 * as the result of calling #snd_config_iterator_end on the father 3176 * of the nodes. 3177 */ 3178 snd_config_iterator_t snd_config_iterator_next(const snd_config_iterator_t iterator) 3179 { 3180 return iterator->next; 3181 } 3182 3183 /** 3184 * \brief Returns an iterator pointing past the last child of a compound configuration node. 3185 * \param node Handle to the compound configuration node. 3186 * \return An iterator pointing past the last child of \p node. 3187 */ 3188 snd_config_iterator_t snd_config_iterator_end(const snd_config_t *node) 3189 { 3190 assert(node->type == SND_CONFIG_TYPE_COMPOUND); 3191 return (const snd_config_iterator_t)&node->u.compound.fields; 3192 } 3193 3194 /** 3195 * \brief Returns the configuration node handle pointed to by an iterator. 3196 * \param iterator A configuration node iterator. 3197 * \return The configuration node handle pointed to by \p iterator. 3198 */ 3199 snd_config_t *snd_config_iterator_entry(const snd_config_iterator_t iterator) 3200 { 3201 return list_entry(iterator, snd_config_t, list); 3202 } 3203 3204 #ifndef DOC_HIDDEN 3205 typedef enum _snd_config_walk_pass { 3206 SND_CONFIG_WALK_PASS_PRE, 3207 SND_CONFIG_WALK_PASS_POST, 3208 SND_CONFIG_WALK_PASS_LEAF, 3209 } snd_config_walk_pass_t; 3210 #endif 3211 3212 /* Return 1 if node needs to be attached to father */ 3213 /* Return 2 if compound is replaced with standard node */ 3214 #ifndef DOC_HIDDEN 3215 typedef int (*snd_config_walk_callback_t)(snd_config_t *src, 3216 snd_config_t *root, 3217 snd_config_t **dst, 3218 snd_config_walk_pass_t pass, 3219 snd_config_t *private_data); 3220 #endif 3221 3222 static int snd_config_walk(snd_config_t *src, 3223 snd_config_t *root, 3224 snd_config_t **dst, 3225 snd_config_walk_callback_t callback, 3226 snd_config_t *private_data) 3227 { 3228 int err; 3229 snd_config_iterator_t i, next; 3230 3231 switch (snd_config_get_type(src)) { 3232 case SND_CONFIG_TYPE_COMPOUND: 3233 err = callback(src, root, dst, SND_CONFIG_WALK_PASS_PRE, private_data); 3234 if (err <= 0) 3235 return err; 3236 snd_config_for_each(i, next, src) { 3237 snd_config_t *s = snd_config_iterator_entry(i); 3238 snd_config_t *d = NULL; 3239 3240 err = snd_config_walk(s, root, (dst && *dst) ? &d : NULL, 3241 callback, private_data); 3242 if (err < 0) 3243 goto _error; 3244 if (err && d) { 3245 err = snd_config_add(*dst, d); 3246 if (err < 0) 3247 goto _error; 3248 } 3249 } 3250 err = callback(src, root, dst, SND_CONFIG_WALK_PASS_POST, private_data); 3251 if (err <= 0) { 3252 _error: 3253 if (dst && *dst) 3254 snd_config_delete(*dst); 3255 } 3256 break; 3257 default: 3258 err = callback(src, root, dst, SND_CONFIG_WALK_PASS_LEAF, private_data); 3259 break; 3260 } 3261 return err; 3262 } 3263 3264 static int _snd_config_copy(snd_config_t *src, 3265 snd_config_t *root ATTRIBUTE_UNUSED, 3266 snd_config_t **dst, 3267 snd_config_walk_pass_t pass, 3268 snd_config_t *private_data ATTRIBUTE_UNUSED) 3269 { 3270 int err; 3271 const char *id = src->id; 3272 snd_config_type_t type = snd_config_get_type(src); 3273 switch (pass) { 3274 case SND_CONFIG_WALK_PASS_PRE: 3275 err = snd_config_make_compound(dst, id, src->u.compound.join); 3276 if (err < 0) 3277 return err; 3278 break; 3279 case SND_CONFIG_WALK_PASS_LEAF: 3280 err = snd_config_make(dst, id, type); 3281 if (err < 0) 3282 return err; 3283 switch (type) { 3284 case SND_CONFIG_TYPE_INTEGER: 3285 { 3286 long v; 3287 err = snd_config_get_integer(src, &v); 3288 assert(err >= 0); 3289 snd_config_set_integer(*dst, v); 3290 break; 3291 } 3292 case SND_CONFIG_TYPE_INTEGER64: 3293 { 3294 long long v; 3295 err = snd_config_get_integer64(src, &v); 3296 assert(err >= 0); 3297 snd_config_set_integer64(*dst, v); 3298 break; 3299 } 3300 case SND_CONFIG_TYPE_REAL: 3301 { 3302 double v; 3303 err = snd_config_get_real(src, &v); 3304 assert(err >= 0); 3305 snd_config_set_real(*dst, v); 3306 break; 3307 } 3308 case SND_CONFIG_TYPE_STRING: 3309 { 3310 const char *s; 3311 err = snd_config_get_string(src, &s); 3312 assert(err >= 0); 3313 err = snd_config_set_string(*dst, s); 3314 if (err < 0) 3315 return err; 3316 break; 3317 } 3318 default: 3319 assert(0); 3320 } 3321 break; 3322 default: 3323 break; 3324 } 3325 return 1; 3326 } 3327 3328 /** 3329 * \brief Creates a copy of a configuration node. 3330 * \param dst The function puts the handle to the new configuration node 3331 * at the address specified by \p dst. 3332 * \param src Handle to the source configuration node. 3333 * \return A non-negative value if successful, otherwise a negative error code. 3334 */ 3335 int snd_config_copy(snd_config_t **dst, 3336 snd_config_t *src) 3337 { 3338 return snd_config_walk(src, NULL, dst, _snd_config_copy, NULL); 3339 } 3340 3341 static int _snd_config_expand(snd_config_t *src, 3342 snd_config_t *root ATTRIBUTE_UNUSED, 3343 snd_config_t **dst, 3344 snd_config_walk_pass_t pass, 3345 snd_config_t *private_data) 3346 { 3347 int err; 3348 const char *id = src->id; 3349 snd_config_type_t type = snd_config_get_type(src); 3350 switch (pass) { 3351 case SND_CONFIG_WALK_PASS_PRE: 3352 { 3353 if (strcmp(id, "@args") == 0) 3354 return 0; 3355 err = snd_config_make_compound(dst, id, src->u.compound.join); 3356 if (err < 0) 3357 return err; 3358 break; 3359 } 3360 case SND_CONFIG_WALK_PASS_LEAF: 3361 switch (type) { 3362 case SND_CONFIG_TYPE_INTEGER: 3363 { 3364 long v; 3365 err = snd_config_get_integer(src, &v); 3366 assert(err >= 0); 3367 err = snd_config_imake_integer(dst, id, v); 3368 if (err < 0) 3369 return err; 3370 break; 3371 } 3372 case SND_CONFIG_TYPE_INTEGER64: 3373 { 3374 long long v; 3375 err = snd_config_get_integer64(src, &v); 3376 assert(err >= 0); 3377 err = snd_config_imake_integer64(dst, id, v); 3378 if (err < 0) 3379 return err; 3380 break; 3381 } 3382 case SND_CONFIG_TYPE_REAL: 3383 { 3384 double v; 3385 err = snd_config_get_real(src, &v); 3386 assert(err >= 0); 3387 err = snd_config_imake_real(dst, id, v); 3388 if (err < 0) 3389 return err; 3390 break; 3391 } 3392 case SND_CONFIG_TYPE_STRING: 3393 { 3394 const char *s; 3395 snd_config_t *val; 3396 snd_config_t *vars = private_data; 3397 snd_config_get_string(src, &s); 3398 if (*s == '$') { 3399 s++; 3400 if (snd_config_search(vars, s, &val) < 0) 3401 return 0; 3402 err = snd_config_copy(dst, val); 3403 if (err < 0) 3404 return err; 3405 err = snd_config_set_id(*dst, id); 3406 if (err < 0) { 3407 snd_config_delete(*dst); 3408 return err; 3409 } 3410 } else { 3411 err = snd_config_imake_string(dst, id, s); 3412 if (err < 0) 3413 return err; 3414 } 3415 break; 3416 } 3417 default: 3418 assert(0); 3419 } 3420 break; 3421 default: 3422 break; 3423 } 3424 return 1; 3425 } 3426 3427 static int _snd_config_evaluate(snd_config_t *src, 3428 snd_config_t *root, 3429 snd_config_t **dst ATTRIBUTE_UNUSED, 3430 snd_config_walk_pass_t pass, 3431 snd_config_t *private_data) 3432 { 3433 int err; 3434 if (pass == SND_CONFIG_WALK_PASS_PRE) { 3435 char *buf = NULL; 3436 const char *lib = NULL, *func_name = NULL; 3437 const char *str; 3438 int (*func)(snd_config_t **dst, snd_config_t *root, 3439 snd_config_t *src, snd_config_t *private_data) = NULL; 3440 void *h = NULL; 3441 snd_config_t *c, *func_conf = NULL; 3442 err = snd_config_search(src, "@func", &c); 3443 if (err < 0) 3444 return 1; 3445 err = snd_config_get_string(c, &str); 3446 if (err < 0) { 3447 SNDERR("Invalid type for @func"); 3448 return err; 3449 } 3450 err = snd_config_search_definition(root, "func", str, &func_conf); 3451 if (err >= 0) { 3452 snd_config_iterator_t i, next; 3453 if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) { 3454 SNDERR("Invalid type for func %s definition", str); 3455 goto _err; 3456 } 3457 snd_config_for_each(i, next, func_conf) { 3458 snd_config_t *n = snd_config_iterator_entry(i); 3459 const char *id = n->id; 3460 if (strcmp(id, "comment") == 0) 3461 continue; 3462 if (strcmp(id, "lib") == 0) { 3463 err = snd_config_get_string(n, &lib); 3464 if (err < 0) { 3465 SNDERR("Invalid type for %s", id); 3466 goto _err; 3467 } 3468 continue; 3469 } 3470 if (strcmp(id, "func") == 0) { 3471 err = snd_config_get_string(n, &func_name); 3472 if (err < 0) { 3473 SNDERR("Invalid type for %s", id); 3474 goto _err; 3475 } 3476 continue; 3477 } 3478 SNDERR("Unknown field %s", id); 3479 } 3480 } 3481 if (!func_name) { 3482 int len = 9 + strlen(str) + 1; 3483 buf = malloc(len); 3484 if (! buf) { 3485 err = -ENOMEM; 3486 goto _err; 3487 } 3488 snprintf(buf, len, "snd_func_%s", str); 3489 buf[len-1] = '\0'; 3490 func_name = buf; 3491 } 3492 h = snd_dlopen(lib, RTLD_NOW); 3493 if (h) 3494 func = snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_EVALUATE)); 3495 err = 0; 3496 if (!h) { 3497 SNDERR("Cannot open shared library %s", lib); 3498 err = -ENOENT; 3499 goto _errbuf; 3500 } else if (!func) { 3501 SNDERR("symbol %s is not defined inside %s", func_name, lib); 3502 snd_dlclose(h); 3503 err = -ENXIO; 3504 goto _errbuf; 3505 } 3506 _err: 3507 if (func_conf) 3508 snd_config_delete(func_conf); 3509 if (err >= 0) { 3510 snd_config_t *eval; 3511 err = func(&eval, root, src, private_data); 3512 if (err < 0) 3513 SNDERR("function %s returned error: %s", func_name, snd_strerror(err)); 3514 snd_dlclose(h); 3515 if (err >= 0 && eval) { 3516 /* substitute merges compound members */ 3517 /* we don't want merging at all */ 3518 err = snd_config_delete_compound_members(src); 3519 if (err >= 0) 3520 err = snd_config_substitute(src, eval); 3521 } 3522 } 3523 _errbuf: 3524 free(buf); 3525 if (err < 0) 3526 return err; 3527 return 0; 3528 } 3529 return 1; 3530 } 3531 3532 /** 3533 * \brief Evaluates a configuration node at runtime. 3534 * \param config Handle to the source configuration node. 3535 * \param root Handle to the root of the source configuration. 3536 * \param private_data Handle to the private data node for runtime evaluation. 3537 * \param result The function puts the handle to the result node at the 3538 * address specified by \p result. \p result is \c NULL for 3539 * in-place evaluation. 3540 * \return A non-negative value if successful, otherwise a negative error code. 3541 * \note Only in-place evaluation is currently implemented. 3542 */ 3543 int snd_config_evaluate(snd_config_t *config, snd_config_t *root, 3544 snd_config_t *private_data, snd_config_t **result) 3545 { 3546 /* FIXME: Only in place evaluation is currently implemented */ 3547 assert(result == NULL); 3548 return snd_config_walk(config, root, result, _snd_config_evaluate, private_data); 3549 } 3550 3551 static int load_defaults(snd_config_t *subs, snd_config_t *defs) 3552 { 3553 snd_config_iterator_t d, dnext; 3554 snd_config_for_each(d, dnext, defs) { 3555 snd_config_t *def = snd_config_iterator_entry(d); 3556 snd_config_iterator_t f, fnext; 3557 if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND) 3558 continue; 3559 snd_config_for_each(f, fnext, def) { 3560 snd_config_t *fld = snd_config_iterator_entry(f); 3561 const char *id = fld->id; 3562 if (strcmp(id, "type") == 0) 3563 continue; 3564 if (strcmp(id, "default") == 0) { 3565 snd_config_t *deflt; 3566 int err; 3567 err = snd_config_copy(&deflt, fld); 3568 if (err < 0) 3569 return err; 3570 err = snd_config_set_id(deflt, def->id); 3571 if (err < 0) { 3572 snd_config_delete(deflt); 3573 return err; 3574 } 3575 err = snd_config_add(subs, deflt); 3576 if (err < 0) { 3577 snd_config_delete(deflt); 3578 return err; 3579 } 3580 continue; 3581 } 3582 SNDERR("Unknown field %s", id); 3583 return -EINVAL; 3584 } 3585 } 3586 return 0; 3587 } 3588 3589 static void skip_blank(const char **ptr) 3590 { 3591 while (1) { 3592 switch (**ptr) { 3593 case ' ': 3594 case '\f': 3595 case '\t': 3596 case '\n': 3597 case '\r': 3598 break; 3599 default: 3600 return; 3601 } 3602 (*ptr)++; 3603 } 3604 } 3605 3606 static int parse_char(const char **ptr) 3607 { 3608 int c; 3609 assert(**ptr == '\\'); 3610 (*ptr)++; 3611 c = **ptr; 3612 switch (c) { 3613 case 'n': 3614 c = '\n'; 3615 break; 3616 case 't': 3617 c = '\t'; 3618 break; 3619 case 'v': 3620 c = '\v'; 3621 break; 3622 case 'b': 3623 c = '\b'; 3624 break; 3625 case 'r': 3626 c = '\r'; 3627 break; 3628 case 'f': 3629 c = '\f'; 3630 break; 3631 case '0' ... '7': 3632 { 3633 int num = c - '0'; 3634 int i = 1; 3635 (*ptr)++; 3636 do { 3637 c = **ptr; 3638 if (c < '0' || c > '7') 3639 break; 3640 num = num * 8 + c - '0'; 3641 i++; 3642 (*ptr)++; 3643 } while (i < 3); 3644 return num; 3645 } 3646 default: 3647 break; 3648 } 3649 (*ptr)++; 3650 return c; 3651 } 3652 3653 static int parse_id(const char **ptr) 3654 { 3655 if (!**ptr) 3656 return -EINVAL; 3657 while (1) { 3658 switch (**ptr) { 3659 case '\f': 3660 case '\t': 3661 case '\n': 3662 case '\r': 3663 case ',': 3664 case '=': 3665 case '\0': 3666 return 0; 3667 default: 3668 break; 3669 } 3670 (*ptr)++; 3671 } 3672 } 3673 3674 static int parse_string(const char **ptr, char **val) 3675 { 3676 const size_t bufsize = 256; 3677 char _buf[bufsize]; 3678 char *buf = _buf; 3679 size_t alloc = bufsize; 3680 char delim = **ptr; 3681 size_t idx = 0; 3682 (*ptr)++; 3683 while (1) { 3684 int c = **ptr; 3685 switch (c) { 3686 case '\0': 3687 SNDERR("Unterminated string"); 3688 return -EINVAL; 3689 case '\\': 3690 c = parse_char(ptr); 3691 if (c < 0) 3692 return c; 3693 break; 3694 default: 3695 (*ptr)++; 3696 if (c == delim) { 3697 *val = malloc(idx + 1); 3698 if (!*val) 3699 return -ENOMEM; 3700 memcpy(*val, buf, idx); 3701 (*val)[idx] = 0; 3702 if (alloc > bufsize) 3703 free(buf); 3704 return 0; 3705 } 3706 } 3707 if (idx >= alloc) { 3708 size_t old_alloc = alloc; 3709 alloc *= 2; 3710 if (old_alloc == bufsize) { 3711 buf = malloc(alloc); 3712 memcpy(buf, _buf, old_alloc); 3713 } else { 3714 buf = realloc(buf, alloc); 3715 } 3716 if (!buf) 3717 return -ENOMEM; 3718 } 3719 buf[idx++] = c; 3720 } 3721 } 3722 3723 3724 /* Parse var=val or val */ 3725 static int parse_arg(const char **ptr, unsigned int *varlen, char **val) 3726 { 3727 const char *str; 3728 int err, vallen; 3729 skip_blank(ptr); 3730 str = *ptr; 3731 if (*str == '"' || *str == '\'') { 3732 err = parse_string(ptr, val); 3733 if (err < 0) 3734 return err; 3735 *varlen = 0; 3736 return 0; 3737 } 3738 err = parse_id(ptr); 3739 if (err < 0) 3740 return err; 3741 vallen = *ptr - str; 3742 skip_blank(ptr); 3743 if (**ptr != '=') { 3744 *varlen = 0; 3745 goto _value; 3746 } 3747 *varlen = vallen; 3748 (*ptr)++; 3749 skip_blank(ptr); 3750 str = *ptr; 3751 if (*str == '"' || *str == '\'') { 3752 err = parse_string(ptr, val); 3753 if (err < 0) 3754 return err; 3755 return 0; 3756 } 3757 err = parse_id(ptr); 3758 if (err < 0) 3759 return err; 3760 vallen = *ptr - str; 3761 _value: 3762 *val = malloc(vallen + 1); 3763 if (!*val) 3764 return -ENOMEM; 3765 memcpy(*val, str, vallen); 3766 (*val)[vallen] = 0; 3767 return 0; 3768 } 3769 3770 3771 /* val1, val2, ... 3772 * var1=val1,var2=val2,... 3773 * { conf syntax } 3774 */ 3775 static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs) 3776 { 3777 int err; 3778 int arg = 0; 3779 if (str == NULL) 3780 return 0; 3781 skip_blank(&str); 3782 if (!*str) 3783 return 0; 3784 if (*str == '{') { 3785 int len = strlen(str); 3786 snd_input_t *input; 3787 snd_config_iterator_t i, next; 3788 while (1) { 3789 switch (str[--len]) { 3790 case ' ': 3791 case '\f': 3792 case '\t': 3793 case '\n': 3794 case '\r': 3795 continue; 3796 default: 3797 break; 3798 } 3799 break; 3800 } 3801 if (str[len] != '}') 3802 return -EINVAL; 3803 err = snd_input_buffer_open(&input, str + 1, len - 1); 3804 if (err < 0) 3805 return err; 3806 err = snd_config_load_override(subs, input); 3807 snd_input_close(input); 3808 if (err < 0) 3809 return err; 3810 snd_config_for_each(i, next, subs) { 3811 snd_config_t *n = snd_config_iterator_entry(i); 3812 snd_config_t *d; 3813 const char *id = n->id; 3814 err = snd_config_search(defs, id, &d); 3815 if (err < 0) { 3816 SNDERR("Unknown parameter %s", id); 3817 return err; 3818 } 3819 } 3820 return 0; 3821 } 3822 3823 while (1) { 3824 char buf[256]; 3825 const char *var = buf; 3826 unsigned int varlen; 3827 snd_config_t *def, *sub, *typ; 3828 const char *new = str; 3829 const char *tmp; 3830 char *val = NULL; 3831 err = parse_arg(&new, &varlen, &val); 3832 if (err < 0) 3833 goto _err; 3834 if (varlen > 0) { 3835 assert(varlen < sizeof(buf)); 3836 memcpy(buf, str, varlen); 3837 buf[varlen] = 0; 3838 } else { 3839 sprintf(buf, "%d", arg); 3840 } 3841 err = snd_config_search_alias(defs, NULL, var, &def); 3842 if (err < 0) { 3843 SNDERR("Unknown parameter %s", var); 3844 goto _err; 3845 } 3846 if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND) { 3847 SNDERR("Parameter %s definition is not correct", var); 3848 err = -EINVAL; 3849 goto _err; 3850 } 3851 var = def->id; 3852 err = snd_config_search(subs, var, &sub); 3853 if (err >= 0) 3854 snd_config_delete(sub); 3855 err = snd_config_search(def, "type", &typ); 3856 if (err < 0) { 3857 _invalid_type: 3858 SNDERR("Parameter %s definition is missing a valid type info", var); 3859 goto _err; 3860 } 3861 err = snd_config_get_string(typ, &tmp); 3862 if (err < 0) 3863 goto _invalid_type; 3864 if (strcmp(tmp, "integer") == 0) { 3865 long v; 3866 err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER); 3867 if (err < 0) 3868 goto _err; 3869 err = safe_strtol(val, &v); 3870 if (err < 0) { 3871 SNDERR("Parameter %s must be an integer", var); 3872 goto _err; 3873 } 3874 err = snd_config_set_integer(sub, v); 3875 if (err < 0) 3876 goto _err; 3877 } else if (strcmp(tmp, "integer64") == 0) { 3878 long long v; 3879 err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER64); 3880 if (err < 0) 3881 goto _err; 3882 err = safe_strtoll(val, &v); 3883 if (err < 0) { 3884 SNDERR("Parameter %s must be an integer", var); 3885 goto _err; 3886 } 3887 err = snd_config_set_integer64(sub, v); 3888 if (err < 0) 3889 goto _err; 3890 } else if (strcmp(tmp, "real") == 0) { 3891 double v; 3892 err = snd_config_make(&sub, var, SND_CONFIG_TYPE_REAL); 3893 if (err < 0) 3894 goto _err; 3895 err = safe_strtod(val, &v); 3896 if (err < 0) { 3897 SNDERR("Parameter %s must be a real", var); 3898 goto _err; 3899 } 3900 err = snd_config_set_real(sub, v); 3901 if (err < 0) 3902 goto _err; 3903 } else if (strcmp(tmp, "string") == 0) { 3904 err = snd_config_make(&sub, var, SND_CONFIG_TYPE_STRING); 3905 if (err < 0) 3906 goto _err; 3907 err = snd_config_set_string(sub, val); 3908 if (err < 0) 3909 goto _err; 3910 } else { 3911 err = -EINVAL; 3912 goto _invalid_type; 3913 } 3914 err = snd_config_set_id(sub, var); 3915 if (err < 0) 3916 goto _err; 3917 err = snd_config_add(subs, sub); 3918 if (err < 0) { 3919 _err: 3920 free(val); 3921 return err; 3922 } 3923 free(val); 3924 if (!*new) 3925 break; 3926 if (*new != ',') 3927 return -EINVAL; 3928 str = new + 1; 3929 arg++; 3930 } 3931 return 0; 3932 } 3933 3934 /** 3935 * \brief Expands a configuration node applying arguments and functions. 3936 * \param config Handle to the configuration node. 3937 * \param root Handle to the root configuration node. 3938 * \param args Arguments string (optional). 3939 * \param private_data Handle to the private data node for functions. 3940 * \param result The function puts the handle to the result configuration node 3941 * at the address specified by \p result. 3942 * \return A non-negative value if successful, otherwise a negative error code. 3943 */ 3944 int snd_config_expand(snd_config_t *config, snd_config_t *root, const char *args, 3945 snd_config_t *private_data, snd_config_t **result) 3946 { 3947 int err; 3948 snd_config_t *defs, *subs = NULL, *res; 3949 err = snd_config_search(config, "@args", &defs); 3950 if (err < 0) { 3951 if (args != NULL) { 3952 SNDERR("Unknown parameters %s", args); 3953 return -EINVAL; 3954 } 3955 err = snd_config_copy(&res, config); 3956 if (err < 0) 3957 return err; 3958 } else { 3959 err = snd_config_top(&subs); 3960 if (err < 0) 3961 return err; 3962 err = load_defaults(subs, defs); 3963 if (err < 0) { 3964 SNDERR("Load defaults error: %s", snd_strerror(err)); 3965 goto _end; 3966 } 3967 err = parse_args(subs, args, defs); 3968 if (err < 0) { 3969 SNDERR("Parse arguments error: %s", snd_strerror(err)); 3970 goto _end; 3971 } 3972 err = snd_config_evaluate(subs, root, private_data, NULL); 3973 if (err < 0) { 3974 SNDERR("Args evaluate error: %s", snd_strerror(err)); 3975 goto _end; 3976 } 3977 err = snd_config_walk(config, root, &res, _snd_config_expand, subs); 3978 if (err < 0) { 3979 SNDERR("Expand error (walk): %s", snd_strerror(err)); 3980 goto _end; 3981 } 3982 } 3983 err = snd_config_evaluate(res, root, private_data, NULL); 3984 if (err < 0) { 3985 SNDERR("Evaluate error: %s", snd_strerror(err)); 3986 snd_config_delete(res); 3987 goto _end; 3988 } 3989 *result = res; 3990 err = 1; 3991 _end: 3992 if (subs) 3993 snd_config_delete(subs); 3994 return err; 3995 } 3996 3997 /** 3998 * \brief Searches for a definition in a configuration tree, using aliases and expanding hooks and arguments. 3999 * \param config Handle to the configuration (sub)tree to search. 4000 * \param base Implicit key base, or \c NULL for none. 4001 * \param name Key suffix. 4002 * \param result The function puts the handle to the expanded found node at 4003 * the address specified by \p result. 4004 * \return A non-negative value if successful, otherwise a negative error code. 4005 * 4006 * First the key is tried, then, if nothing is found, base.key is tried. 4007 * If the value found is a string, this is recursively tried in the 4008 * same way. 4009 * 4010 * If \p key contains a dot (.), the implicit base is ignored and the key 4011 * starts from the root given by \p config. 4012 */ 4013 int snd_config_search_definition(snd_config_t *config, 4014 const char *base, const char *name, 4015 snd_config_t **result) 4016 { 4017 snd_config_t *conf; 4018 char *key; 4019 const char *args = strchr(name, ':'); 4020 int err; 4021 if (args) { 4022 args++; 4023 key = alloca(args - name); 4024 memcpy(key, name, args - name - 1); 4025 key[args - name - 1] = '\0'; 4026 } else { 4027 key = (char *) name; 4028 } 4029 /* 4030 * if key contains dot (.), the implicit base is ignored 4031 * and the key starts from root given by the 'config' parameter 4032 */ 4033 err = snd_config_search_alias_hooks(config, strchr(key, '.') ? NULL : base, key, &conf); 4034 if (err < 0) 4035 return err; 4036 return snd_config_expand(conf, config, args, NULL, result); 4037 } 4038 4039 #ifndef DOC_HIDDEN 4040 void snd_config_set_hop(snd_config_t *conf, int hop) 4041 { 4042 conf->hop = hop; 4043 } 4044 4045 int snd_config_check_hop(snd_config_t *conf) 4046 { 4047 if (conf) { 4048 if (conf->hop >= SND_CONF_MAX_HOPS) { 4049 SYSERR("Too many definition levels (looped?)\n"); 4050 return -EINVAL; 4051 } 4052 return conf->hop; 4053 } 4054 return 0; 4055 } 4056 #endif 4057 4058 #if 0 4059 /* Not strictly needed, but useful to check for memory leaks */ 4060 void _snd_config_end(void) __attribute__ ((destructor)); 4061 4062 static void _snd_config_end(void) 4063 { 4064 int k; 4065 if (snd_config) 4066 snd_config_delete(snd_config); 4067 snd_config = 0; 4068 for (k = 0; k < files_info_count; ++k) 4069 free(files_info[k].name); 4070 free(files_info); 4071 files_info = NULL; 4072 files_info_count = 0; 4073 } 4074 #endif 4075