1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <fs/base.h>
6 #include <fs/conf.h>
7 #include <fs/filesys.h>
8 #include <fs/glib.h>
9 #include <fs/inifile.h>
10 #include <fs/log.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 static int g_initialized = 0;
15 GHashTable *g_hash_table = NULL;
16
17 #define LOG_LINE \
18 "----------------------------------------------------------------------------\n"
19
initialize(void)20 static void initialize(void)
21 {
22 if (g_initialized) {
23 return;
24 }
25 g_initialized = 1;
26 g_hash_table = g_hash_table_new_full(
27 g_str_hash, g_str_equal, g_free, g_free);
28 }
29
fse_init_conf(void)30 void fse_init_conf(void)
31 {
32 initialize();
33 }
34
fs_config_exists(const char * key)35 bool fs_config_exists(const char *key)
36 {
37 return fs_config_get_const_string(key) != NULL;
38 }
39
fs_config_check_auto(const char * key,const char * value)40 bool fs_config_check_auto(const char *key, const char *value)
41 {
42 const char *s = fs_config_get_const_string(key);
43 if (s == NULL) {
44 return true;
45 }
46 if (value && strcasecmp(s, value) == 0) {
47 return true;
48 }
49 return false;
50 }
51
fs_config_check_enabled(const char * key,const char * value)52 bool fs_config_check_enabled(const char *key, const char *value)
53 {
54 const char *s = fs_config_get_const_string(key);
55 if (s == NULL) {
56 return false;
57 }
58 if (value && strcasecmp(s, value) == 0) {
59 return true;
60 }
61 if (strcasecmp(s, "1") == 0) {
62 return true;
63 }
64 return false;
65 }
66
fs_config_check_disabled(const char * key,const char * value)67 bool fs_config_check_disabled(const char *key, const char *value)
68 {
69 const char *s = fs_config_get_const_string(key);
70 if (s == NULL) {
71 return false;
72 }
73 if (value && strcasecmp(s, value) == 0) {
74 return true;
75 }
76 if (strcasecmp(s, "0") == 0) {
77 return true;
78 }
79 return false;
80 }
81
fs_config_get_const_string(const char * key)82 const char *fs_config_get_const_string(const char *key)
83 {
84 if (!g_initialized) {
85 initialize();
86 }
87 const char *value = (const char *) g_hash_table_lookup(g_hash_table, key);
88 if (value && !value[0]) {
89 // an empty string is treated as non-existing (unset value)
90 return NULL;
91 }
92 return value;
93 }
94
fs_config_get_string(const char * key)95 char *fs_config_get_string(const char *key)
96 {
97 const char* value = fs_config_get_const_string(key);
98 if (value) {
99 return g_strdup(value);
100 }
101 return NULL;
102 }
103
process_key_value(const char * key,char * value,int force)104 static void process_key_value(const char *key, char *value, int force)
105 {
106 char *key_lower = g_ascii_strdown(key, -1);
107 g_strdelimit (key_lower, "-", '_');
108 /* Using fs_config_get_const_string here instead of just
109 * g_hash_table_lookup, since that also checks for empty strings, which
110 * should be treated as non-existing keys. */
111 if (!force && fs_config_get_const_string(key_lower)) {
112 fs_log("%s = %s (ignored)\n", key_lower, value);
113 g_free(key_lower);
114 g_free(value);
115 } else {
116 g_strstrip(value);
117 fs_log("%s = %s\n", key_lower, value);
118 /* Hash table now owns both key_lower and value. */
119 g_hash_table_insert(g_hash_table, key_lower, value);
120 }
121 }
122
fs_config_set_string(const char * key,const char * value)123 void fs_config_set_string(const char *key, const char *value)
124 {
125 process_key_value(key, g_strdup(value), 1);
126 }
127
fs_config_set_string_if_unset(const char * key,const char * value)128 void fs_config_set_string_if_unset(const char *key, const char *value)
129 {
130 if (fs_config_get_const_string(key) == NULL) {
131 fs_config_set_string(key, value);
132 }
133 }
134
135 #ifdef FSUAE
136 #define USE_INIFILE
137 #endif
138
139 #ifdef USE_INIFILE
140
fs_config_parse_ini_file(fs_ini_file * ini_file,int force)141 void fs_config_parse_ini_file(fs_ini_file *ini_file, int force)
142 {
143 char **groups = fs_ini_file_get_groups(ini_file, NULL);
144 for (char **group = groups; *group; group++) {
145 const char *prefix = "";
146 if (strcmp(*group, "theme") == 0) {
147 prefix = "theme_";
148 }
149 char **keys = fs_ini_file_get_keys(ini_file, *group, NULL);
150 for (char **key = keys; *key; key++) {
151 char *value = fs_ini_file_get_value(ini_file, *group, *key);
152 if (value) {
153 char *key2 = g_strconcat(prefix, *key, NULL);
154 process_key_value(key2, value, force);
155 g_free(key2);
156 }
157 }
158 g_strfreev(keys);
159 }
160 g_strfreev(groups);
161 }
162
163 #endif
164
fs_config_read_file(const char * path,int force)165 int fs_config_read_file(const char *path, int force)
166 {
167 if (!g_initialized) {
168 initialize();
169 }
170 fs_log("\n");
171 fs_log(LOG_LINE);
172 fs_log("config (%s)\n", path);
173 fs_log(LOG_LINE);
174 fs_log("\n");
175
176 if (!force && fs_config_get_boolean("end_config") == 1) {
177 fs_log("end_config is set, ignoring this config file\n");
178 return 1;
179 }
180 if (!fs_path_is_file(path)) {
181 fs_log("config file %s does not exist\n", path);
182 return 0;
183 }
184
185 #ifdef USE_INIFILE
186 fs_ini_file *ini_file = fs_ini_file_open(path);
187 if (ini_file == NULL) {
188 fs_log("error loading config file\n");
189 return 0;
190 }
191 fs_config_parse_ini_file(ini_file, force);
192 fs_ini_file_destroy(ini_file);
193 return 1;
194 #else
195 return 0;
196 #endif
197 }
198
fs_config_get_boolean(const char * key)199 int fs_config_get_boolean(const char *key)
200 {
201 return fs_config_get_int(key);
202 }
203
fs_config_get_int(const char * key)204 int fs_config_get_int(const char *key)
205 {
206 const char *value = fs_config_get_const_string(key);
207 if (value == NULL) {
208 return FS_CONFIG_NONE;
209 }
210 return atoi(value);
211 }
212
fs_config_get_int_clamped(const char * key,int min,int max)213 int fs_config_get_int_clamped(const char *key, int min, int max)
214 {
215 int value = fs_config_get_int(key);
216 if (value == FS_CONFIG_NONE) {
217 return value;
218 }
219 if (value < min) {
220 fs_log("clamping value %d for key %s to %d\n", value, key, min);
221 return min;
222 }
223 if (value > max) {
224 fs_log("clamping value %d for key %s to %d\n", value, key, max);
225 return max;
226 }
227 return value;
228 }
229
fs_config_get_double(const char * key)230 double fs_config_get_double(const char *key)
231 {
232 const char *value = fs_config_get_const_string(key);
233 if (value == NULL) {
234 return FS_CONFIG_NONE;
235 }
236 return g_ascii_strtod(value, NULL);
237 }
238
fs_config_get_double_clamped(const char * key,double min,double max)239 double fs_config_get_double_clamped(const char *key, double min, double max)
240 {
241 double value = fs_config_get_double(key);
242 if (value == FS_CONFIG_NONE) {
243 return value;
244 }
245 if (value < min) {
246 fs_log("clamping value %d for key %s to %d\n", value, key, min);
247 return min;
248 }
249 if (value > max) {
250 fs_log("clamping value %d for key %s to %d\n", value, key, max);
251 return max;
252 }
253 return value;
254 }
255
fs_config_parse_options(int argc,char ** argv)256 void fs_config_parse_options(int argc, char **argv)
257 {
258 if (!g_initialized) {
259 initialize();
260 }
261 int first = 1;
262 for (int i = 0; i < argc; i++) {
263 char *arg = argv[i];
264 if (!g_str_has_prefix(arg, "--")) {
265 continue;
266 }
267 char *key = arg + 2;
268 char *value = strchr(arg, '=');
269 char *k, *v;
270 if (value) {
271 k = g_strndup(key, value - key);
272 v = g_strdup(value + 1);
273 } else {
274 if (g_str_has_prefix(key, "no-")) {
275 k = g_strdup(key + 3);
276 v = g_strdup("0");
277 } else {
278 k = g_strdup(key);
279 v = g_strdup("1");
280 }
281 }
282
283 if (first) {
284 fs_log("\n");
285 fs_log(LOG_LINE);
286 fs_log("config (command line arguments)\n");
287 fs_log(LOG_LINE);
288 fs_log("\n");
289 first = 0;
290 }
291 process_key_value(k, v, 0);
292 g_free(k);
293 /* v is owned by process_key_file, do not free here! */
294 }
295 }
296