/* confparser.h - Configuration file parser for ck ---------------------*- C -*- * * This file is part of ck, the config keeper * * ----------------------------------------------------------------------------- * * Copyright (C) 2018 Anastasis Grammenos * GPLv3 (see LICENCE for the full notice) * * -------------------------------------------------------------------------- */ #include "confparser.h" #include "ckerrlog.h" ERRLOG(configfile); static const char * const CONFIG_NAME = "/ckrc"; void initialize_conf(Conf *c) { #define X(var, str, name, optional) \ c->var = NULL; CONFIG_VARIABLES_TABLE #undef X } int read_next_line(char *line, FILE *f) { char nextLine[STR_L] = ""; if (fgets(nextLine, STR_L, f) == NULL) { return -1; } strcpy(line, nextLine); return 0; } ConfVar match_variables(char *line, char matched[]) { if (line[0] == '#' || str_is_empty(line)) { return CV_NO_VAL_OR_COMMENT; } #define X(var, str, name, optional) \ if (sscanf(line, str, matched) == 1) { \ return CV_##var; \ } CONFIG_VARIABLES_TABLE #undef X return CV_WRONG_VAL; } void make_config_name(char * ret, const char *confPath) { char tmp[STR_L] = ""; strcpy(tmp, confPath); strcat(tmp, CONFIG_NAME); strcpy(ret, tmp); } int find_config(UserOpt *opt) { /* If env CK_CONFIG is set */ char *config_home = getenv("CK_CONFIG"); if (config_home) { if (util_is_dir(config_home)) { opt->confDir = strdup(config_home); LOG("Using $CK_CONFIG: %s", config_home); return 0; } } LOG("$CK_CONFIG not avaliable.") /* If XDG_CONFIG_HOME exists*/ config_home = getenv("XDG_CONFIG_HOME"); if (config_home) { if (util_is_dir(config_home)) { char defaultConf[STR_S] = "ck"; opt->confDir = malloc(strlen(config_home) + 1 /* '/' */ + strlen(defaultConf) + 1); str_join_dirname_with_basename(opt->confDir, config_home, defaultConf); LOG("Using $XDG_CONFIG_HOME: %s", config_home); return 0; } } LOG("$XDG_CONFIG_HOME not avaliable.") /* fallback to HOME/.ck */ config_home = getenv("HOME"); if (config_home) { if (util_is_dir(config_home)) { char defaultConf[STR_S] = ".ck"; opt->confDir = malloc(strlen(config_home) + 1 /* '/' */ + strlen(defaultConf) + 1); str_join_dirname_with_basename(opt->confDir, config_home, defaultConf); LOG("Using $HOME: %s", config_home); return 0; } } ERR("No config found."); return -1; } int config_file_parse(Conf *conf, UserOpt *opt) { LOG("Using '%s' for ck configuration directory", opt->confDir); FILE *confPtr; char confName[STR_L] = ""; char line[STR_L] = ""; char matched[STR_L] = ""; make_config_name(confName, opt->confDir); if ((confPtr = fopen(confName, "r")) == NULL) { ERR("%s is not readable, check the permissions.", confName) return -1; } while (read_next_line(line, confPtr) == 0) { if (strlen(line) > STR_L) { return -1; } switch(match_variables(line, matched)) { #define X(var, str, name, optional) \ case CV_##var: \ conf->var = malloc(strlen(matched)+1); \ strcpy(conf->var, matched); \ if (!util_is_dir(matched)) { \ ERR("%s %s defined in config doesn't exist", \ name, conf->var); \ return -1; \ } \ LOG("Found %s: %s", name, conf->var); \ break; CONFIG_VARIABLES_TABLE #undef X case CV_NO_VAL_OR_COMMENT: break; default: ERR("In line: %s", line); return -1; } } /* Could add an optional row that would make the config var * optional. */ #define X(var, str, name, optional) \ if (!optional && !conf->var) { \ ERR("Missing %s", name); \ return -1; \ } CONFIG_VARIABLES_TABLE #undef X return 0; } void free_conf(Conf *conf) { #define X(var, str, name, optional) \ if (conf->var) { \ free(conf->var); \ } CONFIG_VARIABLES_TABLE #undef X }