2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "tokenizer.h"
25 #include "glib_compat.h"
36 #define G_LOG_DOMAIN "config"
38 #define MAX_STRING_SIZE MPD_PATH_MAX+80
40 #define CONF_COMMENT '#'
43 const char *const name
;
44 const bool repeatable
;
50 static struct config_entry config_entries
[] = {
51 { .name
= CONF_MUSIC_DIR
, false, false },
52 { .name
= CONF_PLAYLIST_DIR
, false, false },
53 { .name
= CONF_FOLLOW_INSIDE_SYMLINKS
, false, false },
54 { .name
= CONF_FOLLOW_OUTSIDE_SYMLINKS
, false, false },
55 { .name
= CONF_DB_FILE
, false, false },
56 { .name
= CONF_STICKER_FILE
, false, false },
57 { .name
= CONF_LOG_FILE
, false, false },
58 { .name
= CONF_PID_FILE
, false, false },
59 { .name
= CONF_STATE_FILE
, false, false },
60 { .name
= CONF_USER
, false, false },
61 { .name
= CONF_GROUP
, false, false },
62 { .name
= CONF_BIND_TO_ADDRESS
, true, false },
63 { .name
= CONF_PORT
, false, false },
64 { .name
= CONF_LOG_LEVEL
, false, false },
65 { .name
= CONF_ZEROCONF_NAME
, false, false },
66 { .name
= CONF_ZEROCONF_ENABLED
, false, false },
67 { .name
= CONF_PASSWORD
, true, false },
68 { .name
= CONF_DEFAULT_PERMS
, false, false },
69 { .name
= CONF_AUDIO_OUTPUT
, true, true },
70 { .name
= CONF_AUDIO_OUTPUT_FORMAT
, false, false },
71 { .name
= CONF_MIXER_TYPE
, false, false },
72 { .name
= CONF_REPLAYGAIN
, false, false },
73 { .name
= CONF_REPLAYGAIN_PREAMP
, false, false },
74 { .name
= CONF_REPLAYGAIN_MISSING_PREAMP
, false, false },
75 { .name
= CONF_VOLUME_NORMALIZATION
, false, false },
76 { .name
= CONF_SAMPLERATE_CONVERTER
, false, false },
77 { .name
= CONF_AUDIO_BUFFER_SIZE
, false, false },
78 { .name
= CONF_BUFFER_BEFORE_PLAY
, false, false },
79 { .name
= CONF_HTTP_PROXY_HOST
, false, false },
80 { .name
= CONF_HTTP_PROXY_PORT
, false, false },
81 { .name
= CONF_HTTP_PROXY_USER
, false, false },
82 { .name
= CONF_HTTP_PROXY_PASSWORD
, false, false },
83 { .name
= CONF_CONN_TIMEOUT
, false, false },
84 { .name
= CONF_MAX_CONN
, false, false },
85 { .name
= CONF_MAX_PLAYLIST_LENGTH
, false, false },
86 { .name
= CONF_MAX_COMMAND_LIST_SIZE
, false, false },
87 { .name
= CONF_MAX_OUTPUT_BUFFER_SIZE
, false, false },
88 { .name
= CONF_FS_CHARSET
, false, false },
89 { .name
= CONF_ID3V1_ENCODING
, false, false },
90 { .name
= CONF_METADATA_TO_USE
, false, false },
91 { .name
= CONF_SAVE_ABSOLUTE_PATHS
, false, false },
92 { .name
= CONF_DECODER
, true, true },
93 { .name
= CONF_INPUT
, true, true },
94 { .name
= CONF_GAPLESS_MP3_PLAYBACK
, false, false },
95 { .name
= CONF_PLAYLIST_PLUGIN
, true, true },
96 { .name
= CONF_AUTO_UPDATE
, false, false },
97 { .name
= CONF_AUTO_UPDATE_DEPTH
, false, false },
98 { .name
= "filter", true, true },
102 get_bool(const char *value
, bool *value_r
)
104 static const char *t
[] = { "yes", "true", "1", NULL
};
105 static const char *f
[] = { "no", "false", "0", NULL
};
107 if (string_array_contains(t
, value
)) {
112 if (string_array_contains(f
, value
)) {
120 struct config_param
*
121 config_new_param(const char *value
, int line
)
123 struct config_param
*ret
= g_new(struct config_param
, 1);
128 ret
->value
= g_strdup(value
);
132 ret
->num_block_params
= 0;
133 ret
->block_params
= NULL
;
140 config_param_free(struct config_param
*param
)
142 g_free(param
->value
);
144 for (unsigned i
= 0; i
< param
->num_block_params
; i
++) {
145 g_free(param
->block_params
[i
].name
);
146 g_free(param
->block_params
[i
].value
);
149 if (param
->num_block_params
)
150 g_free(param
->block_params
);
156 config_param_free_callback(gpointer data
, G_GNUC_UNUSED gpointer user_data
)
158 struct config_param
*param
= data
;
160 config_param_free(param
);
163 static struct config_entry
*
164 config_entry_get(const char *name
)
166 for (unsigned i
= 0; i
< G_N_ELEMENTS(config_entries
); ++i
) {
167 struct config_entry
*entry
= &config_entries
[i
];
168 if (strcmp(entry
->name
, name
) == 0)
175 void config_global_finish(void)
177 for (unsigned i
= 0; i
< G_N_ELEMENTS(config_entries
); ++i
) {
178 struct config_entry
*entry
= &config_entries
[i
];
180 g_slist_foreach(entry
->params
,
181 config_param_free_callback
, NULL
);
182 g_slist_free(entry
->params
);
186 void config_global_init(void)
191 config_param_check(gpointer data
, G_GNUC_UNUSED gpointer user_data
)
193 struct config_param
*param
= data
;
196 /* this whole config_param was not queried at all -
197 the feature might be disabled at compile time?
198 Silently ignore it here. */
201 for (unsigned i
= 0; i
< param
->num_block_params
; i
++) {
202 struct block_param
*bp
= ¶m
->block_params
[i
];
205 g_warning("option '%s' on line %i was not recognized",
210 void config_global_check(void)
212 for (unsigned i
= 0; i
< G_N_ELEMENTS(config_entries
); ++i
) {
213 struct config_entry
*entry
= &config_entries
[i
];
215 g_slist_foreach(entry
->params
, config_param_check
, NULL
);
220 config_add_block_param(struct config_param
* param
, const char *name
,
221 const char *value
, int line
, GError
**error_r
)
223 struct block_param
*bp
;
225 bp
= config_get_block_param(param
, name
);
227 g_set_error(error_r
, config_quark(), 0,
228 "\"%s\" first defined on line %i, and "
229 "redefined on line %i\n", name
,
234 param
->num_block_params
++;
236 param
->block_params
= g_realloc(param
->block_params
,
237 param
->num_block_params
*
238 sizeof(param
->block_params
[0]));
240 bp
= ¶m
->block_params
[param
->num_block_params
- 1];
242 bp
->name
= g_strdup(name
);
243 bp
->value
= g_strdup(value
);
250 static struct config_param
*
251 config_read_block(FILE *fp
, int *count
, char *string
, GError
**error_r
)
253 struct config_param
*ret
= config_new_param(NULL
, *count
);
254 GError
*error
= NULL
;
259 const char *name
, *value
;
261 line
= fgets(string
, MAX_STRING_SIZE
, fp
);
263 config_param_free(ret
);
264 g_set_error(error_r
, config_quark(), 0,
265 "Expected '}' before end-of-file");
270 line
= g_strchug(line
);
271 if (*line
== 0 || *line
== CONF_COMMENT
)
275 /* end of this block; return from the function
276 (and from this "while" loop) */
278 line
= g_strchug(line
+ 1);
279 if (*line
!= 0 && *line
!= CONF_COMMENT
) {
280 config_param_free(ret
);
281 g_set_error(error_r
, config_quark(), 0,
282 "line %i: Unknown tokens after '}'",
290 /* parse name and value */
292 name
= tokenizer_next_word(&line
, &error
);
295 config_param_free(ret
);
296 g_propagate_prefixed_error(error_r
, error
,
297 "line %i: ", *count
);
301 value
= tokenizer_next_string(&line
, &error
);
303 config_param_free(ret
);
305 g_set_error(error_r
, config_quark(), 0,
306 "line %i: Value missing", *count
);
308 g_propagate_prefixed_error(error_r
, error
,
314 if (*line
!= 0 && *line
!= CONF_COMMENT
) {
315 config_param_free(ret
);
316 g_set_error(error_r
, config_quark(), 0,
317 "line %i: Unknown tokens after value",
322 success
= config_add_block_param(ret
, name
, value
, *count
,
325 config_param_free(ret
);
332 config_read_file(const char *file
, GError
**error_r
)
335 char string
[MAX_STRING_SIZE
+ 1];
337 struct config_entry
*entry
;
338 struct config_param
*param
;
340 g_debug("loading file %s", file
);
342 if (!(fp
= fopen(file
, "r"))) {
343 g_set_error(error_r
, config_quark(), errno
,
344 "Failed to open %s: %s",
345 file
, strerror(errno
));
349 while (fgets(string
, MAX_STRING_SIZE
, fp
)) {
351 const char *name
, *value
;
352 GError
*error
= NULL
;
356 line
= g_strchug(string
);
357 if (*line
== 0 || *line
== CONF_COMMENT
)
360 /* the first token in each line is the name, followed
361 by either the value or '{' */
363 name
= tokenizer_next_word(&line
, &error
);
366 g_propagate_prefixed_error(error_r
, error
,
371 /* get the definition of that option, and check the
374 entry
= config_entry_get(name
);
376 g_set_error(error_r
, config_quark(), 0,
377 "unrecognized parameter in config file at "
378 "line %i: %s\n", count
, name
);
382 if (entry
->params
!= NULL
&& !entry
->repeatable
) {
383 param
= entry
->params
->data
;
384 g_set_error(error_r
, config_quark(), 0,
385 "config parameter \"%s\" is first defined "
386 "on line %i and redefined on line %i\n",
387 name
, param
->line
, count
);
391 /* now parse the block or the value */
394 /* it's a block, call config_read_block() */
397 g_set_error(error_r
, config_quark(), 0,
398 "line %i: '{' expected", count
);
402 line
= g_strchug(line
+ 1);
403 if (*line
!= 0 && *line
!= CONF_COMMENT
) {
404 g_set_error(error_r
, config_quark(), 0,
405 "line %i: Unknown tokens after '{'",
410 param
= config_read_block(fp
, &count
, string
, error_r
);
416 value
= tokenizer_next_string(&line
, &error
);
419 g_set_error(error_r
, config_quark(), 0,
420 "line %i: Value missing",
423 g_set_error(error_r
, config_quark(), 0,
424 "line %i: %s", count
,
432 if (*line
!= 0 && *line
!= CONF_COMMENT
) {
433 g_set_error(error_r
, config_quark(), 0,
434 "line %i: Unknown tokens after value",
439 param
= config_new_param(value
, count
);
442 entry
->params
= g_slist_append(entry
->params
, param
);
449 struct config_param
*
450 config_get_next_param(const char *name
, const struct config_param
* last
)
452 struct config_entry
*entry
;
454 struct config_param
*param
;
456 entry
= config_entry_get(name
);
460 node
= entry
->params
;
463 node
= g_slist_find(node
, last
);
467 node
= g_slist_next(node
);
479 config_get_string(const char *name
, const char *default_value
)
481 const struct config_param
*param
= config_get_param(name
);
484 return default_value
;
490 config_get_path(const char *name
)
492 struct config_param
*param
= config_get_param(name
);
498 path
= parsePath(param
->value
);
500 g_error("error parsing \"%s\" at line %i\n",
503 g_free(param
->value
);
504 return param
->value
= path
;
508 config_get_unsigned(const char *name
, unsigned default_value
)
510 const struct config_param
*param
= config_get_param(name
);
515 return default_value
;
517 value
= strtol(param
->value
, &endptr
, 0);
518 if (*endptr
!= 0 || value
< 0)
519 g_error("Not a valid non-negative number in line %i", param
->line
);
521 return (unsigned)value
;
525 config_get_positive(const char *name
, unsigned default_value
)
527 const struct config_param
*param
= config_get_param(name
);
532 return default_value
;
534 value
= strtol(param
->value
, &endptr
, 0);
536 g_error("Not a valid number in line %i", param
->line
);
539 g_error("Not a positive number in line %i", param
->line
);
541 return (unsigned)value
;
545 config_get_block_param(const struct config_param
* param
, const char *name
)
550 for (unsigned i
= 0; i
< param
->num_block_params
; i
++) {
551 if (0 == strcmp(name
, param
->block_params
[i
].name
)) {
552 struct block_param
*bp
= ¶m
->block_params
[i
];
561 bool config_get_bool(const char *name
, bool default_value
)
563 const struct config_param
*param
= config_get_param(name
);
567 return default_value
;
569 success
= get_bool(param
->value
, &value
);
571 g_error("%s is not a boolean value (yes, true, 1) or "
572 "(no, false, 0) on line %i\n",
579 config_get_block_string(const struct config_param
*param
, const char *name
,
580 const char *default_value
)
582 struct block_param
*bp
= config_get_block_param(param
, name
);
585 return default_value
;
591 config_get_block_unsigned(const struct config_param
*param
, const char *name
,
592 unsigned default_value
)
594 struct block_param
*bp
= config_get_block_param(param
, name
);
599 return default_value
;
601 value
= strtol(bp
->value
, &endptr
, 0);
603 g_error("Not a valid number in line %i", bp
->line
);
606 g_error("Not a positive number in line %i", bp
->line
);
608 return (unsigned)value
;
612 config_get_block_bool(const struct config_param
*param
, const char *name
,
615 struct block_param
*bp
= config_get_block_param(param
, name
);
619 return default_value
;
621 success
= get_bool(bp
->value
, &value
);
623 g_error("%s is not a boolean value (yes, true, 1) or "
624 "(no, false, 0) on line %i\n",