Initial revision 6759
[qball-mpd.git] / src / .svn / text-base / conf.c.svn-base
blobd76d4ad9b4d3bfda9af141705cef4b7be5544be4
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
4  *
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.
9  *
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
17  */
19 #include "conf.h"
21 #include "log.h"
23 #include "utils.h"
24 #include "buffer2array.h"
25 #include "list.h"
27 #include <sys/param.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <sys/types.h>
33 #include <pwd.h>
34 #include <errno.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 {
47         unsigned char mask;
48         List *configParamList;
49 } ConfigEntry;
51 static List *configEntriesList;
53 static ConfigParam *newConfigParam(char *value, int line)
55         ConfigParam *ret = xmalloc(sizeof(ConfigParam));
57         if (!value)
58                 ret->value = NULL;
59         else
60                 ret->value = xstrdup(value);
62         ret->line = line;
64         ret->numberOfBlockParams = 0;
65         ret->blockParams = NULL;
67         return ret;
70 static void freeConfigParam(ConfigParam * param)
72         int i;
74         if (param->value)
75                 free(param->value);
77         for (i = 0; i < param->numberOfBlockParams; i++) {
78                 if (param->blockParams[i].name) {
79                         free(param->blockParams[i].name);
80                 }
81                 if (param->blockParams[i].value) {
82                         free(param->blockParams[i].value);
83                 }
84         }
86         if (param->numberOfBlockParams)
87                 free(param->blockParams);
89         free(param);
92 static ConfigEntry *newConfigEntry(int repeatable, int block)
94         ConfigEntry *ret = xmalloc(sizeof(ConfigEntry));
96         ret->mask = 0;
97         ret->configParamList =
98             makeList((ListFreeDataFunc *) freeConfigParam, 1);
100         if (repeatable)
101                 ret->mask |= CONF_REPEATABLE_MASK;
102         if (block)
103                 ret->mask |= CONF_BLOCK_MASK;
105         return ret;
108 static void freeConfigEntry(ConfigEntry * entry)
110         freeList(entry->configParamList);
111         free(entry);
114 static void registerConfigParam(char *name, int repeatable, int block)
116         ConfigEntry *entry;
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);
131 void initConf(void)
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,
181                           int line)
183         param->numberOfBlockParams++;
185         param->blockParams = xrealloc(param->blockParams,
186                                      param->numberOfBlockParams *
187                                      sizeof(BlockParam));
189         param->blockParams[param->numberOfBlockParams - 1].name = xstrdup(name);
190         param->blockParams[param->numberOfBlockParams - 1].value =
191             xstrdup(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);
199         int i;
200         int numberOfArgs;
201         int argsMinusComment;
203         while (myFgets(string, MAX_STRING_SIZE, fp)) {
204                 char *array[CONF_LINE_TOKEN_MAX] = { NULL };
206                 (*count)++;
208                 numberOfArgs = buffer2array(string, array, CONF_LINE_TOKEN_MAX);
210                 for (i = 0; i < numberOfArgs; i++) {
211                         if (array[i][0] == CONF_COMMENT)
212                                 break;
213                 }
215                 argsMinusComment = i;
217                 if (0 == argsMinusComment) {
218                         continue;
219                 }
221                 if (1 == argsMinusComment &&
222                     0 == strcmp(array[0], CONF_BLOCK_END)) {
223                         break;
224                 }
226                 if (2 != argsMinusComment) {
227                         FATAL("improperly formatted config file at line %i:"
228                               " %s\n", *count, string);
229                 }
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);;
238                 }
240                 addBlockParam(ret, array[0], array[1], *count);
241         }
243         return ret;
246 void readConf(char *file)
248         FILE *fp;
249         char string[MAX_STRING_SIZE + 1];
250         int i;
251         int numberOfArgs;
252         int argsMinusComment;
253         int count = 0;
254         ConfigEntry *entry;
255         void *voidPtr;
256         ConfigParam *param;
258         if (!(fp = fopen(file, "r"))) {
259                 FATAL("problems opening file %s for reading: %s\n", file,
260                       strerror(errno));
261         }
263         while (myFgets(string, MAX_STRING_SIZE, fp)) {
264                 char *array[CONF_LINE_TOKEN_MAX] = { NULL };
265                 count++;
267                 numberOfArgs = buffer2array(string, array, CONF_LINE_TOKEN_MAX);
269                 for (i = 0; i < numberOfArgs; i++) {
270                         if (array[i][0] == CONF_COMMENT)
271                                 break;
272                 }
274                 argsMinusComment = i;
276                 if (0 == argsMinusComment) {
277                         continue;
278                 }
280                 if (2 != argsMinusComment) {
281                         FATAL("improperly formatted config file at line %i:"
282                               " %s\n", count, string);
283                 }
285                 if (!findInList(configEntriesList, array[0], &voidPtr)) {
286                         FATAL("unrecognized parameter in config file at line "
287                               "%i: %s\n", count, string);
288                 }
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],
297                              param->line, count);
298                 }
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);
304                         }
305                         param = readConfigBlock(fp, &count, string);
306                 } else
307                         param = newConfigParam(array[1], count);
309                 insertInListWithoutKey(entry->configParamList, param);
310         }
311         fclose(fp);
314 ConfigParam *getNextConfigParam(char *name, ConfigParam * last)
316         void *voidPtr;
317         ConfigEntry *entry;
318         ListNode *node;
319         ConfigParam *param;
321         if (!findInList(configEntriesList, name, &voidPtr))
322                 return NULL;
324         entry = voidPtr;
326         node = entry->configParamList->firstNode;
328         if (last) {
329                 while (node != NULL) {
330                         param = node->data;
331                         node = node->nextNode;
332                         if (param == last)
333                                 break;
334                 }
335         }
337         if (node == NULL)
338                 return NULL;
340         param = node->data;
342         return param;
345 char *getConfigParamValue(char *name)
347         ConfigParam *param = getConfigParam(name);
349         if (!param)
350                 return NULL;
352         return param->value;
355 int getBoolConfigParam(char *name)
357         ConfigParam *param;
358         
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);
367         return -2;
370 BlockParam *getBlockParam(ConfigParam * param, char *name)
372         BlockParam *ret = NULL;
373         int i;
375         for (i = 0; i < param->numberOfBlockParams; i++) {
376                 if (0 == strcmp(name, param->blockParams[i].name)) {
377                         if (ret) {
378                                 ERROR("\"%s\" first defined on line %i, and "
379                                       "redefined on line %i\n", name,
380                                       ret->line, param->blockParams[i].line);
381                         }
382                         ret = param->blockParams + i;
383                 }
384         }
386         return ret;
389 ConfigParam *parseConfigFilePath(char *name, int force)
391         ConfigParam *param = getConfigParam(name);
392         char *path;
394         if (!param && force)
395                 FATAL("config parameter \"%s\" not found\n", name);
397         if (!param)
398                 return NULL;
400         path = parsePath(param->value);
401         if (!path)
402                 FATAL("error parsing \"%s\" at line %i\n", name, param->line);
404         free(param->value);
405         param->value = path;
407         return param;