Fix whitespace inconsistencies.
[herrie-working.git] / herrie / src / config.c
blobb7a969e8f5d83cceb0aeb5a84a01cda2a3100799
1 /*
2 * Copyright (c) 2006-2011 Ed Schouten <ed@80386.nl>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 /**
27 * @file config.c
28 * @brief Configuration file handling.
31 #include "stdinc.h"
33 #include "config.h"
34 #include "gui.h"
35 #include "vfs.h"
37 /**
38 * @brief Convert a "yes"/"no" string to a boolean value.
40 static int
41 string_to_bool(const char *val)
43 if (strcmp(val, "yes") == 0)
44 return (1);
45 else if (strcmp(val, "no") == 0)
46 return (0);
47 else
48 return (-1);
52 * Configuration value validation
55 /**
56 * @brief Determine if a boolean string is valid
58 static int
59 valid_bool(char *val)
61 return (string_to_bool(val) == -1);
64 /**
65 * @brief Determine if a color string is valid
67 static int
68 valid_color(char *val)
70 return (gui_draw_color_number(val) < -1);
73 /**
74 * @brief Determine if a percentage string is valid
76 static int
77 valid_percentage(char *val)
79 unsigned long pct;
80 char *end = NULL;
82 pct = strtol(val, &end, 10);
83 return (pct > 100 || end == NULL || *end != '\0');
86 #ifdef BUILD_SCROBBLER
87 /**
88 * @brief Determine if a string containing an MD5 hash is valid
90 static int
91 valid_md5(char *val)
93 int i;
95 if (val[0] == '\0')
96 return (0);
98 for (i = 0; i < 32; i++) {
99 /* Silently convert hash to lowercase */
100 val[i] = g_ascii_tolower(val[i]);
102 if (!g_ascii_isxdigit(val[i]))
103 /* Invalid character found */
104 return (-1);
107 if (val[i] != '\0')
108 /* String too long */
109 return (-1);
111 return (0);
113 #endif /* BUILD_SCROBBLER */
116 * @brief Structure containing a single configuration entry of the
117 * application.
119 struct config_entry {
121 * @brief Name it can be located at.
123 const char *name;
125 * @brief Default value.
127 const char *defval;
129 * @brief Function to validate when set.
131 int (*validator)(char *val);
133 * @brief Current value if not equal to the default.
135 char *curval;
139 * List of available configuration switches. Keep this list sorted at
140 * all time; the config lookups have been optimised to expect an
141 * alphabetical lookup. Looking up switches starting with 'z' will take
142 * longer than 'a'.
145 * @brief List of configuration switches.
147 static struct config_entry configlist[] = {
148 #ifdef BUILD_ALSA
149 { "audio.output.alsa.device", "default", NULL, NULL },
150 #ifdef BUILD_VOLUME
151 { "audio.output.alsa.mixer", "PCM", NULL, NULL },
152 #endif /* BUILD_VOLUME */
153 #endif /* BUILD_ALSA */
154 #ifdef BUILD_AO
155 { "audio.output.ao.driver", "", NULL, NULL },
156 { "audio.output.ao.host", "", NULL, NULL },
157 #endif /* BUILD_AO */
158 #ifdef BUILD_OSS
159 { "audio.output.oss.device", OSS_DEVICE, NULL, NULL },
160 #ifdef BUILD_VOLUME
161 { "audio.output.oss.mixer", "/dev/mixer", NULL, NULL },
162 #endif /* BUILD_VOLUME */
163 #endif /* BUILD_OSS */
164 { "gui.browser.defaultpath", "", NULL, NULL },
165 { "gui.color.bar.bg", "blue", valid_color, NULL },
166 { "gui.color.bar.fg", "white", valid_color, NULL },
167 { "gui.color.block.bg", "black", valid_color, NULL },
168 { "gui.color.block.fg", "white", valid_color, NULL },
169 { "gui.color.deselect.bg", "white", valid_color, NULL },
170 { "gui.color.deselect.fg", "black", valid_color, NULL },
171 { "gui.color.enabled", "yes", valid_bool, NULL },
172 { "gui.color.marked.bg", "yellow", valid_color, NULL },
173 { "gui.color.marked.fg", "black", valid_color, NULL },
174 { "gui.color.select.bg", "cyan", valid_color, NULL },
175 { "gui.color.select.fg", "black", valid_color, NULL },
176 { "gui.input.confirm", "yes", valid_bool, NULL },
177 { "gui.input.may_quit", "yes", valid_bool, NULL },
178 { "gui.ratio", "50", valid_percentage, NULL },
179 { "gui.vfslist.scrollpages", "no", valid_bool, NULL },
180 { "playq.autoplay", "no", valid_bool, NULL },
181 { "playq.dumpfile", CONFHOMEDIR PLAYQ_DUMPFILE, NULL, NULL },
182 { "playq.xmms", "no", valid_bool, NULL },
183 #ifdef BUILD_SCROBBLER
184 { "scrobbler.dumpfile", CONFHOMEDIR "scrobbler.queue", NULL, NULL },
185 { "scrobbler.hostname", "post.audioscrobbler.com", NULL, NULL },
186 { "scrobbler.password", "", valid_md5, NULL },
187 { "scrobbler.username", "", NULL, NULL },
188 #endif /* BUILD_SCROBBLER */
189 { "vfs.cache", "no", valid_bool, NULL },
190 { "vfs.dir.hide_dotfiles", "yes", valid_bool, NULL },
191 #ifdef G_OS_UNIX
192 { "vfs.lockup.chroot", "", NULL, NULL },
193 { "vfs.lockup.user", "", NULL, NULL },
194 #endif /* G_OS_UNIX */
197 * @brief The amount of configuration switches available.
199 #define NUM_SWITCHES (sizeof configlist / sizeof(struct config_entry))
202 * @brief Search for an entry in the configlist by name.
204 static struct config_entry *
205 config_search(const char *opt)
207 unsigned int i;
208 int c;
210 for (i = 0; i < NUM_SWITCHES; i++) {
211 c = strcmp(opt, configlist[i].name);
213 if (c == 0)
214 /* Found it */
215 return (&configlist[i]);
216 else if (c < 0)
217 /* We're already too far */
218 break;
221 /* Not found */
222 return (NULL);
226 * @brief Set a value to a configuration switch
228 static int
229 config_setopt(const char *opt, char *val)
231 struct config_entry *ent;
232 char *newval = NULL;
234 if ((ent = config_search(opt)) == NULL)
235 return (-1);
237 if (strcmp(val, ent->defval) != 0) {
238 /* Just unset the value when it's the default */
240 if (ent->validator != NULL) {
241 /* Do not set invalid values */
242 if (ent->validator(val) != 0)
243 return (-1);
245 newval = g_strdup(val);
248 /* Free the current contents */
249 g_free(ent->curval);
250 ent->curval = newval;
252 return (0);
256 * Public configuration file functions
259 void
260 config_load(const char *file, int expand)
262 FILE *fio;
263 char fbuf[512]; /* Should be long enough */
264 char *split;
266 if (expand)
267 fio = vfs_fopen(file, "r");
268 else
269 fio = fopen(file, "r");
270 if (fio == NULL)
271 return;
273 while (vfs_fgets(fbuf, sizeof fbuf, fio) == 0) {
274 /* Split at the = and set the option */
275 split = strchr(fbuf, '=');
276 if (split != NULL) {
277 /* Split the option and value */
278 *split++ = '\0';
279 config_setopt(fbuf, split);
283 fclose(fio);
286 const char *
287 config_getopt(const char *opt)
289 struct config_entry *ent;
291 ent = config_search(opt);
292 g_assert(ent != NULL);
294 /* Return the default if it is unset */
295 return (ent->curval ? ent->curval : ent->defval);
299 config_getopt_bool(const char *val)
301 int bval;
303 bval = string_to_bool(config_getopt(val));
304 g_assert(bval != -1);
305 return (bval);
309 config_getopt_color(const char *val)
311 int col;
313 col = gui_draw_color_number(config_getopt(val));
314 g_assert(col >= -1);
315 return (col);
319 config_getopt_percentage(const char *val)
321 return strtoul(config_getopt(val), NULL, 10);