From c05dcce7244f3f2f8e11d650cb20fabea0c94171 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 21 Aug 2015 21:56:30 +0200 Subject: [PATCH] config: introduce a string type. Global default values will be static strings, but values from the configuration file will be dynamic, so the code remembers whether or it should free the string when cleaning up. Signed-off-by: Richard Cochran --- config.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ config.h | 6 +++++ 2 files changed, 76 insertions(+) diff --git a/config.c b/config.c index 3f92daf..c878178 100644 --- a/config.c +++ b/config.c @@ -38,6 +38,7 @@ enum config_type { CFG_TYPE_INT, CFG_TYPE_DOUBLE, CFG_TYPE_ENUM, + CFG_TYPE_STRING, }; struct config_enum { @@ -48,6 +49,7 @@ struct config_enum { typedef union { int i; double d; + char *s; } any_t; #define CONFIG_LABEL_SIZE 32 @@ -55,6 +57,7 @@ typedef union { #define CFG_ITEM_STATIC (1 << 0) /* statically allocated, not to be freed */ #define CFG_ITEM_LOCKED (1 << 1) /* command line value, may not be changed */ #define CFG_ITEM_PORT (1 << 2) /* item may appear in port sections */ +#define CFG_ITEM_DYNSTR (1 << 4) /* string value dynamically allocated */ struct config_item { char label[CONFIG_LABEL_SIZE]; @@ -91,6 +94,12 @@ struct config_item { .min.i = _min, \ .max.i = _max, \ } +#define CONFIG_ITEM_STRING(_label, _port, _default) { \ + .label = _label, \ + .type = CFG_TYPE_STRING, \ + .flags = _port ? CFG_ITEM_PORT : 0, \ + .val.s = _default, \ +} #define GLOB_ITEM_DBL(label, _default, min, max) \ CONFIG_ITEM_DBL(label, 0, _default, min, max) @@ -101,6 +110,9 @@ struct config_item { #define GLOB_ITEM_INT(label, _default, min, max) \ CONFIG_ITEM_INT(label, 0, _default, min, max) +#define GLOB_ITEM_STR(label, _default) \ + CONFIG_ITEM_STRING(label, 0, _default) + #define PORT_ITEM_DBL(label, _default, min, max) \ CONFIG_ITEM_DBL(label, 1, _default, min, max) @@ -110,6 +122,9 @@ struct config_item { #define PORT_ITEM_INT(label, _default, min, max) \ CONFIG_ITEM_INT(label, 1, _default, min, max) +#define PORT_ITEM_STR(label, _default) \ + CONFIG_ITEM_STRING(label, 1, _default) + static struct config_enum clock_servo_enu[] = { { "pi", CLOCK_SERVO_PI }, { "linreg", CLOCK_SERVO_LINREG }, @@ -274,6 +289,8 @@ static struct config_item *config_item_alloc(struct config *cfg, static void config_item_free(void *ptr) { struct config_item *ci = ptr; + if (ci->type == CFG_TYPE_STRING && ci->flags & CFG_ITEM_DYNSTR) + free(ci->val.s); if (ci->flags & CFG_ITEM_STATIC) return; free(ci); @@ -329,6 +346,10 @@ static enum parser_result parse_item(struct config *cfg, break; } } + break; + case CFG_TYPE_STRING: + r = PARSED_OK; + break; } if (r != PARSED_OK) { return r; @@ -362,6 +383,17 @@ static enum parser_result parse_item(struct config *cfg, case CFG_TYPE_DOUBLE: dst->val.d = df; break; + case CFG_TYPE_STRING: + if (dst->flags & CFG_ITEM_DYNSTR) { + free(dst->val.s); + } + dst->val.s = strdup(value); + if (!dst->val.s) { + pr_err("low memory"); + return NOT_PARSED; + } + dst->flags |= CFG_ITEM_DYNSTR; + break; } return PARSED_OK; } @@ -732,6 +764,7 @@ int config_get_int(struct config *cfg, const char *section, const char *option) } switch (ci->type) { case CFG_TYPE_DOUBLE: + case CFG_TYPE_STRING: pr_err("bug: config option %s type mismatch!", option); exit(-1); case CFG_TYPE_INT: @@ -742,6 +775,19 @@ int config_get_int(struct config *cfg, const char *section, const char *option) return ci->val.i; } +char *config_get_string(struct config *cfg, const char *section, + const char *option) +{ + struct config_item *ci = config_find_item(cfg, section, option); + + if (!ci || ci->type != CFG_TYPE_STRING) { + pr_err("bug: config option %s missing or invalid!", option); + exit(-1); + } + pr_debug("config item %s.%s is '%s'", section, option, ci->val.s); + return ci->val.s; +} + int config_set_double(struct config *cfg, const char *option, double val) { struct config_item *ci = config_find_item(cfg, NULL, option); @@ -768,6 +814,7 @@ int config_set_section_int(struct config *cfg, const char *section, } switch (cgi->type) { case CFG_TYPE_DOUBLE: + case CFG_TYPE_STRING: pr_err("bug: config option %s type mismatch!", option); return -1; case CFG_TYPE_INT: @@ -792,3 +839,26 @@ int config_set_section_int(struct config *cfg, const char *section, pr_debug("section item %s.%s now %d", section, option, dst->val.i); return 0; } + +int config_set_string(struct config *cfg, const char *option, + const char *val) +{ + struct config_item *ci = config_find_item(cfg, NULL, option); + + if (!ci || ci->type != CFG_TYPE_STRING) { + pr_err("bug: config option %s missing or invalid!", option); + return -1; + } + ci->flags |= CFG_ITEM_LOCKED; + if (ci->flags & CFG_ITEM_DYNSTR) { + free(ci->val.s); + } + ci->val.s = strdup(val); + if (!ci->val.s) { + pr_err("low memory"); + return -1; + } + ci->flags |= CFG_ITEM_DYNSTR; + pr_debug("locked item global.%s as '%s'", option, ci->val.s); + return 0; +} diff --git a/config.h b/config.h index c4bf875..7b1473a 100644 --- a/config.h +++ b/config.h @@ -67,6 +67,9 @@ double config_get_double(struct config *cfg, const char *section, int config_get_int(struct config *cfg, const char *section, const char *option); +char *config_get_string(struct config *cfg, const char *section, + const char *option); + int config_set_double(struct config *cfg, const char *option, double val); int config_set_section_int(struct config *cfg, const char *section, @@ -78,4 +81,7 @@ static inline int config_set_int(struct config *cfg, return config_set_section_int(cfg, NULL, option, val); } +int config_set_string(struct config *cfg, const char *option, + const char *val); + #endif