From: Timo Kokkonen Date: Tue, 29 Oct 2013 19:41:26 +0000 (+0200) Subject: Add primitive config file parsing support X-Git-Url: http://git.itanic.dy.fi/?p=log-plotter;a=commitdiff_plain;h=84ab13170c021724847f80663c9136ec8badac57 Add primitive config file parsing support This supports parsing "variable = value" style lines from a config file. The file can also have blank lines and comments starting with '#' character. Anything it doesn't understand are skipped. Signed-off-by: Timo Kokkonen --- diff --git a/Makefile b/Makefile index 328d6a2..f770686 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CC=gcc LD=ld CFLAGS=-Wall -O2 -g -fPIC -LOG-PLOTTER_OBJS = baud.o main.o options.o trace.o data.o +LOG-PLOTTER_OBJS = baud.o main.o options.o trace.o data.o config.o ALL_OBJS = $(LOG-PLOTTER_OBJS) ALL_DEBS = $(patsubst %.o,.%.o.d,$(ALL_OBJS)) diff --git a/config.c b/config.c new file mode 100644 index 0000000..54f672e --- /dev/null +++ b/config.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include + +#include "config.h" +#include "trace.h" + +static int parse_config_line(char *line, char **variable, char **value) +{ +#define SKIP_UNTIL(_str, _cond) \ + while (*_str && (_cond)) \ + _str++; + + SKIP_UNTIL(line, isspace(*line)); + + /* Skip comments */ + if (*line == '#') + return -1; + + /* The actual variable name begins here */ + *variable = line; + + /* Find where the variable name ends */ + SKIP_UNTIL(line, !isspace(*line) && *line != '='); + + if (*line == '=') { + *line = '\0'; + line++; + goto value_start; + } + + /* If we encounter line end already, the line can't be valid */ + if (!*line) + return -1; + + /* Terminate the variable name */ + *line = '\0'; + line++; + + /* Find the equal sign */ + SKIP_UNTIL(line, *line != '='); + + if (*line != '=') + return -1; + line++; + + SKIP_UNTIL(line, isspace(*line)); + +value_start: + *value = line; + + SKIP_UNTIL(line, *line != '\n' && *line != '#'); + *line = 0; + + return 0; +} + +static int store_variable_value_to_plotter_config(const char *variable, + const char *value, + struct plotter_config *cfg) +{ +#define TEST_STR_STORE_STR_RETURN(_cfg, _variable, _str, _value) \ + if (!strcmp(_variable, #_str) && !cfg->_str) { \ + cfg->_str = strdup(_value); \ + return 0; \ + } + +#define TEST_STR_STORE_INT_RETURN(_cfg, _variable, _str, _value) \ + if (!strcmp(_variable, #_str)) { \ + cfg->_str = atoi(_value); \ + return 0; \ + } + + TEST_STR_STORE_STR_RETURN(cfg, variable, charger_name, value); + TEST_STR_STORE_STR_RETURN(cfg, variable, plotter_scripts_dir, value); + TEST_STR_STORE_STR_RETURN(cfg, variable, images_output_dir, value); + TEST_STR_STORE_STR_RETURN(cfg, variable, device_path, value); + TEST_STR_STORE_STR_RETURN(cfg, variable, log_path, value); + TEST_STR_STORE_INT_RETURN(cfg, variable, baudrate, value); + + return -1; +} + +static int read_config_file(FILE *file, struct plotter_config *cfg) +{ + char line[1024]; + char *variable, *value; + + while (fgets(line, sizeof(line), file)) { + if (parse_config_line(line, &variable, &value)) + continue; + + if (!store_variable_value_to_plotter_config(variable, value, + cfg)) + continue; + + pr_debug("Discarding unsupported config variable %s\n", + variable); + } + + return 0; +} + +int populate_config_data_from_file(const char *path, + struct plotter_config *cfg) +{ + glob_t globbuf; + FILE *file; + int ret; + + ret = glob(path, GLOB_TILDE, NULL, &globbuf); + if (ret) + return -1; + + if (globbuf.gl_pathc == 0) { + pr_debug("No config file foud from path %s\n", path); + return -1; + } + + if (globbuf.gl_pathc > 1) { + pr_warn("Found multiple config files from path %s, using the first one\n", + path); + } + + file = fopen(globbuf.gl_pathv[0], "r"); + if (!file) { + pr_err("Failed to open config file %s: %m\n", + globbuf.gl_pathv[0]); + return -1; + } + + return read_config_file(file, cfg); +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..9f817fc --- /dev/null +++ b/config.h @@ -0,0 +1,18 @@ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +struct plotter_config { + char *charger_name; + + char *plotter_scripts_dir; + char *images_output_dir; + + char *device_path; + int baudrate; + char *log_path; +}; + +int populate_config_data_from_file(const char *path, + struct plotter_config *cfg); + +#endif diff --git a/main.c b/main.c index 39ef41c..05e3390 100644 --- a/main.c +++ b/main.c @@ -1,8 +1,10 @@ #include #include #include +#include #include "options.h" +#include "config.h" #include "baud.h" #include "trace.h" #include "data.h" @@ -10,11 +12,17 @@ int main(int argc, char *argv[]) { struct plotter_options options; + struct plotter_config cfg; int fd, baud, ret = 0, out_fd = 0; + bzero(&cfg, sizeof(cfg)); + if (read_args(argc, argv, &options)) return 1; + if (options.config_file_path) + populate_config_data_from_file(options.config_file_path, &cfg); + baud = options.baud_rate; fd = open_at_baud(options.device_path, &baud); if (fd < 0) diff --git a/options.c b/options.c index 48cd259..18db9c5 100644 --- a/options.c +++ b/options.c @@ -15,6 +15,7 @@ void print_help_and_die(const char *exec_name) pr_info(" -o, --output logfile path, stdout only if omited\n"); pr_info(" -v, --verbose increase verbosity\n"); pr_info(" -q, --quiet decrease verbosity\n"); + pr_info(" -c, --config=PATH config file path\n"); pr_info(" -h, --help show this help\n"); exit(0); @@ -37,9 +38,10 @@ int read_args(int argc, char *argv[], struct plotter_options *opts) { .val = 'b', .name = "baud", .has_arg = 1 }, { .val = 'v', .name = "verbose", .has_arg = 2 }, { .val = 'q', .name = "quiet", }, + { .val = 'c', .name = "config", .has_arg = 1 }, { .val = 'h', .name = "help", }, }; - char short_options[] = "d:o:b:vqh"; + char short_options[] = "d:o:b:vqc:h"; set_default_options(opts); @@ -68,6 +70,9 @@ int read_args(int argc, char *argv[], struct plotter_options *opts) trace_level--; pr_debug("Degreased trace level to %d\n", trace_level); break; + case 'c': + opts->config_file_path = optarg; + break; case 'h': print_help_and_die(argv[0]); break; diff --git a/options.h b/options.h index 5312e42..8ec9abc 100644 --- a/options.h +++ b/options.h @@ -5,6 +5,7 @@ struct plotter_options { char *device_path; char *output_path; int baud_rate; + char *config_file_path; }; int read_args(int argc, char *argv[], struct plotter_options *opts);