2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
6 PulseAudio 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.1 of the License,
9 or (at your option) any later version.
11 PulseAudio 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.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <pulse/xmalloc.h>
32 #include <pulsecore/core-error.h>
33 #include <pulsecore/log.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/macro.h>
37 #include "conf-parser.h"
39 #define WHITESPACE " \t\n"
40 #define COMMENTS "#;\n"
42 /* Run the user supplied parser for an assignment */
43 static int normal_assignment(pa_config_parser_state
*state
) {
44 const pa_config_item
*item
;
48 for (item
= state
->item_table
; item
->parse
; item
++) {
50 if (item
->lvalue
&& !pa_streq(state
->lvalue
, item
->lvalue
))
53 if (item
->section
&& !state
->section
)
56 if (item
->section
&& !pa_streq(state
->section
, item
->section
))
59 state
->data
= item
->data
;
61 return item
->parse(state
);
64 pa_log("[%s:%u] Unknown lvalue '%s' in section '%s'.", state
->filename
, state
->lineno
, state
->lvalue
, pa_strna(state
->section
));
69 /* Parse a proplist entry. */
70 static int proplist_assignment(pa_config_parser_state
*state
) {
72 pa_assert(state
->proplist
);
74 if (pa_proplist_sets(state
->proplist
, state
->lvalue
, state
->rvalue
) < 0) {
75 pa_log("[%s:%u] Failed to parse a proplist entry: %s = %s", state
->filename
, state
->lineno
, state
->lvalue
, state
->rvalue
);
82 /* Parse a variable assignment line */
83 static int parse_line(pa_config_parser_state
*state
) {
86 state
->lvalue
= state
->buf
+ strspn(state
->buf
, WHITESPACE
);
88 if ((c
= strpbrk(state
->lvalue
, COMMENTS
)))
94 if (pa_startswith(state
->lvalue
, ".include ")) {
95 char *path
= NULL
, *fn
;
98 fn
= pa_strip(state
->lvalue
+ 9);
99 if (!pa_is_path_absolute(fn
)) {
101 if ((k
= strrchr(state
->filename
, '/'))) {
102 char *dir
= pa_xstrndup(state
->filename
, k
- state
->filename
);
103 fn
= path
= pa_sprintf_malloc("%s" PA_PATH_SEP
"%s", dir
, fn
);
108 r
= pa_config_parse(fn
, NULL
, state
->item_table
, state
->proplist
, state
->userdata
);
113 if (*state
->lvalue
== '[') {
116 k
= strlen(state
->lvalue
);
119 if (state
->lvalue
[k
-1] != ']') {
120 pa_log("[%s:%u] Invalid section header.", state
->filename
, state
->lineno
);
124 pa_xfree(state
->section
);
125 state
->section
= pa_xstrndup(state
->lvalue
+ 1, k
-2);
127 if (pa_streq(state
->section
, "Properties")) {
128 if (!state
->proplist
) {
129 pa_log("[%s:%u] \"Properties\" section is not allowed in this file.", state
->filename
, state
->lineno
);
133 state
->in_proplist
= TRUE
;
135 state
->in_proplist
= FALSE
;
140 if (!(state
->rvalue
= strchr(state
->lvalue
, '='))) {
141 pa_log("[%s:%u] Missing '='.", state
->filename
, state
->lineno
);
148 state
->lvalue
= pa_strip(state
->lvalue
);
149 state
->rvalue
= pa_strip(state
->rvalue
);
151 if (state
->in_proplist
)
152 return proplist_assignment(state
);
154 return normal_assignment(state
);
157 /* Go through the file and parse each line */
158 int pa_config_parse(const char *filename
, FILE *f
, const pa_config_item
*t
, pa_proplist
*proplist
, void *userdata
) {
160 pa_bool_t do_close
= !f
;
161 pa_config_parser_state state
;
168 if (!f
&& !(f
= pa_fopen_cloexec(filename
, "r"))) {
169 if (errno
== ENOENT
) {
170 pa_log_debug("Failed to open configuration file '%s': %s", filename
, pa_cstrerror(errno
));
175 pa_log_warn("Failed to open configuration file '%s': %s", filename
, pa_cstrerror(errno
));
179 state
.filename
= filename
;
180 state
.item_table
= t
;
181 state
.userdata
= userdata
;
184 state
.proplist
= pa_proplist_new();
187 if (!fgets(state
.buf
, sizeof(state
.buf
), f
)) {
191 pa_log_warn("Failed to read configuration file '%s': %s", filename
, pa_cstrerror(errno
));
197 if (parse_line(&state
) < 0)
202 pa_proplist_update(proplist
, PA_UPDATE_REPLACE
, state
.proplist
);
208 pa_proplist_free(state
.proplist
);
210 pa_xfree(state
.section
);
218 int pa_config_parse_int(pa_config_parser_state
*state
) {
226 if (pa_atoi(state
->rvalue
, &k
) < 0) {
227 pa_log("[%s:%u] Failed to parse numeric value: %s", state
->filename
, state
->lineno
, state
->rvalue
);
235 int pa_config_parse_unsigned(pa_config_parser_state
*state
) {
243 if (pa_atou(state
->rvalue
, &k
) < 0) {
244 pa_log("[%s:%u] Failed to parse numeric value: %s", state
->filename
, state
->lineno
, state
->rvalue
);
252 int pa_config_parse_size(pa_config_parser_state
*state
) {
260 if (pa_atou(state
->rvalue
, &k
) < 0) {
261 pa_log("[%s:%u] Failed to parse numeric value: %s", state
->filename
, state
->lineno
, state
->rvalue
);
269 int pa_config_parse_bool(pa_config_parser_state
*state
) {
277 if ((k
= pa_parse_boolean(state
->rvalue
)) < 0) {
278 pa_log("[%s:%u] Failed to parse boolean value: %s", state
->filename
, state
->lineno
, state
->rvalue
);
287 int pa_config_parse_not_bool(pa_config_parser_state
*state
) {
295 if ((k
= pa_parse_boolean(state
->rvalue
)) < 0) {
296 pa_log("[%s:%u] Failed to parse boolean value: %s", state
->filename
, state
->lineno
, state
->rvalue
);
305 int pa_config_parse_string(pa_config_parser_state
*state
) {
313 *s
= *state
->rvalue
? pa_xstrdup(state
->rvalue
) : NULL
;