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