Add a massive set of changes for converting to use the ast_debug() macro.
[asterisk/asterisk.git] / main / config.c
index 7d72e0a..ad71384 100644 (file)
@@ -62,14 +62,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 static char *extconfig_conf = "extconfig.conf";
 
-/*! Growable string buffer */
-static char *comment_buffer;   /*!< this will be a comment collector.*/
-static int   comment_buffer_size;  /*!< the amount of storage so far alloc'd for the comment_buffer */
-
-static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
-static int  lline_buffer_size;
-
 
+/*! \brief Structure to keep comments for rewriting configuration files */
+/*! \brief Structure to keep comments for rewriting configuration files */
 struct ast_comment {
        struct ast_comment *next;
        char cmt[0];
@@ -77,76 +72,76 @@ struct ast_comment {
 
 #define CB_INCR 250
 
-static void CB_INIT(void)
+static void CB_INIT(char **comment_buffer, int *comment_buffer_size, char **lline_buffer, int *lline_buffer_size)
 {
-       if (!comment_buffer) {
-               comment_buffer = ast_malloc(CB_INCR);
-               if (!comment_buffer)
+       if (!(*comment_buffer)) {
+               *comment_buffer = ast_malloc(CB_INCR);
+               if (!(*comment_buffer))
                        return;
-               comment_buffer[0] = 0;
-               comment_buffer_size = CB_INCR;
-               lline_buffer = ast_malloc(CB_INCR);
-               if (!lline_buffer)
+               (*comment_buffer)[0] = 0;
+               *comment_buffer_size = CB_INCR;
+               *lline_buffer = ast_malloc(CB_INCR);
+               if (!(*lline_buffer))
                        return;
-               lline_buffer[0] = 0;
-               lline_buffer_size = CB_INCR;
+               (*lline_buffer)[0] = 0;
+               *lline_buffer_size = CB_INCR;
        } else {
-               comment_buffer[0] = 0;
-               lline_buffer[0] = 0;
+               (*comment_buffer)[0] = 0;
+               (*lline_buffer)[0] = 0;
        }
 }
 
-static void  CB_ADD(char *str)
+static void  CB_ADD(char **comment_buffer, int *comment_buffer_size, char *str)
 {
-       int rem = comment_buffer_size - strlen(comment_buffer) - 1;
+       int rem = *comment_buffer_size - strlen(*comment_buffer) - 1;
        int siz = strlen(str);
        if (rem < siz+1) {
-               comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + siz + 1);
-               if (!comment_buffer)
+               *comment_buffer = ast_realloc(*comment_buffer, *comment_buffer_size + CB_INCR + siz + 1);
+               if (!(*comment_buffer))
                        return;
-               comment_buffer_size += CB_INCR+siz+1;
+               *comment_buffer_size += CB_INCR+siz+1;
        }
-       strcat(comment_buffer,str);
+       strcat(*comment_buffer,str);
 }
 
-static void  CB_ADD_LEN(char *str, int len)
+static void  CB_ADD_LEN(char **comment_buffer, int *comment_buffer_size, char *str, int len)
 {
-       int cbl = strlen(comment_buffer) + 1;
-       int rem = comment_buffer_size - cbl;
+       int cbl = strlen(*comment_buffer) + 1;
+       int rem = *comment_buffer_size - cbl;
        if (rem < len+1) {
-               comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + len + 1);
-               if (!comment_buffer)
+               *comment_buffer = ast_realloc(*comment_buffer, *comment_buffer_size + CB_INCR + len + 1);
+               if (!(*comment_buffer))
                        return;
-               comment_buffer_size += CB_INCR+len+1;
+               *comment_buffer_size += CB_INCR+len+1;
        }
-       strncat(comment_buffer,str,len);
-       comment_buffer[cbl+len-1] = 0;
+       strncat(*comment_buffer,str,len);
+       (*comment_buffer)[cbl+len-1] = 0;
 }
 
-static void  LLB_ADD(char *str)
+static void  LLB_ADD(char **lline_buffer, int *lline_buffer_size, char *str)
 {
-       int rem = lline_buffer_size - strlen(lline_buffer) - 1;
+       int rem = *lline_buffer_size - strlen(*lline_buffer) - 1;
        int siz = strlen(str);
        if (rem < siz+1) {
-               lline_buffer = ast_realloc(lline_buffer, lline_buffer_size + CB_INCR + siz + 1);
-               if (!lline_buffer) 
+               *lline_buffer = ast_realloc(*lline_buffer, *lline_buffer_size + CB_INCR + siz + 1);
+               if (!(*lline_buffer)) 
                        return;
-               lline_buffer_size += CB_INCR + siz + 1;
+               *lline_buffer_size += CB_INCR + siz + 1;
        }
-       strcat(lline_buffer,str);
+       strcat(*lline_buffer,str);
 }
 
-static void CB_RESET(void )  
+static void CB_RESET(char **comment_buffer, char **lline_buffer)  
 { 
-       comment_buffer[0] = 0; 
-       lline_buffer[0] = 0;
+       (*comment_buffer)[0] = 0; 
+       (*lline_buffer)[0] = 0;
 }
-               
 
 
 static struct ast_comment *ALLOC_COMMENT(const char *buffer)
 { 
-       struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
+       struct ast_comment *x;
+       x = ast_calloc(1, sizeof(*x)+strlen(buffer)+1);
        strcpy(x->cmt, buffer);
        return x;
 }
@@ -218,10 +213,10 @@ void ast_variables_destroy(struct ast_variable *v)
 {
        struct ast_variable *vn;
 
-       while(v) {
+       while (v) {
                vn = v;
                v = v->next;
-               free(vn);
+               ast_free(vn);
        }
 }
 
@@ -350,7 +345,7 @@ void ast_category_append(struct ast_config *config, struct ast_category *categor
 void ast_category_destroy(struct ast_category *cat)
 {
        ast_variables_destroy(cat->root);
-       free(cat);
+       ast_free(cat);
 }
 
 static struct ast_category *next_available_category(struct ast_category *cat)
@@ -425,7 +420,7 @@ struct ast_config *ast_config_new(void)
        return config;
 }
 
-int ast_variable_delete(struct ast_category *category, char *variable, char *match)
+int ast_variable_delete(struct ast_category *category, const char *variable, const char *match)
 {
        struct ast_variable *cur, *prev=NULL, *curn;
        int res = -1;
@@ -474,62 +469,49 @@ int ast_variable_delete(struct ast_category *category, char *variable, char *mat
        return res;
 }
 
-int ast_variable_update(struct ast_category *category, char *variable, char *value, char *match)
+int ast_variable_update(struct ast_category *category, const char *variable, 
+       const char *value, const char *match, unsigned int object)
 {
        struct ast_variable *cur, *prev=NULL, *newer;
-       newer = ast_variable_new(variable, value);
-       if (!newer)
+
+       if (!(newer = ast_variable_new(variable, value)))
                return -1;
-       cur = category->root;
-       while (cur) {
-               if (cur->name == variable) {
-                       newer->next = cur->next;
-                       newer->object = cur->object;
-                       if (prev)
-                               prev->next = newer;
-                       else
-                               category->root = newer;
-                       if (category->last == cur)
-                               category->last = newer;
-                       cur->next = NULL;
-                       ast_variables_destroy(cur);
-                       return 0;
-               }
-               prev = cur;
-               cur = cur->next;
-       }
+       
+       newer->object = object;
 
-       prev = NULL;
-       cur = category->root;
-       while (cur) {
-               if (!strcasecmp(cur->name, variable) && (ast_strlen_zero(match) || !strcasecmp(cur->value, match))) {
-                       newer->next = cur->next;
-                       newer->object = cur->object;
-                       if (prev)
-                               prev->next = newer;
-                       else
-                               category->root = newer;
-                       if (category->last == cur)
-                               category->last = newer;
-                       cur->next = NULL;
-                       ast_variables_destroy(cur);
-                       return 0;
-               }
-               prev = cur;
-               cur = cur->next;
+       for (cur = category->root; cur; prev = cur, cur = cur->next) {
+               if (strcasecmp(cur->name, variable) ||
+                       (!ast_strlen_zero(match) && strcasecmp(cur->value, match)))
+                       continue;
+
+               newer->next = cur->next;
+               newer->object = cur->object || object;
+               if (prev)
+                       prev->next = newer;
+               else
+                       category->root = newer;
+               if (category->last == cur)
+                       category->last = newer;
+
+               cur->next = NULL;
+               ast_variables_destroy(cur);
+
+               return 0;
        }
+
        if (prev)
                prev->next = newer;
        else
                category->root = newer;
+
        return 0;
 }
 
-int ast_category_delete(struct ast_config *cfg, char *category)
+int ast_category_delete(struct ast_config *cfg, const char *category)
 {
        struct ast_category *prev=NULL, *cat;
        cat = cfg->root;
-       while(cat) {
+       while (cat) {
                if (cat->name == category) {
                        ast_variables_destroy(cat->root);
                        if (prev) {
@@ -541,7 +523,7 @@ int ast_category_delete(struct ast_config *cfg, char *category)
                                if (cat == cfg->last)
                                        cfg->last = NULL;
                        }
-                       free(cat);
+                       ast_free(cat);
                        return 0;
                }
                prev = cat;
@@ -550,7 +532,7 @@ int ast_category_delete(struct ast_config *cfg, char *category)
 
        prev = NULL;
        cat = cfg->root;
-       while(cat) {
+       while (cat) {
                if (!strcasecmp(cat->name, category)) {
                        ast_variables_destroy(cat->root);
                        if (prev) {
@@ -562,7 +544,7 @@ int ast_category_delete(struct ast_config *cfg, char *category)
                                if (cat == cfg->last)
                                        cfg->last = NULL;
                        }
-                       free(cat);
+                       ast_free(cat);
                        return 0;
                }
                prev = cat;
@@ -579,13 +561,13 @@ void ast_config_destroy(struct ast_config *cfg)
                return;
 
        cat = cfg->root;
-       while(cat) {
+       while (cat) {
                ast_variables_destroy(cat->root);
                catn = cat;
                cat = cat->next;
-               free(catn);
+               ast_free(catn);
        }
-       free(cfg);
+       ast_free(cfg);
 }
 
 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
@@ -599,7 +581,8 @@ void ast_config_set_current_category(struct ast_config *cfg, const struct ast_ca
        cfg->current = (struct ast_category *) cat;
 }
 
-static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile, int withcomments)
+static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile, int withcomments,
+                               char **comment_buffer, int *comment_buffer_size, char **lline_buffer, int *lline_buffer_size)
 {
        char *c;
        char *cur = buf;
@@ -627,14 +610,14 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                        return -1;
                }
                /* add comments */
-               if (withcomments && comment_buffer && comment_buffer[0] ) {
-                       newcat->precomments = ALLOC_COMMENT(comment_buffer);
+               if (withcomments && *comment_buffer && (*comment_buffer)[0] ) {
+                       newcat->precomments = ALLOC_COMMENT(*comment_buffer);
                }
-               if (withcomments && lline_buffer && lline_buffer[0] ) {
-                       newcat->sameline = ALLOC_COMMENT(lline_buffer);
+               if (withcomments && *lline_buffer && (*lline_buffer)[0] ) {
+                       newcat->sameline = ALLOC_COMMENT(*lline_buffer);
                }
-               if( withcomments )
-                       CB_RESET();
+               if ( withcomments )
+                       CB_RESET(comment_buffer, lline_buffer);
                
                /* If there are options or categories to inherit from, process them now */
                if (c) {
@@ -648,8 +631,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                                        (*cat)->ignored = 1;
                                } else if (!strcasecmp(cur, "+")) {
                                        *cat = category_get(cfg, catname, 1);
-                                       if (!*cat) {
-                                               ast_config_destroy(cfg);
+                                       if (!(*cat)) {
                                                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);
@@ -678,17 +660,17 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                /* A directive */
                cur++;
                c = cur;
-               while(*c && (*c > 32)) c++;
+               while (*c && (*c > 32)) c++;
                if (*c) {
                        *c = '\0';
                        /* Find real argument */
                        c = ast_skip_blanks(c + 1);
-                       if (!*c)
+                       if (!(*c))
                                c = NULL;
                } else 
                        c = NULL;
                do_include = !strcasecmp(cur, "include");
-               if(!do_include)
+               if (!do_include)
                        do_exec = !strcasecmp(cur, "exec");
                else
                        do_exec = 0;
@@ -699,7 +681,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                if (do_include || do_exec) {
                        if (c) {
                                /* Strip off leading and trailing "'s and <>'s */
-                               while((*c == '<') || (*c == '>') || (*c == '\"')) c++;
+                               while ((*c == '<') || (*c == '>') || (*c == '\"')) c++;
                                /* Get rid of leading mess */
                                cur = c;
                                while (!ast_strlen_zero(cur)) {
@@ -720,9 +702,9 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                                        exec_file[0] = '\0';
                                /* A #include */
                                do_include = ast_config_internal_load(cur, cfg, withcomments) ? 1 : 0;
-                               if(!ast_strlen_zero(exec_file))
+                               if (!ast_strlen_zero(exec_file))
                                        unlink(exec_file);
-                               if(!do_include)
+                               if (!do_include)
                                        return 0;
 
                        } else {
@@ -737,7 +719,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                        ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
        } else {
                /* Just a line (variable = value) */
-               if (!*cat) {
+               if (!(*cat)) {
                        ast_log(LOG_WARNING,
                                "parse error: No category context for line %d of %s\n", lineno, configfile);
                        return -1;
@@ -759,14 +741,14 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
                                v->blanklines = 0;
                                ast_variable_append(*cat, v);
                                /* add comments */
-                               if (withcomments && comment_buffer && comment_buffer[0] ) {
-                                       v->precomments = ALLOC_COMMENT(comment_buffer);
+                               if (withcomments && *comment_buffer && (*comment_buffer)[0] ) {
+                                       v->precomments = ALLOC_COMMENT(*comment_buffer);
                                }
-                               if (withcomments && lline_buffer && lline_buffer[0] ) {
-                                       v->sameline = ALLOC_COMMENT(lline_buffer);
+                               if (withcomments && *lline_buffer && (*lline_buffer)[0] ) {
+                                       v->sameline = ALLOC_COMMENT(*lline_buffer);
                                }
-                               if( withcomments )
-                                       CB_RESET();
+                               if ( withcomments )
+                                       CB_RESET(comment_buffer, lline_buffer);
                                
                        } else {
                                return -1;
@@ -789,6 +771,13 @@ static struct ast_config *config_text_file_load(const char *database, const char
        struct ast_category *cat = NULL;
        int count = 0;
        struct stat statbuf;
+       /*! Growable string buffer */
+       char *comment_buffer=0;   /*!< this will be a comment collector.*/
+       int   comment_buffer_size=0;  /*!< the amount of storage so far alloc'd for the comment_buffer */
+
+       char *lline_buffer=0;    /*!< A buffer for stuff behind the ; */
+       int  lline_buffer_size=0;
+
        
        cat = ast_config_get_current_category(cfg);
 
@@ -799,7 +788,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
        }
 
        if (withcomments) {
-               CB_INIT();
+               CB_INIT(&comment_buffer, &comment_buffer_size, &lline_buffer, &lline_buffer_size);
                if (!lline_buffer || !comment_buffer) {
                        ast_log(LOG_ERROR, "Failed to initialize the comment buffer!\n");
                        return NULL;
@@ -840,23 +829,20 @@ static struct ast_config *config_text_file_load(const char *database, const char
                        fflush(stdout);
                }
                if (!(f = fopen(fn, "r"))) {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "No file to parse: %s\n", fn);
+                       ast_debug(1, "No file to parse: %s\n", fn);
                        if (option_verbose > 1)
                                ast_verbose( "Not found (%s)\n", strerror(errno));
                        continue;
                }
                count++;
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Parsing %s\n", fn);
+               ast_debug(1, "Parsing %s\n", fn);
                if (option_verbose > 1)
                        ast_verbose("Found\n");
-               while(!feof(f)) {
+               while (!feof(f)) {
                        lineno++;
                        if (fgets(buf, sizeof(buf), f)) {
                                if ( withcomments ) {
-                                       ast_log(LOG_NOTICE, "moo\n");
-                                       CB_ADD(lline_buffer);       /* add the current lline buffer to the comment buffer */
+                                       CB_ADD(&comment_buffer, &comment_buffer_size, lline_buffer);       /* add the current lline buffer to the comment buffer */
                                        lline_buffer[0] = 0;        /* erase the lline buffer */
                                }
                                
@@ -871,7 +857,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
                                                /* Yuck, gotta memmove */
                                                memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
                                                new_buf = comment_p;
-                                       } else if(comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
+                                       } else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
                                                /* Meta-Comment start detected ";--" */
                                                if (comment < MAX_NESTED_COMMENTS) {
                                                        *comment_p = '\0';
@@ -894,8 +880,8 @@ static struct ast_config *config_text_file_load(const char *database, const char
                                                                char *oldptr;
                                                                oldptr = process_buf + strlen(process_buf);
                                                                if ( withcomments ) {
-                                                                       CB_ADD(";");
-                                                                       CB_ADD_LEN(oldptr+1,new_buf-oldptr-1);
+                                                                       CB_ADD(&comment_buffer, &comment_buffer_size, ";");
+                                                                       CB_ADD_LEN(&comment_buffer, &comment_buffer_size, oldptr+1, new_buf-oldptr-1);
                                                                }
                                                                
                                                                memmove(oldptr, new_buf, strlen(new_buf) + 1);
@@ -908,7 +894,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
                                                        /* If ; is found, and we are not nested in a comment, 
                                                           we immediately stop all comment processing */
                                                        if ( withcomments ) {
-                                                               LLB_ADD(comment_p);
+                                                               LLB_ADD(&lline_buffer, &lline_buffer_size, comment_p);
                                                        }
                                                        *comment_p = '\0'; 
                                                        new_buf = comment_p;
@@ -916,15 +902,15 @@ static struct ast_config *config_text_file_load(const char *database, const char
                                                        new_buf = comment_p + 1;
                                        }
                                }
-                               if( withcomments && comment && !process_buf )
+                               if ( withcomments && comment && !process_buf )
                                {
-                                       CB_ADD(buf);  /* the whole line is a comment, store it */
+                                       CB_ADD(&comment_buffer, &comment_buffer_size, buf);  /* the whole line is a comment, store it */
                                }
                                
                                if (process_buf) {
                                        char *buf = ast_strip(process_buf);
                                        if (!ast_strlen_zero(buf)) {
-                                               if (process_text_line(cfg, &cat, buf, lineno, filename, withcomments)) {
+                                               if (process_text_line(cfg, &cat, buf, lineno, fn, withcomments, &comment_buffer, &comment_buffer_size, &lline_buffer, &lline_buffer_size)) {
                                                        cfg = NULL;
                                                        break;
                                                }
@@ -933,7 +919,7 @@ static struct ast_config *config_text_file_load(const char *database, const char
                        }
                }
                fclose(f);              
-       } while(0);
+       } while (0);
        if (comment) {
                ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment]);
        }
@@ -946,9 +932,9 @@ static struct ast_config *config_text_file_load(const char *database, const char
                }
 #endif
 
-       if (cfg->include_level == 1 && withcomments && comment_buffer) {
-               free(comment_buffer);
-               free(lline_buffer);
+       if (cfg && cfg->include_level == 1 && withcomments && comment_buffer) {
+               ast_free(comment_buffer);
+               ast_free(lline_buffer);
                comment_buffer = NULL;
                lline_buffer = NULL;
                comment_buffer_size = 0;
@@ -996,7 +982,7 @@ int config_text_file_save(const char *configfile, const struct ast_config *cfg,
                fprintf(f, ";! Creation Date: %s", date);
                fprintf(f, ";!\n");
                cat = cfg->root;
-               while(cat) {
+               while (cat) {
                        /* Dump section with any appropriate comment */
                        for (cmt = cat->precomments; cmt; cmt=cmt->next)
                        {
@@ -1006,14 +992,14 @@ int config_text_file_save(const char *configfile, const struct ast_config *cfg,
                        if (!cat->precomments)
                                fprintf(f,"\n");
                        fprintf(f, "[%s]", cat->name);
-                       for(cmt = cat->sameline; cmt; cmt=cmt->next)
+                       for (cmt = cat->sameline; cmt; cmt=cmt->next)
                        {
                                fprintf(f,"%s", cmt->cmt);
                        }
                        if (!cat->sameline)
                                fprintf(f,"\n");
                        var = cat->root;
-                       while(var) {
+                       while (var) {
                                for (cmt = var->precomments; cmt; cmt=cmt->next)
                                {
                                        if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
@@ -1040,8 +1026,7 @@ int config_text_file_save(const char *configfile, const struct ast_config *cfg,
                if ((option_verbose > 1) && !option_debug)
                        ast_verbose("Saved\n");
        } else {
-               if (option_debug)
-                       ast_log(LOG_DEBUG, "Unable to open for writing: %s\n", fn);
+               ast_debug(1, "Unable to open for writing: %s\n", fn);
                if (option_verbose > 1)
                        ast_verbose(VERBOSE_PREFIX_2 "Unable to write (%s)", strerror(errno));
                return -1;
@@ -1059,7 +1044,7 @@ static void clear_config_maps(void)
        while (config_maps) {
                map = config_maps;
                config_maps = config_maps->next;
-               free(map);
+               ast_free(map);
        }
                
        ast_mutex_unlock(&config_lock);
@@ -1104,7 +1089,7 @@ int read_config_maps(void)
 {
        struct ast_config *config, *configtmp;
        struct ast_variable *v;
-       char *driver, *table, *database, *stringp;
+       char *driver, *table, *database, *stringp, *tmp;
 
        clear_config_maps();
 
@@ -1120,6 +1105,9 @@ int read_config_maps(void)
                stringp = v->value;
                driver = strsep(&stringp, ",");
 
+               if ((tmp = strchr(stringp, '\"')))
+                       stringp = tmp;
+
                /* check if the database text starts with a double quote */
                if (*stringp == '"') {
                        stringp++;
@@ -1279,6 +1267,8 @@ struct ast_config *ast_config_internal_load(const char *filename, struct ast_con
 
        if (result)
                result->include_level--;
+       else
+               cfg->include_level--;
 
        return result;
 }
@@ -1315,23 +1305,61 @@ struct ast_config *ast_config_load_with_comments(const char *filename)
        return result;
 }
 
-struct ast_variable *ast_load_realtime(const char *family, ...)
+static struct ast_variable *ast_load_realtime_helper(const char *family, va_list ap)
 {
        struct ast_config_engine *eng;
        char db[256]="";
        char table[256]="";
        struct ast_variable *res=NULL;
-       va_list ap;
 
-       va_start(ap, family);
        eng = find_engine(family, db, sizeof(db), table, sizeof(table));
        if (eng && eng->realtime_func) 
                res = eng->realtime_func(db, table, ap);
+
+       return res;
+}
+
+struct ast_variable *ast_load_realtime_all(const char *family, ...)
+{
+       struct ast_variable *res;
+       va_list ap;
+
+       va_start(ap, family);
+       res = ast_load_realtime_helper(family, ap);
        va_end(ap);
 
        return res;
 }
 
+struct ast_variable *ast_load_realtime(const char *family, ...)
+{
+       struct ast_variable *res, *cur, *prev = NULL, *freeme = NULL;
+       va_list ap;
+
+       va_start(ap, family);
+       res = ast_load_realtime_helper(family, ap);
+       va_end(ap);
+
+       /* Eliminate blank entries */
+       for (cur = res; cur; cur = cur->next) {
+               if (freeme) {
+                       ast_free(freeme);
+                       freeme = NULL;
+               }
+
+               if (ast_strlen_zero(cur->value)) {
+                       if (prev)
+                               prev->next = cur->next;
+                       else
+                               res = cur->next;
+                       freeme = cur;
+               } else {
+                       prev = cur;
+               }
+       }
+       return res;
+}
+
 /*! \brief Check if realtime engine is configured for family */
 int ast_check_realtime(const char *family)
 {
@@ -1344,6 +1372,12 @@ int ast_check_realtime(const char *family)
 
 }
 
+/*! \brief Check if there's any realtime engines loaded */
+int ast_realtime_enabled()
+{
+       return config_maps ? 1 : 0;
+}
+
 struct ast_config *ast_load_realtime_multientry(const char *family, ...)
 {
        struct ast_config_engine *eng;
@@ -1378,6 +1412,38 @@ int ast_update_realtime(const char *family, const char *keyfield, const char *lo
        return res;
 }
 
+int ast_store_realtime(const char *family, ...) {
+       struct ast_config_engine *eng;
+       int res = -1;
+       char db[256]="";
+       char table[256]="";
+       va_list ap;
+
+       va_start(ap, family);
+       eng = find_engine(family, db, sizeof(db), table, sizeof(table));
+       if (eng && eng->store_func) 
+               res = eng->store_func(db, table, ap);
+       va_end(ap);
+
+       return res;
+}
+
+int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...) {
+       struct ast_config_engine *eng;
+       int res = -1;
+       char db[256]="";
+       char table[256]="";
+       va_list ap;
+
+       va_start(ap, lookup);
+       eng = find_engine(family, db, sizeof(db), table, sizeof(table));
+       if (eng && eng->destroy_func) 
+               res = eng->destroy_func(db, table, keyfield, lookup, ap);
+       va_end(ap);
+
+       return res;
+}
+
 static int config_command(int fd, int argc, char **argv) 
 {
        struct ast_config_engine *eng;