#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++;
+static int parse_config_line(char *line, char **variable, char **value)
+{
SKIP_UNTIL(line, isspace(*line));
/* Skip comments */
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)
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)
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;
+}