/* 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 "ckutil.h"
#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) \
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) \
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;
}
}
LOG("$XDG_CONFIG_HOME not avaliable.");
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) \
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) \
if (!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) \
if (conf->var) { \
free(conf->var); \
}
CONFIG_VARIABLES_TABLE
#undef X
}