Mercurial > repos > blastem
comparison config.c @ 2053:3414a4423de1 segacd
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 15 Jan 2022 13:15:21 -0800 |
parents | 193b804c9845 |
children | bdd83b47d78a |
comparison
equal
deleted
inserted
replaced
1692:5dacaef602a7 | 2053:3414a4423de1 |
---|---|
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. | 4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. |
5 */ | 5 */ |
6 #include "tern.h" | 6 #include "tern.h" |
7 #include "util.h" | 7 #include "util.h" |
8 #include "paths.h" | 8 #include "paths.h" |
9 #include "config.h" | |
9 #include <stdio.h> | 10 #include <stdio.h> |
10 #include <stdlib.h> | 11 #include <stdlib.h> |
11 #include <string.h> | 12 #include <string.h> |
12 | 13 |
13 #ifdef __MINGW64_VERSION_MAJOR | 14 #ifdef __MINGW64_VERSION_MAJOR |
47 | 48 |
48 config_data = NULL; | 49 config_data = NULL; |
49 curline = strip_ws(curline); | 50 curline = strip_ws(curline); |
50 int len = strlen(curline); | 51 int len = strlen(curline); |
51 if (!len) { | 52 if (!len) { |
52 *line = *line + 1; | 53 (*line)++; |
53 continue; | 54 continue; |
54 } | 55 } |
55 if (curline[0] == '#') { | 56 if (curline[0] == '#') { |
56 *line = *line + 1; | 57 (*line)++; |
57 continue; | 58 continue; |
58 } | 59 } |
59 if (curline[0] == '}') { | 60 if (curline[0] == '}') { |
60 if (started) { | 61 if (started) { |
61 return head; | 62 return head; |
65 | 66 |
66 char * end = curline + len - 1; | 67 char * end = curline + len - 1; |
67 if (*end == '{') { | 68 if (*end == '{') { |
68 *end = 0; | 69 *end = 0; |
69 curline = strip_ws(curline); | 70 curline = strip_ws(curline); |
70 *line = *line + 1; | 71 (*line)++; |
71 head = tern_insert_node(head, curline, parse_config_int(state, 1, line)); | 72 head = tern_insert_node(head, curline, parse_config_int(state, 1, line)); |
72 } else { | 73 } else { |
73 char * val = strip_ws(split_keyval(curline)); | 74 char * val = strip_ws(split_keyval(curline)); |
74 char * key = curline; | 75 char * key = curline; |
75 if (*val) { | 76 if (*val) { |
76 head = tern_insert_ptr(head, key, strdup(val)); | 77 head = tern_insert_ptr(head, key, strdup(val)); |
77 } else { | 78 } else { |
78 fprintf(stderr, "Key %s is missing a value on line %d\n", key, *line); | 79 fprintf(stderr, "Key %s is missing a value on line %d\n", key, *line); |
79 } | 80 } |
80 *line = *line + 1; | 81 (*line)++; |
81 } | 82 } |
82 } | 83 } |
83 return head; | 84 return head; |
84 } | 85 } |
85 | 86 |
172 } | 173 } |
173 long config_size = file_size(config_file); | 174 long config_size = file_size(config_file); |
174 if (!config_size) { | 175 if (!config_size) { |
175 goto config_empty; | 176 goto config_empty; |
176 } | 177 } |
177 char * config_data = malloc(config_size+1); | 178 char *config_data = calloc(config_size + 1, 1); |
178 if (fread(config_data, 1, config_size, config_file) != config_size) { | 179 if (fread(config_data, 1, config_size, config_file) != config_size) { |
179 goto config_read_fail; | 180 goto config_read_fail; |
180 } | 181 } |
181 config_data[config_size] = '\0'; | |
182 | 182 |
183 ret = parse_config(config_data); | 183 ret = parse_config(config_data); |
184 config_read_fail: | 184 config_read_fail: |
185 free(config_data); | 185 free(config_data); |
186 config_empty: | 186 config_empty: |
203 return ret; | 203 return ret; |
204 } | 204 } |
205 | 205 |
206 tern_node *parse_bundled_config(char *config_name) | 206 tern_node *parse_bundled_config(char *config_name) |
207 { | 207 { |
208 tern_node *ret = NULL; | |
209 #ifdef CONFIG_PATH | |
210 if (!strcmp("default.cfg", config_name) || !strcmp("blastem.cfg", config_name)) { | |
211 char *confpath = path_append(CONFIG_PATH, config_name); | |
212 ret = parse_config_file(confpath); | |
213 free(confpath); | |
214 } else { | |
215 #endif | |
208 uint32_t confsize; | 216 uint32_t confsize; |
209 char *confdata = read_bundled_file(config_name, &confsize); | 217 char *confdata = read_bundled_file(config_name, &confsize); |
210 tern_node *ret = NULL; | |
211 if (confdata) { | 218 if (confdata) { |
212 confdata[confsize] = 0; | 219 confdata[confsize] = 0; |
213 ret = parse_config(confdata); | 220 ret = parse_config(confdata); |
214 free(confdata); | 221 free(confdata); |
215 } | 222 } |
216 return ret; | 223 #ifdef CONFIG_PATH |
217 } | 224 } |
218 | 225 #endif |
219 tern_node *load_overrideable_config(char *name, char *bundled_name) | 226 return ret; |
227 } | |
228 | |
229 tern_node *load_overrideable_config(char *name, char *bundled_name, uint8_t *used_config_dir) | |
220 { | 230 { |
221 char const *confdir = get_config_dir(); | 231 char const *confdir = get_config_dir(); |
222 char *confpath = NULL; | 232 char *confpath = NULL; |
223 tern_node *ret; | 233 tern_node *ret; |
224 if (confdir) { | 234 if (confdir) { |
225 confpath = path_append(confdir, name); | 235 confpath = path_append(confdir, name); |
226 ret = parse_config_file(confpath); | 236 ret = parse_config_file(confpath); |
227 if (ret) { | 237 } |
228 free(confpath); | 238 free(confpath); |
229 return ret; | 239 if (used_config_dir) { |
230 } | 240 *used_config_dir = ret != NULL; |
231 } | 241 } |
232 | 242 |
233 ret = parse_bundled_config(bundled_name); | 243 if (!ret) { |
234 if (ret) { | 244 ret = parse_bundled_config(name); |
235 free(confpath); | 245 if (!ret) { |
236 return ret; | 246 ret = parse_bundled_config(bundled_name); |
237 } | 247 } |
238 return NULL; | 248 } |
239 } | 249 |
240 | 250 return ret; |
251 } | |
252 | |
253 static uint8_t app_config_in_config_dir; | |
241 tern_node *load_config() | 254 tern_node *load_config() |
242 { | 255 { |
243 char const *confdir = get_config_dir(); | 256 tern_node *ret = load_overrideable_config("blastem.cfg", "default.cfg", &app_config_in_config_dir); |
244 char *confpath = NULL; | 257 |
245 tern_node *ret = load_overrideable_config("blastem.cfg", "default.cfg"); | 258 if (!ret) { |
246 if (confdir) { | 259 if (get_config_dir()) { |
247 confpath = path_append(confdir, "blastem.cfg"); | 260 fatal_error("Failed to find a config file at %s or in the blastem executable directory\n", get_config_dir()); |
248 ret = parse_config_file(confpath); | 261 } else { |
249 if (ret) { | 262 fatal_error("Failed to find a config file in the BlastEm executable directory and the config directory path could not be determined\n"); |
250 free(confpath); | 263 } |
251 return ret; | 264 } |
252 } | 265 return ret; |
253 } | 266 } |
254 | 267 |
255 ret = parse_bundled_config("default.cfg"); | 268 void persist_config_at(tern_node *app_config, tern_node *to_save, char *fname) |
256 if (ret) { | 269 { |
257 free(confpath); | 270 char*use_exe_dir = tern_find_path_default(app_config, "ui\0config_in_exe_dir\0", (tern_val){.ptrval = "off"}, TVAL_PTR).ptrval; |
258 return ret; | 271 char *confpath; |
259 } | 272 if (!strcmp(use_exe_dir, "on")) { |
260 | 273 confpath = path_append(get_exe_dir(), fname); |
261 if (get_config_dir()) { | 274 if (app_config == to_save && app_config_in_config_dir) { |
262 fatal_error("Failed to find a config file at %s or in the blastem executable directory\n", get_config_dir()); | 275 //user switched to "portable" configs this session and there is an |
276 //existing config file in the user-specific config directory | |
277 //delete it so we don't end up loading it next time | |
278 char *oldpath = path_append(get_config_dir(), fname); | |
279 delete_file(oldpath); | |
280 free(oldpath); | |
281 } | |
263 } else { | 282 } else { |
264 fatal_error("Failed to find a config file in the BlastEm executable directory and the config directory path could not be determined\n"); | 283 char const *confdir = get_config_dir(); |
265 } | 284 if (!confdir) { |
266 //this will never get reached, but the compiler doesn't know that. Let's make it happy | 285 fatal_error("Failed to locate config file directory\n"); |
267 return NULL; | 286 } |
268 } | 287 ensure_dir_exists(confdir); |
269 | 288 confpath = path_append(confdir, fname); |
270 void persist_config_at(tern_node *config, char *fname) | 289 } |
271 { | 290 if (!serialize_config_file(to_save, confpath)) { |
272 char const *confdir = get_config_dir(); | |
273 if (!confdir) { | |
274 fatal_error("Failed to locate config file directory\n"); | |
275 } | |
276 ensure_dir_exists(confdir); | |
277 char *confpath = path_append(confdir, fname); | |
278 if (!serialize_config_file(config, confpath)) { | |
279 fatal_error("Failed to write config to %s\n", confpath); | 291 fatal_error("Failed to write config to %s\n", confpath); |
280 } | 292 } |
281 free(confpath); | 293 free(confpath); |
282 } | 294 } |
283 | 295 |
284 void persist_config(tern_node *config) | 296 void persist_config(tern_node *config) |
285 { | 297 { |
286 persist_config_at(config, "blastem.cfg"); | 298 persist_config_at(config, config, "blastem.cfg"); |
299 } | |
300 | |
301 void delete_custom_config_at(char *fname) | |
302 { | |
303 char *confpath = path_append(get_exe_dir(), fname); | |
304 delete_file(confpath); | |
305 free(confpath); | |
306 confpath = path_append(get_config_dir(), fname); | |
307 delete_file(confpath); | |
308 free(confpath); | |
309 } | |
310 | |
311 void delete_custom_config(void) | |
312 { | |
313 delete_custom_config_at("blastem.cfg"); | |
287 } | 314 } |
288 | 315 |
289 char **get_extension_list(tern_node *config, uint32_t *num_exts_out) | 316 char **get_extension_list(tern_node *config, uint32_t *num_exts_out) |
290 { | 317 { |
291 char *ext_filter = strdup(tern_find_path_default(config, "ui\0extensions\0", (tern_val){.ptrval = "bin gen md smd sms gg"}, TVAL_PTR).ptrval); | 318 char *ext_filter = strdup(tern_find_path_default(config, "ui\0extensions\0", (tern_val){.ptrval = "bin gen md smd sms gg"}, TVAL_PTR).ptrval); |
309 uint32_t get_lowpass_cutoff(tern_node *config) | 336 uint32_t get_lowpass_cutoff(tern_node *config) |
310 { | 337 { |
311 char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval; | 338 char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval; |
312 return lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : DEFAULT_LOWPASS_CUTOFF; | 339 return lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : DEFAULT_LOWPASS_CUTOFF; |
313 } | 340 } |
341 | |
342 tern_node *get_systems_config(void) | |
343 { | |
344 static tern_node *systems; | |
345 if (!systems) { | |
346 systems = parse_bundled_config("systems.cfg"); | |
347 } | |
348 return systems; | |
349 } | |
350 | |
351 tern_node *get_model(tern_node *config, system_type stype) | |
352 { | |
353 char *model = tern_find_path_default(config, "system\0model\0", (tern_val){.ptrval = "md1va3"}, TVAL_PTR).ptrval; | |
354 return tern_find_node(get_systems_config(), model); | |
355 } |