From c1210f1426d11c6baf5865ef5a63b965323460ad Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Sat, 18 Jan 2020 17:36:55 +0000 Subject: [PATCH] Create a simple config loader --- include/cfg.h | 42 ++++++++++++++ src/cfg.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 include/cfg.h create mode 100644 src/cfg.c diff --git a/include/cfg.h b/include/cfg.h new file mode 100644 index 0000000..464eed4 --- /dev/null +++ b/include/cfg.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Andri Yngvason + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#pragma once + +#include +#include + +#define X_CFG_LIST \ + X(bool, enable_auth) \ + X(string, private_key_file) \ + X(string, certificate_file) \ + X(string, username) \ + X(string, password) \ + X(string, address) \ + X(uint, port) \ + +struct cfg { +#define string char* +#define uint uint32_t +#define X(type, name) type name; + X_CFG_LIST +#undef X +#undef uint +#undef string +}; + +int cfg_load(struct cfg* self, const char* path); +void cfg_destroy(struct cfg* self); diff --git a/src/cfg.c b/src/cfg.c new file mode 100644 index 0000000..f379f9d --- /dev/null +++ b/src/cfg.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2020 Andri Yngvason + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "cfg.h" + +#define XSTR(s) STR(s) +#define STR(s) #s + +static char* cfg__get_default_path(void) +{ + static char result[256]; + + char* xdg_config_home = getenv("XDG_CONFIG_HOME"); + if (xdg_config_home) { + snprintf(result, sizeof(result), "%s/wayvnc/config", + xdg_config_home); + result[sizeof(result) - 1] = '\0'; + return result; + } + + char* home = getenv("HOME"); + if (!home) + return NULL; + + snprintf(result, sizeof(result), "%s/.config/wayvnc/config", home); + result[sizeof(result) - 1] = '\0'; + return result; +} + +static char* cfg__trim_left(char* str) +{ + while (isspace(*str)) + ++str; + return str; +} + +static char* cfg__trim_right(char* str) +{ + char* end = str + strlen(str) - 1; + while (str < end && isspace(*end)) + *end-- = '\0'; + return str; +} + +static inline char* cfg__trim(char* str) +{ + return cfg__trim_right(cfg__trim_left(str)); +} + +static int cfg__load_key_value(struct cfg* self, + const char* key, const char* value) +{ +#define LOAD_bool(v) (strcmp(v, "false") != 0) +#define LOAD_string(v) strdup(v) +#define LOAD_uint(v) strtoul(v, NULL, 0) + +#define X(type, name) \ + if (strcmp(XSTR(name), key) == 0) { \ + self->name = LOAD_ ## type(value); \ + return 0; \ + } + + X_CFG_LIST +#undef X + +#undef LOAD_uint +#undef LOAD_string +#undef LOAD_bool + return -1; +} + +static int cfg__load_line(struct cfg* self, char* line) +{ + line = cfg__trim(line); + + if (line[0] == '\0' || line[0] == '#') + return 0; + + char* delim = strchr(line, '='); + if (!delim) + return -1; + + *delim = '\0'; + + char* key = cfg__trim_right(line); + char* value = cfg__trim_left(delim + 1); + + return cfg__load_key_value(self, key, value); +} + +int cfg_load(struct cfg* self, const char* requested_path) +{ + const char* path = requested_path ? requested_path + : cfg__get_default_path(); + + if (!path) + return -1; + + FILE* stream = fopen(path, "r"); + if (!stream) + return -1; + + char* line = NULL; + size_t len = 0; + int lineno = 0; + + while (getline(&line, &len, stream) > 0) { + ++lineno; + + if (cfg__load_line(self, line) < 0) + goto failure; + } + + fclose(stream); + return 0; + +failure: + cfg_destroy(self); + fclose(stream); + return lineno; +} + +void cfg_destroy(struct cfg* self) +{ +#define DESTROY_bool(...) +#define DESTROY_uint(...) +#define DESTROY_string(p) free(p) + +#define X(type, name) DESTROY_ ## type(self->name); + X_CFG_LIST +#undef X + +#undef DESTROY_string +#undef DESTROY_uint +#undef DESTROY_bool +}