]> git.itanic.dy.fi Git - log-plotter/commitdiff
config.c: Add support for replacing variables names from strings
authorTimo Kokkonen <timo.t.kokkonen@iki.fi>
Sun, 29 Dec 2013 11:41:37 +0000 (13:41 +0200)
committerTimo Kokkonen <timo.t.kokkonen@iki.fi>
Sun, 29 Dec 2013 11:41:37 +0000 (13:41 +0200)
Read all unknown config options from the config file and store them in
the config variable array.

Implement a new function that can be used to replace variable names
from a string with the contents of the variable name in question.

Signed-off-by: Timo Kokkonen <timo.t.kokkonen@iki.fi>
config.c
config.h

index 54f672e287d43ed74228fe62d1df251b755687b3..7caa63de662b20fd2b23d1720f4b8b1d5beb9ec2 100644 (file)
--- a/config.c
+++ b/config.c
@@ -7,12 +7,12 @@
 #include "config.h"
 #include "trace.h"
 
 #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++;
 
 #define SKIP_UNTIL(_str, _cond)                \
        while (*_str && (_cond))        \
                _str++;
 
+static int parse_config_line(char *line, char **variable, char **value)
+{
        SKIP_UNTIL(line, isspace(*line));
 
        /* Skip comments */
        SKIP_UNTIL(line, isspace(*line));
 
        /* Skip comments */
@@ -57,6 +57,54 @@ value_start:
        return 0;
 }
 
        return 0;
 }
 
+static void init_variable_value(struct variable_value *v)
+{
+       bzero(v, sizeof(*v));
+}
+
+static int store_str_variable_value_to_array(const char *variable,
+                                       const char *value,
+                                       struct plotter_config *cfg)
+{
+       struct variable_value *v;
+       int i;
+
+       if (!cfg->variables) {
+               cfg->variables =
+                       realloc(cfg->variables, sizeof(*cfg->variables));
+
+               init_variable_value(cfg->variables);
+       }
+
+       v = cfg->variables;
+       for (i = 0; v[i].name; i++) {
+               if (strcmp(variable, v[i].name))
+                       continue;
+
+               free(v[i].name);
+               free(v[i].ptr);
+               goto out_store;
+       }
+
+       /*
+        * Failed to find an existing variable with same type, create
+        * a new one. Resize the variable array so that there is room
+        * for the new entry and one terminator entry (with all fields
+        * zeroed).
+        */
+       cfg->variables = realloc(cfg->variables,
+                               sizeof(*cfg->variables) * (i + 2));
+       v = cfg->variables;
+       init_variable_value(&cfg->variables[i + 1]);
+
+out_store:
+       v[i].name = strdup(variable);
+       v[i].type = TYPE_STRING;
+       v[i].ptr = strdup(value);
+
+       return 0;
+}
+
 static int store_variable_value_to_plotter_config(const char *variable,
                                                const char *value,
                                                struct plotter_config *cfg)
 static int store_variable_value_to_plotter_config(const char *variable,
                                                const char *value,
                                                struct plotter_config *cfg)
@@ -80,7 +128,7 @@ static int store_variable_value_to_plotter_config(const char *variable,
        TEST_STR_STORE_STR_RETURN(cfg, variable, log_path, value);
        TEST_STR_STORE_INT_RETURN(cfg, variable, baudrate, value);
 
        TEST_STR_STORE_STR_RETURN(cfg, variable, log_path, value);
        TEST_STR_STORE_INT_RETURN(cfg, variable, baudrate, value);
 
-       return -1;
+       return store_str_variable_value_to_array(variable, value, cfg);
 }
 
 static int read_config_file(FILE *file, struct plotter_config *cfg)
 }
 
 static int read_config_file(FILE *file, struct plotter_config *cfg)
@@ -133,3 +181,160 @@ int populate_config_data_from_file(const char *path,
 
        return read_config_file(file, cfg);
 }
 
        return read_config_file(file, cfg);
 }
+
+static char *get_value_for_variable(char *variable,
+                       const struct plotter_config *cfg)
+{
+       static char result[256];
+       struct variable_value *values = cfg->variables;
+       int i;
+       int *ip;
+       char *cp;
+
+
+       for (i = 0; values[i].name; i++) {
+               if (strcmp(values[i].name, variable))
+                       continue;
+
+               switch (values[i].type) {
+               case TYPE_INT:
+                       ip = values[i].ptr;
+                       snprintf(result, sizeof(result), "%d", *ip);
+                       break;
+               case TYPE_STRING:
+                       cp = values[i].ptr;
+                       snprintf(result, sizeof(result), "%s", cp);
+                       break;
+               default:
+                       pr_err("BUG: Unknown variable type %d\n",
+                               values[i].type);
+                       return NULL;
+               }
+
+               return result;
+       }
+
+       return NULL;
+}
+
+static int replace_variable_with_value(char *str, size_t len,
+                               char *variable_start, char *variable_end,
+                               const char *value)
+{
+       int value_len = strlen(value);
+       char *from, *to;
+       int overflow = 0;
+
+       if (variable_end - variable_start >= value_len) {
+               /*
+                * The replacement string is shorter than the variable
+                * name, this is the easy case, no need to worry about
+                * overflows.
+                */
+
+               strcpy(variable_start, value);
+
+               from = variable_end + 1;
+               to = variable_start + value_len;
+
+               while (*from) {
+                       *to = *from;
+                       from++;
+                       to++;
+               }
+
+               *to = 0;
+       } else {
+               /*
+                * The replacement string is longer than the space
+                * occupied by the variable name. We need to first
+                * make room for the value, without overflowing the
+                * buffer. Make an overlapping scring copy, start from
+                * the end.
+                */
+
+               /*
+                * The closing parenthesis was replaced with null byte
+                * earlier, put a non-zero char there to avoid
+                * confusing strlen().
+                */
+               *variable_end = '.';
+
+               from = str + strlen(str);
+               to = from + (value_len - (variable_end - variable_start)) - 1;
+               if (to >= str + len - 1) {
+                       to = str + len - 1;
+                       overflow = 1;
+               }
+
+               while (from >= variable_end) {
+                       *to = *from;
+                       from--;
+                       to--;
+               }
+
+               /*
+                * use memcpy to avoid NULL terminating prematurely
+                * the target string
+                */
+               memcpy(variable_start, value, value_len);
+       }
+
+       return overflow;
+}
+
+/*
+ * Replace variable names from a string with the variable
+ * contents. Variable names are in format: $(name)
+ */
+int replace_variables_with_values(char *str, size_t len,
+                               const struct plotter_config *cfg)
+{
+       char *ptr = str;
+       int overflow = 0;
+
+       while (*ptr && ptr < str + len) {
+               char *replace_start, *variable_start, *variable_end, *value;
+
+               SKIP_UNTIL(ptr, *ptr != '$');
+
+               if (!*ptr)
+                       break;
+
+               replace_start = ptr;
+               ptr++;
+
+               /* Skip if not in correct format */
+               if (*ptr != '(')
+                       continue;
+
+               ptr++;
+               variable_start = ptr;
+
+               SKIP_UNTIL(ptr, *ptr != ')');
+
+               variable_end = ptr;
+               *ptr = 0;
+               ptr++;
+
+               value = get_value_for_variable(variable_start, cfg);
+               if (!value) {
+                       pr_debug("Could not substitute unknown variable name %s\n",
+                               variable_start);
+
+                       /*
+                        * Put back the closing parenthesis so that
+                        * the line remains as it was
+                        */
+                       *variable_end = ')';
+                       continue;
+               }
+               overflow = replace_variable_with_value(str, len, replace_start,
+                                       variable_end, value);
+       }
+
+       if (overflow)
+               pr_err("String buffer overflow\n");
+
+       return overflow;
+}
index 37437ea1a52cdf4f262577387c60fe3216e5a11e..851c7d42ca7d8fbed65c58e791577f115d3188bc 100644 (file)
--- a/config.h
+++ b/config.h
@@ -1,6 +1,17 @@
 #ifndef _CONFIG_H_
 #define _CONFIG_H_
 
 #ifndef _CONFIG_H_
 #define _CONFIG_H_
 
+struct variable_value {
+       char *name;
+       int type;
+       void *ptr;
+};
+
+enum {
+       TYPE_INT,
+       TYPE_STRING,
+};
+
 struct plotter_config {
        char *charger_name;
 
 struct plotter_config {
        char *charger_name;
 
@@ -11,10 +22,15 @@ struct plotter_config {
        int baudrate;
        char *log_path;
        char *config_file_path;
        int baudrate;
        char *log_path;
        char *config_file_path;
+
+       struct variable_value *variables;
 };
 
 int read_args(int argc, char *argv[], struct plotter_config *cfg);
 int populate_config_data_from_file(const char *path,
                                struct plotter_config *cfg);
 
 };
 
 int read_args(int argc, char *argv[], struct plotter_config *cfg);
 int populate_config_data_from_file(const char *path,
                                struct plotter_config *cfg);
 
+int replace_variables_with_values(char *str, size_t len,
+                               const struct plotter_config *cfg);
+
 #endif
 #endif