From c8f5ba65044992deb3175e9b89792e13a8af4539 Mon Sep 17 00:00:00 2001 From: mrb0nk500 Date: Thu, 28 Jul 2022 19:46:53 -0300 Subject: config: Make use of `keyword` for parsing config files This get's rid of the old `config_opt` parser, which was way too specific for parsing config files. --- config.c | 74 ++++++++++++++++++++++++---------------------------------------- config.h | 48 ++++++++++++----------------------------- 2 files changed, 42 insertions(+), 80 deletions(-) diff --git a/config.c b/config.c index 1755ad3..012ed3d 100644 --- a/config.c +++ b/config.c @@ -7,42 +7,31 @@ #include "macros.h" #include "misc.h" -config_val parse_option_value(const config_opt *opt, char *value) { - config_val val = {0}; - - switch (opt->type) { - case TYPE_INT : - case TYPE_BOOL : val.i = strtol(value, NULL, 0); break; - case TYPE_STRING: val.str = make_str(value); break; - case TYPE_FLOAT : val.f = strtof(value, NULL); break; - default : break; - } - - return val; -} - -void set_config_opt(config *conf, config_type type, size_t offset, config_val val) { - char *cfg = (char *)conf; - switch (type) { - case TYPE_INT : - case TYPE_BOOL : *(int *)(cfg+offset) = val.i; break; - case TYPE_STRING: *(char **)(cfg+offset) = val.str; break; - case TYPE_FLOAT : *(float *)(cfg+offset) = val.f; break; - default : break; - } -} - void cleanup_config(config *conf) { - char *cfg = (char *)conf; - for (const config_opt *opt = config_opts; opt->name != NULL; opt++) { + for (int i = 0; config_keywords[i] != NULL; ++i) { + /* Get the pointer to the config option. */ + void *cfg = get_keyword_offset_ptr(config_keywords[i], conf); /* Is this config option's type a string, and is the string of that config option in conf not NULL? */ - if (opt->type == TYPE_STRING && *(char **)(cfg+opt->offset) != NULL) { - free(*(char **)(cfg+opt->offset)); + if (config_keywords[i]->type == TYPE_STRING && *(void **)cfg != NULL) { + free(*(void **)cfg); } } free(conf); } +int check_port(void *ctx, void *ret, const keyword *key, keyword_val val) { + if (key->type == TYPE_INT) { + if (val.i > 0 || val.i <= 65535) { + return 0; + } else { + log(LOG_ERR, "Invalid port %d. (Valid port must be between 1, and 65535.)", val.i); + } + } else { + log(LOG_ERR, "Keyword \"%s\" doesn't return an integer.", key->key); + } + return -1; +} + config *parse_config(const char *filename) { /* Size of the file, in bytes. */ long filesize = 0; @@ -69,25 +58,18 @@ config *parse_config(const char *filename) { char *line = get_line(&tmp); char *value; char *name = strtok_r(line, "=", &value); - const config_opt *opt; - - /* Check to see if the config option name we got is valid. */ - for (opt = config_opts; opt->name != NULL && strcmp(name, opt->name); opt++); + int error; - /* Is the config option valid? */ - if (opt->name != NULL) { - config_val val = parse_option_value(opt, value); - if (opt->offset == offsetof(config, port)) { - const int port = strtol(val.str, NULL, 0); - if (port <= 0 || port > 65535) { - log(LOG_ERR, "Invalid port %d. (Valid port must be between 1, and 65535.)", port); - cleanup_config(cfg); - free(line); - free(buf); - return NULL; - } + /* Did we fail to parse the config option? */ + if (error = parse_keywords(config_keywords, name, value, cfg, NULL)) { + if (error == 5) { + cleanup_config(cfg); + free(line); + free(buf); + return NULL; + } else { + log(LOG_WARNING, "Failed to parse config option \"%s\". Error code: %i", name, error); } - set_config_opt(cfg, opt->type, opt->offset, val); } free(line); diff --git a/config.h b/config.h index 5ba0978..4d35af6 100644 --- a/config.h +++ b/config.h @@ -2,20 +2,9 @@ #define CONFIG_H #include +#include "keyword.h" typedef struct config config; -typedef struct config_opt config_opt; -typedef union config_val config_val; -typedef enum config_type config_type; - -enum config_type { - TYPE_NONE, - TYPE_INT, - TYPE_STRING, - TYPE_FLOAT, - TYPE_BOOL, - TYPE_COUNT, -}; struct config { char *git_root; /* Root of git server. */ @@ -27,29 +16,20 @@ struct config { char *key_path; /* Path to maintainer authentication key file. */ }; -struct config_opt { - const char *name; /* Name of the config option. */ - const char *desc; /* Description of the config option. */ - config_type type; /* Datatype of the config option. */ - size_t offset; /* Offset of the member of the config option in the config struct. */ -}; - -union config_val { - int i; /* Integer. */ - char *str; /* String. */ - float f; /* Float. */ -}; - -static const config_opt config_opts[] = { - {"git-root", "Root of git server (can also be a url).", TYPE_STRING, offsetof(config, git_root)}, - {"socket-type", "Socket type to use (options: unix, network. default: network).", TYPE_STRING, offsetof(config, sock_type)}, - {"socket", "Path, IP address, or domain name of socket.", TYPE_STRING, offsetof(config, sock)}, - {"port", "Port to listen on (network socket only).", TYPE_STRING, offsetof(config, port)}, - {"merge-type", "Type of merge (options: 0 = Merge individually, 1 = Merge into one).", TYPE_INT, offsetof(config, merge_type)}, - {"pr-root", "Directory to store pull requests in.", TYPE_STRING, offsetof(config, pr_root)}, - {"key-file", "Path to file containing gpg/pgp public keys of each maintainer.", TYPE_STRING, offsetof(config, key_path)}, - {NULL, NULL, TYPE_NONE, -1}, +int check_port(void *ctx, void *ret, const keyword *key, keyword_val val); + +#define offset_list(...) (size_t []){__VA_ARGS__, -1} +static const keyword *config_keywords[] = { + &(const keyword){"git-root", "Root of git server (can also be a url).", NULL, TYPE_STRING, offset_list(offsetof(config, git_root)), NULL}, + &(const keyword){"socket-type", "Socket type to use (options: unix, network. default: network).", NULL, TYPE_STRING, offset_list(offsetof(config, sock_type)), NULL}, + &(const keyword){"socket", "Path, IP address, or domain name of socket.", NULL, TYPE_STRING, offset_list(offsetof(config, sock)), NULL}, + &(const keyword){"port", "Port to listen on (network socket only).", NULL, TYPE_STRING, offset_list(offsetof(config, port)), check_port}, + &(const keyword){"merge-type", "Type of merge (options: 0 = Merge individually, 1 = Merge into one).", NULL, TYPE_INT, offset_list(offsetof(config, merge_type)), NULL}, + &(const keyword){"pr-root", "Directory to store pull requests in.", NULL, TYPE_STRING, offset_list(offsetof(config, pr_root)), NULL}, + &(const keyword){"key-file", "Path to file containing gpg/pgp public keys of each maintainer.", NULL, TYPE_STRING, offset_list(offsetof(config, key_path)), NULL}, + NULL, }; +#undef offset_list extern config *parse_config(const char *filename); extern void cleanup_config(config *conf); -- cgit v1.2.3-13-gbd6f