diff options
author | matteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b> | 2003-03-09 06:00:18 +0000 |
---|---|---|
committer | matteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b> | 2003-03-09 06:00:18 +0000 |
commit | a5b75bca3546f01dbcf717e036fb85da8a8a8a88 (patch) | |
tree | 55b729e56a44996fffed585a06617bfd8b0602ac /config.c | |
parent | fe1433baf16899179f3c88d94b825af48b000880 (diff) |
Sun Mar 9 07:00:01 CET 2003
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@636 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'config.c')
-rwxr-xr-x | config.c | 397 |
1 files changed, 386 insertions, 11 deletions
@@ -16,6 +16,7 @@ #include <stdlib.h> #include <string.h> #include <errno.h> +#include <time.h> #include <asterisk/config.h> #include <asterisk/options.h> #include <asterisk/logger.h> @@ -28,12 +29,22 @@ struct ast_category { char name[80]; struct ast_variable *root; struct ast_category *next; + struct ast_comment *precomments; + struct ast_comment *sameline; }; struct ast_config { /* Maybe this structure isn't necessary but we'll keep it for now */ struct ast_category *root; + struct ast_category *prev; + struct ast_comment *trailingcomments; +}; + +struct ast_comment_struct +{ + struct ast_comment *root; + struct ast_comment *prev; }; static char *strip(char *buf) @@ -49,6 +60,16 @@ static char *strip(char *buf) return start; } +static void free_comments(struct ast_comment *com) +{ + struct ast_comment *l; + while (com) { + l = com; + com = com->next; + free(l); + } +} + void ast_destroy(struct ast_config *ast) { struct ast_category *cat, *catn; @@ -64,13 +85,18 @@ void ast_destroy(struct ast_config *ast) vn = v; free(v->name); free(v->value); + free_comments(v->precomments); + free_comments(v->sameline); v = v->next; free(vn); } catn = cat; + free_comments(cat->precomments); + free_comments(cat->sameline); cat = cat->next; free(catn); } + free_comments(ast->trailingcomments); free(ast); } @@ -138,6 +164,220 @@ char *ast_variable_retrieve(struct ast_config *config, char *category, char *val return NULL; } +int ast_variable_delete(struct ast_config *cfg, char *category, char *variable, char *value) +{ + struct ast_variable *v, *pv, *bv, *bpv; + struct ast_category *cat; + cat = cfg->root; + while(cat) { + if (cat->name == category) { + break; + } + cat = cat->next; + } + if (!cat) { + cat = cfg->root; + while(cat) { + if (!strcasecmp(cat->name, category)) { + break; + } + cat = cat->next; + } + } + if (!cat) + return -1; + v = cat->root; + pv = NULL; + while (v) { + if ((variable == v->name) && (!value || !strcmp(v->value, value))) + break; + pv = v; + v=v->next; + } + if (!v) { + /* Get the last one that looks like it */ + bv = NULL; + bpv = NULL; + v = cat->root; + pv = NULL; + while (v) { + if (!strcasecmp(variable, v->name) && (!value || !strcmp(v->value, value))) { + bv = v; + bpv = pv; + } + pv = v; + v=v->next; + } + v = bv; + } + + if (v) { + /* Unlink from original position */ + if (pv) + pv->next = v->next; + else + cat->root = v->next; + v->next = NULL; + free(v->name); + if (v->value) + free(v->value); + free_comments(v->sameline); + free_comments(v->precomments); + return 0; + } + return -1; +} + +int ast_category_delete(struct ast_config *cfg, char *category) +{ + struct ast_variable *v, *pv; + struct ast_category *cat, *cprev; + cat = cfg->root; + cprev = NULL; + while(cat) { + if (cat->name == category) { + break; + } + cprev = cat; + cat = cat->next; + } + if (!cat) { + cat = cfg->root; + cprev = NULL; + while(cat) { + if (!strcasecmp(cat->name, category)) { + break; + } + cprev = cat; + cat = cat->next; + } + } + if (!cat) + return -1; + /* Unlink it */ + if (cprev) + cprev->next = cat->next; + else + cfg->root = cat->next; + v = cat->root; + while (v) { + pv = v; + v=v->next; + if (pv->value) + free(pv->value); + if (pv->name) + free(pv->name); + free_comments(pv->sameline); + free_comments(pv->precomments); + free(pv); + } + free_comments(cat->sameline); + free_comments(cat->precomments); + free(cat); + return 0; +} + +struct ast_variable *ast_variable_append_modify(struct ast_config *config, char *category, char *variable, char *value, int newcat, int newvar, int move) +{ + struct ast_variable *v, *pv, *bv, *bpv; + struct ast_category *cat, *pcat; + cat = config->root; + if (!newcat) { + while(cat) { + if (cat->name == category) { + break; + } + cat = cat->next; + } + if (!cat) { + cat = config->root; + while(cat) { + if (!strcasecmp(cat->name, category)) { + break; + } + cat = cat->next; + } + } + } + if (!cat) { + cat = malloc(sizeof(struct ast_category)); + if (!cat) + return NULL; + memset(cat, 0, sizeof(struct ast_category)); + strncpy(cat->name, category, sizeof(cat->name)); + if (config->root) { + /* Put us at the end */ + pcat = config->root; + while(pcat->next) + pcat = pcat->next; + pcat->next = cat; + } else { + /* We're the first one */ + config->root = cat; + } + + } + if (!newvar) { + v = cat->root; + pv = NULL; + while (v) { + if (variable == v->name) + break; + pv = v; + v=v->next; + } + if (!v) { + /* Get the last one that looks like it */ + bv = NULL; + bpv = NULL; + v = cat->root; + pv = NULL; + while (v) { + if (!strcasecmp(variable, v->name)) { + bv = v; + bpv = pv; + } + pv = v; + v=v->next; + } + v = bv; + } + } else v = NULL; + if (v && move) { + /* Unlink from original position */ + if (pv) + pv->next = v->next; + else + cat->root = v->next; + v->next = NULL; + } + if (!v) { + v = malloc(sizeof(struct ast_variable)); + if (!v) + return NULL; + memset(v, 0, sizeof(struct ast_variable)); + v->name = strdup(variable); + move = 1; + } + if (v->value) + free(v->value); + if (value) + v->value = strdup(value); + else + v->value = strdup(""); + if (move) { + if (cat->root) { + pv = cat->root; + while (pv->next) + pv = pv->next; + pv->next = v; + } else { + cat->root = v; + } + } + return v; +} + int ast_category_exist(struct ast_config *config, char *category_name) { struct ast_category *category = NULL; @@ -153,16 +393,33 @@ int ast_category_exist(struct ast_config *config, char *category_name) return 0; } -static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel); -static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel) +static struct ast_comment *build_comment(char *cmt) +{ + struct ast_comment *c; + c = malloc(sizeof(struct ast_comment)); + if (c) { + memset(c, 0, sizeof(struct ast_comment)); + c->comment = strdup(cmt); + } + return c; +} + +static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel, struct ast_comment_struct *acs); +static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel, struct ast_comment_struct *acs) { char *c; char *cur; struct ast_variable *v; + struct ast_comment *com = NULL; + int object; /* Strip off lines using ; as comment */ c = strchr(buf, ';'); - if (c) + if (c) { *c = '\0'; + c++; + if (*c != '!') + com = build_comment(c); + } cur = strip(buf); if (strlen(cur)) { /* Actually parse the entry */ @@ -181,8 +438,16 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru memset(*_tmpc, 0, sizeof(struct ast_category)); strncpy((*_tmpc)->name, cur+1, sizeof((*_tmpc)->name) - 1); (*_tmpc)->root = NULL; - (*_tmpc)->next = tmp->root; - tmp->root = *_tmpc; + (*_tmpc)->precomments = acs->root; + (*_tmpc)->sameline = com; + if (!tmp->prev) + tmp->root = *_tmpc; + else + tmp->prev->next = *_tmpc; + + tmp->prev = *_tmpc; + acs->root = NULL; + acs->prev = NULL; *_last = NULL; } else { ast_log(LOG_WARNING, @@ -216,7 +481,7 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru break; } if (includelevel < MAX_INCLUDE_LEVEL) { - __ast_load(cur, tmp, _tmpc, _last, includelevel + 1); + __ast_load(cur, tmp, _tmpc, _last, includelevel + 1, acs); } else ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", includelevel); } else @@ -237,8 +502,11 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru *c = 0; c++; /* Ignore > in => */ - if (*c== '>') + if (*c== '>') { + object = 1; c++; + } else + object = 0; v = malloc(sizeof(struct ast_variable)); if (v) { memset(v, 0, sizeof(struct ast_variable)); @@ -246,7 +514,14 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru v->name = strdup(strip(cur)); v->value = strdup(strip(c)); v->lineno = lineno; - if (*_last) + v->object = object; + /* Put and reset comments */ + v->precomments = acs->root; + v->blanklines = 0; + acs->prev = NULL; + acs->root = NULL; + v->sameline = com; + if (*_last) (*_last)->next = v; else (*_tmpc)->root = v; @@ -261,16 +536,107 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru } } + } else { + /* store any comments if there are any */ + if (com) { + if (acs->prev) + acs->prev->next = com; + else + acs->root = com; + acs->prev = com; + } else { + if (*_last) + (*_last)->blanklines++; + + } } return 0; } -static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel) +static void dump_comments(FILE *f, struct ast_comment *comment) +{ + while (comment) { + fprintf(f, ";%s", comment->comment); + comment = comment->next; + } +} + +int ast_save(char *configfile, struct ast_config *cfg, char *generator) +{ + FILE *f; + char fn[256]; + char date[256]; + time_t t; + struct ast_variable *var; + struct ast_category *cat; + int blanklines = 0; + if (configfile[0] == '/') { + strncpy(fn, configfile, sizeof(fn)-1); + } else { + snprintf(fn, sizeof(fn), "%s/%s", AST_CONFIG_DIR, configfile); + } + time(&t); + strncpy(date, ctime(&t), sizeof(date)); + if ((f = fopen(fn, "w"))) { + if ((option_verbose > 1) && !option_debug) + ast_verbose( VERBOSE_PREFIX_2 "Saving '%s': ", fn); + fprintf(f, ";!\n"); + fprintf(f, ";! Automatically generated configuration file\n"); + fprintf(f, ";! Filename: %s (%s)\n", configfile, fn); + fprintf(f, ";! Generator: %s\n", generator); + fprintf(f, ";! Creation Date: %s", date); + fprintf(f, ";!\n"); + cat = cfg->root; + while(cat) { + /* Dump any precomments */ + dump_comments(f, cat->precomments); + /* Dump section with any appropriate comment */ + if (cat->sameline) + fprintf(f, "[%s] ; %s\n", cat->name, cat->sameline->comment); + else + fprintf(f, "[%s]\n", cat->name); + var = cat->root; + while(var) { + dump_comments(f, var->precomments); + if (var->sameline) + fprintf(f, "%s %s %s ; %s\n", var->name, (var->object ? "=>" : "="), var->value, var->sameline->comment); + else + fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value); + if (var->blanklines) { + blanklines = var->blanklines; + while (blanklines) { + fprintf(f, "\n"); + blanklines--; + } + } + + var = var->next; + } +#if 0 + /* Put an empty line */ + fprintf(f, "\n"); +#endif + cat = cat->next; + } + dump_comments(f, cfg->trailingcomments); + } else { + if (option_debug) + printf("Unable to open for writing: %s\n", fn); + else if (option_verbose > 1) + printf( "Unable to write (%s)", strerror(errno)); + return -1; + } + fclose(f); + return 0; +} + +static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel, struct ast_comment_struct *acs) { char fn[256]; char buf[256]; FILE *f; int lineno=0; + int master=0; if (configfile[0] == '/') { strncpy(fn, configfile, sizeof(fn)-1); @@ -290,6 +656,8 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s tmp = malloc(sizeof(struct ast_config)); if (tmp) memset(tmp, 0, sizeof(struct ast_config)); + + master = 1; } if (!tmp) { ast_log(LOG_WARNING, "Out of memory\n"); @@ -300,7 +668,7 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s fgets(buf, sizeof(buf), f); lineno++; if (!feof(f)) { - if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel)) { + if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel, acs)) { fclose(f); return NULL; } @@ -313,6 +681,12 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s else if (option_verbose > 1) ast_verbose( "Not found (%s)", strerror(errno)); } + if (master) { + /* Keep trailing comments */ + tmp->trailingcomments = acs->root; + acs->root = NULL; + acs->prev = NULL; + } return tmp; } @@ -320,7 +694,8 @@ struct ast_config *ast_load(char *configfile) { struct ast_category *tmpc=NULL; struct ast_variable *last = NULL; - return __ast_load(configfile, NULL, &tmpc, &last, 0); + struct ast_comment_struct acs = { NULL, NULL }; + return __ast_load(configfile, NULL, &tmpc, &last, 0, &acs); } char *ast_category_browse(struct ast_config *config, char *prev) |