changeset 1489:637fbc3b5063 nuklear_ui

Added code to persist config back to a file
author Michael Pavone <pavone@retrodev.com>
date Wed, 29 Nov 2017 08:41:37 -0800
parents f29bd94ffa76
children 919c0c33885e
files blastem.c config.c config.h paths.c paths.h
diffstat 5 files changed, 115 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- 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);
--- 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 <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -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);
--- 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_
--- 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
--- 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