2 * Copyright (c) 2006-2011 Ed Schouten <ed@80386.nl>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
28 * @brief Configuration file handling.
38 * @brief Convert a "yes"/"no" string to a boolean value.
41 string_to_bool(const char *val
)
43 if (strcmp(val
, "yes") == 0)
45 else if (strcmp(val
, "no") == 0)
52 * Configuration value validation
56 * @brief Determine if a boolean string is valid
61 return (string_to_bool(val
) == -1);
65 * @brief Determine if a color string is valid
68 valid_color(char *val
)
70 return (gui_draw_color_number(val
) < -1);
74 * @brief Determine if a percentage string is valid
77 valid_percentage(char *val
)
82 pct
= strtol(val
, &end
, 10);
83 return (pct
> 100 || end
== NULL
|| *end
!= '\0');
86 #ifdef BUILD_SCROBBLER
88 * @brief Determine if a string containing an MD5 hash is valid
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 */
108 /* String too long */
113 #endif /* BUILD_SCROBBLER */
116 * @brief Structure containing a single configuration entry of the
119 struct config_entry
{
121 * @brief Name it can be located at.
125 * @brief Default value.
129 * @brief Function to validate when set.
131 int (*validator
)(char *val
);
133 * @brief Current value if not equal to the default.
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
145 * @brief List of configuration switches.
147 static struct config_entry configlist
[] = {
149 { "audio.output.alsa.device", "default", NULL
, NULL
},
151 { "audio.output.alsa.mixer", "PCM", NULL
, NULL
},
152 #endif /* BUILD_VOLUME */
153 #endif /* BUILD_ALSA */
155 { "audio.output.ao.driver", "", NULL
, NULL
},
156 { "audio.output.ao.host", "", NULL
, NULL
},
157 #endif /* BUILD_AO */
159 { "audio.output.oss.device", OSS_DEVICE
, NULL
, NULL
},
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
},
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
)
210 for (i
= 0; i
< NUM_SWITCHES
; i
++) {
211 c
= strcmp(opt
, configlist
[i
].name
);
215 return (&configlist
[i
]);
217 /* We're already too far */
226 * @brief Set a value to a configuration switch
229 config_setopt(const char *opt
, char *val
)
231 struct config_entry
*ent
;
234 if ((ent
= config_search(opt
)) == NULL
)
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)
245 newval
= g_strdup(val
);
248 /* Free the current contents */
250 ent
->curval
= newval
;
256 * Public configuration file functions
260 config_load(const char *file
, int expand
)
263 char fbuf
[512]; /* Should be long enough */
267 fio
= vfs_fopen(file
, "r");
269 fio
= fopen(file
, "r");
273 while (vfs_fgets(fbuf
, sizeof fbuf
, fio
) == 0) {
274 /* Split at the = and set the option */
275 split
= strchr(fbuf
, '=');
277 /* Split the option and value */
279 config_setopt(fbuf
, split
);
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
)
303 bval
= string_to_bool(config_getopt(val
));
304 g_assert(bval
!= -1);
309 config_getopt_color(const char *val
)
313 col
= gui_draw_color_number(config_getopt(val
));
319 config_getopt_percentage(const char *val
)
321 return strtoul(config_getopt(val
), NULL
, 10);