10 #define SKIP_UNTIL(_str, _cond) \
11 while (*_str && (_cond)) \
14 static int parse_config_line(char *line, char **variable, char **value)
16 SKIP_UNTIL(line, isspace(*line));
22 /* The actual variable name begins here */
25 /* Find where the variable name ends */
26 SKIP_UNTIL(line, !isspace(*line) && *line != '=');
34 /* If we encounter line end already, the line can't be valid */
38 /* Terminate the variable name */
42 /* Find the equal sign */
43 SKIP_UNTIL(line, *line != '=');
49 SKIP_UNTIL(line, isspace(*line));
54 SKIP_UNTIL(line, *line != '\n' && *line != '#');
60 static void init_variable_value(struct variable_value *v)
65 static struct variable_value *prepare_slot_for_insertion(
66 struct plotter_config *cfg, const char *variable)
68 struct variable_value *v;
71 if (!cfg->variables) {
73 realloc(cfg->variables, sizeof(*cfg->variables));
75 init_variable_value(cfg->variables);
79 for (i = 0; v[i].name; i++) {
80 if (strcmp(variable, v[i].name))
92 * Failed to find an existing variable with same name, create
93 * a new one. Resize the variable array so that there is room
94 * for the new entry and one terminator entry (with all fields
97 cfg->variables = realloc(cfg->variables,
98 sizeof(*cfg->variables) * (i + 2));
100 init_variable_value(&cfg->variables[i + 1]);
105 int store_str_variable_value_to_array(const char *variable, const char *value,
106 struct plotter_config *cfg)
108 struct variable_value *v;
110 v = prepare_slot_for_insertion(cfg, variable);
112 v->name = strdup(variable);
113 v->type = TYPE_STRING;
114 v->ptr = strdup(value);
119 int store_int_variable_value_to_array(const char *variable, int value,
120 struct plotter_config *cfg)
122 struct variable_value *v;
125 v = prepare_slot_for_insertion(cfg, variable);
127 v->name = strdup(variable);
129 p = v->ptr = malloc(sizeof(value));
135 static int store_variable_value_to_plotter_config(const char *variable,
137 struct plotter_config *cfg)
139 #define TEST_STR_STORE_STR_RETURN(_cfg, _variable, _str, _value) \
140 if (!strcmp(_variable, #_str) && !cfg->_str) { \
141 cfg->_str = strdup(_value); \
145 #define TEST_STR_STORE_INT_RETURN(_cfg, _variable, _str, _value) \
146 if (!strcmp(_variable, #_str)) { \
147 cfg->_str = atoi(_value); \
151 TEST_STR_STORE_STR_RETURN(cfg, variable, charger_name, value);
152 TEST_STR_STORE_STR_RETURN(cfg, variable, plotter_scripts_dir, value);
153 TEST_STR_STORE_STR_RETURN(cfg, variable, images_output_dir, value);
154 TEST_STR_STORE_STR_RETURN(cfg, variable, device_path, value);
155 TEST_STR_STORE_STR_RETURN(cfg, variable, log_path, value);
156 TEST_STR_STORE_INT_RETURN(cfg, variable, baudrate, value);
158 return store_str_variable_value_to_array(variable, value, cfg);
161 static int read_config_file(FILE *file, struct plotter_config *cfg)
164 char *variable, *value;
166 while (fgets(line, sizeof(line), file)) {
167 if (parse_config_line(line, &variable, &value))
170 if (!store_variable_value_to_plotter_config(variable, value,
174 pr_debug("Discarding unsupported config variable %s\n",
181 int populate_config_data_from_file(const char *path,
182 struct plotter_config *cfg)
188 ret = glob(path, GLOB_TILDE, NULL, &globbuf);
192 if (globbuf.gl_pathc == 0) {
193 pr_debug("No config file foud from path %s\n", path);
197 if (globbuf.gl_pathc > 1) {
198 pr_warn("Found multiple config files from path %s, using the first one\n",
202 file = fopen(globbuf.gl_pathv[0], "r");
204 pr_err("Failed to open config file %s: %m\n",
205 globbuf.gl_pathv[0]);
209 return read_config_file(file, cfg);
212 static char *get_value_for_variable(char *variable,
213 const struct plotter_config *cfg)
215 static char result[256];
216 struct variable_value *values = cfg->variables;
222 for (i = 0; values[i].name; i++) {
223 if (strcmp(values[i].name, variable))
226 switch (values[i].type) {
229 snprintf(result, sizeof(result), "%d", *ip);
233 snprintf(result, sizeof(result), "%s", cp);
236 pr_err("BUG: Unknown variable type %d\n",
247 static int replace_variable_with_value(char *str, size_t len,
248 char *variable_start, char *variable_end,
249 const char *value, char **endptr)
251 int value_len = strlen(value);
255 if (variable_end - variable_start >= value_len) {
257 * The replacement string is shorter than the variable
258 * name, this is the easy case, no need to worry about
262 strcpy(variable_start, value);
264 from = variable_end + 1;
265 to = variable_start + value_len;
278 * The replacement string is longer than the space
279 * occupied by the variable name. We need to first
280 * make room for the value, without overflowing the
281 * buffer. Make an overlapping scring copy, start from
286 * The closing parenthesis was replaced with null byte
287 * earlier, put a non-zero char there to avoid
288 * confusing strlen().
292 from = str + strlen(str);
293 to = from + (value_len - (variable_end - variable_start)) - 1;
294 if (to >= str + len - 1) {
299 while (from >= variable_end) {
308 * use memcpy to avoid NULL terminating prematurely
311 memcpy(variable_start, value, value_len);
318 * Replace variable names from a string with the variable
319 * contents. Variable names are in format: $(name)
321 int replace_variables_with_values(char *str, size_t len,
322 const struct plotter_config *cfg)
327 while (*ptr && ptr < str + len) {
328 char *replace_start, *variable_start, *variable_end, *value;
330 SKIP_UNTIL(ptr, *ptr != '$');
338 /* Skip if not in correct format */
343 variable_start = ptr;
345 SKIP_UNTIL(ptr, *ptr != ')');
350 value = get_value_for_variable(variable_start, cfg);
352 pr_debug("Could not substitute unknown variable name %s\n",
356 * Put back the closing parenthesis so that
357 * the line remains as it was
362 overflow = replace_variable_with_value(str, len, replace_start,
363 variable_end, value, &ptr);
367 pr_err("String buffer overflow\n");