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 }