1 /* the Music Player Daemon (MPD)
2 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3 * This project's homepage is: 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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "buffer2array.h"
27 #include <sys/param.h>
32 #include <sys/types.h>
36 #define MAX_STRING_SIZE MAXPATHLEN+80
38 #define CONF_COMMENT '#'
39 #define CONF_BLOCK_BEGIN "{"
40 #define CONF_BLOCK_END "}"
42 #define CONF_REPEATABLE_MASK 0x01
43 #define CONF_BLOCK_MASK 0x02
44 #define CONF_LINE_TOKEN_MAX 3
46 typedef struct _configEntry {
48 List *configParamList;
51 static List *configEntriesList;
53 static ConfigParam *newConfigParam(char *value, int line)
55 ConfigParam *ret = xmalloc(sizeof(ConfigParam));
60 ret->value = xstrdup(value);
64 ret->numberOfBlockParams = 0;
65 ret->blockParams = NULL;
70 static void freeConfigParam(ConfigParam * param)
77 for (i = 0; i < param->numberOfBlockParams; i++) {
78 if (param->blockParams[i].name) {
79 free(param->blockParams[i].name);
81 if (param->blockParams[i].value) {
82 free(param->blockParams[i].value);
86 if (param->numberOfBlockParams)
87 free(param->blockParams);
92 static ConfigEntry *newConfigEntry(int repeatable, int block)
94 ConfigEntry *ret = xmalloc(sizeof(ConfigEntry));
97 ret->configParamList =
98 makeList((ListFreeDataFunc *) freeConfigParam, 1);
101 ret->mask |= CONF_REPEATABLE_MASK;
103 ret->mask |= CONF_BLOCK_MASK;
108 static void freeConfigEntry(ConfigEntry * entry)
110 freeList(entry->configParamList);
114 static void registerConfigParam(char *name, int repeatable, int block)
118 if (findInList(configEntriesList, name, NULL))
119 FATAL("config parameter \"%s\" already registered\n", name);
121 entry = newConfigEntry(repeatable, block);
123 insertInList(configEntriesList, name, entry);
126 void finishConf(void)
128 freeList(configEntriesList);
133 configEntriesList = makeList((ListFreeDataFunc *) freeConfigEntry, 1);
135 /* registerConfigParam(name, repeatable, block); */
136 registerConfigParam(CONF_MUSIC_DIR, 0, 0);
137 registerConfigParam(CONF_PLAYLIST_DIR, 0, 0);
138 registerConfigParam(CONF_DB_FILE, 0, 0);
139 registerConfigParam(CONF_LOG_FILE, 0, 0);
140 registerConfigParam(CONF_ERROR_FILE, 0, 0);
141 registerConfigParam(CONF_PID_FILE, 0, 0);
142 registerConfigParam(CONF_STATE_FILE, 0, 0);
143 registerConfigParam(CONF_USER, 0, 0);
144 registerConfigParam(CONF_BIND_TO_ADDRESS, 1, 0);
145 registerConfigParam(CONF_PORT, 0, 0);
146 registerConfigParam(CONF_LOG_LEVEL, 0, 0);
147 registerConfigParam(CONF_ZEROCONF_NAME, 0, 0);
148 registerConfigParam(CONF_ZEROCONF_ENABLED, 0, 0);
149 registerConfigParam(CONF_PASSWORD, 1, 0);
150 registerConfigParam(CONF_DEFAULT_PERMS, 0, 0);
151 registerConfigParam(CONF_AUDIO_OUTPUT, 1, 1);
152 registerConfigParam(CONF_AUDIO_OUTPUT_FORMAT, 0, 0);
153 registerConfigParam(CONF_MIXER_TYPE, 0, 0);
154 registerConfigParam(CONF_MIXER_DEVICE, 0, 0);
155 registerConfigParam(CONF_MIXER_CONTROL, 0, 0);
156 registerConfigParam(CONF_REPLAYGAIN, 0, 0);
157 registerConfigParam(CONF_REPLAYGAIN_PREAMP, 0, 0);
158 registerConfigParam(CONF_VOLUME_NORMALIZATION, 0, 0);
159 registerConfigParam(CONF_SAMPLERATE_CONVERTER, 0, 0);
160 registerConfigParam(CONF_AUDIO_BUFFER_SIZE, 0, 0);
161 registerConfigParam(CONF_BUFFER_BEFORE_PLAY, 0, 0);
162 registerConfigParam(CONF_HTTP_BUFFER_SIZE, 0, 0);
163 registerConfigParam(CONF_HTTP_PREBUFFER_SIZE, 0, 0);
164 registerConfigParam(CONF_HTTP_PROXY_HOST, 0, 0);
165 registerConfigParam(CONF_HTTP_PROXY_PORT, 0, 0);
166 registerConfigParam(CONF_HTTP_PROXY_USER, 0, 0);
167 registerConfigParam(CONF_HTTP_PROXY_PASSWORD, 0, 0);
168 registerConfigParam(CONF_CONN_TIMEOUT, 0, 0);
169 registerConfigParam(CONF_MAX_CONN, 0, 0);
170 registerConfigParam(CONF_MAX_PLAYLIST_LENGTH, 0, 0);
171 registerConfigParam(CONF_MAX_COMMAND_LIST_SIZE, 0, 0);
172 registerConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE, 0, 0);
173 registerConfigParam(CONF_FS_CHARSET, 0, 0);
174 registerConfigParam(CONF_ID3V1_ENCODING, 0, 0);
175 registerConfigParam(CONF_METADATA_TO_USE, 0, 0);
176 registerConfigParam(CONF_SAVE_ABSOLUTE_PATHS, 0, 0);
177 registerConfigParam(CONF_GAPLESS_MP3_PLAYBACK, 0, 0);
180 static void addBlockParam(ConfigParam * param, char *name, char *value,
183 param->numberOfBlockParams++;
185 param->blockParams = xrealloc(param->blockParams,
186 param->numberOfBlockParams *
189 param->blockParams[param->numberOfBlockParams - 1].name = xstrdup(name);
190 param->blockParams[param->numberOfBlockParams - 1].value =
192 param->blockParams[param->numberOfBlockParams - 1].line = line;
195 static ConfigParam *readConfigBlock(FILE * fp, int *count, char *string)
197 ConfigParam *ret = newConfigParam(NULL, *count);
201 int argsMinusComment;
203 while (myFgets(string, MAX_STRING_SIZE, fp)) {
204 char *array[CONF_LINE_TOKEN_MAX] = { NULL };
208 numberOfArgs = buffer2array(string, array, CONF_LINE_TOKEN_MAX);
210 for (i = 0; i < numberOfArgs; i++) {
211 if (array[i][0] == CONF_COMMENT)
215 argsMinusComment = i;
217 if (0 == argsMinusComment) {
221 if (1 == argsMinusComment &&
222 0 == strcmp(array[0], CONF_BLOCK_END)) {
226 if (2 != argsMinusComment) {
227 FATAL("improperly formatted config file at line %i:"
228 " %s\n", *count, string);
231 if (0 == strcmp(array[0], CONF_BLOCK_BEGIN) ||
232 0 == strcmp(array[1], CONF_BLOCK_BEGIN) ||
233 0 == strcmp(array[0], CONF_BLOCK_END) ||
234 0 == strcmp(array[1], CONF_BLOCK_END)) {
235 FATAL("improperly formatted config file at line %i: %s\n"
236 "in block beginning at line %i\n",
237 *count, string, ret->line);;
240 addBlockParam(ret, array[0], array[1], *count);
246 void readConf(char *file)
249 char string[MAX_STRING_SIZE + 1];
252 int argsMinusComment;
258 if (!(fp = fopen(file, "r"))) {
259 FATAL("problems opening file %s for reading: %s\n", file,
263 while (myFgets(string, MAX_STRING_SIZE, fp)) {
264 char *array[CONF_LINE_TOKEN_MAX] = { NULL };
267 numberOfArgs = buffer2array(string, array, CONF_LINE_TOKEN_MAX);
269 for (i = 0; i < numberOfArgs; i++) {
270 if (array[i][0] == CONF_COMMENT)
274 argsMinusComment = i;
276 if (0 == argsMinusComment) {
280 if (2 != argsMinusComment) {
281 FATAL("improperly formatted config file at line %i:"
282 " %s\n", count, string);
285 if (!findInList(configEntriesList, array[0], &voidPtr)) {
286 FATAL("unrecognized parameter in config file at line "
287 "%i: %s\n", count, string);
290 entry = (ConfigEntry *) voidPtr;
292 if (!(entry->mask & CONF_REPEATABLE_MASK) &&
293 entry->configParamList->numberOfNodes) {
294 param = entry->configParamList->firstNode->data;
295 FATAL("config parameter \"%s\" is first defined on line "
296 "%i and redefined on line %i\n", array[0],
300 if (entry->mask & CONF_BLOCK_MASK) {
301 if (0 != strcmp(array[1], CONF_BLOCK_BEGIN)) {
302 FATAL("improperly formatted config file at "
303 "line %i: %s\n", count, string);
305 param = readConfigBlock(fp, &count, string);
307 param = newConfigParam(array[1], count);
309 insertInListWithoutKey(entry->configParamList, param);
314 ConfigParam *getNextConfigParam(char *name, ConfigParam * last)
321 if (!findInList(configEntriesList, name, &voidPtr))
326 node = entry->configParamList->firstNode;
329 while (node != NULL) {
331 node = node->nextNode;
345 char *getConfigParamValue(char *name)
347 ConfigParam *param = getConfigParam(name);
355 int getBoolConfigParam(char *name)
359 param = getConfigParam(name);
360 if (!param) return -1;
362 if (strcmp("yes", param->value) == 0) return 1;
363 else if (strcmp("no", param->value) == 0) return 0;
365 ERROR("%s is not \"yes\" or \"no\" on line %i\n", name, param->line);
370 BlockParam *getBlockParam(ConfigParam * param, char *name)
372 BlockParam *ret = NULL;
375 for (i = 0; i < param->numberOfBlockParams; i++) {
376 if (0 == strcmp(name, param->blockParams[i].name)) {
378 ERROR("\"%s\" first defined on line %i, and "
379 "redefined on line %i\n", name,
380 ret->line, param->blockParams[i].line);
382 ret = param->blockParams + i;
389 ConfigParam *parseConfigFilePath(char *name, int force)
391 ConfigParam *param = getConfigParam(name);
395 FATAL("config parameter \"%s\" not found\n", name);
400 path = parsePath(param->value);
402 FATAL("error parsing \"%s\" at line %i\n", name, param->line);