# HG changeset patch # User Michael Pavone # Date 1511973697 28800 # Node ID 637fbc3b50632acf9031a8df6d91c745c9cb87bc # Parent f29bd94ffa76c9e303cb722e66c61725f0df0451 Added code to persist config back to a file diff -r f29bd94ffa76 -r 637fbc3b5063 blastem.c --- a/blastem.c Sun Nov 26 20:19:36 2017 -0800 +++ b/blastem.c Wed Nov 29 08:41:37 2017 -0800 @@ -286,6 +286,11 @@ update_title(info.name); } +static void save_config(void) +{ + persist_config(config); +} + int main(int argc, char ** argv) { set_exe_str(argv[0]); @@ -521,6 +526,8 @@ } } + atexit(save_config); + #ifndef DISABLE_NUKLEAR if (use_nuklear) { blastem_nuklear_init(!menu); diff -r f29bd94ffa76 -r 637fbc3b5063 config.c --- a/config.c Sun Nov 26 20:19:36 2017 -0800 +++ b/config.c Wed Nov 29 08:41:37 2017 -0800 @@ -5,6 +5,7 @@ */ #include "tern.h" #include "util.h" +#include "paths.h" #include #include #include @@ -36,7 +37,7 @@ } #endif -tern_node * parse_config_int(char **state, int started, int *line) +static tern_node * parse_config_int(char **state, int started, int *line) { char *config_data, *curline; tern_node * head = NULL; @@ -88,6 +89,80 @@ return parse_config_int(&config_data, 0, &line); } +typedef struct { + char *buf; + uint32_t capacity; + uint32_t size; + uint32_t indent; +} serialize_state; + +static void ensure_buf_capacity(uint32_t ensure, serialize_state *state) +{ + if (ensure + state->size > state->capacity) { + state->capacity = state->capacity * 2; + state->buf = realloc(state->buf, state->capacity); + } +} + +static void indent(serialize_state *state) +{ + memset(state->buf + state->size, '\t', state->indent); + state->size += state->indent; +} + +static void serialize_config_int(tern_node *config, serialize_state *state); + +static void serialize_iter(char *key, tern_val val, uint8_t valtype, void *data) +{ + serialize_state *state = data; + uint32_t keylen = strlen(key); + uint32_t vallen = 0; + if (valtype == TVAL_PTR) { + vallen = strlen(val.ptrval); + } + ensure_buf_capacity(state->indent + keylen + 2 + vallen, state); + state->buf[state->size++] = '\n'; + indent(state); + memcpy(state->buf + state->size, key, keylen); + state->size += keylen; + state->buf[state->size++] = ' '; + if (valtype == TVAL_PTR) { + memcpy(state->buf + state->size, val.ptrval, vallen); + state->size += vallen; + } else { + serialize_config_int(val.ptrval, state); + } +} + +static void serialize_config_int(tern_node *config, serialize_state *state) +{ + ensure_buf_capacity(1, state); + state->buf[state->size++] = '{'; + state->indent++; + + tern_foreach(config, serialize_iter, state); + + --state->indent; + ensure_buf_capacity(2 + state->indent, state); + state->buf[state->size++] = '\n'; + indent(state); + state->buf[state->size++] = '}'; +} + +char *serialize_config(tern_node *config, uint32_t *size_out) +{ + serialize_state state = { + .size = 0, + .capacity = 1024, + .indent = 0 + }; + state.buf = malloc(state.capacity); + tern_foreach(config, serialize_iter, &state); + //serialize_config_int(config, &state); + *size_out = state.size; + return state.buf; +} + tern_node *parse_config_file(char *config_path) { tern_node * ret = NULL; @@ -114,6 +189,19 @@ return ret; } +uint8_t serialize_config_file(tern_node *config, char *path) +{ + FILE *f = fopen(path, "w"); + if (!f) { + return 0; + } + uint32_t buf_size; + char *buffer = serialize_config(config, &buf_size); + uint8_t ret = buf_size == fwrite(buffer, 1, buf_size, f); + fclose(f); + return ret; +} + tern_node *parse_bundled_config(char *config_name) { uint32_t confsize; @@ -133,7 +221,7 @@ char *confpath = NULL; tern_node *ret; if (confdir) { - confpath = alloc_concat(confdir, "/blastem.cfg"); + confpath = path_append(confdir, "blastem.cfg"); ret = parse_config_file(confpath); if (ret) { free(confpath); @@ -156,6 +244,19 @@ return NULL; } +void persist_config(tern_node *config) +{ + char const *confdir = get_config_dir(); + if (!confdir) { + fatal_error("Failed to locate config file directory\n"); + } + char *confpath = path_append(confdir, "blastem.cfg"); + if (!serialize_config_file(config, confpath)) { + fatal_error("Failed to write config to %s\n", confpath); + } + free(confpath); +} + char **get_extension_list(tern_node *config, uint32_t *num_exts_out) { char *ext_filter = strdup(tern_find_path_default(config, "ui\0extensions\0", (tern_val){.ptrval = "bin gen md smd sms gg"}, TVAL_PTR).ptrval); diff -r f29bd94ffa76 -r 637fbc3b5063 config.h --- a/config.h Sun Nov 26 20:19:36 2017 -0800 +++ b/config.h Wed Nov 29 08:41:37 2017 -0800 @@ -10,6 +10,9 @@ tern_node *parse_config_file(char *config_path); tern_node *parse_bundled_config(char *config_name); tern_node *load_config(); +char *serialize_config(tern_node *config, uint32_t *size_out); +uint8_t serialize_config_file(tern_node *config, char *path); +void persist_config(tern_node *config); char **get_extension_list(tern_node *config, uint32_t *num_exts_out); #endif //CONFIG_H_ diff -r f29bd94ffa76 -r 637fbc3b5063 paths.c --- a/paths.c Sun Nov 26 20:19:36 2017 -0800 +++ b/paths.c Wed Nov 29 08:41:37 2017 -0800 @@ -102,7 +102,7 @@ tern_free(vars); } -char *path_append(char *base, char *suffix) +char *path_append(const char *base, const char *suffix) { if (!strcmp(suffix, "..")) { #ifdef _WIN32 diff -r f29bd94ffa76 -r 637fbc3b5063 paths.h --- a/paths.h Sun Nov 26 20:19:36 2017 -0800 +++ b/paths.h Wed Nov 29 08:41:37 2017 -0800 @@ -2,6 +2,6 @@ #define PATHS_H_ void get_initial_browse_path(char **dst); -char *path_append(char *base, char *suffix); +char *path_append(const char *base, const char *suffix); #endif //PATHS_H_ \ No newline at end of file