From c16a1cea13c70e9c40a8db82d561e71bd04f404f Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sun, 16 Nov 2014 16:51:30 -0500 Subject: Reorg a bit, introduce a control struct --- conf.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 conf.c (limited to 'conf.c') diff --git a/conf.c b/conf.c new file mode 100644 index 0000000..5aedc6e --- /dev/null +++ b/conf.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include + +#include "conf.h" +#include "util.h" + +static size_t strtrim(char *str) { + char *left = str, *right; + + if (!str || *str == '\0') { + return 0; + } + + while (isspace((unsigned char)*left)) { + left++; + } + if (left != str) { + memmove(str, left, (strlen(left) + 1)); + left = str; + } + + if (*str == '\0') { + return 0; + } + + right = strchr(str, '\0') - 1; + while (isspace((unsigned char)*right)) { + right--; + } + *++right = '\0'; + + return right - left; +} + +int is_section(const char *s, int n) { + return s[0] == '[' && s[n-1] == ']'; +} + +static int config_add_repo(config_t *config, char *reponame) { + /* first time setup */ + if (config->repos == NULL) { + config->repos = calloc(10, sizeof(char*)); + if (config->repos == NULL) { + return -ENOMEM; + } + + config->size = 0; + config->capacity = 10; + } + + /* grow when needed */ + if (config->size == config->capacity) { + void *ptr; + + ptr = realloc(config->repos, config->capacity * 2.5 * sizeof(char*)); + if (ptr == NULL) { + return -ENOMEM; + } + + config->repos = ptr; + } + + config->repos[config->size] = strdup(reponame); + ++config->size; + + return 0; +} + +static int parse_one_file(config_t *config, const char *filename, char **section); + +static int parse_include(config_t *config, const char *include, char **section) { + _cleanup_(globfreep) glob_t globbuf = {}; + + if (glob(include, GLOB_NOCHECK, NULL, &globbuf) != 0) { + fprintf(stderr, "warning: globbing failed on '%s': out of memory\n", + include); + return -ENOMEM; + } + + for (size_t i = 0; i < globbuf.gl_pathc; ++i) { + int r; + r = parse_one_file(config, globbuf.gl_pathv[i], section); + if (r < 0) + return r; + } + + return 0; +} + +static char *split_keyval(char *line, const char *sep) { + strsep(&line, sep); + return line; +} + +static int parse_one_file(config_t *config, const char *filename, char **section) { + _cleanup_(fclosep) FILE *fp = NULL; + _cleanup_free_ char *line = NULL; + size_t n = 0; + int in_options = 0; + + if (*section) + in_options = strcmp(*section, "options") == 0; + + fp = fopen(filename, "r"); + if (fp == NULL) + return -errno; + + for (;;) { + ssize_t len; + + errno = 0; + len = getline(&line, &n, fp); + if (len < 0) { + if (errno != 0) + return -errno; + + /* EOF */ + break; + } + + len = strtrim(line); + if (len == 0 || line[0] == '#') + continue; + + if (is_section(line, len)) { + free(*section); + *section = strndup(&line[1], len - 2); + if (*section == NULL) + return -ENOMEM; + + in_options = strcmp(*section, "options") == 0; + if (!in_options) { + int r; + + r = config_add_repo(config, *section); + if (r < 0) + return r; + + } + continue; + } + + if (in_options && memchr(line, '=', len)) { + char *val; + + val = split_keyval(line, "="); + strtrim(line); + + if (strcmp(line, "Include") == 0) { + int k; + + strtrim(val); + + k = parse_include(config, val, section); + if (k < 0) + return k; + } + } + } + + return 0; +} + +void config_reset(config_t *config) { + if (config == NULL) + return; + + for (int i = 0; i < config->size; ++i) + free(config->repos[i]); + + free(config->repos); +} + +int config_parse(config_t *config, const char *filename) { + _cleanup_free_ char *section = NULL; + + return parse_one_file(config, filename, §ion); +} + +/* vim: set et ts=2 sw=2: */ -- cgit v1.2.3-54-g00ecf