Add category inheritance (bug #3099)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4925 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.2-netsec
Mark Spencer 21 years ago
parent f85cf0138c
commit 0b04b3dfb2

@ -62,6 +62,7 @@ struct ast_comment {
struct ast_category { struct ast_category {
char name[80]; char name[80];
int ignored; /* do not let user of the config see this category */
struct ast_variable *root; struct ast_variable *root;
struct ast_variable *last; struct ast_variable *last;
struct ast_category *next; struct ast_category *next;
@ -123,13 +124,59 @@ struct ast_variable *ast_variable_new(const char *name, const char *value)
return variable; return variable;
} }
static struct ast_variable *variable_get(const struct ast_category *category, const char *name)
{
struct ast_variable *variable;
for (variable = category->root; variable; variable = variable->next)
if (!strcasecmp(variable->name, name))
return variable;
return NULL;
}
static void variable_remove(struct ast_category *category, const struct ast_variable *variable)
{
struct ast_variable *prev = category->root;
if (!prev)
return;
if (prev == variable) {
category->root = prev->next;
if (category->last == variable)
category->last = NULL;
} else {
while (prev->next && (prev->next != variable)) prev = prev->next;
if (prev->next) {
prev->next = variable->next;
if (category->last == variable)
category->last = prev;
}
}
}
void ast_variable_append(struct ast_category *category, struct ast_variable *variable) void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
{ {
if (category->last) /* Note: this function also implements "variable replacement"... if the
category->last->next = variable; new variable's value is empty, then existing variables of the same
else name in the category are removed (and the new variable is destroyed)
category->root = variable; */
category->last = variable; if (variable->value && !ast_strlen_zero(variable->value)) {
if (category->last)
category->last->next = variable;
else
category->root = variable;
category->last = variable;
} else {
struct ast_variable *v;
while ((v = variable_get(category, variable->name))) {
variable_remove(category, v);
ast_variables_destroy(v);
}
ast_variables_destroy(variable);
}
} }
void ast_variables_destroy(struct ast_variable *v) void ast_variables_destroy(struct ast_variable *v)
@ -181,6 +228,34 @@ char *ast_variable_retrieve(const struct ast_config *config, const char *categor
return NULL; return NULL;
} }
static struct ast_variable *variable_clone(const struct ast_variable *old)
{
struct ast_variable *new = ast_variable_new(old->name, old->value);
if (new) {
new->lineno = old->lineno;
new->object = old->object;
new->blanklines = old->blanklines;
/* TODO: clone comments? */
}
return new;
}
static void move_variables(struct ast_category *old, struct ast_category *new)
{
struct ast_variable *var;
struct ast_variable *next;
next = old->root;
old->root = NULL;
for (var = next; var; var = next) {
next = var->next;
var->next = NULL;
ast_variable_append(new, var);
}
}
struct ast_category *ast_category_new(const char *name) struct ast_category *ast_category_new(const char *name)
{ {
struct ast_category *category; struct ast_category *category;
@ -194,23 +269,28 @@ struct ast_category *ast_category_new(const char *name)
return category; return category;
} }
struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name) static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
{ {
struct ast_category *cat; struct ast_category *cat;
for (cat = config->root; cat; cat = cat->next) { for (cat = config->root; cat; cat = cat->next) {
if (cat->name == category_name) if (cat->name == category_name && (ignored || !cat->ignored))
return cat; return cat;
} }
for (cat = config->root; cat; cat = cat->next) { for (cat = config->root; cat; cat = cat->next) {
if (!strcasecmp(cat->name, category_name)) if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
return cat; return cat;
} }
return NULL; return NULL;
} }
struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
{
return category_get(config, category_name, 0);
}
int ast_category_exist(const struct ast_config *config, const char *category_name) int ast_category_exist(const struct ast_config *config, const char *category_name)
{ {
return !!ast_category_get(config, category_name); return !!ast_category_get(config, category_name);
@ -232,6 +312,13 @@ void ast_category_destroy(struct ast_category *cat)
free(cat); free(cat);
} }
static struct ast_category *next_available_category(struct ast_category *cat)
{
for (; cat && cat->ignored; cat = cat->next);
return cat;
}
char *ast_category_browse(struct ast_config *config, const char *prev) char *ast_category_browse(struct ast_config *config, const char *prev)
{ {
struct ast_category *cat = NULL; struct ast_category *cat = NULL;
@ -256,6 +343,9 @@ char *ast_category_browse(struct ast_config *config, const char *prev)
} }
} }
} }
if (cat)
cat = next_available_category(cat);
config->last_browse = cat; config->last_browse = cat;
if (cat) if (cat)
@ -279,6 +369,19 @@ void ast_category_rename(struct ast_category *cat, const char *name)
strncpy(cat->name, name, sizeof(cat->name) - 1); strncpy(cat->name, name, sizeof(cat->name) - 1);
} }
static void inherit_category(struct ast_category *new, const struct ast_category *base)
{
struct ast_variable *var;
for (var = base->root; var; var = var->next) {
struct ast_variable *v;
v = variable_clone(var);
if (v)
ast_variable_append(new, v);
}
}
struct ast_config *ast_config_new(void) struct ast_config *ast_config_new(void)
{ {
struct ast_config *config; struct ast_config *config;
@ -323,30 +426,69 @@ void ast_config_set_current_category(struct ast_config *cfg, const struct ast_ca
static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile) static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile)
{ {
char *c; char *c;
char *cur; char *cur = buf;
struct ast_variable *v; struct ast_variable *v;
int object; int object;
cur = ast_strip(buf);
if (ast_strlen_zero(cur))
return 0;
/* Actually parse the entry */ /* Actually parse the entry */
if (cur[0] == '[') { if (cur[0] == '[') {
struct ast_category *newcat = NULL;
char *catname;
/* A category header */ /* A category header */
c = strchr(cur, ']'); c = strchr(cur, ']');
if (!c) { if (!c) {
ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile); ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
return -1; return -1;
} }
*c = '\0'; *c++ = '\0';
cur++; cur++;
*cat = ast_category_new(cur); if (*c++ != '(')
if (!*cat) { c = NULL;
catname = cur;
*cat = newcat = ast_category_new(catname);
if (!newcat) {
ast_log(LOG_WARNING, "Out of memory, line %d of %s\n", lineno, configfile); ast_log(LOG_WARNING, "Out of memory, line %d of %s\n", lineno, configfile);
return -1; return -1;
} }
ast_category_append(cfg, *cat); /* If there are options or categories to inherit from, process them now */
if (c) {
if (!(cur = strchr(c, ')'))) {
ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
return -1;
}
*cur = '\0';
while ((cur = strsep(&c, ","))) {
if (!strcasecmp(cur, "!")) {
(*cat)->ignored = 1;
} else if (!strcasecmp(cur, "+")) {
*cat = category_get(cfg, catname, 1);
if (!*cat) {
ast_destroy(cfg);
if (newcat)
ast_category_destroy(newcat);
ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
return -1;
}
if (newcat) {
move_variables(newcat, *cat);
ast_category_destroy(newcat);
newcat = NULL;
}
} else {
struct ast_category *base;
base = category_get(cfg, cur, 1);
if (!base) {
ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
return -1;
}
inherit_category(*cat, base);
}
}
}
if (newcat)
ast_category_append(cfg, *cat);
} else if (cur[0] == '#') { } else if (cur[0] == '#') {
/* A directive */ /* A directive */
cur++; cur++;
@ -518,9 +660,13 @@ static struct ast_config *config_text_file_load(const char *database, const char
new_buf = comment_p + 1; new_buf = comment_p + 1;
} }
} }
if (process_buf && process_text_line(cfg, &cat, process_buf, lineno, filename)) { if (process_buf) {
cfg = NULL; char *buf = ast_strip(process_buf);
break; if (!ast_strlen_zero(buf))
if (process_text_line(cfg, &cat, buf, lineno, filename)) {
cfg = NULL;
break;
}
} }
} }
} }

Loading…
Cancel
Save