From 44fd8cde61e3e89e5f83c98900a403e922073727 Mon Sep 17 00:00:00 2001 From: Albert Cervin Date: Tue, 21 Feb 2023 22:26:36 +0100 Subject: Implement support for settings Settings are a flat "dictionary" containing paths to settings on the format: ... --- src/settings.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 src/settings.c (limited to 'src/settings.c') diff --git a/src/settings.c b/src/settings.c new file mode 100644 index 0000000..08e31d4 --- /dev/null +++ b/src/settings.c @@ -0,0 +1,168 @@ +#include "settings.h" +#include "command.h" +#include "hash.h" +#include "minibuffer.h" + +#include +#include +#include + +static struct settings g_settings = {0}; + +void settings_resize(uint32_t new_capacity) { + if (new_capacity > g_settings.capacity) { + g_settings.settings = + realloc(g_settings.settings, sizeof(struct setting) * new_capacity); + } +} + +void settings_init(uint32_t initial_capacity) { + settings_resize(initial_capacity); + g_settings.capacity = initial_capacity; + g_settings.nsettings = 0; +} + +void settings_destroy() { + for (uint32_t i = 0; i < g_settings.nsettings; ++i) { + struct setting *setting = &g_settings.settings[i]; + if (setting->value.type == Setting_String) { + free(setting->value.string_value); + } + } + + free(g_settings.settings); + g_settings.settings = NULL; + g_settings.capacity = 0; + g_settings.nsettings = 0; +} + +void settings_register_setting(const char *path, + struct setting_value default_value) { + if (g_settings.nsettings + 1 == g_settings.capacity) { + g_settings.capacity *= 2; + settings_resize(g_settings.capacity); + } + + struct setting *s = &g_settings.settings[g_settings.nsettings]; + s->value = default_value; + s->hash = hash_name(path); + strncpy(s->path, path, 128); + s->path[127] = '\0'; + + ++g_settings.nsettings; +} + +struct setting *settings_get(const char *path) { + uint32_t needle = hash_name(path); + + for (uint32_t i = 0; i < g_settings.nsettings; ++i) { + struct setting *setting = &g_settings.settings[i]; + if (setting->hash == needle) { + return setting; + } + } + + return NULL; +} + +void settings_get_prefix(const char *prefix, struct setting **settings_out[], + uint32_t *nsettings_out) { + + uint32_t capacity = 16; + struct setting **res = malloc(sizeof(struct setting *) * capacity); + uint32_t nsettings = 0; + for (uint32_t i = 0; i < g_settings.nsettings; ++i) { + struct setting *setting = &g_settings.settings[i]; + if (strncmp(prefix, setting->path, strlen(prefix)) == 0) { + if (nsettings + 1 == capacity) { + capacity *= 2; + res = realloc(res, sizeof(struct setting *) * capacity); + } + + res[nsettings] = setting; + ++nsettings; + } + } + + *nsettings_out = nsettings; + *settings_out = res; +} + +void settings_set(const char *path, struct setting_value value) { + struct setting *setting = settings_get(path); + if (setting != NULL && setting->value.type == value.type) { + setting->value = value; + } +} + +void setting_to_string(struct setting *setting, char *buf, size_t n) { + switch (setting->value.type) { + case Setting_Bool: + snprintf(buf, n, "%s", setting->value.bool_value ? "true" : false); + break; + case Setting_Number: + snprintf(buf, n, "%ld", setting->value.number_value); + break; + case Setting_String: + snprintf(buf, n, "%s", setting->value.string_value); + break; + } +} + +int32_t settings_get_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + if (argc == 0) { + return minibuffer_prompt(ctx, "setting: "); + } + + struct setting *setting = settings_get(argv[0]); + if (setting == NULL) { + minibuffer_echo_timeout(4, "no such setting \"%s\"", argv[0]); + return 1; + } else { + char buf[128]; + setting_to_string(setting, buf, 128); + minibuffer_echo("%s = %s", argv[0], buf); + } + + return 0; +} + +int32_t settings_set_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + if (argc == 0) { + return minibuffer_prompt(ctx, "setting: "); + } else if (argc == 1) { + // validate setting here as well + struct setting *setting = settings_get(argv[0]); + if (setting == NULL) { + minibuffer_echo_timeout(4, "no such setting \"%s\"", argv[0]); + return 1; + } + + command_ctx_push_arg(&ctx, argv[0]); + return minibuffer_prompt(ctx, "value: "); + } + + struct setting *setting = settings_get(argv[0]); + if (setting == NULL) { + minibuffer_echo_timeout(4, "no such setting \"%s\"", argv[0]); + return 1; + } else { + const char *value = argv[1]; + struct setting_value new_value = {.type = setting->value.type}; + switch (setting->value.type) { + case Setting_Bool: + new_value.bool_value = strncmp("true", value, 4) == 0; + break; + case Setting_Number: + new_value.number_value = atol(value); + break; + case Setting_String: + new_value.string_value = strdup(value); + break; + } + + setting->value = new_value; + } + + return 0; +} -- cgit v1.2.3