split polypcore/util.[ch] into polypcore/core-util.[ch] and polyp/util.[ch]
[profile/ivi/pulseaudio.git] / src / polypcore / conf-parser.c
1 /* $Id$ */
2
3 /***
4   This file is part of polypaudio.
5
6   polypaudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2 of the License,
9   or (at your option) any later version.
10
11   polypaudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with polypaudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <assert.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <errno.h>
30
31 #include <polyp/xmalloc.h>
32
33 #include <polypcore/log.h>
34 #include <polypcore/core-util.h>
35
36 #include "conf-parser.h"
37
38 #define WHITESPACE " \t\n"
39 #define COMMENTS "#;\n"
40
41 /* Run the user supplied parser for an assignment */
42 static int next_assignment(const char *filename, unsigned line, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) {
43     assert(filename && t && lvalue && rvalue);
44     
45     for (; t->parse; t++)
46         if (!strcmp(lvalue, t->lvalue))
47             return t->parse(filename, line, lvalue, rvalue, t->data, userdata);
48
49     pa_log(__FILE__": [%s:%u] Unknown lvalue '%s'.", filename, line, lvalue);
50     
51     return -1;
52 }
53
54 /* Returns non-zero when c is contained in s */
55 static int in_string(char c, const char *s) {
56     assert(s);
57     
58     for (; *s; s++)
59         if (*s == c)
60             return 1;
61     
62     return 0;
63 }
64
65 /* Remove all whitepsapce from the beginning and the end of *s. *s may
66  * be modified. */
67 static char *strip(char *s) {
68     char *b = s+strspn(s, WHITESPACE);
69     char *e, *l = NULL;
70
71     for (e = b; *e; e++)
72         if (!in_string(*e, WHITESPACE))
73             l = e;
74
75     if (l)
76         *(l+1) = 0;
77
78     return b;
79 }
80
81 /* Parse a variable assignment line */
82 static int parse_line(const char *filename, unsigned line, const pa_config_item *t, char *l, void *userdata) {
83     char *e, *c, *b = l+strspn(l, WHITESPACE);
84
85     if ((c = strpbrk(b, COMMENTS)))
86         *c = 0;
87     
88     if (!*b)
89         return 0;
90
91     if (!(e = strchr(b, '='))) {
92         pa_log(__FILE__": [%s:%u] Missing '='.", filename, line);
93         return -1;
94     }
95
96     *e = 0;
97     e++;
98
99     return next_assignment(filename, line, t, strip(b), strip(e), userdata);
100 }
101
102 /* Go through the file and parse each line */
103 int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata) {
104     int r = -1;
105     unsigned line = 0;
106     int do_close = !f;
107     assert(filename && t);
108     
109     if (!f && !(f = fopen(filename, "r"))) {
110         if (errno == ENOENT) {
111             r = 0;
112             goto finish;
113         }
114         
115         pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, strerror(errno));
116         goto finish;
117     }
118
119     while (!feof(f)) {
120         char l[256];
121         if (!fgets(l, sizeof(l), f)) {
122             if (feof(f))
123                 break;
124             
125             pa_log(__FILE__": WARNING: failed to read configuration file '%s': %s", filename, strerror(errno));
126             goto finish;
127         }
128             
129         if (parse_line(filename, ++line, t,  l, userdata) < 0)
130             goto finish;
131     }
132     
133     r = 0;
134     
135 finish:
136
137     if (do_close && f)
138         fclose(f);
139     
140     return r;
141 }
142
143 int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
144     int *i = data;
145     int32_t k;
146     assert(filename && lvalue && rvalue && data);
147
148     if (pa_atoi(rvalue, &k) < 0) {
149         pa_log(__FILE__": [%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
150         return -1;
151     }
152     
153     *i = (int) k;
154     return 0; 
155 }
156
157 int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
158     int *b = data, k;
159     assert(filename && lvalue && rvalue && data);
160     
161     if ((k = pa_parse_boolean(rvalue)) < 0) {
162         pa_log(__FILE__": [%s:%u] Failed to parse boolean value: %s", filename, line, rvalue);
163         return -1;
164     }
165     
166     *b = k;
167     
168     return 0;
169 }
170
171 int pa_config_parse_string(const char *filename, PA_GCC_UNUSED unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
172     char **s = data;
173     assert(filename && lvalue && rvalue && data);
174
175     pa_xfree(*s);
176     *s = *rvalue ? pa_xstrdup(rvalue) : NULL;
177     return 0;
178 }