00001
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00417 #include <stdarg.h>
00418 #include <dlfcn.h>
00419 #include <limits.h>
00420 #include <sys/stat.h>
00421 #include <pthread.h>
00422 #include <locale.h>
00423 #include "local.h"
00424
00425 #ifndef DOC_HIDDEN
00426
00427 struct _snd_config {
00428 char *id;
00429 snd_config_type_t type;
00430 union {
00431 long integer;
00432 long long integer64;
00433 char *string;
00434 double real;
00435 const void *ptr;
00436 struct {
00437 struct list_head fields;
00438 int join;
00439 } compound;
00440 } u;
00441 struct list_head list;
00442 snd_config_t *father;
00443 int hop;
00444 };
00445
00446 struct filedesc {
00447 char *name;
00448 snd_input_t *in;
00449 unsigned int line, column;
00450 struct filedesc *next;
00451 };
00452
00453 #define LOCAL_ERROR (-0x68000000)
00454
00455 #define LOCAL_UNTERMINATED_STRING (LOCAL_ERROR - 0)
00456 #define LOCAL_UNTERMINATED_QUOTE (LOCAL_ERROR - 1)
00457 #define LOCAL_UNEXPECTED_CHAR (LOCAL_ERROR - 2)
00458 #define LOCAL_UNEXPECTED_EOF (LOCAL_ERROR - 3)
00459
00460 typedef struct {
00461 struct filedesc *current;
00462 int unget;
00463 int ch;
00464 } input_t;
00465
00466 static int safe_strtoll(const char *str, long long *val)
00467 {
00468 long long v;
00469 int endidx;
00470 if (!*str)
00471 return -EINVAL;
00472 errno = 0;
00473 if (sscanf(str, "%Li%n", &v, &endidx) < 1)
00474 return -EINVAL;
00475 if (str[endidx])
00476 return -EINVAL;
00477 *val = v;
00478 return 0;
00479 }
00480
00481 int safe_strtol(const char *str, long *val)
00482 {
00483 char *end;
00484 long v;
00485 if (!*str)
00486 return -EINVAL;
00487 errno = 0;
00488 v = strtol(str, &end, 0);
00489 if (errno)
00490 return -errno;
00491 if (*end)
00492 return -EINVAL;
00493 *val = v;
00494 return 0;
00495 }
00496
00497 static int safe_strtod(const char *str, double *val)
00498 {
00499 char *end;
00500 double v;
00501 char *saved_locale;
00502 char locstr[64];
00503 int err;
00504
00505 if (!*str)
00506 return -EINVAL;
00507 saved_locale = setlocale(LC_NUMERIC, NULL);
00508 if (saved_locale) {
00509 snprintf(locstr, sizeof(locstr), "%s", saved_locale);
00510 setlocale(LC_NUMERIC, "C");
00511 }
00512 errno = 0;
00513 v = strtod(str, &end);
00514 err = -errno;
00515 if (saved_locale)
00516 setlocale(LC_NUMERIC, locstr);
00517 if (err)
00518 return err;
00519 if (*end)
00520 return -EINVAL;
00521 *val = v;
00522 return 0;
00523 }
00524
00525 static int get_char(input_t *input)
00526 {
00527 int c;
00528 struct filedesc *fd;
00529 if (input->unget) {
00530 input->unget = 0;
00531 return input->ch;
00532 }
00533 again:
00534 fd = input->current;
00535 c = snd_input_getc(fd->in);
00536 switch (c) {
00537 case '\n':
00538 fd->column = 0;
00539 fd->line++;
00540 break;
00541 case '\t':
00542 fd->column += 8 - fd->column % 8;
00543 break;
00544 case EOF:
00545 if (fd->next) {
00546 snd_input_close(fd->in);
00547 free(fd->name);
00548 input->current = fd->next;
00549 free(fd);
00550 goto again;
00551 }
00552 return LOCAL_UNEXPECTED_EOF;
00553 default:
00554 fd->column++;
00555 break;
00556 }
00557 return (unsigned char)c;
00558 }
00559
00560 static void unget_char(int c, input_t *input)
00561 {
00562 assert(!input->unget);
00563 input->ch = c;
00564 input->unget = 1;
00565 }
00566
00567 static int get_delimstring(char **string, int delim, input_t *input);
00568
00569 static int get_char_skip_comments(input_t *input)
00570 {
00571 int c;
00572 while (1) {
00573 c = get_char(input);
00574 if (c == '<') {
00575 char *str;
00576 snd_input_t *in;
00577 struct filedesc *fd;
00578 int err = get_delimstring(&str, '>', input);
00579 if (err < 0)
00580 return err;
00581 if (!strncmp(str, "confdir:", 8)) {
00582 char *tmp = malloc(strlen("/share" "/alsa") + 1 + strlen(str + 8) + 1);
00583 if (tmp == NULL) {
00584 free(str);
00585 return -ENOMEM;
00586 }
00587 sprintf(tmp, "/share" "/alsa/%s", str + 8);
00588 free(str);
00589 str = tmp;
00590 }
00591 err = snd_input_stdio_open(&in, str, "r");
00592 if (err < 0) {
00593 free(str);
00594 return err;
00595 }
00596 fd = malloc(sizeof(*fd));
00597 if (!fd) {
00598 free(str);
00599 return -ENOMEM;
00600 }
00601 fd->name = str;
00602 fd->in = in;
00603 fd->next = input->current;
00604 fd->line = 1;
00605 fd->column = 0;
00606 input->current = fd;
00607 continue;
00608 }
00609 if (c != '#')
00610 break;
00611 while (1) {
00612 c = get_char(input);
00613 if (c < 0)
00614 return c;
00615 if (c == '\n')
00616 break;
00617 }
00618 }
00619
00620 return c;
00621 }
00622
00623
00624 static int get_nonwhite(input_t *input)
00625 {
00626 int c;
00627 while (1) {
00628 c = get_char_skip_comments(input);
00629 switch (c) {
00630 case ' ':
00631 case '\f':
00632 case '\t':
00633 case '\n':
00634 case '\r':
00635 break;
00636 default:
00637 return c;
00638 }
00639 }
00640 }
00641
00642 static int get_quotedchar(input_t *input)
00643 {
00644 int c;
00645 c = get_char(input);
00646 switch (c) {
00647 case 'n':
00648 return '\n';
00649 case 't':
00650 return '\t';
00651 case 'v':
00652 return '\v';
00653 case 'b':
00654 return '\b';
00655 case 'r':
00656 return '\r';
00657 case 'f':
00658 return '\f';
00659 case '0' ... '7':
00660 {
00661 int num = c - '0';
00662 int i = 1;
00663 do {
00664 c = get_char(input);
00665 if (c < '0' || c > '7') {
00666 unget_char(c, input);
00667 break;
00668 }
00669 num = num * 8 + c - '0';
00670 i++;
00671 } while (i < 3);
00672 return num;
00673 }
00674 default:
00675 return c;
00676 }
00677 }
00678
00679 #define LOCAL_STR_BUFSIZE 64
00680 struct local_string {
00681 char *buf;
00682 size_t alloc;
00683 size_t idx;
00684 char tmpbuf[LOCAL_STR_BUFSIZE];
00685 };
00686
00687 static void init_local_string(struct local_string *s)
00688 {
00689 memset(s, 0, sizeof(*s));
00690 s->buf = s->tmpbuf;
00691 s->alloc = LOCAL_STR_BUFSIZE;
00692 }
00693
00694 static void free_local_string(struct local_string *s)
00695 {
00696 if (s->buf != s->tmpbuf)
00697 free(s->buf);
00698 }
00699
00700 static int add_char_local_string(struct local_string *s, int c)
00701 {
00702 if (s->idx >= s->alloc) {
00703 size_t nalloc = s->alloc * 2;
00704 if (s->buf == s->tmpbuf) {
00705 s->buf = malloc(nalloc);
00706 if (s->buf == NULL)
00707 return -ENOMEM;
00708 memcpy(s->buf, s->tmpbuf, s->alloc);
00709 } else {
00710 char *ptr = realloc(s->buf, nalloc);
00711 if (ptr == NULL)
00712 return -ENOMEM;
00713 s->buf = ptr;
00714 }
00715 s->alloc = nalloc;
00716 }
00717 s->buf[s->idx++] = c;
00718 return 0;
00719 }
00720
00721 static char *copy_local_string(struct local_string *s)
00722 {
00723 char *dst = malloc(s->idx + 1);
00724 if (dst) {
00725 memcpy(dst, s->buf, s->idx);
00726 dst[s->idx] = '\0';
00727 }
00728 return dst;
00729 }
00730
00731 static int get_freestring(char **string, int id, input_t *input)
00732 {
00733 struct local_string str;
00734 int c;
00735
00736 init_local_string(&str);
00737 while (1) {
00738 c = get_char(input);
00739 if (c < 0) {
00740 if (c == LOCAL_UNEXPECTED_EOF) {
00741 *string = copy_local_string(&str);
00742 if (! *string)
00743 c = -ENOMEM;
00744 else
00745 c = 0;
00746 }
00747 break;
00748 }
00749 switch (c) {
00750 case '.':
00751 if (!id)
00752 break;
00753 case ' ':
00754 case '\f':
00755 case '\t':
00756 case '\n':
00757 case '\r':
00758 case '=':
00759 case ',':
00760 case ';':
00761 case '{':
00762 case '}':
00763 case '[':
00764 case ']':
00765 case '\'':
00766 case '"':
00767 case '\\':
00768 case '#':
00769 *string = copy_local_string(&str);
00770 if (! *string)
00771 c = -ENOMEM;
00772 else {
00773 unget_char(c, input);
00774 c = 0;
00775 }
00776 goto _out;
00777 default:
00778 break;
00779 }
00780 if (add_char_local_string(&str, c) < 0) {
00781 c = -ENOMEM;
00782 break;
00783 }
00784 }
00785 _out:
00786 free_local_string(&str);
00787 return c;
00788 }
00789
00790 static int get_delimstring(char **string, int delim, input_t *input)
00791 {
00792 struct local_string str;
00793 int c;
00794
00795 init_local_string(&str);
00796 while (1) {
00797 c = get_char(input);
00798 if (c < 0)
00799 break;
00800 if (c == '\\') {
00801 c = get_quotedchar(input);
00802 if (c < 0)
00803 break;
00804 if (c == '\n')
00805 continue;
00806 } else if (c == delim) {
00807 *string = copy_local_string(&str);
00808 if (! *string)
00809 c = -ENOMEM;
00810 else
00811 c = 0;
00812 break;
00813 }
00814 if (add_char_local_string(&str, c) < 0) {
00815 c = -ENOMEM;
00816 break;
00817 }
00818 }
00819 free_local_string(&str);
00820 return c;
00821 }
00822
00823
00824 static int get_string(char **string, int id, input_t *input)
00825 {
00826 int c = get_nonwhite(input), err;
00827 if (c < 0)
00828 return c;
00829 switch (c) {
00830 case '=':
00831 case ',':
00832 case ';':
00833 case '.':
00834 case '{':
00835 case '}':
00836 case '[':
00837 case ']':
00838 case '\\':
00839 return LOCAL_UNEXPECTED_CHAR;
00840 case '\'':
00841 case '"':
00842 err = get_delimstring(string, c, input);
00843 if (err < 0)
00844 return err;
00845 return 1;
00846 default:
00847 unget_char(c, input);
00848 err = get_freestring(string, id, input);
00849 if (err < 0)
00850 return err;
00851 return 0;
00852 }
00853 }
00854
00855 static int _snd_config_make(snd_config_t **config, char **id, snd_config_type_t type)
00856 {
00857 snd_config_t *n;
00858 assert(config);
00859 n = calloc(1, sizeof(*n));
00860 if (n == NULL) {
00861 if (*id) {
00862 free(*id);
00863 *id = NULL;
00864 }
00865 return -ENOMEM;
00866 }
00867 if (id) {
00868 n->id = *id;
00869 *id = NULL;
00870 }
00871 n->type = type;
00872 if (type == SND_CONFIG_TYPE_COMPOUND)
00873 INIT_LIST_HEAD(&n->u.compound.fields);
00874 *config = n;
00875 return 0;
00876 }
00877
00878
00879 static int _snd_config_make_add(snd_config_t **config, char **id,
00880 snd_config_type_t type, snd_config_t *father)
00881 {
00882 snd_config_t *n;
00883 int err;
00884 assert(father->type == SND_CONFIG_TYPE_COMPOUND);
00885 err = _snd_config_make(&n, id, type);
00886 if (err < 0)
00887 return err;
00888 n->father = father;
00889 list_add_tail(&n->list, &father->u.compound.fields);
00890 *config = n;
00891 return 0;
00892 }
00893
00894 static int _snd_config_search(snd_config_t *config,
00895 const char *id, int len, snd_config_t **result)
00896 {
00897 snd_config_iterator_t i, next;
00898 snd_config_for_each(i, next, config) {
00899 snd_config_t *n = snd_config_iterator_entry(i);
00900 if (len < 0) {
00901 if (strcmp(n->id, id) != 0)
00902 continue;
00903 } else if (strlen(n->id) != (size_t) len ||
00904 memcmp(n->id, id, (size_t) len) != 0)
00905 continue;
00906 if (result)
00907 *result = n;
00908 return 0;
00909 }
00910 return -ENOENT;
00911 }
00912
00913 static int parse_value(snd_config_t **_n, snd_config_t *father, input_t *input, char **id, int skip)
00914 {
00915 snd_config_t *n = *_n;
00916 char *s;
00917 int err;
00918
00919 err = get_string(&s, 0, input);
00920 if (err < 0)
00921 return err;
00922 if (skip) {
00923 free(s);
00924 return 0;
00925 }
00926 if (err == 0 && ((s[0] >= '0' && s[0] <= '9') || s[0] == '-')) {
00927 long long i;
00928 errno = 0;
00929 err = safe_strtoll(s, &i);
00930 if (err < 0) {
00931 double r;
00932 err = safe_strtod(s, &r);
00933 if (err >= 0) {
00934 free(s);
00935 if (n) {
00936 if (n->type != SND_CONFIG_TYPE_REAL) {
00937 SNDERR("%s is not a real", *id);
00938 return -EINVAL;
00939 }
00940 } else {
00941 err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_REAL, father);
00942 if (err < 0)
00943 return err;
00944 }
00945 n->u.real = r;
00946 *_n = n;
00947 return 0;
00948 }
00949 } else {
00950 free(s);
00951 if (n) {
00952 if (n->type != SND_CONFIG_TYPE_INTEGER && n->type != SND_CONFIG_TYPE_INTEGER64) {
00953 SNDERR("%s is not an integer", *id);
00954 return -EINVAL;
00955 }
00956 } else {
00957 if (i <= INT_MAX)
00958 err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER, father);
00959 else
00960 err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_INTEGER64, father);
00961 if (err < 0)
00962 return err;
00963 }
00964 if (n->type == SND_CONFIG_TYPE_INTEGER)
00965 n->u.integer = (long) i;
00966 else
00967 n->u.integer64 = i;
00968 *_n = n;
00969 return 0;
00970 }
00971 }
00972 if (n) {
00973 if (n->type != SND_CONFIG_TYPE_STRING) {
00974 SNDERR("%s is not a string", *id);
00975 free(s);
00976 return -EINVAL;
00977 }
00978 } else {
00979 err = _snd_config_make_add(&n, id, SND_CONFIG_TYPE_STRING, father);
00980 if (err < 0)
00981 return err;
00982 }
00983 free(n->u.string);
00984 n->u.string = s;
00985 *_n = n;
00986 return 0;
00987 }
00988
00989 static int parse_defs(snd_config_t *father, input_t *input, int skip, int override);
00990 static int parse_array_defs(snd_config_t *farther, input_t *input, int skip, int override);
00991
00992 static int parse_array_def(snd_config_t *father, input_t *input, int idx, int skip, int override)
00993 {
00994 char *id = NULL;
00995 int c;
00996 int err;
00997 snd_config_t *n = NULL;
00998
00999 if (!skip) {
01000 char static_id[12];
01001 snprintf(static_id, sizeof(static_id), "%i", idx);
01002 id = strdup(static_id);
01003 if (id == NULL)
01004 return -ENOMEM;
01005 }
01006 c = get_nonwhite(input);
01007 if (c < 0) {
01008 err = c;
01009 goto __end;
01010 }
01011 switch (c) {
01012 case '{':
01013 case '[':
01014 {
01015 char endchr;
01016 if (!skip) {
01017 if (n) {
01018 if (n->type != SND_CONFIG_TYPE_COMPOUND) {
01019 SNDERR("%s is not a compound", id);
01020 err = -EINVAL;
01021 goto __end;
01022 }
01023 } else {
01024 err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father);
01025 if (err < 0)
01026 goto __end;
01027 }
01028 }
01029 if (c == '{') {
01030 err = parse_defs(n, input, skip, override);
01031 endchr = '}';
01032 } else {
01033 err = parse_array_defs(n, input, skip, override);
01034 endchr = ']';
01035 }
01036 c = get_nonwhite(input);
01037 if (c < 0) {
01038 err = c;
01039 goto __end;
01040 }
01041 if (c != endchr) {
01042 if (n)
01043 snd_config_delete(n);
01044 err = LOCAL_UNEXPECTED_CHAR;
01045 goto __end;
01046 }
01047 break;
01048 }
01049 default:
01050 unget_char(c, input);
01051 err = parse_value(&n, father, input, &id, skip);
01052 if (err < 0)
01053 goto __end;
01054 break;
01055 }
01056 err = 0;
01057 __end:
01058 free(id);
01059 return err;
01060 }
01061
01062 static int parse_array_defs(snd_config_t *father, input_t *input, int skip, int override)
01063 {
01064 int idx = 0;
01065 while (1) {
01066 int c = get_nonwhite(input), err;
01067 if (c < 0)
01068 return c;
01069 unget_char(c, input);
01070 if (c == ']')
01071 return 0;
01072 err = parse_array_def(father, input, idx++, skip, override);
01073 if (err < 0)
01074 return err;
01075 }
01076 return 0;
01077 }
01078
01079 static int parse_def(snd_config_t *father, input_t *input, int skip, int override)
01080 {
01081 char *id = NULL;
01082 int c;
01083 int err;
01084 snd_config_t *n;
01085 enum {MERGE_CREATE, MERGE, OVERRIDE, DONT_OVERRIDE} mode;
01086 while (1) {
01087 c = get_nonwhite(input);
01088 if (c < 0)
01089 return c;
01090 switch (c) {
01091 case '+':
01092 mode = MERGE_CREATE;
01093 break;
01094 case '-':
01095 mode = MERGE;
01096 break;
01097 case '?':
01098 mode = DONT_OVERRIDE;
01099 break;
01100 case '!':
01101 mode = OVERRIDE;
01102 break;
01103 default:
01104 mode = !override ? MERGE_CREATE : OVERRIDE;
01105 unget_char(c, input);
01106 }
01107 err = get_string(&id, 1, input);
01108 if (err < 0)
01109 return err;
01110 c = get_nonwhite(input);
01111 if (c != '.')
01112 break;
01113 if (skip) {
01114 free(id);
01115 continue;
01116 }
01117 if (_snd_config_search(father, id, -1, &n) == 0) {
01118 if (mode == DONT_OVERRIDE) {
01119 skip = 1;
01120 free(id);
01121 continue;
01122 }
01123 if (mode != OVERRIDE) {
01124 if (n->type != SND_CONFIG_TYPE_COMPOUND) {
01125 SNDERR("%s is not a compound", id);
01126 return -EINVAL;
01127 }
01128 n->u.compound.join = 1;
01129 father = n;
01130 free(id);
01131 continue;
01132 }
01133 snd_config_delete(n);
01134 }
01135 if (mode == MERGE) {
01136 SNDERR("%s does not exists", id);
01137 err = -ENOENT;
01138 goto __end;
01139 }
01140 err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father);
01141 if (err < 0)
01142 goto __end;
01143 n->u.compound.join = 1;
01144 father = n;
01145 }
01146 if (c == '=') {
01147 c = get_nonwhite(input);
01148 if (c < 0)
01149 return c;
01150 }
01151 if (!skip) {
01152 if (_snd_config_search(father, id, -1, &n) == 0) {
01153 if (mode == DONT_OVERRIDE) {
01154 skip = 1;
01155 n = NULL;
01156 } else if (mode == OVERRIDE) {
01157 snd_config_delete(n);
01158 n = NULL;
01159 }
01160 } else {
01161 n = NULL;
01162 if (mode == MERGE) {
01163 SNDERR("%s does not exists", id);
01164 err = -ENOENT;
01165 goto __end;
01166 }
01167 }
01168 }
01169 switch (c) {
01170 case '{':
01171 case '[':
01172 {
01173 char endchr;
01174 if (!skip) {
01175 if (n) {
01176 if (n->type != SND_CONFIG_TYPE_COMPOUND) {
01177 SNDERR("%s is not a compound", id);
01178 err = -EINVAL;
01179 goto __end;
01180 }
01181 } else {
01182 err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, father);
01183 if (err < 0)
01184 goto __end;
01185 }
01186 }
01187 if (c == '{') {
01188 err = parse_defs(n, input, skip, override);
01189 endchr = '}';
01190 } else {
01191 err = parse_array_defs(n, input, skip, override);
01192 endchr = ']';
01193 }
01194 c = get_nonwhite(input);
01195 if (c != endchr) {
01196 if (n)
01197 snd_config_delete(n);
01198 err = LOCAL_UNEXPECTED_CHAR;
01199 goto __end;
01200 }
01201 break;
01202 }
01203 default:
01204 unget_char(c, input);
01205 err = parse_value(&n, father, input, &id, skip);
01206 if (err < 0)
01207 goto __end;
01208 break;
01209 }
01210 c = get_nonwhite(input);
01211 switch (c) {
01212 case ';':
01213 case ',':
01214 break;
01215 default:
01216 unget_char(c, input);
01217 }
01218 __end:
01219 free(id);
01220 return err;
01221 }
01222
01223 static int parse_defs(snd_config_t *father, input_t *input, int skip, int override)
01224 {
01225 int c, err;
01226 while (1) {
01227 c = get_nonwhite(input);
01228 if (c < 0)
01229 return c == LOCAL_UNEXPECTED_EOF ? 0 : c;
01230 unget_char(c, input);
01231 if (c == '}')
01232 return 0;
01233 err = parse_def(father, input, skip, override);
01234 if (err < 0)
01235 return err;
01236 }
01237 return 0;
01238 }
01239
01240 static void string_print(char *str, int id, snd_output_t *out)
01241 {
01242 unsigned char *p = (unsigned char *)str;
01243 if (!id) {
01244 switch (*p) {
01245 case 0:
01246 assert(0);
01247 break;
01248 case '0' ... '9':
01249 case '-':
01250 goto quoted;
01251 }
01252 }
01253 if (!*p) {
01254 snd_output_puts(out, "''");
01255 return;
01256 }
01257 loop:
01258 switch (*p) {
01259 case 0:
01260 goto nonquoted;
01261 case 1 ... 31:
01262 case 127 ... 255:
01263 case ' ':
01264 case '=':
01265 case ';':
01266 case ',':
01267 case '.':
01268 case '{':
01269 case '}':
01270 case '\'':
01271 case '"':
01272 goto quoted;
01273 default:
01274 p++;
01275 goto loop;
01276 }
01277 nonquoted:
01278 snd_output_puts(out, str);
01279 return;
01280 quoted:
01281 snd_output_putc(out, '\'');
01282 p = (unsigned char *)str;
01283 while (*p) {
01284 int c;
01285 c = *p;
01286 switch (c) {
01287 case '\n':
01288 snd_output_putc(out, '\\');
01289 snd_output_putc(out, 'n');
01290 break;
01291 case '\t':
01292 snd_output_putc(out, '\\');
01293 snd_output_putc(out, 't');
01294 break;
01295 case '\v':
01296 snd_output_putc(out, '\\');
01297 snd_output_putc(out, 'v');
01298 break;
01299 case '\b':
01300 snd_output_putc(out, '\\');
01301 snd_output_putc(out, 'b');
01302 break;
01303 case '\r':
01304 snd_output_putc(out, '\\');
01305 snd_output_putc(out, 'r');
01306 break;
01307 case '\f':
01308 snd_output_putc(out, '\\');
01309 snd_output_putc(out, 'f');
01310 break;
01311 case '\'':
01312 snd_output_putc(out, '\\');
01313 snd_output_putc(out, c);
01314 break;
01315 case 32 ... '\'' - 1:
01316 case '\'' + 1 ... 126:
01317 snd_output_putc(out, c);
01318 break;
01319 default:
01320 snd_output_printf(out, "\\%04o", c);
01321 break;
01322 }
01323 p++;
01324 }
01325 snd_output_putc(out, '\'');
01326 }
01327
01328 static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsigned int level, unsigned int joins);
01329
01330 static int _snd_config_save_leaf(snd_config_t *n, snd_output_t *out,
01331 unsigned int level)
01332 {
01333 int err;
01334 unsigned int k;
01335 switch (n->type) {
01336 case SND_CONFIG_TYPE_INTEGER:
01337 snd_output_printf(out, "%ld", n->u.integer);
01338 break;
01339 case SND_CONFIG_TYPE_INTEGER64:
01340 snd_output_printf(out, "%Ld", n->u.integer64);
01341 break;
01342 case SND_CONFIG_TYPE_REAL:
01343 snd_output_printf(out, "%-16g", n->u.real);
01344 break;
01345 case SND_CONFIG_TYPE_STRING:
01346 string_print(n->u.string, 0, out);
01347 break;
01348 case SND_CONFIG_TYPE_POINTER:
01349 SNDERR("cannot save runtime pointer type");
01350 return -EINVAL;
01351 case SND_CONFIG_TYPE_COMPOUND:
01352 snd_output_putc(out, '{');
01353 snd_output_putc(out, '\n');
01354 err = _snd_config_save_leaves(n, out, level + 1, 0);
01355 if (err < 0)
01356 return err;
01357 for (k = 0; k < level; ++k) {
01358 snd_output_putc(out, '\t');
01359 }
01360 snd_output_putc(out, '}');
01361 break;
01362 }
01363 return 0;
01364 }
01365
01366 static void id_print(snd_config_t *n, snd_output_t *out, unsigned int joins)
01367 {
01368 if (joins > 0) {
01369 assert(n->father);
01370 id_print(n->father, out, joins - 1);
01371 snd_output_putc(out, '.');
01372 }
01373 string_print(n->id, 1, out);
01374 }
01375
01376 static int _snd_config_save_leaves(snd_config_t *config, snd_output_t *out, unsigned int level, unsigned int joins)
01377 {
01378 unsigned int k;
01379 int err;
01380 snd_config_iterator_t i, next;
01381 assert(config && out);
01382 snd_config_for_each(i, next, config) {
01383 snd_config_t *n = snd_config_iterator_entry(i);
01384 if (n->type == SND_CONFIG_TYPE_COMPOUND &&
01385 n->u.compound.join) {
01386 err = _snd_config_save_leaves(n, out, level, joins + 1);
01387 if (err < 0)
01388 return err;
01389 continue;
01390 }
01391 for (k = 0; k < level; ++k) {
01392 snd_output_putc(out, '\t');
01393 }
01394 id_print(n, out, joins);
01395 #if 0
01396 snd_output_putc(out, ' ');
01397 snd_output_putc(out, '=');
01398 #endif
01399 snd_output_putc(out, ' ');
01400 err = _snd_config_save_leaf(n, out, level);
01401 if (err < 0)
01402 return err;
01403 #if 0
01404 snd_output_putc(out, ';');
01405 #endif
01406 snd_output_putc(out, '\n');
01407 }
01408 return 0;
01409 }
01410 #endif
01411
01412
01428 int snd_config_substitute(snd_config_t *dst, snd_config_t *src)
01429 {
01430 assert(dst && src);
01431 if (dst->type == SND_CONFIG_TYPE_COMPOUND &&
01432 src->type == SND_CONFIG_TYPE_COMPOUND) {
01433 snd_config_iterator_t i, next;
01434 snd_config_for_each(i, next, src) {
01435 snd_config_t *n = snd_config_iterator_entry(i);
01436 n->father = dst;
01437 }
01438 src->u.compound.fields.next->prev = &dst->u.compound.fields;
01439 src->u.compound.fields.prev->next = &dst->u.compound.fields;
01440 } else if (dst->type == SND_CONFIG_TYPE_COMPOUND) {
01441 int err;
01442 err = snd_config_delete_compound_members(dst);
01443 if (err < 0)
01444 return err;
01445 }
01446 free(dst->id);
01447 dst->id = src->id;
01448 dst->type = src->type;
01449 dst->u = src->u;
01450 free(src);
01451 return 0;
01452 }
01453
01461 int snd_config_get_type_ascii(const char *ascii, snd_config_type_t *type)
01462 {
01463 assert(ascii && type);
01464 if (!strcmp(ascii, "integer")) {
01465 *type = SND_CONFIG_TYPE_INTEGER;
01466 return 0;
01467 }
01468 if (!strcmp(ascii, "integer64")) {
01469 *type = SND_CONFIG_TYPE_INTEGER64;
01470 return 0;
01471 }
01472 if (!strcmp(ascii, "real")) {
01473 *type = SND_CONFIG_TYPE_REAL;
01474 return 0;
01475 }
01476 if (!strcmp(ascii, "string")) {
01477 *type = SND_CONFIG_TYPE_STRING;
01478 return 0;
01479 }
01480 if (!strcmp(ascii, "compound")) {
01481 *type = SND_CONFIG_TYPE_COMPOUND;
01482 return 0;
01483 }
01484 return -EINVAL;
01485 }
01486
01492 snd_config_type_t snd_config_get_type(const snd_config_t *config)
01493 {
01494 return config->type;
01495 }
01496
01507 int snd_config_get_id(const snd_config_t *config, const char **id)
01508 {
01509 assert(config && id);
01510 *id = config->id;
01511 return 0;
01512 }
01513
01520 int snd_config_set_id(snd_config_t *config, const char *id)
01521 {
01522 char *new_id;
01523 assert(config && id);
01524 new_id = strdup(id);
01525 if (!new_id)
01526 return -ENOMEM;
01527 free(config->id);
01528 config->id = new_id;
01529 return 0;
01530 }
01531
01540 int snd_config_top(snd_config_t **config)
01541 {
01542 assert(config);
01543 return _snd_config_make(config, 0, SND_CONFIG_TYPE_COMPOUND);
01544 }
01545
01546 static int snd_config_load1(snd_config_t *config, snd_input_t *in, int override)
01547 {
01548 int err;
01549 input_t input;
01550 struct filedesc *fd, *fd_next;
01551 assert(config && in);
01552 fd = malloc(sizeof(*fd));
01553 if (!fd)
01554 return -ENOMEM;
01555 fd->name = NULL;
01556 fd->in = in;
01557 fd->line = 1;
01558 fd->column = 0;
01559 fd->next = NULL;
01560 input.current = fd;
01561 input.unget = 0;
01562 err = parse_defs(config, &input, 0, override);
01563 fd = input.current;
01564 if (err < 0) {
01565 const char *str;
01566 switch (err) {
01567 case LOCAL_UNTERMINATED_STRING:
01568 str = "Unterminated string";
01569 err = -EINVAL;
01570 break;
01571 case LOCAL_UNTERMINATED_QUOTE:
01572 str = "Unterminated quote";
01573 err = -EINVAL;
01574 break;
01575 case LOCAL_UNEXPECTED_CHAR:
01576 str = "Unexpected char";
01577 err = -EINVAL;
01578 break;
01579 case LOCAL_UNEXPECTED_EOF:
01580 str = "Unexpected end of file";
01581 err = -EINVAL;
01582 break;
01583 default:
01584 str = strerror(-err);
01585 break;
01586 }
01587 SNDERR("%s:%d:%d:%s", fd->name ? fd->name : "_toplevel_", fd->line, fd->column, str);
01588 goto _end;
01589 }
01590 if (get_char(&input) != LOCAL_UNEXPECTED_EOF) {
01591 SNDERR("%s:%d:%d:Unexpected }", fd->name ? fd->name : "", fd->line, fd->column);
01592 err = -EINVAL;
01593 goto _end;
01594 }
01595 _end:
01596 while (fd->next) {
01597 fd_next = fd->next;
01598 snd_input_close(fd->in);
01599 free(fd->name);
01600 free(fd);
01601 fd = fd_next;
01602 }
01603 free(fd);
01604 return err;
01605 }
01606
01613 int snd_config_load(snd_config_t *config, snd_input_t *in)
01614 {
01615 return snd_config_load1(config, in, 0);
01616 }
01617
01624 int snd_config_load_override(snd_config_t *config, snd_input_t *in)
01625 {
01626 return snd_config_load1(config, in, 1);
01627 }
01628
01635 int snd_config_add(snd_config_t *father, snd_config_t *leaf)
01636 {
01637 snd_config_iterator_t i, next;
01638 assert(father && leaf);
01639 snd_config_for_each(i, next, father) {
01640 snd_config_t *n = snd_config_iterator_entry(i);
01641 if (strcmp(leaf->id, n->id) == 0)
01642 return -EEXIST;
01643 }
01644 leaf->father = father;
01645 list_add_tail(&leaf->list, &father->u.compound.fields);
01646 return 0;
01647 }
01648
01656 int snd_config_remove(snd_config_t *config)
01657 {
01658 assert(config);
01659 if (config->father)
01660 list_del(&config->list);
01661 config->father = NULL;
01662 return 0;
01663 }
01664
01674 int snd_config_delete(snd_config_t *config)
01675 {
01676 assert(config);
01677 switch (config->type) {
01678 case SND_CONFIG_TYPE_COMPOUND:
01679 {
01680 int err;
01681 struct list_head *i;
01682 i = config->u.compound.fields.next;
01683 while (i != &config->u.compound.fields) {
01684 struct list_head *nexti = i->next;
01685 snd_config_t *leaf = snd_config_iterator_entry(i);
01686 err = snd_config_delete(leaf);
01687 if (err < 0)
01688 return err;
01689 i = nexti;
01690 }
01691 break;
01692 }
01693 case SND_CONFIG_TYPE_STRING:
01694 free(config->u.string);
01695 break;
01696 default:
01697 break;
01698 }
01699 if (config->father)
01700 list_del(&config->list);
01701 free(config->id);
01702 free(config);
01703 return 0;
01704 }
01705
01713 int snd_config_delete_compound_members(const snd_config_t *config)
01714 {
01715 int err;
01716 struct list_head *i;
01717
01718 assert(config);
01719 if (config->type != SND_CONFIG_TYPE_COMPOUND)
01720 return -EINVAL;
01721 i = config->u.compound.fields.next;
01722 while (i != &config->u.compound.fields) {
01723 struct list_head *nexti = i->next;
01724 snd_config_t *leaf = snd_config_iterator_entry(i);
01725 err = snd_config_delete(leaf);
01726 if (err < 0)
01727 return err;
01728 i = nexti;
01729 }
01730 return 0;
01731 }
01732
01741 int snd_config_make(snd_config_t **config, const char *id,
01742 snd_config_type_t type)
01743 {
01744 char *id1;
01745 assert(config);
01746 if (id) {
01747 id1 = strdup(id);
01748 if (!id1)
01749 return -ENOMEM;
01750 } else
01751 id1 = NULL;
01752 return _snd_config_make(config, &id1, type);
01753 }
01754
01764 int snd_config_make_integer(snd_config_t **config, const char *id)
01765 {
01766 return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER);
01767 }
01768
01778 int snd_config_make_integer64(snd_config_t **config, const char *id)
01779 {
01780 return snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64);
01781 }
01782
01792 int snd_config_make_real(snd_config_t **config, const char *id)
01793 {
01794 return snd_config_make(config, id, SND_CONFIG_TYPE_REAL);
01795 }
01796
01806 int snd_config_make_string(snd_config_t **config, const char *id)
01807 {
01808 return snd_config_make(config, id, SND_CONFIG_TYPE_STRING);
01809 }
01810
01820 int snd_config_make_pointer(snd_config_t **config, const char *id)
01821 {
01822 return snd_config_make(config, id, SND_CONFIG_TYPE_POINTER);
01823 }
01824
01834 int snd_config_make_compound(snd_config_t **config, const char *id,
01835 int join)
01836 {
01837 int err;
01838 err = snd_config_make(config, id, SND_CONFIG_TYPE_COMPOUND);
01839 if (err < 0)
01840 return err;
01841 (*config)->u.compound.join = join;
01842 return 0;
01843 }
01844
01853 int snd_config_imake_integer(snd_config_t **config, const char *id, const long value)
01854 {
01855 int err;
01856
01857 err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER);
01858 if (err < 0)
01859 return err;
01860 (*config)->u.integer = value;
01861 return 0;
01862 }
01863
01872 int snd_config_imake_integer64(snd_config_t **config, const char *id, const long long value)
01873 {
01874 int err;
01875
01876 err = snd_config_make(config, id, SND_CONFIG_TYPE_INTEGER64);
01877 if (err < 0)
01878 return err;
01879 (*config)->u.integer64 = value;
01880 return 0;
01881 }
01882
01891 int snd_config_imake_real(snd_config_t **config, const char *id, const double value)
01892 {
01893 int err;
01894
01895 err = snd_config_make(config, id, SND_CONFIG_TYPE_REAL);
01896 if (err < 0)
01897 return err;
01898 (*config)->u.real = value;
01899 return 0;
01900 }
01901
01912 int snd_config_imake_string(snd_config_t **config, const char *id, const char *value)
01913 {
01914 int err;
01915 snd_config_t *tmp;
01916
01917 err = snd_config_make(&tmp, id, SND_CONFIG_TYPE_STRING);
01918 if (err < 0)
01919 return err;
01920 if (value) {
01921 tmp->u.string = strdup(value);
01922 if (!tmp->u.string) {
01923 snd_config_delete(tmp);
01924 return -ENOMEM;
01925 }
01926 } else {
01927 tmp->u.string = NULL;
01928 }
01929 *config = tmp;
01930 return 0;
01931 }
01932
01941 int snd_config_imake_pointer(snd_config_t **config, const char *id, const void *value)
01942 {
01943 int err;
01944
01945 err = snd_config_make(config, id, SND_CONFIG_TYPE_POINTER);
01946 if (err < 0)
01947 return err;
01948 (*config)->u.ptr = value;
01949 return 0;
01950 }
01951
01958 int snd_config_set_integer(snd_config_t *config, long value)
01959 {
01960 assert(config);
01961 if (config->type != SND_CONFIG_TYPE_INTEGER)
01962 return -EINVAL;
01963 config->u.integer = value;
01964 return 0;
01965 }
01966
01973 int snd_config_set_integer64(snd_config_t *config, long long value)
01974 {
01975 assert(config);
01976 if (config->type != SND_CONFIG_TYPE_INTEGER64)
01977 return -EINVAL;
01978 config->u.integer64 = value;
01979 return 0;
01980 }
01981
01988 int snd_config_set_real(snd_config_t *config, double value)
01989 {
01990 assert(config);
01991 if (config->type != SND_CONFIG_TYPE_REAL)
01992 return -EINVAL;
01993 config->u.real = value;
01994 return 0;
01995 }
01996
02006 int snd_config_set_string(snd_config_t *config, const char *value)
02007 {
02008 char *new_string;
02009 assert(config);
02010 if (config->type != SND_CONFIG_TYPE_STRING)
02011 return -EINVAL;
02012 if (value) {
02013 new_string = strdup(value);
02014 if (!new_string)
02015 return -ENOMEM;
02016 } else {
02017 new_string = NULL;
02018 }
02019 free(config->u.string);
02020 config->u.string = new_string;
02021 return 0;
02022 }
02023
02032 int snd_config_set_pointer(snd_config_t *config, const void *value)
02033 {
02034 assert(config);
02035 if (config->type != SND_CONFIG_TYPE_POINTER)
02036 return -EINVAL;
02037 config->u.ptr = value;
02038 return 0;
02039 }
02040
02050 int snd_config_set_ascii(snd_config_t *config, const char *ascii)
02051 {
02052 assert(config && ascii);
02053 switch (config->type) {
02054 case SND_CONFIG_TYPE_INTEGER:
02055 {
02056 long i;
02057 int err = safe_strtol(ascii, &i);
02058 if (err < 0)
02059 return err;
02060 config->u.integer = i;
02061 }
02062 break;
02063 case SND_CONFIG_TYPE_INTEGER64:
02064 {
02065 long long i;
02066 int err = safe_strtoll(ascii, &i);
02067 if (err < 0)
02068 return err;
02069 config->u.integer64 = i;
02070 }
02071 break;
02072 case SND_CONFIG_TYPE_REAL:
02073 {
02074 double d;
02075 int err = safe_strtod(ascii, &d);
02076 if (err < 0)
02077 return err;
02078 config->u.real = d;
02079 break;
02080 }
02081 case SND_CONFIG_TYPE_STRING:
02082 {
02083 char *ptr = strdup(ascii);
02084 if (ptr == NULL)
02085 return -ENOMEM;
02086 free(config->u.string);
02087 config->u.string = ptr;
02088 }
02089 break;
02090 default:
02091 return -EINVAL;
02092 }
02093 return 0;
02094 }
02095
02103 int snd_config_get_integer(const snd_config_t *config, long *ptr)
02104 {
02105 assert(config && ptr);
02106 if (config->type != SND_CONFIG_TYPE_INTEGER)
02107 return -EINVAL;
02108 *ptr = config->u.integer;
02109 return 0;
02110 }
02111
02119 int snd_config_get_integer64(const snd_config_t *config, long long *ptr)
02120 {
02121 assert(config && ptr);
02122 if (config->type != SND_CONFIG_TYPE_INTEGER64)
02123 return -EINVAL;
02124 *ptr = config->u.integer64;
02125 return 0;
02126 }
02127
02135 int snd_config_get_real(const snd_config_t *config, double *ptr)
02136 {
02137 assert(config && ptr);
02138 if (config->type != SND_CONFIG_TYPE_REAL)
02139 return -EINVAL;
02140 *ptr = config->u.real;
02141 return 0;
02142 }
02143
02154 int snd_config_get_ireal(const snd_config_t *config, double *ptr)
02155 {
02156 assert(config && ptr);
02157 if (config->type == SND_CONFIG_TYPE_REAL)
02158 *ptr = config->u.real;
02159 else if (config->type == SND_CONFIG_TYPE_INTEGER)
02160 *ptr = config->u.integer;
02161 else if (config->type == SND_CONFIG_TYPE_INTEGER64)
02162 *ptr = config->u.integer64;
02163 else
02164 return -EINVAL;
02165 return 0;
02166 }
02167
02178 int snd_config_get_string(const snd_config_t *config, const char **ptr)
02179 {
02180 assert(config && ptr);
02181 if (config->type != SND_CONFIG_TYPE_STRING)
02182 return -EINVAL;
02183 *ptr = config->u.string;
02184 return 0;
02185 }
02186
02194 int snd_config_get_pointer(const snd_config_t *config, const void **ptr)
02195 {
02196 assert(config && ptr);
02197 if (config->type != SND_CONFIG_TYPE_POINTER)
02198 return -EINVAL;
02199 *ptr = config->u.ptr;
02200 return 0;
02201 }
02202
02213 int snd_config_get_ascii(const snd_config_t *config, char **ascii)
02214 {
02215 assert(config && ascii);
02216 switch (config->type) {
02217 case SND_CONFIG_TYPE_INTEGER:
02218 {
02219 char res[12];
02220 int err;
02221 err = snprintf(res, sizeof(res), "%li", config->u.integer);
02222 if (err < 0 || err == sizeof(res)) {
02223 assert(0);
02224 return -ENOMEM;
02225 }
02226 *ascii = strdup(res);
02227 }
02228 break;
02229 case SND_CONFIG_TYPE_INTEGER64:
02230 {
02231 char res[32];
02232 int err;
02233 err = snprintf(res, sizeof(res), "%Li", config->u.integer64);
02234 if (err < 0 || err == sizeof(res)) {
02235 assert(0);
02236 return -ENOMEM;
02237 }
02238 *ascii = strdup(res);
02239 }
02240 break;
02241 case SND_CONFIG_TYPE_REAL:
02242 {
02243 char res[32];
02244 int err;
02245 err = snprintf(res, sizeof(res), "%-16g", config->u.real);
02246 if (err < 0 || err == sizeof(res)) {
02247 assert(0);
02248 return -ENOMEM;
02249 }
02250 if (res[0]) {
02251 char *ptr;
02252 ptr = res + strlen(res) - 1;
02253 while (ptr != res && *ptr == ' ')
02254 ptr--;
02255 if (*ptr != ' ')
02256 ptr++;
02257 *ptr = '\0';
02258 }
02259 *ascii = strdup(res);
02260 }
02261 break;
02262 case SND_CONFIG_TYPE_STRING:
02263 if (config->u.string)
02264 *ascii = strdup(config->u.string);
02265 else {
02266 *ascii = NULL;
02267 return 0;
02268 }
02269 break;
02270 default:
02271 return -EINVAL;
02272 }
02273 if (*ascii == NULL)
02274 return -ENOMEM;
02275 return 0;
02276 }
02277
02284 int snd_config_test_id(const snd_config_t *config, const char *id)
02285 {
02286 assert(config && id);
02287 return strcmp(config->id, id);
02288 }
02289
02296 int snd_config_save(snd_config_t *config, snd_output_t *out)
02297 {
02298 assert(config && out);
02299 if (config->type == SND_CONFIG_TYPE_COMPOUND)
02300 return _snd_config_save_leaves(config, out, 0, 0);
02301 else
02302 return _snd_config_save_leaf(config, out, 0);
02303 }
02304
02305
02306
02307
02308
02309 #ifndef DOC_HIDDEN
02310
02311 #define SND_CONFIG_SEARCH(config, key, result, extra_code) \
02312 { \
02313 snd_config_t *n; \
02314 int err; \
02315 const char *p; \
02316 assert(config && key); \
02317 while (1) { \
02318 if (config->type != SND_CONFIG_TYPE_COMPOUND) \
02319 return -ENOENT; \
02320 { extra_code ; } \
02321 p = strchr(key, '.'); \
02322 if (p) { \
02323 err = _snd_config_search(config, key, p - key, &n); \
02324 if (err < 0) \
02325 return err; \
02326 config = n; \
02327 key = p + 1; \
02328 } else \
02329 return _snd_config_search(config, key, -1, result); \
02330 } \
02331 }
02332
02333 #define SND_CONFIG_SEARCHA(root, config, key, result, fcn, extra_code) \
02334 { \
02335 snd_config_t *n; \
02336 int err; \
02337 const char *p; \
02338 assert(config && key); \
02339 while (1) { \
02340 if (config->type != SND_CONFIG_TYPE_COMPOUND) { \
02341 if (snd_config_get_string(config, &p) < 0) \
02342 return -ENOENT; \
02343 err = fcn(root, root, p, &config); \
02344 if (err < 0) \
02345 return err; \
02346 } \
02347 { extra_code ; } \
02348 p = strchr(key, '.'); \
02349 if (p) { \
02350 err = _snd_config_search(config, key, p - key, &n); \
02351 if (err < 0) \
02352 return err; \
02353 config = n; \
02354 key = p + 1; \
02355 } else \
02356 return _snd_config_search(config, key, -1, result); \
02357 } \
02358 }
02359
02360 #define SND_CONFIG_SEARCHV(config, result, fcn) \
02361 { \
02362 snd_config_t *n; \
02363 va_list arg; \
02364 assert(config); \
02365 va_start(arg, result); \
02366 while (1) { \
02367 const char *k = va_arg(arg, const char *); \
02368 int err; \
02369 if (!k) \
02370 break; \
02371 err = fcn(config, k, &n); \
02372 if (err < 0) \
02373 return err; \
02374 config = n; \
02375 } \
02376 va_end(arg); \
02377 if (result) \
02378 *result = n; \
02379 return 0; \
02380 }
02381
02382 #define SND_CONFIG_SEARCHVA(root, config, result, fcn) \
02383 { \
02384 snd_config_t *n; \
02385 va_list arg; \
02386 assert(config); \
02387 va_start(arg, result); \
02388 while (1) { \
02389 const char *k = va_arg(arg, const char *); \
02390 int err; \
02391 if (!k) \
02392 break; \
02393 err = fcn(root, config, k, &n); \
02394 if (err < 0) \
02395 return err; \
02396 config = n; \
02397 } \
02398 va_end(arg); \
02399 if (result) \
02400 *result = n; \
02401 return 0; \
02402 }
02403
02404 #define SND_CONFIG_SEARCH_ALIAS(config, base, key, result, fcn1, fcn2) \
02405 { \
02406 snd_config_t *res = NULL; \
02407 char *old_key; \
02408 int err, first = 1, maxloop = 1000; \
02409 assert(config && key); \
02410 while (1) { \
02411 old_key = strdup(key); \
02412 if (old_key == NULL) { \
02413 err = -ENOMEM; \
02414 res = NULL; \
02415 break; \
02416 } \
02417 err = first && base ? -EIO : fcn1(config, config, key, &res); \
02418 if (err < 0) { \
02419 if (!base) \
02420 break; \
02421 err = fcn2(config, config, &res, base, key, NULL); \
02422 if (err < 0) \
02423 break; \
02424 } \
02425 if (snd_config_get_string(res, &key) < 0) \
02426 break; \
02427 if (!first && (strcmp(key, old_key) == 0 || maxloop <= 0)) { \
02428 if (maxloop == 0) \
02429 SNDERR("maximum loop count reached (circular configuration?)"); \
02430 else \
02431 SNDERR("key %s refers to itself", key); \
02432 err = -EINVAL; \
02433 res = NULL; \
02434 break; \
02435 } \
02436 free(old_key); \
02437 first = 0; \
02438 maxloop--; \
02439 } \
02440 free(old_key); \
02441 if (!res) \
02442 return err; \
02443 if (result) \
02444 *result = res; \
02445 return 0; \
02446 }
02447
02448 #endif
02449
02458 int snd_config_search(snd_config_t *config, const char *key, snd_config_t **result)
02459 {
02460 SND_CONFIG_SEARCH(config, key, result, );
02461 }
02462
02473 int snd_config_searcha(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result)
02474 {
02475 SND_CONFIG_SEARCHA(root, config, key, result, snd_config_searcha, );
02476 }
02477
02486 int snd_config_searchv(snd_config_t *config, snd_config_t **result, ...)
02487 {
02488 SND_CONFIG_SEARCHV(config, result, snd_config_search);
02489 }
02490
02501 int snd_config_searchva(snd_config_t *root, snd_config_t *config, snd_config_t **result, ...)
02502 {
02503 SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha);
02504 }
02505
02519 int snd_config_search_alias(snd_config_t *config,
02520 const char *base, const char *key,
02521 snd_config_t **result)
02522 {
02523 SND_CONFIG_SEARCH_ALIAS(config, base, key, result,
02524 snd_config_searcha, snd_config_searchva);
02525 }
02526
02527 static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data);
02528
02537 int snd_config_search_hooks(snd_config_t *config, const char *key, snd_config_t **result)
02538 {
02539 SND_CONFIG_SEARCH(config, key, result, \
02540 err = snd_config_hooks(config, NULL); \
02541 if (err < 0) \
02542 return err; \
02543 );
02544 }
02545
02556 int snd_config_searcha_hooks(snd_config_t *root, snd_config_t *config, const char *key, snd_config_t **result)
02557 {
02558 SND_CONFIG_SEARCHA(root, config, key, result,
02559 snd_config_searcha_hooks,
02560 err = snd_config_hooks(config, NULL); \
02561 if (err < 0) \
02562 return err; \
02563 );
02564 }
02565
02576 int snd_config_searchva_hooks(snd_config_t *root, snd_config_t *config,
02577 snd_config_t **result, ...)
02578 {
02579 SND_CONFIG_SEARCHVA(root, config, result, snd_config_searcha_hooks);
02580 }
02581
02595 int snd_config_search_alias_hooks(snd_config_t *config,
02596 const char *base, const char *key,
02597 snd_config_t **result)
02598 {
02599 SND_CONFIG_SEARCH_ALIAS(config, base, key, result,
02600 snd_config_searcha_hooks,
02601 snd_config_searchva_hooks);
02602 }
02603
02605 #define ALSA_CONFIG_PATH_VAR "ALSA_CONFIG_PATH"
02606
02608 #define ALSA_CONFIG_PATH_DEFAULT "/share/alsa/alsa.conf"
02609
02614 snd_config_t *snd_config = NULL;
02615
02616 #ifndef DOC_HIDDEN
02617 struct finfo {
02618 char *name;
02619 dev_t dev;
02620 ino_t ino;
02621 time_t mtime;
02622 };
02623
02624 struct _snd_config_update {
02625 unsigned int count;
02626 struct finfo *finfo;
02627 };
02628 #endif
02629
02630 static snd_config_update_t *snd_config_global_update = NULL;
02631
02632 static int snd_config_hooks_call(snd_config_t *root, snd_config_t *config, snd_config_t *private_data)
02633 {
02634 void *h = NULL;
02635 snd_config_t *c, *func_conf = NULL;
02636 char *buf = NULL;
02637 const char *lib = NULL, *func_name = NULL;
02638 const char *str;
02639 int (*func)(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data) = NULL;
02640 int err;
02641
02642 err = snd_config_search(config, "func", &c);
02643 if (err < 0) {
02644 SNDERR("Field func is missing");
02645 return err;
02646 }
02647 err = snd_config_get_string(c, &str);
02648 if (err < 0) {
02649 SNDERR("Invalid type for field func");
02650 return err;
02651 }
02652 err = snd_config_search_definition(root, "hook_func", str, &func_conf);
02653 if (err >= 0) {
02654 snd_config_iterator_t i, next;
02655 if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) {
02656 SNDERR("Invalid type for func %s definition", str);
02657 goto _err;
02658 }
02659 snd_config_for_each(i, next, func_conf) {
02660 snd_config_t *n = snd_config_iterator_entry(i);
02661 const char *id = n->id;
02662 if (strcmp(id, "comment") == 0)
02663 continue;
02664 if (strcmp(id, "lib") == 0) {
02665 err = snd_config_get_string(n, &lib);
02666 if (err < 0) {
02667 SNDERR("Invalid type for %s", id);
02668 goto _err;
02669 }
02670 continue;
02671 }
02672 if (strcmp(id, "func") == 0) {
02673 err = snd_config_get_string(n, &func_name);
02674 if (err < 0) {
02675 SNDERR("Invalid type for %s", id);
02676 goto _err;
02677 }
02678 continue;
02679 }
02680 SNDERR("Unknown field %s", id);
02681 }
02682 }
02683 if (!func_name) {
02684 int len = 16 + strlen(str) + 1;
02685 buf = malloc(len);
02686 if (! buf) {
02687 err = -ENOMEM;
02688 goto _err;
02689 }
02690 snprintf(buf, len, "snd_config_hook_%s", str);
02691 buf[len-1] = '\0';
02692 func_name = buf;
02693 }
02694 h = snd_dlopen(lib, RTLD_NOW);
02695 func = h ? snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_HOOK)) : NULL;
02696 err = 0;
02697 if (!h) {
02698 SNDERR("Cannot open shared library %s", lib);
02699 err = -ENOENT;
02700 } else if (!func) {
02701 SNDERR("symbol %s is not defined inside %s", func_name, lib);
02702 snd_dlclose(h);
02703 err = -ENXIO;
02704 }
02705 _err:
02706 if (func_conf)
02707 snd_config_delete(func_conf);
02708 if (err >= 0) {
02709 snd_config_t *nroot;
02710 err = func(root, config, &nroot, private_data);
02711 if (err < 0)
02712 SNDERR("function %s returned error: %s", func_name, snd_strerror(err));
02713 snd_dlclose(h);
02714 if (err >= 0 && nroot)
02715 err = snd_config_substitute(root, nroot);
02716 }
02717 free(buf);
02718 if (err < 0)
02719 return err;
02720 return 0;
02721 }
02722
02723 static int snd_config_hooks(snd_config_t *config, snd_config_t *private_data)
02724 {
02725 snd_config_t *n;
02726 snd_config_iterator_t i, next;
02727 int err, hit, idx = 0;
02728
02729 if ((err = snd_config_search(config, "@hooks", &n)) < 0)
02730 return 0;
02731 snd_config_remove(n);
02732 do {
02733 hit = 0;
02734 snd_config_for_each(i, next, n) {
02735 snd_config_t *n = snd_config_iterator_entry(i);
02736 const char *id = n->id;
02737 long i;
02738 err = safe_strtol(id, &i);
02739 if (err < 0) {
02740 SNDERR("id of field %s is not and integer", id);
02741 err = -EINVAL;
02742 goto _err;
02743 }
02744 if (i == idx) {
02745 err = snd_config_hooks_call(config, n, private_data);
02746 if (err < 0)
02747 return err;
02748 idx++;
02749 hit = 1;
02750 }
02751 }
02752 } while (hit);
02753 err = 0;
02754 _err:
02755 snd_config_delete(n);
02756 return err;
02757 }
02758
02768 int snd_config_hook_load(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data)
02769 {
02770 snd_config_t *n;
02771 snd_config_iterator_t i, next;
02772 struct finfo *fi = NULL;
02773 int err, idx = 0, fi_count = 0, errors = 1, hit;
02774
02775 assert(root && dst);
02776 if ((err = snd_config_search(config, "errors", &n)) >= 0) {
02777 char *tmp;
02778 err = snd_config_get_ascii(n, &tmp);
02779 if (err < 0)
02780 return err;
02781 errors = snd_config_get_bool_ascii(tmp);
02782 free(tmp);
02783 if (errors < 0) {
02784 SNDERR("Invalid bool value in field errors");
02785 return errors;
02786 }
02787 }
02788 if ((err = snd_config_search(config, "files", &n)) < 0) {
02789 SNDERR("Unable to find field files in the pre-load section");
02790 return -EINVAL;
02791 }
02792 if ((err = snd_config_expand(n, root, NULL, private_data, &n)) < 0) {
02793 SNDERR("Unable to expand filenames in the pre-load section");
02794 return err;
02795 }
02796 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
02797 SNDERR("Invalid type for field filenames");
02798 goto _err;
02799 }
02800 snd_config_for_each(i, next, n) {
02801 snd_config_t *c = snd_config_iterator_entry(i);
02802 const char *str;
02803 if ((err = snd_config_get_string(c, &str)) < 0) {
02804 SNDERR("Field %s is not a string", c->id);
02805 goto _err;
02806 }
02807 fi_count++;
02808 }
02809 fi = calloc(fi_count, sizeof(*fi));
02810 if (fi == NULL) {
02811 err = -ENOMEM;
02812 goto _err;
02813 }
02814 do {
02815 hit = 0;
02816 snd_config_for_each(i, next, n) {
02817 snd_config_t *n = snd_config_iterator_entry(i);
02818 const char *id = n->id;
02819 long i;
02820 err = safe_strtol(id, &i);
02821 if (err < 0) {
02822 SNDERR("id of field %s is not and integer", id);
02823 err = -EINVAL;
02824 goto _err;
02825 }
02826 if (i == idx) {
02827 char *name;
02828 if ((err = snd_config_get_ascii(n, &name)) < 0)
02829 goto _err;
02830 if ((err = snd_user_file(name, &fi[idx].name)) < 0)
02831 fi[idx].name = name;
02832 else
02833 free(name);
02834 idx++;
02835 hit = 1;
02836 }
02837 }
02838 } while (hit);
02839 for (idx = 0; idx < fi_count; idx++) {
02840 snd_input_t *in;
02841 if (!errors && access(fi[idx].name, R_OK) < 0)
02842 continue;
02843 err = snd_input_stdio_open(&in, fi[idx].name, "r");
02844 if (err >= 0) {
02845 err = snd_config_load(root, in);
02846 snd_input_close(in);
02847 if (err < 0) {
02848 SNDERR("%s may be old or corrupted: consider to remove or fix it", fi[idx].name);
02849 goto _err;
02850 }
02851 } else {
02852 SNDERR("cannot access file %s", fi[idx].name);
02853 }
02854 }
02855 *dst = NULL;
02856 err = 0;
02857 _err:
02858 if (fi)
02859 for (idx = 0; idx < fi_count; idx++)
02860 free(fi[idx].name);
02861 free(fi);
02862 snd_config_delete(n);
02863 return err;
02864 }
02865 #ifndef DOC_HIDDEN
02866 SND_DLSYM_BUILD_VERSION(snd_config_hook_load, SND_CONFIG_DLSYM_VERSION_HOOK);
02867 #endif
02868
02869 #ifndef DOC_HIDDEN
02870 int snd_determine_driver(int card, char **driver);
02871 #endif
02872
02882 int snd_config_hook_load_for_all_cards(snd_config_t *root, snd_config_t *config, snd_config_t **dst, snd_config_t *private_data ATTRIBUTE_UNUSED)
02883 {
02884 int card = -1, err;
02885
02886 do {
02887 err = snd_card_next(&card);
02888 if (err < 0)
02889 return err;
02890 if (card >= 0) {
02891 snd_config_t *n, *private_data = NULL;
02892 const char *driver;
02893 char *fdriver = NULL;
02894 err = snd_determine_driver(card, &fdriver);
02895 if (err < 0)
02896 return err;
02897 if (snd_config_search(root, fdriver, &n) >= 0) {
02898 if (snd_config_get_string(n, &driver) < 0)
02899 continue;
02900 while (1) {
02901 char *s = strchr(driver, '.');
02902 if (s == NULL)
02903 break;
02904 driver = s + 1;
02905 }
02906 if (snd_config_search(root, driver, &n) >= 0)
02907 continue;
02908 } else {
02909 driver = fdriver;
02910 }
02911 err = snd_config_imake_string(&private_data, "string", driver);
02912 if (err < 0)
02913 goto __err;
02914 err = snd_config_hook_load(root, config, &n, private_data);
02915 __err:
02916 if (private_data)
02917 snd_config_delete(private_data);
02918 free(fdriver);
02919 if (err < 0)
02920 return err;
02921 }
02922 } while (card >= 0);
02923 *dst = NULL;
02924 return 0;
02925 }
02926 #ifndef DOC_HIDDEN
02927 SND_DLSYM_BUILD_VERSION(snd_config_hook_load_for_all_cards, SND_CONFIG_DLSYM_VERSION_HOOK);
02928 #endif
02929
02947 int snd_config_update_r(snd_config_t **_top, snd_config_update_t **_update, const char *cfgs)
02948 {
02949 int err;
02950 const char *configs, *c;
02951 unsigned int k;
02952 size_t l;
02953 snd_config_update_t *local;
02954 snd_config_update_t *update;
02955 snd_config_t *top;
02956
02957 assert(_top && _update);
02958 top = *_top;
02959 update = *_update;
02960 configs = cfgs;
02961 if (!configs) {
02962 configs = getenv(ALSA_CONFIG_PATH_VAR);
02963 if (!configs)
02964 configs = ALSA_CONFIG_PATH_DEFAULT;
02965 }
02966 for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) {
02967 c += l;
02968 k++;
02969 if (!*c)
02970 break;
02971 c++;
02972 }
02973 if (k == 0) {
02974 local = NULL;
02975 goto _reread;
02976 }
02977 local = (snd_config_update_t *)calloc(1, sizeof(snd_config_update_t));
02978 if (!local)
02979 return -ENOMEM;
02980 local->count = k;
02981 local->finfo = calloc(local->count, sizeof(struct finfo));
02982 if (!local->finfo) {
02983 free(local);
02984 return -ENOMEM;
02985 }
02986 for (k = 0, c = configs; (l = strcspn(c, ": ")) > 0; ) {
02987 char name[l + 1];
02988 memcpy(name, c, l);
02989 name[l] = 0;
02990 err = snd_user_file(name, &local->finfo[k].name);
02991 if (err < 0)
02992 goto _end;
02993 c += l;
02994 k++;
02995 if (!*c)
02996 break;
02997 c++;
02998 }
02999 for (k = 0; k < local->count; ++k) {
03000 struct stat st;
03001 struct finfo *lf = &local->finfo[k];
03002 if (stat(lf->name, &st) >= 0) {
03003 lf->dev = st.st_dev;
03004 lf->ino = st.st_ino;
03005 lf->mtime = st.st_mtime;
03006 } else {
03007 memmove(&local->finfo[k], &local->finfo[k+1], sizeof(struct finfo) * (local->count - k - 1));
03008 k--;
03009 local->count--;
03010 }
03011 }
03012 if (!update)
03013 goto _reread;
03014 if (local->count != update->count)
03015 goto _reread;
03016 for (k = 0; k < local->count; ++k) {
03017 struct finfo *lf = &local->finfo[k];
03018 struct finfo *uf = &update->finfo[k];
03019 if (strcmp(lf->name, uf->name) != 0 ||
03020 lf->dev != uf->dev ||
03021 lf->ino != uf->ino ||
03022 lf->mtime != uf->mtime)
03023 goto _reread;
03024 }
03025 err = 0;
03026
03027 _end:
03028 if (err < 0) {
03029 if (top) {
03030 snd_config_delete(top);
03031 *_top = NULL;
03032 }
03033 if (update) {
03034 snd_config_update_free(update);
03035 *_update = NULL;
03036 }
03037 }
03038 if (local)
03039 snd_config_update_free(local);
03040 return err;
03041
03042 _reread:
03043 *_top = NULL;
03044 *_update = NULL;
03045 if (update) {
03046 snd_config_update_free(update);
03047 update = NULL;
03048 }
03049 if (top) {
03050 snd_config_delete(top);
03051 top = NULL;
03052 }
03053 err = snd_config_top(&top);
03054 if (err < 0)
03055 goto _end;
03056 if (!local)
03057 goto _skip;
03058 for (k = 0; k < local->count; ++k) {
03059 snd_input_t *in;
03060 err = snd_input_stdio_open(&in, local->finfo[k].name, "r");
03061 if (err >= 0) {
03062 err = snd_config_load(top, in);
03063 snd_input_close(in);
03064 if (err < 0) {
03065 SNDERR("%s may be old or corrupted: consider to remove or fix it", local->finfo[k].name);
03066 goto _end;
03067 }
03068 } else {
03069 SNDERR("cannot access file %s", local->finfo[k].name);
03070 }
03071 }
03072 _skip:
03073 err = snd_config_hooks(top, NULL);
03074 if (err < 0) {
03075 SNDERR("hooks failed, removing configuration");
03076 goto _end;
03077 }
03078 *_top = top;
03079 *_update = local;
03080 return 1;
03081 }
03082
03083 static pthread_mutex_t snd_config_update_mutex = PTHREAD_MUTEX_INITIALIZER;
03084
03098 int snd_config_update(void)
03099 {
03100 int err;
03101
03102 pthread_mutex_lock(&snd_config_update_mutex);
03103 err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL);
03104 pthread_mutex_unlock(&snd_config_update_mutex);
03105 return err;
03106 }
03107
03113 int snd_config_update_free(snd_config_update_t *update)
03114 {
03115 unsigned int k;
03116
03117 assert(update);
03118 for (k = 0; k < update->count; k++)
03119 free(update->finfo[k].name);
03120 free(update->finfo);
03121 free(update);
03122 return 0;
03123 }
03124
03129 int snd_config_update_free_global(void)
03130 {
03131 pthread_mutex_lock(&snd_config_update_mutex);
03132 if (snd_config)
03133 snd_config_delete(snd_config);
03134 snd_config = NULL;
03135 if (snd_config_global_update)
03136 snd_config_update_free(snd_config_global_update);
03137 snd_config_global_update = NULL;
03138 pthread_mutex_unlock(&snd_config_update_mutex);
03139
03140
03141 snd_dlobj_cache_cleanup();
03142
03143 return 0;
03144 }
03145
03151 snd_config_iterator_t snd_config_iterator_first(const snd_config_t *node)
03152 {
03153 assert(node->type == SND_CONFIG_TYPE_COMPOUND);
03154 return node->u.compound.fields.next;
03155 }
03156
03165 snd_config_iterator_t snd_config_iterator_next(const snd_config_iterator_t iterator)
03166 {
03167 return iterator->next;
03168 }
03169
03175 snd_config_iterator_t snd_config_iterator_end(const snd_config_t *node)
03176 {
03177 assert(node->type == SND_CONFIG_TYPE_COMPOUND);
03178 return (const snd_config_iterator_t)&node->u.compound.fields;
03179 }
03180
03186 snd_config_t *snd_config_iterator_entry(const snd_config_iterator_t iterator)
03187 {
03188 return list_entry(iterator, snd_config_t, list);
03189 }
03190
03191 #ifndef DOC_HIDDEN
03192 typedef enum _snd_config_walk_pass {
03193 SND_CONFIG_WALK_PASS_PRE,
03194 SND_CONFIG_WALK_PASS_POST,
03195 SND_CONFIG_WALK_PASS_LEAF,
03196 } snd_config_walk_pass_t;
03197 #endif
03198
03199
03200
03201 #ifndef DOC_HIDDEN
03202 typedef int (*snd_config_walk_callback_t)(snd_config_t *src,
03203 snd_config_t *root,
03204 snd_config_t **dst,
03205 snd_config_walk_pass_t pass,
03206 snd_config_t *private_data);
03207 #endif
03208
03209 static int snd_config_walk(snd_config_t *src,
03210 snd_config_t *root,
03211 snd_config_t **dst,
03212 snd_config_walk_callback_t callback,
03213 snd_config_t *private_data)
03214 {
03215 int err;
03216 snd_config_iterator_t i, next;
03217
03218 switch (snd_config_get_type(src)) {
03219 case SND_CONFIG_TYPE_COMPOUND:
03220 err = callback(src, root, dst, SND_CONFIG_WALK_PASS_PRE, private_data);
03221 if (err <= 0)
03222 return err;
03223 snd_config_for_each(i, next, src) {
03224 snd_config_t *s = snd_config_iterator_entry(i);
03225 snd_config_t *d = NULL;
03226
03227 err = snd_config_walk(s, root, (dst && *dst) ? &d : NULL,
03228 callback, private_data);
03229 if (err < 0)
03230 goto _error;
03231 if (err && d) {
03232 err = snd_config_add(*dst, d);
03233 if (err < 0)
03234 goto _error;
03235 }
03236 }
03237 err = callback(src, root, dst, SND_CONFIG_WALK_PASS_POST, private_data);
03238 if (err <= 0) {
03239 _error:
03240 if (dst && *dst)
03241 snd_config_delete(*dst);
03242 }
03243 break;
03244 default:
03245 err = callback(src, root, dst, SND_CONFIG_WALK_PASS_LEAF, private_data);
03246 break;
03247 }
03248 return err;
03249 }
03250
03251 static int _snd_config_copy(snd_config_t *src,
03252 snd_config_t *root ATTRIBUTE_UNUSED,
03253 snd_config_t **dst,
03254 snd_config_walk_pass_t pass,
03255 snd_config_t *private_data ATTRIBUTE_UNUSED)
03256 {
03257 int err;
03258 const char *id = src->id;
03259 snd_config_type_t type = snd_config_get_type(src);
03260 switch (pass) {
03261 case SND_CONFIG_WALK_PASS_PRE:
03262 err = snd_config_make_compound(dst, id, src->u.compound.join);
03263 if (err < 0)
03264 return err;
03265 break;
03266 case SND_CONFIG_WALK_PASS_LEAF:
03267 err = snd_config_make(dst, id, type);
03268 if (err < 0)
03269 return err;
03270 switch (type) {
03271 case SND_CONFIG_TYPE_INTEGER:
03272 {
03273 long v;
03274 err = snd_config_get_integer(src, &v);
03275 assert(err >= 0);
03276 snd_config_set_integer(*dst, v);
03277 break;
03278 }
03279 case SND_CONFIG_TYPE_INTEGER64:
03280 {
03281 long long v;
03282 err = snd_config_get_integer64(src, &v);
03283 assert(err >= 0);
03284 snd_config_set_integer64(*dst, v);
03285 break;
03286 }
03287 case SND_CONFIG_TYPE_REAL:
03288 {
03289 double v;
03290 err = snd_config_get_real(src, &v);
03291 assert(err >= 0);
03292 snd_config_set_real(*dst, v);
03293 break;
03294 }
03295 case SND_CONFIG_TYPE_STRING:
03296 {
03297 const char *s;
03298 err = snd_config_get_string(src, &s);
03299 assert(err >= 0);
03300 err = snd_config_set_string(*dst, s);
03301 if (err < 0)
03302 return err;
03303 break;
03304 }
03305 default:
03306 assert(0);
03307 }
03308 break;
03309 default:
03310 break;
03311 }
03312 return 1;
03313 }
03314
03322 int snd_config_copy(snd_config_t **dst,
03323 snd_config_t *src)
03324 {
03325 return snd_config_walk(src, NULL, dst, _snd_config_copy, NULL);
03326 }
03327
03328 static int _snd_config_expand(snd_config_t *src,
03329 snd_config_t *root ATTRIBUTE_UNUSED,
03330 snd_config_t **dst,
03331 snd_config_walk_pass_t pass,
03332 snd_config_t *private_data)
03333 {
03334 int err;
03335 const char *id = src->id;
03336 snd_config_type_t type = snd_config_get_type(src);
03337 switch (pass) {
03338 case SND_CONFIG_WALK_PASS_PRE:
03339 {
03340 if (strcmp(id, "@args") == 0)
03341 return 0;
03342 err = snd_config_make_compound(dst, id, src->u.compound.join);
03343 if (err < 0)
03344 return err;
03345 break;
03346 }
03347 case SND_CONFIG_WALK_PASS_LEAF:
03348 switch (type) {
03349 case SND_CONFIG_TYPE_INTEGER:
03350 {
03351 long v;
03352 err = snd_config_get_integer(src, &v);
03353 assert(err >= 0);
03354 err = snd_config_imake_integer(dst, id, v);
03355 if (err < 0)
03356 return err;
03357 break;
03358 }
03359 case SND_CONFIG_TYPE_INTEGER64:
03360 {
03361 long long v;
03362 err = snd_config_get_integer64(src, &v);
03363 assert(err >= 0);
03364 err = snd_config_imake_integer64(dst, id, v);
03365 if (err < 0)
03366 return err;
03367 break;
03368 }
03369 case SND_CONFIG_TYPE_REAL:
03370 {
03371 double v;
03372 err = snd_config_get_real(src, &v);
03373 assert(err >= 0);
03374 err = snd_config_imake_real(dst, id, v);
03375 if (err < 0)
03376 return err;
03377 break;
03378 }
03379 case SND_CONFIG_TYPE_STRING:
03380 {
03381 const char *s;
03382 snd_config_t *val;
03383 snd_config_t *vars = private_data;
03384 snd_config_get_string(src, &s);
03385 if (*s == '$') {
03386 s++;
03387 if (snd_config_search(vars, s, &val) < 0)
03388 return 0;
03389 err = snd_config_copy(dst, val);
03390 if (err < 0)
03391 return err;
03392 err = snd_config_set_id(*dst, id);
03393 if (err < 0) {
03394 snd_config_delete(*dst);
03395 return err;
03396 }
03397 } else {
03398 err = snd_config_imake_string(dst, id, s);
03399 if (err < 0)
03400 return err;
03401 }
03402 break;
03403 }
03404 default:
03405 assert(0);
03406 }
03407 break;
03408 default:
03409 break;
03410 }
03411 return 1;
03412 }
03413
03414 static int _snd_config_evaluate(snd_config_t *src,
03415 snd_config_t *root,
03416 snd_config_t **dst ATTRIBUTE_UNUSED,
03417 snd_config_walk_pass_t pass,
03418 snd_config_t *private_data)
03419 {
03420 int err;
03421 if (pass == SND_CONFIG_WALK_PASS_PRE) {
03422 char *buf = NULL;
03423 const char *lib = NULL, *func_name = NULL;
03424 const char *str;
03425 int (*func)(snd_config_t **dst, snd_config_t *root,
03426 snd_config_t *src, snd_config_t *private_data) = NULL;
03427 void *h = NULL;
03428 snd_config_t *c, *func_conf = NULL;
03429 err = snd_config_search(src, "@func", &c);
03430 if (err < 0)
03431 return 1;
03432 err = snd_config_get_string(c, &str);
03433 if (err < 0) {
03434 SNDERR("Invalid type for @func");
03435 return err;
03436 }
03437 err = snd_config_search_definition(root, "func", str, &func_conf);
03438 if (err >= 0) {
03439 snd_config_iterator_t i, next;
03440 if (snd_config_get_type(func_conf) != SND_CONFIG_TYPE_COMPOUND) {
03441 SNDERR("Invalid type for func %s definition", str);
03442 goto _err;
03443 }
03444 snd_config_for_each(i, next, func_conf) {
03445 snd_config_t *n = snd_config_iterator_entry(i);
03446 const char *id = n->id;
03447 if (strcmp(id, "comment") == 0)
03448 continue;
03449 if (strcmp(id, "lib") == 0) {
03450 err = snd_config_get_string(n, &lib);
03451 if (err < 0) {
03452 SNDERR("Invalid type for %s", id);
03453 goto _err;
03454 }
03455 continue;
03456 }
03457 if (strcmp(id, "func") == 0) {
03458 err = snd_config_get_string(n, &func_name);
03459 if (err < 0) {
03460 SNDERR("Invalid type for %s", id);
03461 goto _err;
03462 }
03463 continue;
03464 }
03465 SNDERR("Unknown field %s", id);
03466 }
03467 }
03468 if (!func_name) {
03469 int len = 9 + strlen(str) + 1;
03470 buf = malloc(len);
03471 if (! buf) {
03472 err = -ENOMEM;
03473 goto _err;
03474 }
03475 snprintf(buf, len, "snd_func_%s", str);
03476 buf[len-1] = '\0';
03477 func_name = buf;
03478 }
03479 h = snd_dlopen(lib, RTLD_NOW);
03480 if (h)
03481 func = snd_dlsym(h, func_name, SND_DLSYM_VERSION(SND_CONFIG_DLSYM_VERSION_EVALUATE));
03482 err = 0;
03483 if (!h) {
03484 SNDERR("Cannot open shared library %s", lib);
03485 err = -ENOENT;
03486 goto _errbuf;
03487 } else if (!func) {
03488 SNDERR("symbol %s is not defined inside %s", func_name, lib);
03489 snd_dlclose(h);
03490 err = -ENXIO;
03491 goto _errbuf;
03492 }
03493 _err:
03494 if (func_conf)
03495 snd_config_delete(func_conf);
03496 if (err >= 0) {
03497 snd_config_t *eval;
03498 err = func(&eval, root, src, private_data);
03499 if (err < 0)
03500 SNDERR("function %s returned error: %s", func_name, snd_strerror(err));
03501 snd_dlclose(h);
03502 if (err >= 0 && eval) {
03503
03504
03505 err = snd_config_delete_compound_members(src);
03506 if (err >= 0)
03507 err = snd_config_substitute(src, eval);
03508 }
03509 }
03510 _errbuf:
03511 free(buf);
03512 if (err < 0)
03513 return err;
03514 return 0;
03515 }
03516 return 1;
03517 }
03518
03530 int snd_config_evaluate(snd_config_t *config, snd_config_t *root,
03531 snd_config_t *private_data, snd_config_t **result)
03532 {
03533
03534 assert(result == NULL);
03535 return snd_config_walk(config, root, result, _snd_config_evaluate, private_data);
03536 }
03537
03538 static int load_defaults(snd_config_t *subs, snd_config_t *defs)
03539 {
03540 snd_config_iterator_t d, dnext;
03541 snd_config_for_each(d, dnext, defs) {
03542 snd_config_t *def = snd_config_iterator_entry(d);
03543 snd_config_iterator_t f, fnext;
03544 if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND)
03545 continue;
03546 snd_config_for_each(f, fnext, def) {
03547 snd_config_t *fld = snd_config_iterator_entry(f);
03548 const char *id = fld->id;
03549 if (strcmp(id, "type") == 0)
03550 continue;
03551 if (strcmp(id, "default") == 0) {
03552 snd_config_t *deflt;
03553 int err;
03554 err = snd_config_copy(&deflt, fld);
03555 if (err < 0)
03556 return err;
03557 err = snd_config_set_id(deflt, def->id);
03558 if (err < 0) {
03559 snd_config_delete(deflt);
03560 return err;
03561 }
03562 err = snd_config_add(subs, deflt);
03563 if (err < 0) {
03564 snd_config_delete(deflt);
03565 return err;
03566 }
03567 continue;
03568 }
03569 SNDERR("Unknown field %s", id);
03570 return -EINVAL;
03571 }
03572 }
03573 return 0;
03574 }
03575
03576 static void skip_blank(const char **ptr)
03577 {
03578 while (1) {
03579 switch (**ptr) {
03580 case ' ':
03581 case '\f':
03582 case '\t':
03583 case '\n':
03584 case '\r':
03585 break;
03586 default:
03587 return;
03588 }
03589 (*ptr)++;
03590 }
03591 }
03592
03593 static int parse_char(const char **ptr)
03594 {
03595 int c;
03596 assert(**ptr == '\\');
03597 (*ptr)++;
03598 c = **ptr;
03599 switch (c) {
03600 case 'n':
03601 c = '\n';
03602 break;
03603 case 't':
03604 c = '\t';
03605 break;
03606 case 'v':
03607 c = '\v';
03608 break;
03609 case 'b':
03610 c = '\b';
03611 break;
03612 case 'r':
03613 c = '\r';
03614 break;
03615 case 'f':
03616 c = '\f';
03617 break;
03618 case '0' ... '7':
03619 {
03620 int num = c - '0';
03621 int i = 1;
03622 (*ptr)++;
03623 do {
03624 c = **ptr;
03625 if (c < '0' || c > '7')
03626 break;
03627 num = num * 8 + c - '0';
03628 i++;
03629 (*ptr)++;
03630 } while (i < 3);
03631 return num;
03632 }
03633 default:
03634 break;
03635 }
03636 (*ptr)++;
03637 return c;
03638 }
03639
03640 static int parse_id(const char **ptr)
03641 {
03642 if (!**ptr)
03643 return -EINVAL;
03644 while (1) {
03645 switch (**ptr) {
03646 case '\f':
03647 case '\t':
03648 case '\n':
03649 case '\r':
03650 case ',':
03651 case '=':
03652 case '\0':
03653 return 0;
03654 default:
03655 break;
03656 }
03657 (*ptr)++;
03658 }
03659 }
03660
03661 static int parse_string(const char **ptr, char **val)
03662 {
03663 const size_t bufsize = 256;
03664 char _buf[bufsize];
03665 char *buf = _buf;
03666 size_t alloc = bufsize;
03667 char delim = **ptr;
03668 size_t idx = 0;
03669 (*ptr)++;
03670 while (1) {
03671 int c = **ptr;
03672 switch (c) {
03673 case '\0':
03674 SNDERR("Unterminated string");
03675 return -EINVAL;
03676 case '\\':
03677 c = parse_char(ptr);
03678 if (c < 0)
03679 return c;
03680 break;
03681 default:
03682 (*ptr)++;
03683 if (c == delim) {
03684 *val = malloc(idx + 1);
03685 if (!*val)
03686 return -ENOMEM;
03687 memcpy(*val, buf, idx);
03688 (*val)[idx] = 0;
03689 if (alloc > bufsize)
03690 free(buf);
03691 return 0;
03692 }
03693 }
03694 if (idx >= alloc) {
03695 size_t old_alloc = alloc;
03696 alloc *= 2;
03697 if (old_alloc == bufsize) {
03698 buf = malloc(alloc);
03699 memcpy(buf, _buf, old_alloc);
03700 } else {
03701 buf = realloc(buf, alloc);
03702 }
03703 if (!buf)
03704 return -ENOMEM;
03705 }
03706 buf[idx++] = c;
03707 }
03708 }
03709
03710
03711
03712 static int parse_arg(const char **ptr, unsigned int *varlen, char **val)
03713 {
03714 const char *str;
03715 int err, vallen;
03716 skip_blank(ptr);
03717 str = *ptr;
03718 if (*str == '"' || *str == '\'') {
03719 err = parse_string(ptr, val);
03720 if (err < 0)
03721 return err;
03722 *varlen = 0;
03723 return 0;
03724 }
03725 err = parse_id(ptr);
03726 if (err < 0)
03727 return err;
03728 vallen = *ptr - str;
03729 skip_blank(ptr);
03730 if (**ptr != '=') {
03731 *varlen = 0;
03732 goto _value;
03733 }
03734 *varlen = vallen;
03735 (*ptr)++;
03736 skip_blank(ptr);
03737 str = *ptr;
03738 if (*str == '"' || *str == '\'') {
03739 err = parse_string(ptr, val);
03740 if (err < 0)
03741 return err;
03742 return 0;
03743 }
03744 err = parse_id(ptr);
03745 if (err < 0)
03746 return err;
03747 vallen = *ptr - str;
03748 _value:
03749 *val = malloc(vallen + 1);
03750 if (!*val)
03751 return -ENOMEM;
03752 memcpy(*val, str, vallen);
03753 (*val)[vallen] = 0;
03754 return 0;
03755 }
03756
03757
03758
03759
03760
03761
03762 static int parse_args(snd_config_t *subs, const char *str, snd_config_t *defs)
03763 {
03764 int err;
03765 int arg = 0;
03766 if (str == NULL)
03767 return 0;
03768 skip_blank(&str);
03769 if (!*str)
03770 return 0;
03771 if (*str == '{') {
03772 int len = strlen(str);
03773 snd_input_t *input;
03774 snd_config_iterator_t i, next;
03775 while (1) {
03776 switch (str[--len]) {
03777 case ' ':
03778 case '\f':
03779 case '\t':
03780 case '\n':
03781 case '\r':
03782 continue;
03783 default:
03784 break;
03785 }
03786 break;
03787 }
03788 if (str[len] != '}')
03789 return -EINVAL;
03790 err = snd_input_buffer_open(&input, str + 1, len - 1);
03791 if (err < 0)
03792 return err;
03793 err = snd_config_load_override(subs, input);
03794 snd_input_close(input);
03795 if (err < 0)
03796 return err;
03797 snd_config_for_each(i, next, subs) {
03798 snd_config_t *n = snd_config_iterator_entry(i);
03799 snd_config_t *d;
03800 const char *id = n->id;
03801 err = snd_config_search(defs, id, &d);
03802 if (err < 0) {
03803 SNDERR("Unknown parameter %s", id);
03804 return err;
03805 }
03806 }
03807 return 0;
03808 }
03809
03810 while (1) {
03811 char buf[256];
03812 const char *var = buf;
03813 unsigned int varlen;
03814 snd_config_t *def, *sub, *typ;
03815 const char *new = str;
03816 const char *tmp;
03817 char *val = NULL;
03818 err = parse_arg(&new, &varlen, &val);
03819 if (err < 0)
03820 goto _err;
03821 if (varlen > 0) {
03822 assert(varlen < sizeof(buf));
03823 memcpy(buf, str, varlen);
03824 buf[varlen] = 0;
03825 } else {
03826 sprintf(buf, "%d", arg);
03827 }
03828 err = snd_config_search_alias(defs, NULL, var, &def);
03829 if (err < 0) {
03830 SNDERR("Unknown parameter %s", var);
03831 goto _err;
03832 }
03833 if (snd_config_get_type(def) != SND_CONFIG_TYPE_COMPOUND) {
03834 SNDERR("Parameter %s definition is not correct", var);
03835 err = -EINVAL;
03836 goto _err;
03837 }
03838 var = def->id;
03839 err = snd_config_search(subs, var, &sub);
03840 if (err >= 0)
03841 snd_config_delete(sub);
03842 err = snd_config_search(def, "type", &typ);
03843 if (err < 0) {
03844 _invalid_type:
03845 SNDERR("Parameter %s definition is missing a valid type info", var);
03846 goto _err;
03847 }
03848 err = snd_config_get_string(typ, &tmp);
03849 if (err < 0)
03850 goto _invalid_type;
03851 if (strcmp(tmp, "integer") == 0) {
03852 long v;
03853 err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER);
03854 if (err < 0)
03855 goto _err;
03856 err = safe_strtol(val, &v);
03857 if (err < 0) {
03858 SNDERR("Parameter %s must be an integer", var);
03859 goto _err;
03860 }
03861 err = snd_config_set_integer(sub, v);
03862 if (err < 0)
03863 goto _err;
03864 } else if (strcmp(tmp, "integer64") == 0) {
03865 long long v;
03866 err = snd_config_make(&sub, var, SND_CONFIG_TYPE_INTEGER64);
03867 if (err < 0)
03868 goto _err;
03869 err = safe_strtoll(val, &v);
03870 if (err < 0) {
03871 SNDERR("Parameter %s must be an integer", var);
03872 goto _err;
03873 }
03874 err = snd_config_set_integer64(sub, v);
03875 if (err < 0)
03876 goto _err;
03877 } else if (strcmp(tmp, "real") == 0) {
03878 double v;
03879 err = snd_config_make(&sub, var, SND_CONFIG_TYPE_REAL);
03880 if (err < 0)
03881 goto _err;
03882 err = safe_strtod(val, &v);
03883 if (err < 0) {
03884 SNDERR("Parameter %s must be a real", var);
03885 goto _err;
03886 }
03887 err = snd_config_set_real(sub, v);
03888 if (err < 0)
03889 goto _err;
03890 } else if (strcmp(tmp, "string") == 0) {
03891 err = snd_config_make(&sub, var, SND_CONFIG_TYPE_STRING);
03892 if (err < 0)
03893 goto _err;
03894 err = snd_config_set_string(sub, val);
03895 if (err < 0)
03896 goto _err;
03897 } else {
03898 err = -EINVAL;
03899 goto _invalid_type;
03900 }
03901 err = snd_config_set_id(sub, var);
03902 if (err < 0)
03903 goto _err;
03904 err = snd_config_add(subs, sub);
03905 if (err < 0) {
03906 _err:
03907 free(val);
03908 return err;
03909 }
03910 free(val);
03911 if (!*new)
03912 break;
03913 if (*new != ',')
03914 return -EINVAL;
03915 str = new + 1;
03916 arg++;
03917 }
03918 return 0;
03919 }
03920
03931 int snd_config_expand(snd_config_t *config, snd_config_t *root, const char *args,
03932 snd_config_t *private_data, snd_config_t **result)
03933 {
03934 int err;
03935 snd_config_t *defs, *subs = NULL, *res;
03936 err = snd_config_search(config, "@args", &defs);
03937 if (err < 0) {
03938 err = snd_config_copy(&res, config);
03939 if (err < 0)
03940 return err;
03941 } else {
03942 err = snd_config_top(&subs);
03943 if (err < 0)
03944 return err;
03945 err = load_defaults(subs, defs);
03946 if (err < 0) {
03947 SNDERR("Load defaults error: %s", snd_strerror(err));
03948 goto _end;
03949 }
03950 err = parse_args(subs, args, defs);
03951 if (err < 0) {
03952 SNDERR("Parse arguments error: %s", snd_strerror(err));
03953 goto _end;
03954 }
03955 err = snd_config_evaluate(subs, root, private_data, NULL);
03956 if (err < 0) {
03957 SNDERR("Args evaluate error: %s", snd_strerror(err));
03958 goto _end;
03959 }
03960 err = snd_config_walk(config, root, &res, _snd_config_expand, subs);
03961 if (err < 0) {
03962 SNDERR("Expand error (walk): %s", snd_strerror(err));
03963 goto _end;
03964 }
03965 }
03966 err = snd_config_evaluate(res, root, private_data, NULL);
03967 if (err < 0) {
03968 SNDERR("Evaluate error: %s", snd_strerror(err));
03969 snd_config_delete(res);
03970 goto _end;
03971 }
03972 *result = res;
03973 err = 1;
03974 _end:
03975 if (subs)
03976 snd_config_delete(subs);
03977 return err;
03978 }
03979
03996 int snd_config_search_definition(snd_config_t *config,
03997 const char *base, const char *name,
03998 snd_config_t **result)
03999 {
04000 snd_config_t *conf;
04001 char *key;
04002 const char *args = strchr(name, ':');
04003 int err;
04004 if (args) {
04005 args++;
04006 key = alloca(args - name);
04007 memcpy(key, name, args - name - 1);
04008 key[args - name - 1] = '\0';
04009 } else {
04010 key = (char *) name;
04011 }
04012
04013
04014
04015
04016 err = snd_config_search_alias_hooks(config, strchr(key, '.') ? NULL : base, key, &conf);
04017 if (err < 0)
04018 return err;
04019 return snd_config_expand(conf, config, args, NULL, result);
04020 }
04021
04022 #ifndef DOC_HIDDEN
04023 void snd_config_set_hop(snd_config_t *conf, int hop)
04024 {
04025 conf->hop = hop;
04026 }
04027
04028 int snd_config_check_hop(snd_config_t *conf)
04029 {
04030 if (conf) {
04031 if (conf->hop >= SND_CONF_MAX_HOPS) {
04032 SYSERR("Too many definition levels (looped?)\n");
04033 return -EINVAL;
04034 }
04035 return conf->hop;
04036 }
04037 return 0;
04038 }
04039 #endif
04040
04041 #if 0
04042
04043 void _snd_config_end(void) __attribute__ ((destructor));
04044
04045 static void _snd_config_end(void)
04046 {
04047 int k;
04048 if (snd_config)
04049 snd_config_delete(snd_config);
04050 snd_config = 0;
04051 for (k = 0; k < files_info_count; ++k)
04052 free(files_info[k].name);
04053 free(files_info);
04054 files_info = NULL;
04055 files_info_count = 0;
04056 }
04057 #endif