2 * Asterisk -- A telephony toolkit for Linux.
4 * Configuration File Parser
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
20 #include <asterisk/config.h>
21 #include <asterisk/options.h>
22 #include <asterisk/logger.h>
26 #define MAX_INCLUDE_LEVEL 10
30 struct ast_variable *root;
31 struct ast_category *next;
32 #ifdef PRESERVE_COMMENTS
33 struct ast_comment *precomments;
34 struct ast_comment *sameline;
39 /* Maybe this structure isn't necessary but we'll keep it
41 struct ast_category *root;
42 struct ast_category *prev;
43 #ifdef PRESERVE_COMMENTS
44 struct ast_comment *trailingcomments;
48 #ifdef PRESERVE_COMMENTS
49 struct ast_comment_struct
51 struct ast_comment *root;
52 struct ast_comment *prev;
56 static char *strip(char *buf)
59 /* Strip off trailing whitespace, returns, etc */
60 while(strlen(buf) && (buf[strlen(buf)-1]<33))
61 buf[strlen(buf)-1] = '\0';
63 /* Strip off leading whitespace, returns, etc */
64 while(*start && (*start < 33))
69 #ifdef PRESERVE_COMMENTS
70 static void free_comments(struct ast_comment *com)
72 struct ast_comment *l;
81 void ast_destroy(struct ast_config *ast)
83 struct ast_category *cat, *catn;
84 struct ast_variable *v, *vn;
96 #ifdef PRESERVE_COMMENTS
97 free_comments(v->precomments);
98 free_comments(v->sameline);
104 #ifdef PRESERVE_COMMENTS
105 free_comments(cat->precomments);
106 free_comments(cat->sameline);
111 #ifdef PRESERVE_COMMENTS
112 free_comments(ast->trailingcomments);
117 int ast_true(char *s)
121 /* Determine if this is a true value */
122 if (!strcasecmp(s, "yes") ||
123 !strcasecmp(s, "true") ||
124 !strcasecmp(s, "y") ||
125 !strcasecmp(s, "t") ||
131 int ast_false(char *s)
135 /* Determine if this is a false value */
136 if (!strcasecmp(s, "no") ||
137 !strcasecmp(s, "false") ||
138 !strcasecmp(s, "n") ||
139 !strcasecmp(s, "f") ||
145 struct ast_variable *ast_variable_browse(struct ast_config *config, char *category)
147 struct ast_category *cat;
150 if (cat->name == category)
156 if (!strcasecmp(cat->name, category))
163 char *ast_variable_retrieve(struct ast_config *config, char *category, char *value)
165 struct ast_variable *v;
167 v = ast_variable_browse(config, category);
169 if (value == v->name)
173 v = ast_variable_browse(config, category);
175 if (!strcasecmp(value, v->name))
180 struct ast_category *cat;
185 if (!strcasecmp(value, v->name))
195 #ifdef PRESERVE_COMMENTS
196 int ast_variable_delete(struct ast_config *cfg, char *category, char *variable, char *value)
198 struct ast_variable *v, *pv, *bv, *bpv;
199 struct ast_category *cat;
202 if (cat->name == category) {
210 if (!strcasecmp(cat->name, category)) {
221 if ((variable == v->name) && (!value || !strcmp(v->value, value)))
227 /* Get the last one that looks like it */
233 if (!strcasecmp(variable, v->name) && (!value || !strcmp(v->value, value))) {
244 /* Unlink from original position */
253 free_comments(v->sameline);
254 free_comments(v->precomments);
260 int ast_category_delete(struct ast_config *cfg, char *category)
262 struct ast_variable *v, *pv;
263 struct ast_category *cat, *cprev;
267 if (cat->name == category) {
277 if (!strcasecmp(cat->name, category)) {
288 cprev->next = cat->next;
290 cfg->root = cat->next;
299 free_comments(pv->sameline);
300 free_comments(pv->precomments);
303 free_comments(cat->sameline);
304 free_comments(cat->precomments);
309 struct ast_variable *ast_variable_append_modify(struct ast_config *config, char *category, char *variable, char *value, int newcat, int newvar, int move)
311 struct ast_variable *v, *pv=NULL, *bv, *bpv;
312 struct ast_category *cat, *pcat;
316 if (cat->name == category) {
324 if (!strcasecmp(cat->name, category)) {
332 cat = malloc(sizeof(struct ast_category));
335 memset(cat, 0, sizeof(struct ast_category));
336 strncpy(cat->name, category, sizeof(cat->name));
338 /* Put us at the end */
344 /* We're the first one */
353 if (variable == v->name)
359 /* Get the last one that looks like it */
365 if (!strcasecmp(variable, v->name)) {
376 /* Unlink from original position */
384 v = malloc(sizeof(struct ast_variable));
387 memset(v, 0, sizeof(struct ast_variable));
388 v->name = strdup(variable);
394 v->value = strdup(value);
396 v->value = strdup("");
411 int ast_category_exist(struct ast_config *config, char *category_name)
413 struct ast_category *category = NULL;
415 category = config->root;
418 if (!strcasecmp(category->name,category_name))
420 category = category->next;
426 #ifdef PRESERVE_COMMENTS
427 static struct ast_comment *build_comment(char *cmt)
429 struct ast_comment *c;
430 int len = strlen(cmt) + 1;
431 c = malloc(sizeof(struct ast_comment) + len);
433 /* Memset the header */
434 memset(c, 0, sizeof(struct ast_comment));
442 static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel
443 #ifdef PRESERVE_COMMENTS
444 , struct ast_comment_struct *acs
448 static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel
449 #ifdef PRESERVE_COMMENTS
450 ,struct ast_comment_struct *acs
456 struct ast_variable *v;
457 #ifdef PRESERVE_COMMENTS
458 struct ast_comment *com = NULL;
461 /* Strip off lines using ; as comment */
462 c = strchr(buf, ';');
465 #ifdef PRESERVE_COMMENTS
468 com = build_comment(c);
473 /* Actually parse the entry */
475 /* A category header */
476 c = strchr(cur, ']');
479 *_tmpc = malloc(sizeof(struct ast_category));
483 "Out of memory, line %d\n", lineno);
486 memset(*_tmpc, 0, sizeof(struct ast_category));
487 strncpy((*_tmpc)->name, cur+1, sizeof((*_tmpc)->name) - 1);
488 (*_tmpc)->root = NULL;
489 #ifdef PRESERVE_COMMENTS
490 (*_tmpc)->precomments = acs->root;
491 (*_tmpc)->sameline = com;
496 tmp->prev->next = *_tmpc;
499 #ifdef PRESERVE_COMMENTS
506 "parse error: no closing ']', line %d of %s\n", lineno, configfile);
508 } else if (cur[0] == '#') {
512 while(*c && (*c > 32)) c++;
516 /* Find real argument */
517 while(*c && (*c < 33)) c++;
522 if (!strcasecmp(cur, "include")) {
525 while((*c == '<') || (*c == '>') || (*c == '\"')) c++;
526 /* Get rid of leading mess */
529 c = cur + strlen(cur) - 1;
530 if ((*c == '>') || (*c == '<') || (*c == '\"'))
535 if (includelevel < MAX_INCLUDE_LEVEL) {
536 __ast_load(cur, tmp, _tmpc, _last, includelevel + 1
537 #ifdef PRESERVE_COMMENTS
542 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", includelevel);
544 ast_log(LOG_WARNING, "Directive '#include' needs an argument (filename) at line %d of %s\n", lineno, configfile);
545 /* Strip off leading and trailing "'s and <>'s */
547 ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
549 /* Just a line (variable = value) */
552 "parse error: No category context for line %d of %s\n", lineno, configfile);
556 c = strchr(cur, '=');
566 v = malloc(sizeof(struct ast_variable));
568 memset(v, 0, sizeof(struct ast_variable));
570 v->name = strdup(strip(cur));
571 v->value = strdup(strip(c));
574 /* Put and reset comments */
575 #ifdef PRESERVE_COMMENTS
576 v->precomments = acs->root;
589 ast_log(LOG_WARNING, "Out of memory, line %d\n", lineno);
593 ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
598 /* store any comments if there are any */
599 #ifdef PRESERVE_COMMENTS
602 acs->prev->next = com;
608 (*_last)->blanklines++;
616 #ifdef PRESERVE_COMMENTS
617 static void dump_comments(FILE *f, struct ast_comment *comment)
620 fprintf(f, ";%s", comment->cmt);
621 comment = comment->next;
626 int ast_save(char *configfile, struct ast_config *cfg, char *generator)
632 struct ast_variable *var;
633 struct ast_category *cat;
635 if (configfile[0] == '/') {
636 strncpy(fn, configfile, sizeof(fn)-1);
638 snprintf(fn, sizeof(fn), "%s/%s", AST_CONFIG_DIR, configfile);
641 strncpy(date, ctime(&t), sizeof(date));
642 if ((f = fopen(fn, "w"))) {
643 if ((option_verbose > 1) && !option_debug)
644 ast_verbose( VERBOSE_PREFIX_2 "Saving '%s': ", fn);
646 fprintf(f, ";! Automatically generated configuration file\n");
647 fprintf(f, ";! Filename: %s (%s)\n", configfile, fn);
648 fprintf(f, ";! Generator: %s\n", generator);
649 fprintf(f, ";! Creation Date: %s", date);
653 #ifdef PRESERVE_COMMENTS
654 /* Dump any precomments */
655 dump_comments(f, cat->precomments);
657 /* Dump section with any appropriate comment */
658 #ifdef PRESERVE_COMMENTS
660 fprintf(f, "[%s] ; %s\n", cat->name, cat->sameline->cmt);
663 fprintf(f, "[%s]\n", cat->name);
666 #ifdef PRESERVE_COMMENTS
667 dump_comments(f, var->precomments);
670 fprintf(f, "%s %s %s ; %s\n", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
672 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
673 if (var->blanklines) {
674 blanklines = var->blanklines;
684 /* Put an empty line */
689 #ifdef PRESERVE_COMMENTS
690 dump_comments(f, cfg->trailingcomments);
694 printf("Unable to open for writing: %s\n", fn);
695 else if (option_verbose > 1)
696 printf( "Unable to write (%s)", strerror(errno));
703 static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel
704 #ifdef PRESERVE_COMMENTS
705 , struct ast_comment_struct *acs
715 if (configfile[0] == '/') {
716 strncpy(fn, configfile, sizeof(fn)-1);
718 snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, configfile);
720 if ((option_verbose > 1) && !option_debug) {
721 ast_verbose( VERBOSE_PREFIX_2 "Parsing '%s': ", fn);
724 if ((f = fopen(fn, "r"))) {
726 ast_log(LOG_DEBUG, "Parsing %s\n", fn);
727 else if (option_verbose > 1)
728 ast_verbose( "Found\n");
730 tmp = malloc(sizeof(struct ast_config));
732 memset(tmp, 0, sizeof(struct ast_config));
737 ast_log(LOG_WARNING, "Out of memory\n");
742 fgets(buf, sizeof(buf), f);
745 if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel
746 #ifdef PRESERVE_COMMENTS
758 ast_log(LOG_DEBUG, "No file to parse: %s\n", fn);
759 else if (option_verbose > 1)
760 ast_verbose( "Not found (%s)\n", strerror(errno));
762 #ifdef PRESERVE_COMMENTS
764 /* Keep trailing comments */
765 tmp->trailingcomments = acs->root;
773 struct ast_config *ast_load(char *configfile)
775 struct ast_category *tmpc=NULL;
776 struct ast_variable *last = NULL;
777 #ifdef PRESERVE_COMMENTS
778 struct ast_comment_struct acs = { NULL, NULL };
780 return __ast_load(configfile, NULL, &tmpc, &last, 0
781 #ifdef PRESERVE_COMMENTS
787 char *ast_category_browse(struct ast_config *config, char *prev)
789 struct ast_category *cat;
792 return config->root->name;
798 if (cat->name == prev) {
800 return cat->next->name;
808 if (!strcasecmp(cat->name, prev)) {
810 return cat->next->name;