#include "xlog.h"
static void conf_load_defaults (int);
+static int conf_set(int , char *, char *, char *,
+ char *, int , int );
struct conf_trans {
TAILQ_ENTRY (conf_trans) link;
int trans;
enum conf_op { CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION } op;
char *section;
+ char *arg;
char *tag;
char *value;
int override;
struct conf_binding {
LIST_ENTRY (conf_binding) link;
char *section;
+ char *arg;
char *tag;
char *value;
int is_default;
LIST_REMOVE(cb, link);
xlog(LOG_INFO,"[%s]:%s->%s removed", section, tag, cb->value);
free(cb->section);
+ free(cb->arg);
free(cb->tag);
free(cb->value);
free(cb);
LIST_REMOVE(cb, link);
xlog(LOG_INFO, "[%s]:%s->%s removed", section, cb->tag, cb->value);
free(cb->section);
+ free(cb->arg);
free(cb->tag);
free(cb->value);
free(cb);
* into SECTION of our configuration database.
*/
static int
-conf_set_now(char *section, char *tag, char *value, int override,
- int is_default)
+conf_set_now(char *section, char *arg, char *tag,
+ char *value, int override, int is_default)
{
struct conf_binding *node = 0;
if (override)
conf_remove_now(section, tag);
- else if (conf_get_str(section, tag)) {
+ else if (conf_get_section(section, arg, tag)) {
if (!is_default) {
xlog(LOG_INFO, "conf_set: duplicate tag [%s]:%s, ignoring...\n",
section, tag);
}
return 1;
}
-
node = calloc(1, sizeof *node);
if (!node) {
xlog_warn("conf_set: calloc (1, %lu) failed", (unsigned long)sizeof *node);
return 1;
}
node->section = strdup(section);
+ if (arg)
+ node->arg = strdup(arg);
node->tag = strdup(tag);
node->value = strdup(value);
node->is_default = is_default;
static void
conf_parse_line(int trans, char *line, size_t sz)
{
- char *val;
+ char *val, *ptr;
size_t i;
int j;
static char *section = 0;
+ static char *arg = 0;
static int ln = 0;
/* Lines starting with '#' or ';' are comments. */
/* Strip off any blanks after '[' */
while (isblank(*line))
line++;
-
for (i = 0; i < sz; i++) {
if (line[i] == ']') {
break;
val++, j++;
if (*val)
i = j;
-
section = malloc(i);
if (!section) {
xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln,
return;
}
strncpy(section, line, i);
+
+ if (arg)
+ free(arg);
+ arg = 0;
+
+ ptr = strchr(val, '"');
+ if (ptr == NULL)
+ return;
+ line = ++ptr;
+ while (*ptr && *ptr != '"')
+ ptr++;
+ if (*ptr == '\0') {
+ xlog_warn("conf_parse_line: line %d:"
+ "non-matched '\"', ignoring until next section", ln);
+ } else {
+ *ptr = '\0';
+ arg = strdup(line);
+ if (!arg)
+ xlog_warn("conf_parse_line: %d: malloc arg failed", ln);
+ }
return;
}
for (j = sz - (val - line) - 1; j > 0 && isspace(val[j]); j--)
val[j] = '\0';
/* XXX Perhaps should we not ignore errors? */
- conf_set(trans, section, line, val, 0, 0);
+ conf_set(trans, section, arg, line, val, 0, 0);
return;
}
}
}
return 0;
}
+/*
+ * Find a section that may or may not have an argument
+ */
+char *
+conf_get_section(char *section, char *arg, char *tag)
+{
+ struct conf_binding *cb;
+
+ cb = LIST_FIRST (&conf_bindings[conf_hash (section)]);
+ for (; cb; cb = LIST_NEXT (cb, link)) {
+ if (strcasecmp(section, cb->section) != 0)
+ continue;
+ if (arg && strcasecmp(arg, cb->arg) != 0)
+ continue;
+ if (strcasecmp(tag, cb->tag) != 0)
+ continue;
+ return cb->value;
+ }
+ return 0;
+}
/*
* Build a list of string values out of the comma separated value denoted by
}
/* Queue a set operation. */
-int
-conf_set(int transaction, char *section, char *tag,
- char *value, int override, int is_default)
+static int
+conf_set(int transaction, char *section, char *arg,
+ char *tag, char *value, int override, int is_default)
{
struct conf_trans *node;
/* Make Section names case-insensitive */
upper2lower(node->section);
+ if (arg) {
+ node->arg = strdup(arg);
+ if (!node->arg) {
+ xlog_warn("conf_set: strdup(\"%s\") failed", arg);
+ goto fail;
+ }
+ } else
+ node->arg = NULL;
+
node->tag = strdup(tag);
if (!node->tag) {
xlog_warn("conf_set: strdup(\"%s\") failed", tag);
if (commit) {
switch (node->op) {
case CONF_SET:
- conf_set_now(node->section, node->tag, node->value,
- node->override, node->is_default);
+ conf_set_now(node->section, node->arg,
+ node->tag, node->value, node->override,
+ node->is_default);
break;
case CONF_REMOVE:
conf_remove_now(node->section, node->tag);
conf_report (void)
{
struct conf_binding *cb, *last = 0;
- unsigned int i, len;
+ unsigned int i, len, diff_arg = 0;
char *current_section = (char *)0;
+ char *current_arg = (char *)0;
struct dumper *dumper, *dnode;
dumper = dnode = (struct dumper *)calloc(1, sizeof *dumper);
for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
for (cb = LIST_FIRST(&conf_bindings[i]); cb; cb = LIST_NEXT(cb, link)) {
if (!cb->is_default) {
+ /* Make sure the Section arugment is the same */
+ if (current_arg && current_section && cb->arg) {
+ if (strcmp(cb->section, current_section) == 0 &&
+ strcmp(cb->arg, current_arg) != 0)
+ diff_arg = 1;
+ }
/* Dump this entry. */
- if (!current_section || strcmp(cb->section, current_section)) {
- if (current_section) {
+ if (!current_section || strcmp(cb->section, current_section)
+ || diff_arg) {
+ if (current_section || diff_arg) {
len = strlen (current_section) + 3;
+ if (current_arg)
+ len += strlen(current_arg) + 3;
dnode->s = malloc(len);
if (!dnode->s)
goto mem_fail;
- snprintf(dnode->s, len, "[%s]", current_section);
+ if (current_arg)
+ snprintf(dnode->s, len, "[%s \"%s\"]",
+ current_section, current_arg);
+ else
+ snprintf(dnode->s, len, "[%s]", current_section);
+
dnode->next =
(struct dumper *)calloc(1, sizeof (struct dumper));
dnode = dnode->next;
goto mem_fail;
}
current_section = cb->section;
+ current_arg = cb->arg;
+ diff_arg = 0;
}
dnode->s = cb->tag;
dnode->v = cb->value;
if (last) {
len = strlen(last->section) + 3;
+ if (last->arg)
+ len += strlen(last->arg) + 3;
dnode->s = malloc(len);
if (!dnode->s)
goto mem_fail;
- snprintf(dnode->s, len, "[%s]", last->section);
+ if (last->arg)
+ snprintf(dnode->s, len, "[%s \"%s\"]", last->section, last->arg);
+ else
+ snprintf(dnode->s, len, "[%s]", last->section);
}
conf_report_dump(dumper);
return;