Mercurial > repos > blastem
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 } |