document a nice technique to exit from a block in case of errors.
[asterisk/asterisk.git] / main / config.c
index 736c542..1f29ee1 100644 (file)
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
+#include "asterisk/paths.h"    /* use ast_config_AST_CONFIG_DIR */
+#include "asterisk/network.h"  /* we do some sockaddr manipulation here */
 #include <time.h>
 #include <sys/stat.h>
-#include <sys/socket.h>                /* for AF_INET */
 #define AST_INCLUDE_GLOB 1
 #ifdef AST_INCLUDE_GLOB
 #if defined(__Darwin__) || defined(__CYGWIN__)
@@ -49,8 +45,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/config.h"
 #include "asterisk/cli.h"
 #include "asterisk/lock.h"
-#include "asterisk/options.h"
-#include "asterisk/logger.h"
 #include "asterisk/utils.h"
 #include "asterisk/channel.h"
 #include "asterisk/app.h"
@@ -220,7 +214,7 @@ struct ast_category_template_instance {
 
 struct ast_category {
        char name[80];
-       int ignored;                    /*!< do not let user of the config see this category */
+       int ignored;                    /*!< do not let user of the config see this category -- set by (!) after the category decl; a template */
        int include_level;
        char *file;                /*!< the file name from whence this declaration was read */
        int lineno;
@@ -259,14 +253,16 @@ struct ast_variable *ast_variable_new(const char *name, const char *value, const
 {
        struct ast_variable *variable;
        int name_len = strlen(name) + 1;        
-
-       if ((variable = ast_calloc(1, name_len + strlen(value) + 1 + strlen(filename) + 1 + sizeof(*variable)))) {
-               variable->name = variable->stuff;
-               variable->value = variable->stuff + name_len;           
-               variable->file = variable->stuff + name_len + strlen(value) + 1;
-               strcpy(variable->name,name);
-               strcpy(variable->value,value);
-               strcpy(variable->file,filename);
+       int val_len = strlen(value) + 1;        
+       int fn_len = strlen(filename) + 1;      
+
+       if ((variable = ast_calloc(1, name_len + val_len + fn_len + sizeof(*variable)))) {
+               char *dst = variable->stuff;    /* writable space starts here */
+               variable->name = strcpy(dst, name);
+               dst += name_len;
+               variable->value = strcpy(dst, value);
+               dst += val_len;
+               variable->file = strcpy(dst, filename);
        }
        return variable;
 }
@@ -545,11 +541,9 @@ static void ast_destroy_comments(struct ast_category *cat)
 static void ast_destroy_template_list(struct ast_category *cat)
 {
        struct ast_category_template_instance *x;
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&cat->template_instances, x, next) {
-               AST_LIST_REMOVE_CURRENT(&cat->template_instances, next);
+
+       while ((x = AST_LIST_REMOVE_HEAD(&cat->template_instances, next)))
                free(x);
-       }
-       AST_LIST_TRAVERSE_SAFE_END;
 }
 
 void ast_category_destroy(struct ast_category *cat)
@@ -587,6 +581,12 @@ static struct ast_category *next_available_category(struct ast_category *cat)
        return cat;
 }
 
+/*! return the first var of a category */
+struct ast_variable *ast_category_first(struct ast_category *cat)
+{
+       return (cat) ? cat->root : NULL;
+}
+
 struct ast_variable *ast_category_root(struct ast_config *config, char *cat)
 {
        struct ast_category *category = ast_category_get(config, cat);
@@ -878,21 +878,36 @@ static void config_cache_attribute(const char *configfile, enum config_cache_att
        AST_LIST_UNLOCK(&cfmtime_head);
 }
 
-static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile, struct ast_flags flags,
-                                                        char **comment_buffer, int *comment_buffer_size, char **lline_buffer, int *lline_buffer_size, const char *suggested_include_file, struct ast_category **last_cat, struct ast_variable **last_var)
+/*! \brief parse one line in the configuration.
+ * We can have a category header       [foo](...)
+ * a directive                         #include / #exec
+ * or a regular line                   name = value
+ */
+static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
+       char *buf, int lineno, const char *configfile, struct ast_flags flags,
+       char **comment_buffer, int *comment_buffer_size,
+       char **lline_buffer, int *lline_buffer_size,
+       const char *suggested_include_file,
+       struct ast_category **last_cat, struct ast_variable **last_var)
 {
        char *c;
        char *cur = buf;
        struct ast_variable *v;
        char cmd[512], exec_file[512];
-       int object, do_exec, do_include;
 
        /* Actually parse the entry */
-       if (cur[0] == '[') {
+       if (cur[0] == '[') { /* A category header */
+               /* format is one of the following:
+                * [foo]        define a new category named 'foo'
+                * [foo](!)     define a new template category named 'foo'
+                * [foo](+)     append to category 'foo', error if foo does not exist.
+                * [foo](a)     define a new category and inherit from template a.
+                *              You can put a comma-separated list of templates and '!' and '+'
+                *              between parentheses, with obvious meaning.
+                */
                struct ast_category *newcat = NULL;
                char *catname;
 
-               /* A category header */
                c = strchr(cur, ']');
                if (!c) {
                        ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
@@ -957,8 +972,9 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                }
                if (newcat)
                        ast_category_append(cfg, *cat);
-       } else if (cur[0] == '#') {
-               /* A directive */
+       } else if (cur[0] == '#') { /* A directive - #include or #exec */
+               int do_exec, do_include;
+
                cur++;
                c = cur;
                while (*c && (*c > 32)) c++;
@@ -1040,6 +1056,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                }
                c = strchr(cur, '=');
                if (c) {
+                       int object;
                        *c = 0;
                        c++;
                        /* Ignore > in => */
@@ -1136,6 +1153,11 @@ static struct ast_config *config_text_file_load(const char *database, const char
                        for (i=0; i<globbuf.gl_pathc; i++) {
                                ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
 #endif
+       /*
+        * The following is not a loop, but just a convenient way to define a block
+        * (using do { } while(0) ), and be able to exit from it with 'continue'
+        * or 'break' in case of errors. Nice trick.
+        */
        do {
                if (stat(fn, &statbuf))
                        continue;
@@ -1431,7 +1453,6 @@ static void set_fn(char *fn, int fn_size, const char *file, const char *configfi
                fx->lineno = 1;
                *fi = fx;
                ao2_link(fileset, fx);
-               ao2_ref(fx,1); /* bump the ref count, so it looks like we just got the ref from find */
        }
 }
 
@@ -1723,7 +1744,7 @@ static void clear_config_maps(void)
        ast_mutex_unlock(&config_lock);
 }
 
-static int append_mapping(char *name, char *driver, char *database, char *table)
+static int append_mapping(const char *name, const char *driver, const char *database, const char *table)
 {
        struct ast_config_map *map;
        int length;
@@ -1774,7 +1795,9 @@ int read_config_maps(void)
        }
 
        for (v = ast_variable_browse(config, "settings"); v; v = v->next) {
-               stringp = v->value;
+               char buf[512];
+               ast_copy_string(buf, v->value, sizeof(buf));
+               stringp = buf;
                driver = strsep(&stringp, ",");
 
                if ((tmp = strchr(stringp, '\"')))