comparison config.c @ 1692:5dacaef602a7 segacd

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 05 Jan 2019 00:58:08 -0800
parents 1fc61c844ec5
children ba3fb7a3be6b
comparison
equal deleted inserted replaced
1504:95b3a1a8b26c 1692:5dacaef602a7
3 This file is part of BlastEm. 3 This file is part of BlastEm.
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 <stdio.h> 9 #include <stdio.h>
9 #include <stdlib.h> 10 #include <stdlib.h>
10 #include <string.h> 11 #include <string.h>
11 12
12 #ifdef __MINGW64_VERSION_MAJOR 13 #ifdef __MINGW64_VERSION_MAJOR
34 } 35 }
35 return NULL; 36 return NULL;
36 } 37 }
37 #endif 38 #endif
38 39
39 tern_node * parse_config_int(char **state, int started, int *line) 40 static tern_node * parse_config_int(char **state, int started, int *line)
40 { 41 {
41 char *config_data, *curline; 42 char *config_data, *curline;
42 tern_node * head = NULL; 43 tern_node * head = NULL;
43 config_data = started ? NULL : *state; 44 config_data = started ? NULL : *state;
44 while ((curline = strtok_r(config_data, "\n", state))) 45 while ((curline = strtok_r(config_data, "\n", state)))
86 { 87 {
87 int line = 1; 88 int line = 1;
88 return parse_config_int(&config_data, 0, &line); 89 return parse_config_int(&config_data, 0, &line);
89 } 90 }
90 91
92 typedef struct {
93 char *buf;
94 uint32_t capacity;
95 uint32_t size;
96 uint32_t indent;
97 } serialize_state;
98
99 static void ensure_buf_capacity(uint32_t ensure, serialize_state *state)
100 {
101 if (ensure + state->size > state->capacity) {
102 state->capacity = state->capacity * 2;
103 state->buf = realloc(state->buf, state->capacity);
104 }
105 }
106
107 static void indent(serialize_state *state)
108 {
109 memset(state->buf + state->size, '\t', state->indent);
110 state->size += state->indent;
111 }
112
113 static void serialize_config_int(tern_node *config, serialize_state *state);
114
115 static void serialize_iter(char *key, tern_val val, uint8_t valtype, void *data)
116 {
117 serialize_state *state = data;
118 uint32_t keylen = strlen(key);
119 uint32_t vallen = 0;
120 if (valtype == TVAL_PTR) {
121 vallen = strlen(val.ptrval);
122 }
123 ensure_buf_capacity(state->indent + keylen + 2 + vallen, state);
124 state->buf[state->size++] = '\n';
125 indent(state);
126 memcpy(state->buf + state->size, key, keylen);
127 state->size += keylen;
128 state->buf[state->size++] = ' ';
129 if (valtype == TVAL_PTR) {
130 memcpy(state->buf + state->size, val.ptrval, vallen);
131 state->size += vallen;
132 } else {
133 serialize_config_int(val.ptrval, state);
134 }
135 }
136
137 static void serialize_config_int(tern_node *config, serialize_state *state)
138 {
139 ensure_buf_capacity(1, state);
140 state->buf[state->size++] = '{';
141 state->indent++;
142
143 tern_foreach(config, serialize_iter, state);
144
145 --state->indent;
146 ensure_buf_capacity(2 + state->indent, state);
147 state->buf[state->size++] = '\n';
148 indent(state);
149 state->buf[state->size++] = '}';
150 }
151
152 char *serialize_config(tern_node *config, uint32_t *size_out)
153 {
154 serialize_state state = {
155 .size = 0,
156 .capacity = 1024,
157 .indent = 0
158 };
159 state.buf = malloc(state.capacity);
160 tern_foreach(config, serialize_iter, &state);
161 //serialize_config_int(config, &state);
162 *size_out = state.size;
163 return state.buf;
164 }
165
91 tern_node *parse_config_file(char *config_path) 166 tern_node *parse_config_file(char *config_path)
92 { 167 {
93 tern_node * ret = NULL; 168 tern_node * ret = NULL;
94 FILE * config_file = fopen(config_path, "rb"); 169 FILE * config_file = fopen(config_path, "rb");
95 if (!config_file) { 170 if (!config_file) {
112 fclose(config_file); 187 fclose(config_file);
113 open_fail: 188 open_fail:
114 return ret; 189 return ret;
115 } 190 }
116 191
192 uint8_t serialize_config_file(tern_node *config, char *path)
193 {
194 FILE *f = fopen(path, "w");
195 if (!f) {
196 return 0;
197 }
198 uint32_t buf_size;
199 char *buffer = serialize_config(config, &buf_size);
200 uint8_t ret = buf_size == fwrite(buffer, 1, buf_size, f);
201 free(buffer);
202 fclose(f);
203 return ret;
204 }
205
117 tern_node *parse_bundled_config(char *config_name) 206 tern_node *parse_bundled_config(char *config_name)
118 { 207 {
119 uint32_t confsize; 208 uint32_t confsize;
120 char *confdata = read_bundled_file(config_name, &confsize); 209 char *confdata = read_bundled_file(config_name, &confsize);
121 tern_node *ret = NULL; 210 tern_node *ret = NULL;
125 free(confdata); 214 free(confdata);
126 } 215 }
127 return ret; 216 return ret;
128 } 217 }
129 218
130 tern_node *load_config() 219 tern_node *load_overrideable_config(char *name, char *bundled_name)
131 { 220 {
132 char const *confdir = get_config_dir(); 221 char const *confdir = get_config_dir();
133 char *confpath = NULL; 222 char *confpath = NULL;
134 tern_node *ret; 223 tern_node *ret;
135 if (confdir) { 224 if (confdir) {
136 confpath = alloc_concat(confdir, "/blastem.cfg"); 225 confpath = path_append(confdir, name);
137 ret = parse_config_file(confpath); 226 ret = parse_config_file(confpath);
138 if (ret) { 227 if (ret) {
139 free(confpath); 228 free(confpath);
140 return ret; 229 return ret;
141 } 230 }
142 } 231 }
143 232
233 ret = parse_bundled_config(bundled_name);
234 if (ret) {
235 free(confpath);
236 return ret;
237 }
238 return NULL;
239 }
240
241 tern_node *load_config()
242 {
243 char const *confdir = get_config_dir();
244 char *confpath = NULL;
245 tern_node *ret = load_overrideable_config("blastem.cfg", "default.cfg");
246 if (confdir) {
247 confpath = path_append(confdir, "blastem.cfg");
248 ret = parse_config_file(confpath);
249 if (ret) {
250 free(confpath);
251 return ret;
252 }
253 }
254
144 ret = parse_bundled_config("default.cfg"); 255 ret = parse_bundled_config("default.cfg");
145 if (ret) { 256 if (ret) {
146 free(confpath); 257 free(confpath);
147 return ret; 258 return ret;
148 } 259 }
149 260
150 if (confpath) { 261 if (get_config_dir()) {
151 fatal_error("Failed to find a config file at %s or in the blastem executable directory\n", confpath); 262 fatal_error("Failed to find a config file at %s or in the blastem executable directory\n", get_config_dir());
152 } else { 263 } else {
153 fatal_error("Failed to find a config file in the BlastEm executable directory and the config directory path could not be determined\n"); 264 fatal_error("Failed to find a config file in the BlastEm executable directory and the config directory path could not be determined\n");
154 } 265 }
155 //this will never get reached, but the compiler doesn't know that. Let's make it happy 266 //this will never get reached, but the compiler doesn't know that. Let's make it happy
156 return NULL; 267 return NULL;
157 } 268 }
269
270 void persist_config_at(tern_node *config, char *fname)
271 {
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);
280 }
281 free(confpath);
282 }
283
284 void persist_config(tern_node *config)
285 {
286 persist_config_at(config, "blastem.cfg");
287 }
288
289 char **get_extension_list(tern_node *config, uint32_t *num_exts_out)
290 {
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);
292 uint32_t num_exts = 0, ext_storage = 5;
293 char **ext_list = malloc(sizeof(char *) * ext_storage);
294 char *cur_filter = ext_filter;
295 while (*cur_filter)
296 {
297 if (num_exts == ext_storage) {
298 ext_storage *= 2;
299 ext_list = realloc(ext_list, sizeof(char *) * ext_storage);
300 }
301 ext_list[num_exts++] = cur_filter;
302 cur_filter = split_keyval(cur_filter);
303 }
304 *num_exts_out = num_exts;
305 return ext_list;
306 }
307
308 #define DEFAULT_LOWPASS_CUTOFF 3390
309 uint32_t get_lowpass_cutoff(tern_node *config)
310 {
311 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;
313 }