diff options
| author | Albert Cervin <albert@acervin.com> | 2023-05-18 23:51:51 +0200 |
|---|---|---|
| committer | Albert Cervin <albert@acervin.com> | 2023-05-24 22:18:12 +0200 |
| commit | 4f3b576db6b01c8c88076985478e2a7fa37be340 (patch) | |
| tree | 9723ed39a19872fd52f2867613e78e02de3cf79b /src/dged/settings.c | |
| parent | a4d17ddb8e7d23ccca13132f4d88cfc5f5730b76 (diff) | |
| download | dged-4f3b576db6b01c8c88076985478e2a7fa37be340.tar.gz dged-4f3b576db6b01c8c88076985478e2a7fa37be340.tar.xz dged-4f3b576db6b01c8c88076985478e2a7fa37be340.zip | |
TOML settings parsing
Currently a very simplistic parser that do not support all TOML
datatypes. Supported are:
- Tables
- Strings (incl multiline)
- Integers
- Inline Tables
- Booleans
- Comments
Diffstat (limited to 'src/dged/settings.c')
| -rw-r--r-- | src/dged/settings.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/src/dged/settings.c b/src/dged/settings.c index 524aa9b..4370aa9 100644 --- a/src/dged/settings.c +++ b/src/dged/settings.c @@ -3,11 +3,15 @@ #include "hash.h" #include "hashmap.h" #include "minibuffer.h" +#include "settings-parse.h" +#include "utf8.h" #include "vec.h" +#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> static struct settings g_settings = {0}; @@ -80,6 +84,15 @@ void settings_set(const char *path, struct setting_value value) { } } +static void settings_upsert(const char *path, struct setting_value value) { + struct setting *setting = settings_get(path); + if (setting != NULL) { + setting_set_value(setting, value); + } else { + settings_register_setting(path, value); + } +} + void setting_to_string(struct setting *setting, char *buf, size_t n) { switch (setting->value.type) { case Setting_Bool: @@ -93,3 +106,186 @@ void setting_to_string(struct setting *setting, char *buf, size_t n) { break; } } + +static int32_t parse_toml(struct parser *state, char **errmsgs[]) { + char *curtbl = NULL; + char *curkey = NULL; + uint32_t errcnt = 0; + + VEC(char *) errs; + VEC_INIT(&errs, 16); + + struct token t = {0}; + while (parser_next_token(state, &t)) { + switch (t.type) { + case Token_Table: + if (curtbl != NULL) { + free(curtbl); + } + curtbl = calloc(t.len + 1, 1); + strncpy(curtbl, (char *)t.data, t.len); + break; + + case Token_InlineTable: + if (curkey != NULL) { + free(curtbl); + curtbl = strdup(curkey); + } + break; + + case Token_Key: + if (curkey != NULL) { + free(curkey); + } + uint32_t len = t.len + 1; + if (curtbl != NULL) { + len += strlen(curtbl) /* space for the . */ + 1; + } + + curkey = calloc(len, 1); + if (curtbl != NULL) { + strcpy(curkey, curtbl); + strncat(curkey, ".", 1); + } + + strncat(curkey, (char *)t.data, t.len); + break; + + case Token_IntValue: + int64_t i = *((int64_t *)t.data); + settings_upsert(curkey, (struct setting_value){.type = Setting_Number, + .number_value = i}); + break; + + case Token_BoolValue: + bool b = *((bool *)t.data); + settings_upsert(curkey, (struct setting_value){.type = Setting_Bool, + .bool_value = b}); + break; + + case Token_StringValue: + char *v = calloc(t.len + 1, 1); + strncpy(v, (char *)t.data, t.len); + settings_upsert(curkey, (struct setting_value){.type = Setting_String, + .string_value = v}); + free(v); + break; + + case Token_Error: + char *err = malloc(t.len + 128); + snprintf(err, t.len + 128, "error (%d:%d): %.*s\n", t.row, t.col, t.len, + (char *)t.data); + VEC_PUSH(&errs, err); + break; + } + } + + if (curtbl != NULL) { + free(curtbl); + } + + if (curkey != NULL) { + free(curkey); + } + + if (!VEC_EMPTY(&errs)) { + *errmsgs = VEC_ENTRIES(&errs); + } else { + *errmsgs = NULL; + VEC_DESTROY(&errs); + } + return VEC_SIZE(&errs); +} + +struct str_cursor { + const char *data; + uint32_t pos; + uint32_t size; +}; + +size_t get_bytes_from_str(size_t nbytes, uint8_t *buf, void *userdata) { + struct str_cursor *c = (struct str_cursor *)userdata; + size_t left = c->size - c->pos; + size_t to_copy = nbytes > left ? left : nbytes; + if (to_copy > 0) { + memcpy(buf, c->data + c->pos, to_copy); + } + + c->pos += to_copy; + + return to_copy; +} + +int32_t settings_from_string(const char *toml, char **errmsgs[]) { + struct str_cursor cursor = { + .data = toml, + .pos = 0, + .size = strlen(toml), + }; + + struct reader reader = { + .getbytes = get_bytes_from_str, + .userdata = (void *)&cursor, + }; + + struct parser parser = parser_create(reader); + int32_t ret = parse_toml(&parser, errmsgs); + + parser_destroy(&parser); + return ret; +} + +#define FILE_READER_BUFSZ 1024 +struct file_reader { + int fd; + uint8_t buffer[FILE_READER_BUFSZ]; + uint32_t buflen; +}; + +static struct file_reader file_reader_create(int fd) { + return (struct file_reader){ + .fd = fd, + .buffer = {0}, + .buflen = 0, + }; +} + +static size_t get_bytes_from_file(size_t nbytes, uint8_t *buf, void *userdata) { + struct file_reader *r = (struct file_reader *)userdata; + if (nbytes > FILE_READER_BUFSZ) { + return read(r->fd, buf, nbytes); + } + + if (nbytes > r->buflen) { + // fill buffer + r->buflen += + read(r->fd, r->buffer + r->buflen, FILE_READER_BUFSZ - r->buflen); + } + + size_t to_read = nbytes > r->buflen ? r->buflen : nbytes; + memcpy(buf, r->buffer, to_read); + + r->buflen -= to_read; + memcpy(r->buffer, r->buffer + to_read, r->buflen); + return to_read; +} + +int32_t settings_from_file(const char *path, char **errmsgs[]) { + int fd = open(path, O_RDONLY); + if (fd < 0) { + return fd; + } + + struct file_reader file_reader = file_reader_create(fd); + + struct reader reader = { + .getbytes = get_bytes_from_file, + .userdata = (void *)&file_reader, + }; + + struct parser parser = parser_create(reader); + int32_t ret = parse_toml(&parser, errmsgs); + + parser_destroy(&parser); + return ret; +} |
