#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) { glob_t globbuf; int r = 0; 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) { r = parse_one_file(config, globbuf.gl_pathv[i], section); if (r < 0) break; } globfree(&globbuf); return r; } 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; } else if (strcmp(line, "DBPath") == 0) { config->dbpath = strdup(val); if (config->dbpath == NULL) return -ENOMEM; } else if (strcmp(line, "RootDir") == 0) { config->dbroot = strdup(val); if (config->dbpath == NULL) return -ENOMEM; } } } 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->dbroot); free(config->dbpath); 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: */