@@ -9,6 +9,7 @@
enum parse_conf_type {
CONFIG_STRING,
+ CONFIG_SEARCH_SECTION,
CONFIG_END,
MONITOR_CALLBACK,
};
@@ -20,6 +21,10 @@ typedef int parse_conf_cb(const struct config *, const char *config_file);
struct config {
enum parse_conf_type type;
+ const char *section;
+ const char *search_key;
+ const char *search_val;
+ const char *get_key;
const char *key;
void *value;
void *defval;
@@ -31,6 +36,16 @@ struct config {
#define CONF_END() { .type = CONFIG_END }
#define CONF_STR(k,v,d) \
{ .type = CONFIG_STRING, .key = (k), .value = check_vtype(v, const char **), .defval = (d) }
+#define CONF_SEARCH(s, sk, sv, gk, v, d) \
+{ \
+ .type = CONFIG_SEARCH_SECTION, \
+ .section = (s), \
+ .search_key = (sk), \
+ .search_val = (sv), \
+ .get_key = (gk), \
+ .value = check_vtype(v, const char **), \
+ .defval = (d) \
+}
#define CONF_MONITOR(k,f) \
{ .type = MONITOR_CALLBACK, .key = (k), .callback = (f)}
@@ -39,6 +39,54 @@ static void set_str_val(const char **value, const char *val)
*value = strbuf_detach(&buf, NULL);
}
+static const char *search_section_kv(dictionary *d, const struct config *c)
+{
+ int i;
+
+ for (i = 0; i < iniparser_getnsec(d); i++) {
+ const char *cur_sec_full = iniparser_getsecname(d, i);
+ char *cur_sec = strdup(cur_sec_full);
+ const char *search_val, *ret_val;
+ const char *delim = " \t\n\r";
+ char *save, *cur, *query;
+
+ if (!cur_sec)
+ return NULL;
+ if (!c->section || !c->search_key || !c->search_val || !c->get_key) {
+ fprintf(stderr, "warning: malformed config query, skipping\n");
+ return NULL;
+ }
+
+ cur = strtok_r(cur_sec, delim, &save);
+ if ((cur == NULL) || (strcmp(cur, c->section) != 0))
+ goto out_sec;
+
+ if (asprintf(&query, "%s:%s", cur_sec_full, c->search_key) < 0)
+ goto out_sec;
+ search_val = iniparser_getstring(d, query, NULL);
+ if (!search_val)
+ goto out_query;
+ if (strcmp(search_val, c->search_val) != 0)
+ goto out_query;
+
+ /* we're now in a matching section */
+ free(query);
+ if (asprintf(&query, "%s:%s", cur_sec_full, c->get_key) < 0)
+ goto out_sec;
+ ret_val = iniparser_getstring(d, query, NULL);
+ free(query);
+ free(cur_sec);
+ return ret_val;
+
+out_query:
+ free(query);
+out_sec:
+ free(cur_sec);
+ }
+
+ return NULL;
+}
+
static int parse_config_file(const char *config_file,
const struct config *configs)
{
@@ -55,6 +103,9 @@ static int parse_config_file(const char *config_file,
iniparser_getstring(dic,
configs->key, configs->defval));
break;
+ case CONFIG_SEARCH_SECTION:
+ set_str_val((const char **)configs->value,
+ search_section_kv(dic, configs));
case MONITOR_CALLBACK:
case CONFIG_END:
break;