(closes issue #6002)
authorSteve Murphy <murf@digium.com>
Fri, 7 Mar 2008 18:57:57 +0000 (18:57 +0000)
committerSteve Murphy <murf@digium.com>
Fri, 7 Mar 2008 18:57:57 +0000 (18:57 +0000)
Reported by: rizzo
Tested by: murf

Proposal of the changes to be made, and then an announcement of how they were accomplished:

http://lists.digium.com/pipermail/asterisk-dev/2008-February/032065.html

and:

http://lists.digium.com/pipermail/asterisk-dev/2008-March/032124.html

Here is a recap, file by file, of what I have done:

pbx/pbx_config.c
pbx/pbx_ael.c

All funcs that were passed a ptr to the context list, now will ALSO be passed a hashtab ptr to the same set.
Why? because (for the time being), the dialplan is stored in both, to facilitate a quick, low-cost move to
hash-tables to speed up dialplan processing. If it was deemed necessary to pass the context LIST, well, it
is just as necessary to have the TABLE available. This is because the list/table in question might not be
the global one, but temporary ones we would use to stage the dialplan on, and then swap into the global
position when things are ready.

We now have one external function for apps to use, "ast_context_find_or_create()" instead of the pre-existing
"find" and "create", as all existing usages used both in tandem anyway.

pbx_config, and pbx_ael, will stage the reloaded dialplan into local lists and tables, and
then call merge_contexts_and_delete, which will merge (now) existing contexts and
priorities from other registrars into this local set by copying them. Then, merge_contexts_and_delete will
lock down the contexts, swap the lists and tables, and unlock (real quick), and then
destroy the old dialplan.

chan_sip.c
chan_iax.c
chan_skinny.c

All the channel drivers that would add regcontexts now use the ast_context_find_or_create now.

chan_sip also includes a small fix to get rid of warnings about removing priorities that never got entered.

apps/app_meetme.c
apps/app_dial.c
apps/app_queue.c

All the apps that added a context/exten/priority were also modified to use ast_context_find_or_create instead.

include/asterisk/pbx.h

ast_context_create() is removed. Find_or_create_ is the new method.
ast_context_find_or_create()  interface gets the hashtab added.
ast_merge_contexts_and_delete() gets the local hashtab arg added.
ast_wrlock_contexts_version() is added so you can detect if someone else got a writelock between your readlocking and writelocking.
ast_hashtab_compare_contexts was made public for use in pbx_config/pbx_ael
ast_hashtab_hash_contexts was in like fashion make public.

include/asterisk/pval.h

ast_compile_ael2() interface changed to include the local hashtab table ptr.

main/features.c

For the sake of the parking context, we use ast_context_find_or_create().

main/pbx.c

I changed all the "tree" names to "table" instead. That's because the original
implementation was based on binary trees. (had a free library). Then I moved
to hashtabs. Now, the names move forward too.

refcount field added to contexts, so you can keep track of how many modules
wanted this context to exist.

Some log messages that are warnings were inflated from LOG_NOTICE to LOG_WARNING.

Added some calls to ast_verb(3,...) for debug messages

Lots of little mods to ast_context_remove_extension2, which is now excersized in ways
it was not previously; one definite bug fixed.

find_or_create was upgraded to handle both local lists/tables as well as the globals.

context_merge() was added to do the per-context merging of the old/present contexts/extens/prios into the new/proposed local list/tables

ast_merge_contexts_and_delete() was heavily modified.

ast_add_extension2() was also upgraded to handle changes.

the context_destroy() code was re-engineered to handle the new way of doing things,
by exten/prio instead of by context.

res/ael/pval.c
res/ael/ael.tab.c
res/ael/ael.tab.h
res/ael/ael.y
res/ael/ael_lex.c
res/ael/ael.flex
utils/ael_main.c
utils/extconf.c
utils/conf2ael.c
utils/Makefile

Had to change the interface to ast_compile_ael2(), to include the hashtab ptr.
This ended up involving several external apps.  The main gotcha was I had to
include lock.h and hashtab.h in several places.

As a side note, I tested this stuff pretty thoroughly, I replicated the problems
originally reported by Luigi, and made triply sure that reloads worked, and everything
worked thru "stop gracefully". I found a and fixed a few bugs as I was merging into
trunk, that did not appear in my tests of bug6002.

How's this for verbose commit messages?

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@106757 65c4cc65-6c06-0410-ace0-fbb531ad65f3

22 files changed:
apps/app_dial.c
apps/app_meetme.c
apps/app_queue.c
channels/chan_iax2.c
channels/chan_sip.c
channels/chan_skinny.c
include/asterisk/pbx.h
include/asterisk/pval.h
main/features.c
main/pbx.c
pbx/pbx_ael.c
pbx/pbx_config.c
res/ael/ael.flex
res/ael/ael.tab.c
res/ael/ael.tab.h
res/ael/ael.y
res/ael/ael_lex.c
res/ael/pval.c
utils/Makefile
utils/ael_main.c
utils/conf2ael.c
utils/extconf.c

index b52a97b..dfd6f83 100644 (file)
@@ -2096,9 +2096,7 @@ static int load_module(void)
        int res;
        struct ast_context *con;
 
-       con = ast_context_find("app_dial_gosub_virtual_context");
-       if (!con)
-               con = ast_context_create(NULL, "app_dial_gosub_virtual_context", "app_dial");
+       con = ast_context_find_or_create(NULL, NULL, "app_dial_gosub_virtual_context", "app_dial");
        if (!con)
                ast_log(LOG_ERROR, "Dial virtual context 'app_dial_gosub_virtual_context' does not exist and unable to create\n");
        else
index 471477a..b7a72ae 100644 (file)
@@ -5280,7 +5280,7 @@ static int sla_build_trunk(struct ast_config *cfg, const char *cat)
 
        if (!ast_strlen_zero(trunk->autocontext)) {
                struct ast_context *context;
-               context = ast_context_find_or_create(NULL, trunk->autocontext, sla_registrar);
+               context = ast_context_find_or_create(NULL, NULL, trunk->autocontext, sla_registrar);
                if (!context) {
                        ast_log(LOG_ERROR, "Failed to automatically find or create "
                                "context '%s' for SLA!\n", trunk->autocontext);
@@ -5417,7 +5417,7 @@ static int sla_build_station(struct ast_config *cfg, const char *cat)
        if (!ast_strlen_zero(station->autocontext)) {
                struct ast_context *context;
                struct sla_trunk_ref *trunk_ref;
-               context = ast_context_find_or_create(NULL, station->autocontext, sla_registrar);
+               context = ast_context_find_or_create(NULL, NULL, station->autocontext, sla_registrar);
                if (!context) {
                        ast_log(LOG_ERROR, "Failed to automatically find or create "
                                "context '%s' for SLA!\n", station->autocontext);
index 5ab932c..bd2487d 100644 (file)
@@ -6147,9 +6147,7 @@ static int load_module(void)
        if (!reload_queues(0))
                return AST_MODULE_LOAD_DECLINE;
 
-       con = ast_context_find("app_queue_gosub_virtual_context");
-       if (!con)
-               con = ast_context_create(NULL, "app_queue_gosub_virtual_context", "app_queue");
+       con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
        if (!con)
                ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n");
        else
index 1df3cf3..d19adbe 100644 (file)
@@ -10771,8 +10771,7 @@ static int set_config(char *config_file, int reload)
                } else if (!strcasecmp(v->name, "regcontext")) {
                        ast_copy_string(regcontext, v->value, sizeof(regcontext));
                        /* Create context if it doesn't exist already */
-                       if (!ast_context_find(regcontext))
-                               ast_context_create(NULL, regcontext, "IAX2");
+                       ast_context_find_or_create(NULL, NULL, regcontext, "IAX2");
                } else if (!strcasecmp(v->name, "tos")) {
                        if (ast_str2tos(v->value, &tos))
                                ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
index 4064521..a4afae1 100644 (file)
@@ -3388,6 +3388,7 @@ static void register_peer_exten(struct sip_peer *peer, int onoff)
 {
        char multi[256];
        char *stringp, *ext, *context;
+       struct pbx_find_info q = { .stacklen = 0 };
 
        /* XXX note that global_regcontext is both a global 'enable' flag and
         * the name of the global regexten context, if not specified
@@ -3408,11 +3409,12 @@ static void register_peer_exten(struct sip_peer *peer, int onoff)
                } else {
                        context = global_regcontext;
                }
-               if (onoff)
+               if (onoff) {
                        ast_add_extension(context, 1, ext, 1, NULL, NULL, "Noop",
                                 ast_strdup(peer->name), ast_free_ptr, "SIP");
-               else
+               } else if (pbx_find_extension(NULL, NULL, &q, context, ext, 1, NULL, "", E_MATCH)) {
                        ast_context_remove_extension(context, ext, 1, NULL);
+               }
        }
 }
 
@@ -20297,8 +20299,7 @@ static int reload_config(enum channelreloadreason reason)
                        /* Create contexts if they don't exist already */
                        while ((context = strsep(&stringp, "&"))) {
                                ast_copy_string(used_context, context, sizeof(used_context));
-                               if (!ast_context_find(context))
-                                       ast_context_create(NULL, context, "SIP");
+                               ast_context_find_or_create(NULL, NULL, context, "SIP");
                        }
                        ast_copy_string(global_regcontext, v->value, sizeof(global_regcontext));
                } else if (!strcasecmp(v->name, "regextenonqualify")) {
index 44d88ae..4baa577 100644 (file)
@@ -5801,8 +5801,7 @@ static int reload_config(void)
                        /* Create contexts if they don't exist already */
                        while ((context = strsep(&stringp, "&"))) {
                                ast_copy_string(used_context, context, sizeof(used_context));
-                               if (!ast_context_find(context))
-                                       ast_context_create(NULL, context, "Skinny");
+                               ast_context_find_or_create(NULL, NULL, context, "Skinny");
                        }
                        ast_copy_string(regcontext, v->value, sizeof(regcontext));
                } else if (!strcasecmp(v->name, "dateformat")) {
index 1ba9b0d..14e7af4 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "asterisk/sched.h"
 #include "asterisk/chanvars.h"
+#include "asterisk/hashtab.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
@@ -167,45 +168,36 @@ struct ast_app *pbx_findapp(const char *app);
 int pbx_exec(struct ast_channel *c, struct ast_app *app, void *data);
 
 /*!
- * \brief Register a new context
- *
- * \param extcontexts pointer to the ast_context structure pointer
- * \param name name of the new context
- * \param registrar registrar of the context
- *
- * This will first search for a context with your name.  If it exists already, it will not
- * create a new one.  If it does not exist, it will create a new one with the given name
- * and registrar.
- *
- * \return NULL on failure, and an ast_context structure on success
- */
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar);
-
-/*!
  * \brief Register a new context or find an existing one
  *
  * \param extcontexts pointer to the ast_context structure pointer
+ * \param exttable pointer to the hashtable that contains all the elements in extcontexts
  * \param name name of the new context
  * \param registrar registrar of the context
  *
+ * This function allows you to play in two environments: the global contexts (active dialplan)
+ * or an external context set of your choosing. To act on the external set, make sure extcontexts
+ * and exttable are set; for the globals, make sure both extcontexts and exttable are NULL.
+ *
  * This will first search for a context with your name.  If it exists already, it will not
  * create a new one.  If it does not exist, it will create a new one with the given name
  * and registrar.
  *
  * \return NULL on failure, and an ast_context structure on success
  */
-struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar);
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar);
 
 /*!
  * \brief Merge the temporary contexts into a global contexts list and delete from the 
  *        global list the ones that are being added
  *
- * \param extcontexts pointer to the ast_context structure pointer
+ * \param extcontexts pointer to the ast_context structure
+ * \param exttable pointer to the ast_hashtab structure that contains all the elements in extcontexts
  * \param registrar of the context; if it's set the routine will delete all contexts 
  *        that belong to that registrar; if NULL only the contexts that are specified 
  *        in extcontexts
  */
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar);
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar);
 
 /*!
  * \brief Destroy a context (matches the specified context (or ANY context if NULL)
@@ -973,8 +965,18 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
                                                                         struct ast_context *bypass, struct pbx_find_info *q,
                                                                         const char *context, const char *exten, int priority,
                                                                         const char *label, const char *callerid, enum ext_match_t action);
+
+
+/* every time a write lock is obtained for contexts,
+   a counter is incremented. You can check this via the
+   following func */
+
+int ast_wrlock_contexts_version(void);
        
 
+/* hashtable functions for contexts */
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+unsigned int ast_hashtab_hash_contexts(const void *obj);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
index edfd647..ea545e4 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASTERISK_PVAL_H
 #define _ASTERISK_PVAL_H
 
+/* whatever includes this, better include asterisk/lock.h and asterisk/hashtab.h */
 
 typedef enum 
 {
@@ -143,7 +144,7 @@ void destroy_extensions(struct ael_extension *exten);
    static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *context ); */
 void set_priorities(struct ael_extension *exten);
 void add_extensions(struct ael_extension *exten);
-void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root);
+void ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
 void destroy_pval(pval *item);
 void destroy_pval_item(pval *item);
 int is_float(char *arg );
index d26ac5b..2a284cb 100644 (file)
@@ -488,9 +488,7 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
                ast_adsi_unload_session(peer);
        }
 
-       con = ast_context_find(parking_con);
-       if (!con) 
-               con = ast_context_create(NULL, parking_con, registrar);
+       con = ast_context_find_or_create(NULL, NULL, parking_con, registrar);
        if (!con)       /* Still no context? Bad */
                ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
        /* Tell the peer channel the number of the parking space */
@@ -2228,12 +2226,9 @@ static void *do_parking_thread(void *ignore)
                                                if (peername_flat[i] == '/') 
                                                        peername_flat[i]= '0';
                                        }
-                                       con = ast_context_find(parking_con_dial);
-                                       if (!con) {
-                                               con = ast_context_create(NULL, parking_con_dial, registrar);
-                                               if (!con)
-                                                       ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
-                                       }
+                                       con = ast_context_find_or_create(NULL, NULL, parking_con_dial, registrar);
+                                       if (!con)
+                                               ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
                                        if (con) {
                                                char returnexten[AST_MAX_EXTENSION];
                                                struct ast_datastore *features_datastore;
@@ -2822,7 +2817,7 @@ static int load_config(void)
                ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
        }
        
-       if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
+       if (!(con = ast_context_find_or_create(NULL, NULL, parking_con, registrar))) {
                ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
                return -1;
        }
index 8d9658f..427c0cc 100644 (file)
@@ -48,6 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/cdr.h"
 #include "asterisk/config.h"
 #include "asterisk/term.h"
+#include "asterisk/time.h"
 #include "asterisk/manager.h"
 #include "asterisk/ast_expr.h"
 #include "asterisk/linkedlists.h"
@@ -140,8 +141,8 @@ struct ast_exten {
        void *data;                     /*!< Data to use (arguments) */
        void (*datad)(void *);          /*!< Data destructor */
        struct ast_exten *peer;         /*!< Next higher priority with our extension */
-       struct ast_hashtab *peer_tree;    /*!< Priorities list in tree form -- only on the head of the peer list */
-       struct ast_hashtab *peer_label_tree; /*!< labeled priorities in the peer list -- only on the head of the peer list */
+       struct ast_hashtab *peer_table;    /*!< Priorities list in hashtab form -- only on the head of the peer list */
+       struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */
        const char *registrar;          /*!< Registrar */
        struct ast_exten *next;         /*!< Extension with a greater ID */
        char stuff[0];
@@ -203,12 +204,13 @@ struct scoreboard  /* make sure all fields are 0 before calling new_find_extensi
 struct ast_context {
        ast_rwlock_t lock;                      /*!< A lock to prevent multiple threads from clobbering the context */
        struct ast_exten *root;                 /*!< The root of the list of extensions */
-       struct ast_hashtab *root_tree;            /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree  */
+       struct ast_hashtab *root_table;            /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree  */
        struct match_char *pattern_tree;        /*!< A tree to speed up extension pattern matching */
        struct ast_context *next;               /*!< Link them together */
        struct ast_include *includes;           /*!< Include other contexts */
        struct ast_ignorepat *ignorepats;       /*!< Patterns for which to continue playing dialtone */
        const char *registrar;                  /*!< Registrar */
+       int refcount;                   /*!< each module that would have created this context should inc/dec this as appropriate */
        AST_LIST_HEAD_NOLOCK(, ast_sw) alts;    /*!< Alternative switches */
        ast_mutex_t macrolock;                  /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
        char name[0];                           /*!< Name of the context */
@@ -327,17 +329,18 @@ static struct match_char *add_pattern_node(struct ast_context *con, struct match
 static void create_match_char_tree(struct ast_context *con);
 static struct ast_exten *get_canmatch_exten(struct match_char *node);
 static void destroy_pattern_tree(struct match_char *pattern_tree);
-static int hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
 static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
-static unsigned int hashtab_hash_contexts(const void *obj);
+unsigned int ast_hashtab_hash_contexts(const void *obj);
 static unsigned int hashtab_hash_extens(const void *obj);
 static unsigned int hashtab_hash_priority(const void *obj);
 static unsigned int hashtab_hash_labels(const void *obj);
+static void __ast_internal_context_destroy( struct ast_context *con);
 
 /* labels, contexts are case sensitive  priority numbers are ints */
-static int hashtab_compare_contexts(const void *ah_a, const void *ah_b)
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
 {
        const struct ast_context *ac = ah_a;
        const struct ast_context *bc = ah_b;
@@ -376,7 +379,7 @@ static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
        return strcmp(ac->label, bc->label);
 }
 
-static unsigned int hashtab_hash_contexts(const void *obj)
+unsigned int ast_hashtab_hash_contexts(const void *obj)
 {
        const struct ast_context *ac = obj;
        return ast_hashtab_hash_string(ac->name);
@@ -684,7 +687,7 @@ static struct pbx_builtin {
 };
 
 static struct ast_context *contexts;
-static struct ast_hashtab *contexts_tree = NULL;
+static struct ast_hashtab *contexts_table = NULL;
 
 AST_RWLOCK_DEFINE_STATIC(conlock);             /*!< Lock for the ast_context list */
 
@@ -1252,11 +1255,11 @@ static void create_match_char_tree(struct ast_context *con)
        int biggest_bucket, resizes, numobjs, numbucks;
        
        ast_log(LOG_DEBUG,"Creating Extension Trie for context %s\n", con->name);
-       ast_hashtab_get_stats(con->root_tree, &biggest_bucket, &resizes, &numobjs, &numbucks);
+       ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
        ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
                        numobjs, numbucks, biggest_bucket, resizes);
 #endif
-       t1 = ast_hashtab_start_traversal(con->root_tree);
+       t1 = ast_hashtab_start_traversal(con->root_table);
        while( (e1 = ast_hashtab_next(t1)) ) {
                if (e1->exten)
                        add_exten_to_pattern_tree(con, e1, 0);
@@ -1582,12 +1585,13 @@ struct fake_context /* this struct is purely for matching in the hashtab */
 {
        ast_rwlock_t lock;                      
        struct ast_exten *root;         
-       struct ast_hashtab *root_tree;            
+       struct ast_hashtab *root_table;            
        struct match_char *pattern_tree;       
        struct ast_context *next;       
        struct ast_include *includes;           
        struct ast_ignorepat *ignorepats;       
-       const char *registrar;  
+       const char *registrar;
+       int refcount;
        AST_LIST_HEAD_NOLOCK(, ast_sw) alts;    
        ast_mutex_t macrolock;          
        char name[256];         
@@ -1599,8 +1603,8 @@ struct ast_context *ast_context_find(const char *name)
        struct fake_context item;
        strncpy(item.name,name,256);
        ast_rdlock_contexts();
-       if( contexts_tree ) {
-               tmp = ast_hashtab_lookup(contexts_tree,&item);
+       if( contexts_table ) {
+               tmp = ast_hashtab_lookup(contexts_table,&item);
        } else {
                while ( (tmp = ast_walk_contexts(tmp)) ) {
                        if (!name || !strcasecmp(name, tmp->name))
@@ -1668,7 +1672,7 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
        else {  /* look in contexts */
                struct fake_context item;
                strncpy(item.name,context,256);
-               tmp = ast_hashtab_lookup(contexts_tree,&item);
+               tmp = ast_hashtab_lookup(contexts_table,&item);
 #ifdef NOTNOW
                tmp = NULL;
                while ((tmp = ast_walk_contexts(tmp)) ) {
@@ -1690,7 +1694,7 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
        score.total_specificity = 0;
        score.exten = 0;
        score.total_length = 0;
-       if (!tmp->pattern_tree && tmp->root_tree)
+       if (!tmp->pattern_tree && tmp->root_table)
        {
                create_match_char_tree(tmp);
 #ifdef NEED_DEBUG
@@ -1750,9 +1754,9 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
                        if (action == E_FINDLABEL && label ) {
                                if (q->status < STATUS_NO_LABEL)
                                        q->status = STATUS_NO_LABEL;
-                               e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
+                               e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
                        } else {
-                               e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+                               e = ast_hashtab_lookup(eroot->peer_table, &pattern);
                        }
                        if (e) {        /* found a valid match */
                                q->status = STATUS_SUCCESS;
@@ -1786,9 +1790,9 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
                        if (action == E_FINDLABEL && label ) {
                                if (q->status < STATUS_NO_LABEL)
                                        q->status = STATUS_NO_LABEL;
-                               e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
+                               e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
                        } else {
-                               e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+                               e = ast_hashtab_lookup(eroot->peer_table, &pattern);
                        }
 #ifdef NOTNOW
                        while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
@@ -2465,7 +2469,7 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
                                vare++;
                        }
                        if (brackets)
-                               ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
+                               ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
                        len = vare - vars - 1;
 
                        /* Skip totally over variable string */
@@ -2552,7 +2556,7 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
                                vare++;
                        }
                        if (brackets)
-                               ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
+                               ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
                        len = vare - vars - 1;
 
                        /* Skip totally over expression */
@@ -3479,14 +3483,14 @@ static int increase_call_count(const struct ast_channel *c)
        ast_mutex_lock(&maxcalllock);
        if (option_maxcalls) {
                if (countcalls >= option_maxcalls) {
-                       ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
+                       ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
                        failed = -1;
                }
        }
        if (option_maxload) {
                getloadavg(&curloadavg, 1);
                if (curloadavg >= option_maxload) {
-                       ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
+                       ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
                        failed = -1;
                }
        }
@@ -3527,10 +3531,10 @@ static void destroy_exten(struct ast_exten *e)
        if (e->priority == PRIORITY_HINT)
                ast_remove_hint(e);
 
-       if (e->peer_tree)
-               ast_hashtab_destroy(e->peer_tree,0);
-       if (e->peer_label_tree)
-               ast_hashtab_destroy(e->peer_label_tree, 0);
+       if (e->peer_table)
+               ast_hashtab_destroy(e->peer_table,0);
+       if (e->peer_label_table)
+               ast_hashtab_destroy(e->peer_label_table, 0);
        if (e->datad)
                e->datad(e->data);
        ast_free(e);
@@ -3627,8 +3631,7 @@ static struct ast_context *find_context_locked(const char *context)
        ast_copy_string(item.name, context, sizeof(item.name));
 
        ast_rdlock_contexts();
-
-       c = ast_hashtab_lookup(contexts_tree,&item);
+       c = ast_hashtab_lookup(contexts_table,&item);
 
 #ifdef NOTNOW
 
@@ -3789,19 +3792,19 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
        /* Handle this is in the new world */
 
 #ifdef NEED_DEBUG
-       ast_log(LOG_NOTICE,"Removing %s/%s/%d from trees, registrar=%s\n", con->name, extension, priority, registrar);
+       ast_verb(3,"Removing %s/%s/%d from trees, registrar=%s\n", con->name, extension, priority, registrar);
 #endif
        /* find this particular extension */
        ex.exten = dummy_name;
        ex.matchcid = 0;
        ast_copy_string(dummy_name,extension, sizeof(dummy_name));
-       exten = ast_hashtab_lookup(con->root_tree, &ex);
+       exten = ast_hashtab_lookup(con->root_table, &ex);
        if (exten) {
                if (priority == 0)
                {
-                       exten2 = ast_hashtab_remove_this_object(con->root_tree, exten);
+                       exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
                        if (!exten2)
-                               ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_tree\n", extension, con->name);
+                               ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_table\n", extension, con->name);
                        if (con->pattern_tree) {
                                
                                struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
@@ -3815,24 +3818,28 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
                        }
                } else {
                        ex.priority = priority;
-                       exten2 = ast_hashtab_lookup(exten->peer_tree, &ex);
+                       exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
                        if (exten2) {
                                
                                if (exten2->label) { /* if this exten has a label, remove that, too */
-                                       exten3 = ast_hashtab_remove_this_object(exten->peer_label_tree,exten2);
+                                       exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
                                        if (!exten3)
-                                               ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_tree of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
+                                               ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
                                }
                                
-                               exten3 = ast_hashtab_remove_this_object(exten->peer_tree, exten2);
+                               exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
                                if (!exten3)
-                                       ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_tree of context %s, extension %s!\n", priority, con->name, exten2->exten);
-                               if (ast_hashtab_size(exten->peer_tree) == 0) {
+                                       ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten);
+                               if (exten2 == exten && exten2->peer) {
+                                       exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
+                                       ast_hashtab_insert_immediate(con->root_table, exten2->peer);
+                               }
+                               if (ast_hashtab_size(exten->peer_table) == 0) {
                                        /* well, if the last priority of an exten is to be removed,
                                           then, the extension is removed, too! */
-                                       exten3 = ast_hashtab_remove_this_object(con->root_tree, exten);
+                                       exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
                                        if (!exten3)
-                                               ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_tree (%s) (priority %d)\n", exten->exten, con->name, priority);
+                                               ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
                                        if (con->pattern_tree) {
                                                struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
                                                if (x->exten) { /* this test for safety purposes */
@@ -3848,7 +3855,7 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
                }
        } else {
                /* hmmm? this exten is not in this pattern tree? */
-               ast_log(LOG_WARNING,"Cannot find extension %s in root_tree in context %s\n",
+               ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
                                extension, con->name);
        }
 #ifdef NEED_DEBUG
@@ -3905,10 +3912,10 @@ int ast_context_remove_extension2(struct ast_context *con, const char *extension
                         */
                        struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
                        if (next_node && next_node == peer->peer) {
-                               next_node->peer_tree = exten->peer_tree; /* move the priority hash tabs over */
-                               exten->peer_tree = 0;
-                               next_node->peer_label_tree = exten->peer_label_tree;
-                               exten->peer_label_tree = 0;
+                               next_node->peer_table = exten->peer_table; /* move the priority hash tabs over */
+                               exten->peer_table = 0;
+                               next_node->peer_label_table = exten->peer_label_table;
+                               exten->peer_label_table = 0;
                        }
                        if (!prev_exten) {      /* change the root... */
                                con->root = next_node;
@@ -3946,7 +3953,7 @@ int ast_context_lockmacro(const char *context)
        ast_rdlock_contexts();
 
        strncpy(item.name,context,256);
-       c = ast_hashtab_lookup(contexts_tree,&item);
+       c = ast_hashtab_lookup(contexts_table,&item);
        if (c)
                ret = 0;
 
@@ -3984,7 +3991,7 @@ int ast_context_unlockmacro(const char *context)
        ast_rdlock_contexts();
 
        strncpy(item.name, context, 256);
-       c = ast_hashtab_lookup(contexts_tree,&item);
+       c = ast_hashtab_lookup(contexts_table,&item);
        if (c)
                ret = 0;
 #ifdef NOTNOW
@@ -4578,7 +4585,7 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
                        if (exten) {
                                /* Check all includes for the requested extension */
                                if (includecount >= AST_PBX_MAX_STACK) {
-                                       ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
+                                       ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
                                } else {
                                        int dupe = 0;
                                        int x;
@@ -5127,42 +5134,37 @@ int ast_unregister_application(const char *app)
        return tmp ? 0 : -1;
 }
 
-static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
 {
        struct ast_context *tmp, **local_contexts;
        struct fake_context search;
        int length = sizeof(struct ast_context) + strlen(name) + 1;
 
-       if (!contexts_tree) {
-               contexts_tree = ast_hashtab_create(17,
-                                                                                  hashtab_compare_contexts, 
+       if (!contexts_table) {
+               contexts_table = ast_hashtab_create(17,
+                                                                                  ast_hashtab_compare_contexts, 
                                                                                   ast_hashtab_resize_java,
                                                                                   ast_hashtab_newsize_java,
-                                                                                  hashtab_hash_contexts,
+                                                                                  ast_hashtab_hash_contexts,
                                                                                   0);
        }
        
+       strncpy(search.name,name,sizeof(search.name));
        if (!extcontexts) {
                ast_rdlock_contexts();
                local_contexts = &contexts;
-               strncpy(search.name,name,sizeof(search.name));
-               tmp = ast_hashtab_lookup(contexts_tree, &search);
-               if (!existsokay && tmp) {
-                       ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
-               }
+               tmp = ast_hashtab_lookup(contexts_table, &search);
                ast_unlock_contexts();
-               if (tmp)
+               if (tmp) {
+                       tmp->refcount++;
                        return tmp;
+               }
        } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
                local_contexts = extcontexts;
-               for (tmp = *local_contexts; tmp; tmp = tmp->next) {
-                       if (!strcasecmp(tmp->name, name)) {
-                               if (!existsokay) {
-                                       ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
-                                       tmp = NULL;
-                               }
-                               return tmp;
-                       }
+               tmp = ast_hashtab_lookup(exttable, &search);
+               if (tmp) {
+                       tmp->refcount++;
+                       return tmp;
                }
        }
        
@@ -5171,19 +5173,26 @@ static struct ast_context *__ast_context_create(struct ast_context **extcontexts
                ast_mutex_init(&tmp->macrolock);
                strcpy(tmp->name, name);
                tmp->root = NULL;
-               tmp->root_tree = NULL;
+               tmp->root_table = NULL;
                tmp->registrar = registrar;
                tmp->includes = NULL;
                tmp->ignorepats = NULL;
+               tmp->refcount = 1;
+       } else {
+               ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
+               return NULL;
        }
+       
        if (!extcontexts) {
                ast_wrlock_contexts();
                tmp->next = *local_contexts;
                *local_contexts = tmp;
-               ast_hashtab_insert_safe(contexts_tree, tmp); /*put this context into the tree */
+               ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
                ast_unlock_contexts();
        } else {
                tmp->next = *local_contexts;
+               if (exttable)
+                       ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
                *local_contexts = tmp;
        }
        ast_debug(1, "Registered context '%s'\n", tmp->name);
@@ -5191,16 +5200,7 @@ static struct ast_context *__ast_context_create(struct ast_context **extcontexts
        return tmp;
 }
 
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
-{
-       return __ast_context_create(extcontexts, name, registrar, 0);
-}
-
-struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
-{
-       return __ast_context_create(extcontexts, name, registrar, 1);
-}
-void __ast_context_destroy(struct ast_context *con, const char *registrar);
+void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
 
 struct store_hint {
        char *context;
@@ -5213,17 +5213,89 @@ struct store_hint {
 
 AST_LIST_HEAD(store_hints, store_hint);
 
+/* the purpose of this routine is to duplicate a context, with all its substructure,
+   except for any extens that have a matching registrar */
+static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
+{
+       struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
+       struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
+       struct ast_hashtab_iter *exten_iter;
+       struct ast_hashtab_iter *prio_iter;
+       int insert_count = 0;
+       
+       /* We'll traverse all the extensions/prios, and see which are not registrar'd with
+          the current registrar, and copy them to the new context. If the new context does not
+          exist, we'll create it "on demand". If no items are in this context to copy, then we'll
+          only create the empty matching context if the old one meets the criteria */
+       if (context->root_table) {
+               exten_iter = ast_hashtab_start_traversal(context->root_table);
+               while ((exten_item=ast_hashtab_next(exten_iter))) {
+                       if (new) {
+                               new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
+                       } else {
+                               new_exten_item = NULL;
+                       }
+                       prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
+                       while ((prio_item=ast_hashtab_next(prio_iter))) {
+                               int res1;
+                               
+                               if (new_exten_item) {
+                                       new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
+                               } else {
+                                       new_prio_item = NULL;
+                               }
+                               if (strcmp(prio_item->registrar,registrar) == 0) {
+                                       continue;
+                               }
+                               /* make sure the new context exists, so we have somewhere to stick this exten/prio */
+                               if (!new) {
+                                       new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar); /* a new context created via priority from a different context in the old dialplan, gets its registrar from the prio's registrar */
+                               }
+                               if (!new) {
+                                       ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
+                                       return; /* no sense continuing. */
+                               }
+                               /* we will not replace existing entries in the new context with stuff from the old context.
+                                  but, if this is because of some sort of registrar conflict, we ought to say something... */
+                               res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label, 
+                                                                                 prio_item->cidmatch, prio_item->app, prio_item->data, prio_item->datad, prio_item->registrar);
+                               if (!res1 && new_exten_item && new_prio_item){
+                                       ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
+                                                       context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
+                               } else {
+                                       prio_item->data = NULL; /* we pass the priority data from the old to the new */
+                                       insert_count++;
+                               }
+                       }
+                       ast_hashtab_end_traversal(prio_iter);
+               }
+               ast_hashtab_end_traversal(exten_iter);
+       }
+       
+       if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
+                 (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
+               
+               /* we could have given it the registrar of the other module who incremented the refcount,
+                  but that's not available, so we give it the registrar we know about */
+               new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
+       }
+}
+
+
 /* XXX this does not check that multiple contexts are merged */
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
 {
-       struct ast_context *tmp, *lasttmp = NULL;
+       double ft;
+       struct ast_context *tmp, *oldcontextslist;
+       struct ast_hashtab *oldtable;
        struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
        struct store_hint *this;
        struct ast_hint *hint;
        struct ast_exten *exten;
        int length;
        struct ast_state_cb *thiscb, *prevcb;
-
+       struct ast_hashtab_iter *iter;
+       
        /* it is very important that this function hold the hint list lock _and_ the conlock
           during its operation; not only do we need to ensure that the list of contexts
           and extensions does not change, but also that no hint callbacks (watchers) are
@@ -5232,8 +5304,29 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
           in addition, the locks _must_ be taken in this order, because there are already
           other code paths that use this order
        */
+       
+       struct timeval begintime, writelocktime, endlocktime, enddeltime;
+       int wrlock_ver;
+       
+       begintime = ast_tvnow();
+       ast_rdlock_contexts();
+       iter = ast_hashtab_start_traversal(contexts_table);
+       while ((tmp=ast_hashtab_next(iter))) {
+               context_merge(extcontexts, exttable, tmp, registrar);
+       }
+       ast_hashtab_end_traversal(iter);
+       wrlock_ver = ast_wrlock_contexts_version();
+
+       ast_unlock_contexts(); /* this feels real retarded, but you must do
+                                                         what you must do If this isn't done, the following 
+                                                     wrlock is a guraranteed deadlock */
        ast_wrlock_contexts();
+       if (ast_wrlock_contexts_version() > wrlock_ver+1) {
+               ast_log(LOG_WARNING,"Something changed the contexts in the middle of merging contexts!\n");
+       }
+       
        AST_RWLIST_WRLOCK(&hints);
+       writelocktime = ast_tvnow();
 
        /* preserve all watchers for hints associated with this registrar */
        AST_RWLIST_TRAVERSE(&hints, hint, list) {
@@ -5252,36 +5345,14 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
                }
        }
 
-       tmp = *extcontexts;
-       if (registrar) {
-               /* XXX remove previous contexts from same registrar */
-               ast_debug(1, "must remove any reg %s\n", registrar);
-               __ast_context_destroy(NULL,registrar);
-               while (tmp) {
-                       lasttmp = tmp;
-                       tmp = tmp->next;
-               }
-       } else {
-               /* XXX remove contexts with the same name */
-               while (tmp) {
-                       ast_log(LOG_WARNING, "must remove %s  reg %s\n", tmp->name, tmp->registrar);
-                       __ast_context_destroy(tmp,tmp->registrar);
-                       lasttmp = tmp;
-                       tmp = tmp->next;
-               }
-       }
-       tmp = *extcontexts;
-       while (tmp) {
-               ast_hashtab_insert_safe(contexts_tree, tmp); /*put this context into the tree */
-               tmp = tmp->next;
-       }
-       if (lasttmp) {
-               lasttmp->next = contexts;
-               contexts = *extcontexts;
-               *extcontexts = NULL;
-       } else
-               ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
+       /* save the old table and list */
+       oldtable = contexts_table;
+       oldcontextslist = contexts;
 
+       /* move in the new table and list */
+       contexts_table = exttable;
+       contexts = *extcontexts;
+       
        /* restore the watchers for hints that can be found; notify those that
           cannot be restored
        */
@@ -5316,7 +5387,36 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
 
        AST_RWLIST_UNLOCK(&hints);
        ast_unlock_contexts();
+       endlocktime = ast_tvnow();
+       
+       /* the old list and hashtab no longer are relevant, delete them while the rest of asterisk
+          is now freely using the new stuff instead */
+       
+       ast_hashtab_destroy(oldtable, NULL);
 
+       for (tmp = oldcontextslist; tmp; ) {
+               struct ast_context *next;       /* next starting point */
+               next = tmp->next;
+               __ast_internal_context_destroy(tmp);
+               tmp = next;
+       }
+       enddeltime = ast_tvnow();
+       
+       ft = ast_tvdiff_us(writelocktime, begintime);
+       ft /= 1000000.0;
+       ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
+       
+       ft = ast_tvdiff_us(endlocktime, writelocktime);
+       ft /= 1000000.0;
+       ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
+
+       ft = ast_tvdiff_us(enddeltime, endlocktime);
+       ft /= 1000000.0;
+       ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
+
+       ft = ast_tvdiff_us(enddeltime, begintime);
+       ft /= 1000000.0;
+       ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
        return;
 }
 
@@ -5854,6 +5954,7 @@ int ast_add_extension(const char *context, int replace, const char *extension,
                        application, data, datad, registrar);
                ast_unlock_contexts();
        }
+       
        return ret;
 }
 
@@ -5980,9 +6081,9 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
                        break;
        }
        if (!e) {       /* go at the end, and ep is surely set because the list is not empty */
-               ast_hashtab_insert_safe(eh->peer_tree, tmp);
+               ast_hashtab_insert_safe(eh->peer_table, tmp);
                if (tmp->label)
-                       ast_hashtab_insert_safe(eh->peer_label_tree, tmp);
+                       ast_hashtab_insert_safe(eh->peer_label_table, tmp);
                ep->peer = tmp;
                return 0;       /* success */
        }
@@ -6002,25 +6103,25 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
                tmp->next = e->next;    /* not meaningful if we are not first in the peer list */
                tmp->peer = e->peer;    /* always meaningful */
                if (ep) {               /* We're in the peer list, just insert ourselves */
-                       ast_hashtab_remove_object_via_lookup(eh->peer_tree,e);
+                       ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
                        if (e->label)
-                               ast_hashtab_remove_object_via_lookup(eh->peer_label_tree,e);
-                       ast_hashtab_insert_safe(eh->peer_tree,tmp);
+                               ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
+                       ast_hashtab_insert_safe(eh->peer_table,tmp);
                        if (tmp->label)
-                               ast_hashtab_insert_safe(eh->peer_label_tree,tmp);
+                               ast_hashtab_insert_safe(eh->peer_label_table,tmp);
                        ep->peer = tmp;
                } else if (el) {                /* We're the first extension. Take over e's functions */
                        struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
-                       tmp->peer_tree = e->peer_tree;
-                       tmp->peer_label_tree = e->peer_label_tree;
-                       ast_hashtab_remove_object_via_lookup(tmp->peer_tree,e);
-                       ast_hashtab_insert_safe(tmp->peer_tree,tmp);
+                       tmp->peer_table = e->peer_table;
+                       tmp->peer_label_table = e->peer_label_table;
+                       ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
+                       ast_hashtab_insert_safe(tmp->peer_table,tmp);
                        if (e->label)
-                               ast_hashtab_remove_object_via_lookup(tmp->peer_label_tree,e);
+                               ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
                        if (tmp->label)
-                               ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
-                       ast_hashtab_remove_object_via_lookup(con->root_tree, e);
-                       ast_hashtab_insert_safe(con->root_tree, tmp);
+                               ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
+                       ast_hashtab_remove_object_via_lookup(con->root_table, e);
+                       ast_hashtab_insert_safe(con->root_table, tmp);
                        el->next = tmp;
                        /* The pattern trie points to this exten; replace the pointer,
                           and all will be well */
@@ -6032,18 +6133,18 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
                        }
                } else {                        /* We're the very first extension.  */
                        struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
-                       ast_hashtab_remove_object_via_lookup(con->root_tree,e);
-                       ast_hashtab_insert_safe(con->root_tree,tmp);
-                       tmp->peer_tree = e->peer_tree;
-                       tmp->peer_label_tree = e->peer_label_tree;
-                       ast_hashtab_remove_object_via_lookup(tmp->peer_tree,e);
-                       ast_hashtab_insert_safe(tmp->peer_tree,tmp);
+                       ast_hashtab_remove_object_via_lookup(con->root_table, e);
+                       ast_hashtab_insert_safe(con->root_table, tmp);
+                       tmp->peer_table = e->peer_table;
+                       tmp->peer_label_table = e->peer_label_table;
+                       ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
+                       ast_hashtab_insert_safe(tmp->peer_table, tmp);
                        if (e->label)
-                               ast_hashtab_remove_object_via_lookup(tmp->peer_label_tree,e);
+                               ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
                        if (tmp->label)
-                       ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
-                       ast_hashtab_remove_object_via_lookup(con->root_tree, e);
-                       ast_hashtab_insert_safe(con->root_tree, tmp);
+                       ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
+                       ast_hashtab_remove_object_via_lookup(con->root_table, e);
+                       ast_hashtab_insert_safe(con->root_table, tmp);
                        con->root = tmp;
                        /* The pattern trie points to this exten; replace the pointer,
                           and all will be well */
@@ -6064,20 +6165,20 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
                tmp->next = e->next;    /* extension chain, or NULL if e is not the first extension */
                if (ep) {                       /* Easy enough, we're just in the peer list */
                        if (tmp->label)
-                               ast_hashtab_insert_safe(eh->peer_label_tree, tmp);
-                       ast_hashtab_insert_safe(eh->peer_tree, tmp);
+                               ast_hashtab_insert_safe(eh->peer_label_table, tmp);
+                       ast_hashtab_insert_safe(eh->peer_table, tmp);
                        ep->peer = tmp;
                } else {                        /* we are the first in some peer list, so link in the ext list */
-                       tmp->peer_tree = e->peer_tree;
-                       tmp->peer_label_tree = e ->peer_label_tree;
-                       e->peer_tree = 0;
-                       e->peer_label_tree = 0;
-                       ast_hashtab_insert_safe(tmp->peer_tree,tmp);
+                       tmp->peer_table = e->peer_table;
+                       tmp->peer_label_table = e->peer_label_table;
+                       e->peer_table = 0;
+                       e->peer_label_table = 0;
+                       ast_hashtab_insert_safe(tmp->peer_table, tmp);
                        if (tmp->label) {
-                               ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
+                               ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
                        }
-                       ast_hashtab_remove_object_via_lookup(con->root_tree,e);
-                       ast_hashtab_insert_safe(con->root_tree,tmp);
+                       ast_hashtab_remove_object_via_lookup(con->root_table, e);
+                       ast_hashtab_insert_safe(con->root_table, tmp);
                        if (el)
                                el->next = tmp; /* in the middle... */
                        else
@@ -6159,6 +6260,9 @@ int ast_add_extension2(struct ast_context *con,
        if (!(tmp = ast_calloc(1, length)))
                return -1;
 
+       if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
+               label = 0;
+
        /* use p as dst in assignments, as the fields are const char * */
        p = tmp->stuff;
        if (label) {
@@ -6170,7 +6274,7 @@ int ast_add_extension2(struct ast_context *con,
        p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
        tmp->priority = priority;
        tmp->cidmatch = p;      /* but use p for assignments below */
-       if (callerid) {
+       if (!ast_strlen_zero(callerid)) {
                p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
                tmp->matchcid = 1;
        } else {
@@ -6192,11 +6296,11 @@ int ast_add_extension2(struct ast_context *con,
                dummy_exten.exten = dummy_name;
                dummy_exten.matchcid = 0;
                dummy_exten.cidmatch = 0;
-               tmp2 = ast_hashtab_lookup(con->root_tree,&dummy_exten);
+               tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
                if (!tmp2) {
                        /* hmmm, not in the trie; */
                        add_exten_to_pattern_tree(con, tmp, 0);
-                       ast_hashtab_insert_safe(con->root_tree, tmp); /* for the sake of completeness */
+                       ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
                }
        }
        res = 0; /* some compilers will think it is uninitialized otherwise */
@@ -6230,48 +6334,48 @@ int ast_add_extension2(struct ast_context *con,
                tmp->next = e;
                if (el) {  /* there is another exten already in this context */
                        el->next = tmp;
-                       tmp->peer_tree = ast_hashtab_create(13,
+                       tmp->peer_table = ast_hashtab_create(13,
                                                        hashtab_compare_exten_numbers,
                                                        ast_hashtab_resize_java,
                                                        ast_hashtab_newsize_java,
                                                        hashtab_hash_priority,
                                                        0);
-                       tmp->peer_label_tree = ast_hashtab_create(7,
+                       tmp->peer_label_table = ast_hashtab_create(7,
                                                                hashtab_compare_exten_labels,
                                                                ast_hashtab_resize_java,
                                                                ast_hashtab_newsize_java,
                                                                hashtab_hash_labels,
                                                                0);
                        if (label)
-                               ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
-                       ast_hashtab_insert_safe(tmp->peer_tree, tmp);
+                               ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
+                       ast_hashtab_insert_safe(tmp->peer_table, tmp);
 
                } else {  /* this is the first exten in this context */
-                       if (!con->root_tree)
-                               con->root_tree = ast_hashtab_create(27,
+                       if (!con->root_table)
+                               con->root_table = ast_hashtab_create(27,
                                                                                                        hashtab_compare_extens,
                                                                                                        ast_hashtab_resize_java,
                                                                                                        ast_hashtab_newsize_java,
                                                                                                        hashtab_hash_extens,
                                                                                                        0);
                        con->root = tmp;
-                       con->root->peer_tree = ast_hashtab_create(13,
+                       con->root->peer_table = ast_hashtab_create(13,
                                                                hashtab_compare_exten_numbers,
                                                                ast_hashtab_resize_java,
                                                                ast_hashtab_newsize_java,
                                                                hashtab_hash_priority,
                                                                0);
-                       con->root->peer_label_tree = ast_hashtab_create(7,
+                       con->root->peer_label_table = ast_hashtab_create(7,
                                                                        hashtab_compare_exten_labels,
                                                                        ast_hashtab_resize_java,
                                                                        ast_hashtab_newsize_java,
                                                                        hashtab_hash_labels,
                                                                        0);
                        if (label)
-                               ast_hashtab_insert_safe(con->root->peer_label_tree,tmp);
-                       ast_hashtab_insert_safe(con->root->peer_tree, tmp);
+                               ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
+                       ast_hashtab_insert_safe(con->root->peer_table, tmp);
                }
-               ast_hashtab_insert_safe(con->root_tree, tmp);
+               ast_hashtab_insert_safe(con->root_table, tmp);
                ast_unlock_context(con);
                if (tmp->priority == PRIORITY_HINT)
                        ast_add_hint(tmp);
@@ -6287,7 +6391,7 @@ int ast_add_extension2(struct ast_context *con,
        }
 
        if (tmp->matchcid) {
-               ast_verb(3, "Added extension '%s' priority %d (CID match '%s')to %s\n",
+               ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s\n",
                        tmp->exten, tmp->priority, tmp->cidmatch, con->name);
        } else {
                ast_verb(3, "Added extension '%s' priority %d to %s\n",
@@ -6684,68 +6788,125 @@ outgoing_app_cleanup:
        return res;
 }
 
-void __ast_context_destroy(struct ast_context *con, const char *registrar)
+/* this is the guts of destroying a context --
+   freeing up the structure, traversing and destroying the
+   extensions, switches, ignorepats, includes, etc. etc. */
+
+static void __ast_internal_context_destroy( struct ast_context *con)
 {
-       struct ast_context *tmp, *tmpl=NULL;
        struct ast_include *tmpi;
        struct ast_sw *sw;
        struct ast_exten *e, *el, *en;
        struct ast_ignorepat *ipi;
+       struct ast_context *tmp = con;
 
-       for (tmp = contexts; tmp; ) {
-               struct ast_context *next;       /* next starting point */
+       for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
+               struct ast_include *tmpil = tmpi;
+               tmpi = tmpi->next;
+               ast_free(tmpil);
+       }
+       for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
+               struct ast_ignorepat *ipl = ipi;
+               ipi = ipi->next;
+               ast_free(ipl);
+       }
+       /* destroy the hash tabs */
+       if (tmp->root_table) {
+               ast_hashtab_destroy(tmp->root_table, 0);
+       }
+       /* and destroy the pattern tree */
+       if (tmp->pattern_tree)
+               destroy_pattern_tree(tmp->pattern_tree);
+       
+       while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
+               ast_free(sw);
+       for (e = tmp->root; e;) {
+               for (en = e->peer; en;) {
+                       el = en;
+                       en = en->peer;
+                       destroy_exten(el);
+               }
+               el = e;
+               e = e->next;
+               destroy_exten(el);
+       }
+       tmp->root = NULL;
+       ast_rwlock_destroy(&tmp->lock);
+       ast_free(tmp);
+}
+
+
+void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
+{
+       struct ast_context *tmp, *tmpl=NULL;
+       struct ast_exten *exten_item, *prio_item;
+
+
+       for (tmp = list; tmp; ) {
+               struct ast_context *next = NULL;        /* next starting point */
                for (; tmp; tmpl = tmp, tmp = tmp->next) {
                        ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
-                       if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
-                            (!con || !strcasecmp(tmp->name, con->name)) )
+                       if ( registrar || (con && strcasecmp(tmp->name, con->name)) )
                                break;  /* found it */
                }
                if (!tmp)       /* not found, we are done */
                        break;
                ast_wrlock_context(tmp);
-               ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
-               ast_hashtab_remove_this_object(contexts_tree,tmp);
-               
-               next = tmp->next;
-               if (tmpl)
-                       tmpl->next = next;
-               else
-                       contexts = next;
-               /* Okay, now we're safe to let it go -- in a sense, we were
-                  ready to let it go as soon as we locked it. */
-               ast_unlock_context(tmp);
-               for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
-                       struct ast_include *tmpil = tmpi;
-                       tmpi = tmpi->next;
-                       ast_free(tmpil);
-               }
-               for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
-                       struct ast_ignorepat *ipl = ipi;
-                       ipi = ipi->next;
-                       ast_free(ipl);
-               }
-               /* destroy the hash tabs */
-               if (tmp->root_tree) {
-                       ast_hashtab_destroy(tmp->root_tree, 0);
-               }
-               /* and destroy the pattern tree */
-               if (tmp->pattern_tree)
-                       destroy_pattern_tree(tmp->pattern_tree);
-               
-               while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
-                       ast_free(sw);
-               for (e = tmp->root; e;) {
-                       for (en = e->peer; en;) {
-                               el = en;
-                               en = en->peer;
-                               destroy_exten(el);
+
+               if (registrar) {
+                       /* then search thru and remove any extens that match registrar. */
+                       struct ast_hashtab_iter *exten_iter;
+                       struct ast_hashtab_iter *prio_iter;
+
+                       if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
+                               exten_iter = ast_hashtab_start_traversal(tmp->root_table);
+                               while ((exten_item=ast_hashtab_next(exten_iter))) {
+                                       prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
+                                       while ((prio_item=ast_hashtab_next(prio_iter))) {
+                                               if (strcmp(prio_item->registrar, registrar) != 0) {
+                                                       continue;
+                                               }
+                                               ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
+                                                               tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
+                                               
+                                               ast_context_remove_extension2(tmp, prio_item->exten, prio_item->priority, registrar);
+                                       }
+                                       ast_hashtab_end_traversal(prio_iter);
+                               }
+                               ast_hashtab_end_traversal(exten_iter);
                        }
-                       el = e;
-                       e = e->next;
-                       destroy_exten(el);
+       
+                       /* delete the context if it's registrar matches, is empty, has refcount of 1, */
+                       if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root) {
+                               ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
+                               ast_hashtab_remove_this_object(contexttab, tmp);
+                               
+                               next = tmp->next;
+                               if (tmpl)
+                                       tmpl->next = next;
+                               else
+                                       contexts = next;
+                               /* Okay, now we're safe to let it go -- in a sense, we were
+                                  ready to let it go as soon as we locked it. */
+                               ast_unlock_context(tmp);
+                               __ast_internal_context_destroy(tmp);
+                       }
+               } else if (con) {
+                       ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
+                       ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
+                       ast_hashtab_remove_this_object(contexttab, tmp);
+                       
+                       next = tmp->next;
+                       if (tmpl)
+                               tmpl->next = next;
+                       else
+                               contexts = next;
+                       /* Okay, now we're safe to let it go -- in a sense, we were
+                          ready to let it go as soon as we locked it. */
+                       ast_unlock_context(tmp);
+                       __ast_internal_context_destroy(tmp);
                }
-               ast_rwlock_destroy(&tmp->lock);
-               ast_free(tmp);
+
                /* if we have a specific match, we are done, otherwise continue */
                tmp = con ? NULL : next;
        }
@@ -6754,7 +6915,7 @@ void __ast_context_destroy(struct ast_context *con, const char *registrar)
 void ast_context_destroy(struct ast_context *con, const char *registrar)
 {
        ast_wrlock_contexts();
-       __ast_context_destroy(con,registrar);
+       __ast_context_destroy(contexts, contexts_table, con,registrar);
        ast_unlock_contexts();
 }
 
@@ -6899,7 +7060,7 @@ static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
                        return -1;
                }
                        
-               ast_log(LOG_NOTICE, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
+               ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
        }
 
        if (!chan->hangupcause) {
@@ -7568,12 +7729,21 @@ int load_pbx(void)
 
        return 0;
 }
+static int conlock_wrlock_version = 0;
+
+int ast_wrlock_contexts_version(void)
+{
+       return conlock_wrlock_version;
+}
 
 /*
  * Lock context list functions ...
  */
 int ast_wrlock_contexts()
 {
+       int res = ast_rwlock_wrlock(&conlock);
+       if (!res)
+               ast_atomic_fetchadd_int(&conlock_wrlock_version, 1);
        return ast_rwlock_wrlock(&conlock);
 }
 
index fa4b7d5..0e40c94 100644 (file)
@@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/cli.h"
 #include "asterisk/app.h"
 #include "asterisk/callerid.h"
+#include "asterisk/hashtab.h"
 #include "asterisk/ael_structs.h"
 #include "asterisk/pval.h"
 #ifdef AAL_ARGCHECK
@@ -88,7 +89,7 @@ void linkprio(struct ael_extension *exten, struct ael_priority *prio);
 void destroy_extensions(struct ael_extension *exten);
 void set_priorities(struct ael_extension *exten);
 void add_extensions(struct ael_extension *exten);
-void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root);
+void ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root);
 void destroy_pval(pval *item);
 void destroy_pval_item(pval *item);
 int is_float(char *arg );
@@ -108,6 +109,8 @@ static int pbx_load_module(void)
        int errs=0, sem_err=0, sem_warn=0, sem_note=0;
        char *rfilename;
        struct ast_context *local_contexts=NULL, *con;
+       struct ast_hashtab *local_table=NULL;
+       
        struct pval *parse_tree;
 
        ast_log(LOG_NOTICE, "Starting AEL load process.\n");
@@ -127,10 +130,13 @@ static int pbx_load_module(void)
        ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
        if (errs == 0 && sem_err == 0) {
                ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
-               ast_compile_ael2(&local_contexts, parse_tree);
+               local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
+               ast_compile_ael2(&local_contexts, local_table, parse_tree);
                ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
                
-               ast_merge_contexts_and_delete(&local_contexts, registrar);
+               ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
+               local_table = NULL; /* it's the dialplan global now */
+               local_contexts = NULL;
                ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
                for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
                        ast_context_verify_includes(con);
index 4a7a3d3..bf707a9 100644 (file)
@@ -51,7 +51,7 @@ static int extenpatternmatchnew_config = 0;
 AST_MUTEX_DEFINE_STATIC(save_dialplan_lock);
 
 static struct ast_context *local_contexts = NULL;
-
+static struct ast_hashtab *local_table = NULL;
 /*
  * Prototypes for our completion functions
  */
@@ -1371,7 +1371,6 @@ static int pbx_load_config(const char *config_file)
        const char *aft;
        const char *newpm;
        struct ast_flags config_flags = { 0 };
-
        cfg = ast_config_load(config_file, config_flags);
        if (!cfg)
                return 0;
@@ -1399,7 +1398,7 @@ static int pbx_load_config(const char *config_file)
                /* All categories but "general" or "globals" are considered contexts */
                if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
                        continue;
-               con=ast_context_find_or_create(&local_contexts,cxt, registrar);
+               con=ast_context_find_or_create(&local_contexts, local_table, cxt, registrar);
                if (con == NULL)
                        continue;
 
@@ -1601,7 +1600,7 @@ static void pbx_load_users(void)
                        /* Only create a context here when it is really needed. Otherwise default empty context
                        created by pbx_config may conflict with the one explicitly created by pbx_ael */
                        if (!con)
-                               con = ast_context_find_or_create(&local_contexts, userscontext, registrar);
+                               con = ast_context_find_or_create(&local_contexts, local_table, userscontext, registrar);
 
                        if (!con) {
                                ast_log(LOG_ERROR, "Can't find/create user context '%s'\n", userscontext);
@@ -1626,12 +1625,17 @@ static int pbx_load_module(void)
 {
        struct ast_context *con;
 
-       if(!pbx_load_config(config))
+       if (!local_table)
+               local_table = ast_hashtab_create(17, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
+
+       if (!pbx_load_config(config))
                return AST_MODULE_LOAD_DECLINE;
        
        pbx_load_users();
 
-       ast_merge_contexts_and_delete(&local_contexts, registrar);
+       ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
+       local_table = NULL; /* the local table has been moved into the global one. */
+       local_contexts = NULL;
 
        for (con = NULL; (con = ast_walk_contexts(con));)
                ast_context_verify_includes(con);
index cf2d36a..1ca6427 100644 (file)
@@ -60,6 +60,7 @@
 %option bison-locations
 
 %{
+#include "asterisk.h"
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <sys/types.h>
@@ -70,9 +71,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #define GLOB_ABORTED GLOB_ABEND
 #endif
 # include <glob.h>
-
 #include "asterisk/logger.h"
 #include "asterisk/utils.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
 #include "ael/ael.tab.h"
 #include "asterisk/ael_structs.h"
 
index aa1ec0f..16c62ba 100644 (file)
@@ -188,6 +188,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <string.h>
 
 #include "asterisk/logger.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
 #include "asterisk/ael_structs.h"
 
 pval * linku1(pval *head, pval *tail);
@@ -227,14 +229,14 @@ static char *ael_token_subst(const char *mess);
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 54 "ael.y"
+#line 56 "ael.y"
 {
        int     intval;         /* integer value, typically flags */
        char    *str;           /* strings */
        struct pval *pval;      /* full objects */
 }
 /* Line 198 of yacc.c.  */
-#line 238 "ael.tab.c"
+#line 240 "ael.tab.c"
        YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -256,7 +258,7 @@ typedef struct YYLTYPE
 
 
 /* Copy the second part of user declarations.  */
-#line 60 "ael.y"
+#line 62 "ael.y"
 
        /* declaring these AFTER the union makes things a lot simpler! */
 void yyerror(YYLTYPE *locp, struct parse_io *parseio, char const *s);
@@ -279,7 +281,7 @@ static pval *update_last(pval *, YYLTYPE *);
 
 
 /* Line 221 of yacc.c.  */
-#line 283 "ael.tab.c"
+#line 285 "ael.tab.c"
 
 #ifdef short
 # undef short
@@ -625,21 +627,21 @@ static const yytype_int8 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   186,   186,   189,   190,   191,   194,   195,   196,   197,
-     200,   201,   204,   213,   214,   215,   216,   217,   220,   226,
-     232,   233,   234,   237,   237,   243,   243,   250,   251,   252,
-     253,   256,   257,   258,   261,   262,   263,   264,   265,   266,
-     267,   268,   269,   272,   277,   281,   289,   294,   299,   308,
-     309,   310,   316,   321,   325,   333,   333,   337,   340,   343,
-     354,   355,   362,   363,   367,   371,   377,   378,   383,   391,
-     392,   396,   402,   411,   414,   415,   416,   419,   422,   425,
-     426,   427,   425,   433,   437,   438,   439,   440,   443,   443,
-     476,   477,   478,   479,   483,   486,   487,   490,   491,   494,
-     497,   501,   505,   509,   515,   516,   520,   523,   529,   529,
-     534,   542,   542,   553,   560,   563,   564,   567,   568,   571,
-     574,   575,   578,   582,   586,   592,   593,   596,   597,   598,
-     604,   609,   614,   615,   616,   618,   621,   622,   629,   630,
-     631,   634,   637
+       0,   188,   188,   191,   192,   193,   196,   197,   198,   199,
+     202,   203,   206,   215,   216,   217,   218,   219,   222,   228,
+     234,   235,   236,   239,   239,   245,   245,   252,   253,   254,
+     255,   258,   259,   260,   263,   264,   265,   266,   267,   268,
+     269,   270,   271,   274,   279,   283,   291,   296,   301,   310,
+     311,   312,   318,   323,   327,   335,   335,   339,   342,   345,
+     356,   357,   364,   365,   369,   373,   379,   380,   385,   393,
+     394,   398,   404,   413,   416,   417,   418,   421,   424,   427,
+     428,   429,   427,   435,   439,   440,   441,   442,   445,   445,
+     478,   479,   480,   481,   485,   488,   489,   492,   493,   496,
+     499,   503,   507,   511,   517,   518,   522,   525,   531,   531,
+     536,   544,   544,   555,   562,   565,   566,   569,   570,   573,
+     576,   577,   580,   584,   588,   594,   595,   598,   599,   600,
+     606,   611,   616,   617,   618,   620,   623,   624,   631,   632,
+     633,   636,   639
 };
 #endif
 
@@ -1450,329 +1452,329 @@ yydestruct (yymsg, yytype, yyvaluep, yylocationp, parseio)
   switch (yytype)
     {
       case 43: /* "word" */
-#line 178 "ael.y"
+#line 180 "ael.y"
        { free((yyvaluep->str));};
-#line 1456 "ael.tab.c"
+#line 1458 "ael.tab.c"
        break;
       case 46: /* "objects" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1464 "ael.tab.c"
+#line 1466 "ael.tab.c"
        break;
       case 47: /* "object" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1472 "ael.tab.c"
+#line 1474 "ael.tab.c"
        break;
       case 48: /* "context_name" */
-#line 178 "ael.y"
+#line 180 "ael.y"
        { free((yyvaluep->str));};
-#line 1477 "ael.tab.c"
+#line 1479 "ael.tab.c"
        break;
       case 49: /* "context" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1485 "ael.tab.c"
+#line 1487 "ael.tab.c"
        break;
       case 51: /* "macro" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1493 "ael.tab.c"
+#line 1495 "ael.tab.c"
        break;
       case 52: /* "globals" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1501 "ael.tab.c"
+#line 1503 "ael.tab.c"
        break;
       case 53: /* "global_statements" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1509 "ael.tab.c"
+#line 1511 "ael.tab.c"
        break;
       case 54: /* "assignment" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1517 "ael.tab.c"
+#line 1519 "ael.tab.c"
        break;
       case 56: /* "local_assignment" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1525 "ael.tab.c"
+#line 1527 "ael.tab.c"
        break;
       case 58: /* "arglist" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1533 "ael.tab.c"
+#line 1535 "ael.tab.c"
        break;
       case 59: /* "elements" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1541 "ael.tab.c"
+#line 1543 "ael.tab.c"
        break;
       case 60: /* "element" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1549 "ael.tab.c"
+#line 1551 "ael.tab.c"
        break;
       case 61: /* "ignorepat" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1557 "ael.tab.c"
+#line 1559 "ael.tab.c"
        break;
       case 62: /* "extension" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1565 "ael.tab.c"
+#line 1567 "ael.tab.c"
        break;
       case 63: /* "statements" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1573 "ael.tab.c"
+#line 1575 "ael.tab.c"
        break;
       case 64: /* "timerange" */
-#line 178 "ael.y"
+#line 180 "ael.y"
        { free((yyvaluep->str));};
-#line 1578 "ael.tab.c"
+#line 1580 "ael.tab.c"
        break;
       case 65: /* "timespec" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1586 "ael.tab.c"
+#line 1588 "ael.tab.c"
        break;
       case 66: /* "test_expr" */
-#line 178 "ael.y"
+#line 180 "ael.y"
        { free((yyvaluep->str));};
-#line 1591 "ael.tab.c"
+#line 1593 "ael.tab.c"
        break;
       case 68: /* "if_like_head" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1599 "ael.tab.c"
+#line 1601 "ael.tab.c"
        break;
       case 69: /* "word_list" */
-#line 178 "ael.y"
+#line 180 "ael.y"
        { free((yyvaluep->str));};
-#line 1604 "ael.tab.c"
+#line 1606 "ael.tab.c"
        break;
       case 71: /* "word3_list" */
-#line 178 "ael.y"
+#line 180 "ael.y"
        { free((yyvaluep->str));};
-#line 1609 "ael.tab.c"
+#line 1611 "ael.tab.c"
        break;
       case 72: /* "goto_word" */
-#line 178 "ael.y"
+#line 180 "ael.y"
        { free((yyvaluep->str));};
-#line 1614 "ael.tab.c"
+#line 1616 "ael.tab.c"
        break;
       case 73: /* "switch_statement" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1622 "ael.tab.c"
+#line 1624 "ael.tab.c"
        break;
       case 74: /* "statement" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1630 "ael.tab.c"
+#line 1632 "ael.tab.c"
        break;
       case 79: /* "opt_else" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1638 "ael.tab.c"
+#line 1640 "ael.tab.c"
        break;
       case 80: /* "target" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1646 "ael.tab.c"
+#line 1648 "ael.tab.c"
        break;
       case 81: /* "opt_pri" */
-#line 178 "ael.y"
+#line 180 "ael.y"
        { free((yyvaluep->str));};
-#line 1651 "ael.tab.c"
+#line 1653 "ael.tab.c"
        break;
       case 82: /* "jumptarget" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1659 "ael.tab.c"
+#line 1661 "ael.tab.c"
        break;
       case 83: /* "macro_call" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1667 "ael.tab.c"
+#line 1669 "ael.tab.c"
        break;
       case 85: /* "application_call_head" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1675 "ael.tab.c"
+#line 1677 "ael.tab.c"
        break;
       case 87: /* "application_call" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1683 "ael.tab.c"
+#line 1685 "ael.tab.c"
        break;
       case 88: /* "opt_word" */
-#line 178 "ael.y"
+#line 180 "ael.y"
        { free((yyvaluep->str));};
-#line 1688 "ael.tab.c"
+#line 1690 "ael.tab.c"
        break;
       case 89: /* "eval_arglist" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1696 "ael.tab.c"
+#line 1698 "ael.tab.c"
        break;
       case 90: /* "case_statements" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1704 "ael.tab.c"
+#line 1706 "ael.tab.c"
        break;
       case 91: /* "case_statement" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1712 "ael.tab.c"
+#line 1714 "ael.tab.c"
        break;
       case 92: /* "macro_statements" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1720 "ael.tab.c"
+#line 1722 "ael.tab.c"
        break;
       case 93: /* "macro_statement" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1728 "ael.tab.c"
+#line 1730 "ael.tab.c"
        break;
       case 94: /* "switches" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1736 "ael.tab.c"
+#line 1738 "ael.tab.c"
        break;
       case 95: /* "eswitches" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1744 "ael.tab.c"
+#line 1746 "ael.tab.c"
        break;
       case 96: /* "switchlist" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1752 "ael.tab.c"
+#line 1754 "ael.tab.c"
        break;
       case 97: /* "included_entry" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1760 "ael.tab.c"
+#line 1762 "ael.tab.c"
        break;
       case 98: /* "includeslist" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1768 "ael.tab.c"
+#line 1770 "ael.tab.c"
        break;
       case 99: /* "includes" */
-#line 165 "ael.y"
+#line 167 "ael.y"
        {
                destroy_pval((yyvaluep->pval));
                prev_word=0;
        };
-#line 1776 "ael.tab.c"
+#line 1778 "ael.tab.c"
        break;
 
       default:
@@ -2095,57 +2097,57 @@ yyreduce:
   switch (yyn)
     {
         case 2:
-#line 186 "ael.y"
+#line 188 "ael.y"
     { (yyval.pval) = parseio->pval = (yyvsp[(1) - (1)].pval); ;}
     break;
 
   case 3:
-#line 189 "ael.y"
+#line 191 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 4:
-#line 190 "ael.y"
+#line 192 "ael.y"
     { (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
     break;
 
   case 5:
-#line 191 "ael.y"
+#line 193 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (2)].pval);;}
     break;
 
   case 6:
-#line 194 "ael.y"
+#line 196 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 7:
-#line 195 "ael.y"
+#line 197 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 8:
-#line 196 "ael.y"
+#line 198 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 9:
-#line 197 "ael.y"
+#line 199 "ael.y"
     {(yyval.pval)=0;/* allow older docs to be read */;}
     break;
 
   case 10:
-#line 200 "ael.y"
+#line 202 "ael.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str); ;}
     break;
 
   case 11:
-#line 201 "ael.y"
+#line 203 "ael.y"
     { (yyval.str) = strdup("default"); ;}
     break;
 
   case 12:
-#line 204 "ael.y"
+#line 206 "ael.y"
     {
                (yyval.pval) = npval2(PV_CONTEXT, &(yylsp[(1) - (6)]), &(yylsp[(6) - (6)]));
                (yyval.pval)->u1.str = (yyvsp[(3) - (6)].str);
@@ -2155,32 +2157,32 @@ yyreduce:
     break;
 
   case 13:
-#line 213 "ael.y"
+#line 215 "ael.y"
     { (yyval.intval) = 1; ;}
     break;
 
   case 14:
-#line 214 "ael.y"
+#line 216 "ael.y"
     { (yyval.intval) = 0; ;}
     break;
 
   case 15:
-#line 215 "ael.y"
+#line 217 "ael.y"
     { (yyval.intval) = 2; ;}
     break;
 
   case 16:
-#line 216 "ael.y"
+#line 218 "ael.y"
     { (yyval.intval)=3; ;}
     break;
 
   case 17:
-#line 217 "ael.y"
+#line 219 "ael.y"
     { (yyval.intval)=3; ;}
     break;
 
   case 18:
-#line 220 "ael.y"
+#line 222 "ael.y"
     {
                (yyval.pval) = npval2(PV_MACRO, &(yylsp[(1) - (8)]), &(yylsp[(8) - (8)]));
                (yyval.pval)->u1.str = (yyvsp[(2) - (8)].str); (yyval.pval)->u2.arglist = (yyvsp[(4) - (8)].pval); (yyval.pval)->u3.macro_statements = (yyvsp[(7) - (8)].pval);
@@ -2188,7 +2190,7 @@ yyreduce:
     break;
 
   case 19:
-#line 226 "ael.y"
+#line 228 "ael.y"
     {
                (yyval.pval) = npval2(PV_GLOBALS, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)]));
                (yyval.pval)->u1.statements = (yyvsp[(3) - (4)].pval);
@@ -2196,27 +2198,27 @@ yyreduce:
     break;
 
   case 20:
-#line 232 "ael.y"
+#line 234 "ael.y"
     { (yyval.pval) = NULL; ;}
     break;
 
   case 21:
-#line 233 "ael.y"
+#line 235 "ael.y"
     {(yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
     break;
 
   case 22:
-#line 234 "ael.y"
+#line 236 "ael.y"
     {(yyval.pval)=(yyvsp[(2) - (2)].pval);;}
     break;
 
   case 23:
-#line 237 "ael.y"
+#line 239 "ael.y"
     { reset_semicount(parseio->scanner); ;}
     break;
 
   case 24:
-#line 237 "ael.y"
+#line 239 "ael.y"
     {
                (yyval.pval) = npval2(PV_VARDEC, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)]));
                (yyval.pval)->u1.str = (yyvsp[(1) - (5)].str);
@@ -2224,12 +2226,12 @@ yyreduce:
     break;
 
   case 25:
-#line 243 "ael.y"
+#line 245 "ael.y"
     { reset_semicount(parseio->scanner); ;}
     break;
 
   case 26:
-#line 243 "ael.y"
+#line 245 "ael.y"
     {
                (yyval.pval) = npval2(PV_LOCALVARDEC, &(yylsp[(1) - (6)]), &(yylsp[(6) - (6)]));
                (yyval.pval)->u1.str = (yyvsp[(2) - (6)].str);
@@ -2237,94 +2239,94 @@ yyreduce:
     break;
 
   case 27:
-#line 250 "ael.y"
+#line 252 "ael.y"
     { (yyval.pval) = NULL; ;}
     break;
 
   case 28:
-#line 251 "ael.y"
+#line 253 "ael.y"
     { (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;}
     break;
 
   case 29:
-#line 252 "ael.y"
+#line 254 "ael.y"
     { (yyval.pval) = linku1((yyvsp[(1) - (3)].pval), nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)]))); ;}
     break;
 
   case 30:
-#line 253 "ael.y"
+#line 255 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (2)].pval);;}
     break;
 
   case 31:
-#line 256 "ael.y"
+#line 258 "ael.y"
     {(yyval.pval)=0;;}
     break;
 
   case 32:
-#line 257 "ael.y"
+#line 259 "ael.y"
     { (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
     break;
 
   case 33:
-#line 258 "ael.y"
+#line 260 "ael.y"
     { (yyval.pval)=(yyvsp[(2) - (2)].pval);;}
     break;
 
   case 34:
-#line 261 "ael.y"
+#line 263 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 35:
-#line 262 "ael.y"
+#line 264 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 36:
-#line 263 "ael.y"
+#line 265 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 37:
-#line 264 "ael.y"
+#line 266 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 38:
-#line 265 "ael.y"
+#line 267 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 39:
-#line 266 "ael.y"
+#line 268 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 40:
-#line 267 "ael.y"
+#line 269 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 41:
-#line 268 "ael.y"
+#line 270 "ael.y"
     {free((yyvsp[(1) - (2)].str)); (yyval.pval)=0;;}
     break;
 
   case 42:
-#line 269 "ael.y"
+#line 271 "ael.y"
     {(yyval.pval)=0;/* allow older docs to be read */;}
     break;
 
   case 43:
-#line 272 "ael.y"
+#line 274 "ael.y"
     {
                (yyval.pval) = npval2(PV_IGNOREPAT, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)]));
                (yyval.pval)->u1.str = (yyvsp[(3) - (4)].str);;}
     break;
 
   case 44:
-#line 277 "ael.y"
+#line 279 "ael.y"
     {
                (yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
                (yyval.pval)->u1.str = (yyvsp[(1) - (3)].str);
@@ -2332,7 +2334,7 @@ yyreduce:
     break;
 
   case 45:
-#line 281 "ael.y"
+#line 283 "ael.y"
     {
                (yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (5)]), &(yylsp[(3) - (5)]));
                (yyval.pval)->u1.str = malloc(strlen((yyvsp[(1) - (5)].str))+strlen((yyvsp[(3) - (5)].str))+2);
@@ -2344,7 +2346,7 @@ yyreduce:
     break;
 
   case 46:
-#line 289 "ael.y"
+#line 291 "ael.y"
     {
                (yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)]));
                (yyval.pval)->u1.str = (yyvsp[(2) - (4)].str);
@@ -2353,7 +2355,7 @@ yyreduce:
     break;
 
   case 47:
-#line 294 "ael.y"
+#line 296 "ael.y"
     {
                (yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (7)]), &(yylsp[(7) - (7)]));
                (yyval.pval)->u1.str = (yyvsp[(5) - (7)].str);
@@ -2362,7 +2364,7 @@ yyreduce:
     break;
 
   case 48:
-#line 299 "ael.y"
+#line 301 "ael.y"
     {
                (yyval.pval) = npval2(PV_EXTENSION, &(yylsp[(1) - (8)]), &(yylsp[(8) - (8)]));
                (yyval.pval)->u1.str = (yyvsp[(6) - (8)].str);
@@ -2372,22 +2374,22 @@ yyreduce:
     break;
 
   case 49:
-#line 308 "ael.y"
+#line 310 "ael.y"
     { (yyval.pval) = NULL; ;}
     break;
 
   case 50:
-#line 309 "ael.y"
+#line 311 "ael.y"
     { (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
     break;
 
   case 51:
-#line 310 "ael.y"
+#line 312 "ael.y"
     {(yyval.pval)=(yyvsp[(2) - (2)].pval);;}
     break;
 
   case 52:
-#line 316 "ael.y"
+#line 318 "ael.y"
     {
                asprintf(&(yyval.str), "%s:%s:%s", (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str));
                free((yyvsp[(1) - (5)].str));
@@ -2396,12 +2398,12 @@ yyreduce:
     break;
 
   case 53:
-#line 321 "ael.y"
+#line 323 "ael.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str); ;}
     break;
 
   case 54:
-#line 325 "ael.y"
+#line 327 "ael.y"
     {
                (yyval.pval) = nword((yyvsp[(1) - (7)].str), &(yylsp[(1) - (7)]));
                (yyval.pval)->next = nword((yyvsp[(3) - (7)].str), &(yylsp[(3) - (7)]));
@@ -2410,31 +2412,31 @@ yyreduce:
     break;
 
   case 55:
-#line 333 "ael.y"
+#line 335 "ael.y"
     { reset_parencount(parseio->scanner); ;}
     break;
 
   case 56:
-#line 333 "ael.y"
+#line 335 "ael.y"
     { (yyval.str) = (yyvsp[(3) - (4)].str); ;}
     break;
 
   case 57:
-#line 337 "ael.y"
+#line 339 "ael.y"
     {
                (yyval.pval)= npval2(PV_IF, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)]));
                (yyval.pval)->u1.str = (yyvsp[(2) - (2)].str); ;}
     break;
 
   case 58:
-#line 340 "ael.y"
+#line 342 "ael.y"
     {
                (yyval.pval) = npval2(PV_RANDOM, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)]));
                (yyval.pval)->u1.str=(yyvsp[(2) - (2)].str);;}
     break;
 
   case 59:
-#line 343 "ael.y"
+#line 345 "ael.y"
     {
                (yyval.pval) = npval2(PV_IFTIME, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)]));
                (yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval);
@@ -2442,12 +2444,12 @@ yyreduce:
     break;
 
   case 60:
-#line 354 "ael.y"
+#line 356 "ael.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str);;}
     break;
 
   case 61:
-#line 355 "ael.y"
+#line 357 "ael.y"
     {
                asprintf(&((yyval.str)), "%s%s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str));
                free((yyvsp[(1) - (2)].str));
@@ -2456,12 +2458,12 @@ yyreduce:
     break;
 
   case 62:
-#line 362 "ael.y"
+#line 364 "ael.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str); ;}
     break;
 
   case 63:
-#line 363 "ael.y"
+#line 365 "ael.y"
     {
                asprintf(&((yyval.str)), "%s %s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str));
                free((yyvsp[(1) - (2)].str));
@@ -2469,7 +2471,7 @@ yyreduce:
     break;
 
   case 64:
-#line 367 "ael.y"
+#line 369 "ael.y"
     {
                asprintf(&((yyval.str)), "%s:%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str));
                free((yyvsp[(1) - (3)].str));
@@ -2477,7 +2479,7 @@ yyreduce:
     break;
 
   case 65:
-#line 371 "ael.y"
+#line 373 "ael.y"
     {  /* there are often '&' in hints */
                asprintf(&((yyval.str)), "%s&%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str));
                free((yyvsp[(1) - (3)].str));
@@ -2485,12 +2487,12 @@ yyreduce:
     break;
 
   case 66:
-#line 377 "ael.y"
+#line 379 "ael.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str);;}
     break;
 
   case 67:
-#line 378 "ael.y"
+#line 380 "ael.y"
     {
                asprintf(&((yyval.str)), "%s%s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str));
                free((yyvsp[(1) - (2)].str));
@@ -2499,7 +2501,7 @@ yyreduce:
     break;
 
   case 68:
-#line 383 "ael.y"
+#line 385 "ael.y"
     {
                asprintf(&((yyval.str)), "%s%s%s", (yyvsp[(1) - (3)].str), (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str));
                free((yyvsp[(1) - (3)].str));
@@ -2509,12 +2511,12 @@ yyreduce:
     break;
 
   case 69:
-#line 391 "ael.y"
+#line 393 "ael.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str);;}
     break;
 
   case 70:
-#line 392 "ael.y"
+#line 394 "ael.y"
     {
                asprintf(&((yyval.str)), "%s%s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str));
                free((yyvsp[(1) - (2)].str));
@@ -2522,7 +2524,7 @@ yyreduce:
     break;
 
   case 71:
-#line 396 "ael.y"
+#line 398 "ael.y"
     {
                asprintf(&((yyval.str)), "%s:%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str));
                free((yyvsp[(1) - (3)].str));
@@ -2530,7 +2532,7 @@ yyreduce:
     break;
 
   case 72:
-#line 402 "ael.y"
+#line 404 "ael.y"
     {
                (yyval.pval) = npval2(PV_SWITCH, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)]));
                (yyval.pval)->u1.str = (yyvsp[(2) - (5)].str);
@@ -2538,60 +2540,60 @@ yyreduce:
     break;
 
   case 73:
-#line 411 "ael.y"
+#line 413 "ael.y"
     {
                (yyval.pval) = npval2(PV_STATEMENTBLOCK, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
                (yyval.pval)->u1.list = (yyvsp[(2) - (3)].pval); set_dads((yyval.pval),(yyvsp[(2) - (3)].pval));;}
     break;
 
   case 74:
-#line 414 "ael.y"
+#line 416 "ael.y"
     { (yyval.pval) = (yyvsp[(1) - (1)].pval); ;}
     break;
 
   case 75:
-#line 415 "ael.y"
+#line 417 "ael.y"
     { (yyval.pval) = (yyvsp[(1) - (1)].pval); ;}
     break;
 
   case 76:
-#line 416 "ael.y"
+#line 418 "ael.y"
     {
                (yyval.pval) = npval2(PV_GOTO, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
                (yyval.pval)->u1.list = (yyvsp[(2) - (3)].pval);;}
     break;
 
   case 77:
-#line 419 "ael.y"
+#line 421 "ael.y"
     {
                (yyval.pval) = npval2(PV_GOTO, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
                (yyval.pval)->u1.list = (yyvsp[(2) - (3)].pval);;}
     break;
 
   case 78:
-#line 422 "ael.y"
+#line 424 "ael.y"
     {
                (yyval.pval) = npval2(PV_LABEL, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)]));
                (yyval.pval)->u1.str = (yyvsp[(1) - (2)].str); ;}
     break;
 
   case 79:
-#line 425 "ael.y"
+#line 427 "ael.y"
     {reset_semicount(parseio->scanner);;}
     break;
 
   case 80:
-#line 426 "ael.y"
+#line 428 "ael.y"
     {reset_semicount(parseio->scanner);;}
     break;
 
   case 81:
-#line 427 "ael.y"
+#line 429 "ael.y"
     {reset_parencount(parseio->scanner);;}
     break;
 
   case 82:
-#line 427 "ael.y"
+#line 429 "ael.y"
     { /* XXX word_list maybe ? */
                (yyval.pval) = npval2(PV_FOR, &(yylsp[(1) - (12)]), &(yylsp[(12) - (12)]));
                (yyval.pval)->u1.for_init = (yyvsp[(4) - (12)].str);
@@ -2601,7 +2603,7 @@ yyreduce:
     break;
 
   case 83:
-#line 433 "ael.y"
+#line 435 "ael.y"
     {
                (yyval.pval) = npval2(PV_WHILE, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
                (yyval.pval)->u1.str = (yyvsp[(2) - (3)].str);
@@ -2609,34 +2611,34 @@ yyreduce:
     break;
 
   case 84:
-#line 437 "ael.y"
+#line 439 "ael.y"
     { (yyval.pval) = (yyvsp[(1) - (1)].pval); ;}
     break;
 
   case 85:
-#line 438 "ael.y"
+#line 440 "ael.y"
     { (yyval.pval) = update_last((yyvsp[(2) - (3)].pval), &(yylsp[(2) - (3)])); ;}
     break;
 
   case 86:
-#line 439 "ael.y"
+#line 441 "ael.y"
     { (yyval.pval) = update_last((yyvsp[(1) - (2)].pval), &(yylsp[(2) - (2)])); ;}
     break;
 
   case 87:
-#line 440 "ael.y"
+#line 442 "ael.y"
     {
                (yyval.pval)= npval2(PV_APPLICATION_CALL, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)]));
                (yyval.pval)->u1.str = (yyvsp[(1) - (2)].str);;}
     break;
 
   case 88:
-#line 443 "ael.y"
+#line 445 "ael.y"
     {reset_semicount(parseio->scanner);;}
     break;
 
   case 89:
-#line 443 "ael.y"
+#line 445 "ael.y"
     {
                char *bufx;
                int tot=0;
@@ -2673,22 +2675,22 @@ yyreduce:
     break;
 
   case 90:
-#line 476 "ael.y"
+#line 478 "ael.y"
     { (yyval.pval) = npval2(PV_BREAK, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); ;}
     break;
 
   case 91:
-#line 477 "ael.y"
+#line 479 "ael.y"
     { (yyval.pval) = npval2(PV_RETURN, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); ;}
     break;
 
   case 92:
-#line 478 "ael.y"
+#line 480 "ael.y"
     { (yyval.pval) = npval2(PV_CONTINUE, &(yylsp[(1) - (2)]), &(yylsp[(2) - (2)])); ;}
     break;
 
   case 93:
-#line 479 "ael.y"
+#line 481 "ael.y"
     {
                (yyval.pval) = update_last((yyvsp[(1) - (3)].pval), &(yylsp[(2) - (3)]));
                (yyval.pval)->u2.statements = (yyvsp[(2) - (3)].pval); set_dads((yyval.pval),(yyvsp[(2) - (3)].pval));
@@ -2696,41 +2698,41 @@ yyreduce:
     break;
 
   case 94:
-#line 483 "ael.y"
+#line 485 "ael.y"
     { (yyval.pval)=0; ;}
     break;
 
   case 95:
-#line 486 "ael.y"
+#line 488 "ael.y"
     { (yyval.pval) = (yyvsp[(2) - (2)].pval); ;}
     break;
 
   case 96:
-#line 487 "ael.y"
+#line 489 "ael.y"
     { (yyval.pval) = NULL ; ;}
     break;
 
   case 97:
-#line 490 "ael.y"
+#line 492 "ael.y"
     { (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;}
     break;
 
   case 98:
-#line 491 "ael.y"
+#line 493 "ael.y"
     {
                (yyval.pval) = nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)]));
                (yyval.pval)->next = nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)])); ;}
     break;
 
   case 99:
-#line 494 "ael.y"
+#line 496 "ael.y"
     {
                (yyval.pval) = nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)]));
                (yyval.pval)->next = nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)])); ;}
     break;
 
   case 100:
-#line 497 "ael.y"
+#line 499 "ael.y"
     {
                (yyval.pval) = nword((yyvsp[(1) - (5)].str), &(yylsp[(1) - (5)]));
                (yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)]));
@@ -2738,7 +2740,7 @@ yyreduce:
     break;
 
   case 101:
-#line 501 "ael.y"
+#line 503 "ael.y"
     {
                (yyval.pval) = nword((yyvsp[(1) - (5)].str), &(yylsp[(1) - (5)]));
                (yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)]));
@@ -2746,7 +2748,7 @@ yyreduce:
     break;
 
   case 102:
-#line 505 "ael.y"
+#line 507 "ael.y"
     {
                (yyval.pval) = nword(strdup("default"), &(yylsp[(1) - (5)]));
                (yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)]));
@@ -2754,7 +2756,7 @@ yyreduce:
     break;
 
   case 103:
-#line 509 "ael.y"
+#line 511 "ael.y"
     {
                (yyval.pval) = nword(strdup("default"), &(yylsp[(1) - (5)]));
                (yyval.pval)->next = nword((yyvsp[(3) - (5)].str), &(yylsp[(3) - (5)]));
@@ -2762,24 +2764,24 @@ yyreduce:
     break;
 
   case 104:
-#line 515 "ael.y"
+#line 517 "ael.y"
     { (yyval.str) = strdup("1"); ;}
     break;
 
   case 105:
-#line 516 "ael.y"
+#line 518 "ael.y"
     { (yyval.str) = (yyvsp[(2) - (2)].str); ;}
     break;
 
   case 106:
-#line 520 "ael.y"
+#line 522 "ael.y"
     {                  /* ext[, pri] default 1 */
                (yyval.pval) = nword((yyvsp[(1) - (2)].str), &(yylsp[(1) - (2)]));
                (yyval.pval)->next = nword((yyvsp[(2) - (2)].str), &(yylsp[(2) - (2)])); ;}
     break;
 
   case 107:
-#line 523 "ael.y"
+#line 525 "ael.y"
     {  /* context, ext, pri */
                (yyval.pval) = nword((yyvsp[(4) - (4)].str), &(yylsp[(4) - (4)]));
                (yyval.pval)->next = nword((yyvsp[(1) - (4)].str), &(yylsp[(1) - (4)]));
@@ -2787,12 +2789,12 @@ yyreduce:
     break;
 
   case 108:
-#line 529 "ael.y"
+#line 531 "ael.y"
     {reset_argcount(parseio->scanner);;}
     break;
 
   case 109:
-#line 529 "ael.y"
+#line 531 "ael.y"
     {
                /* XXX original code had @2 but i think we need @5 */
                (yyval.pval) = npval2(PV_MACRO_CALL, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)]));
@@ -2801,19 +2803,19 @@ yyreduce:
     break;
 
   case 110:
-#line 534 "ael.y"
+#line 536 "ael.y"
     {
                (yyval.pval)= npval2(PV_MACRO_CALL, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
                (yyval.pval)->u1.str = (yyvsp[(1) - (3)].str); ;}
     break;
 
   case 111:
-#line 542 "ael.y"
+#line 544 "ael.y"
     {reset_argcount(parseio->scanner);;}
     break;
 
   case 112:
-#line 542 "ael.y"
+#line 544 "ael.y"
     {
                if (strcasecmp((yyvsp[(1) - (3)].str),"goto") == 0) {
                        (yyval.pval) = npval2(PV_GOTO, &(yylsp[(1) - (3)]), &(yylsp[(2) - (3)]));
@@ -2826,7 +2828,7 @@ yyreduce:
     break;
 
   case 113:
-#line 553 "ael.y"
+#line 555 "ael.y"
     {
                (yyval.pval) = update_last((yyvsp[(1) - (3)].pval), &(yylsp[(3) - (3)]));
                if( (yyval.pval)->type == PV_GOTO )
@@ -2837,49 +2839,49 @@ yyreduce:
     break;
 
   case 114:
-#line 560 "ael.y"
+#line 562 "ael.y"
     { (yyval.pval) = update_last((yyvsp[(1) - (2)].pval), &(yylsp[(2) - (2)])); ;}
     break;
 
   case 115:
-#line 563 "ael.y"
+#line 565 "ael.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str) ;}
     break;
 
   case 116:
-#line 564 "ael.y"
+#line 566 "ael.y"
     { (yyval.str) = strdup(""); ;}
     break;
 
   case 117:
-#line 567 "ael.y"
+#line 569 "ael.y"
     { (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;}
     break;
 
   case 118:
-#line 568 "ael.y"
+#line 570 "ael.y"
     {
                (yyval.pval)= npval(PV_WORD,0/*@1.first_line*/,0/*@1.last_line*/,0/* @1.first_column*/, 0/*@1.last_column*/);
                (yyval.pval)->u1.str = strdup(""); ;}
     break;
 
   case 119:
-#line 571 "ael.y"
+#line 573 "ael.y"
     { (yyval.pval) = linku1((yyvsp[(1) - (3)].pval), nword((yyvsp[(3) - (3)].str), &(yylsp[(3) - (3)]))); ;}
     break;
 
   case 120:
-#line 574 "ael.y"
+#line 576 "ael.y"
     { (yyval.pval) = NULL; ;}
     break;
 
   case 121:
-#line 575 "ael.y"
+#line 577 "ael.y"
     { (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
     break;
 
   case 122:
-#line 578 "ael.y"
+#line 580 "ael.y"
     {
                (yyval.pval) = npval2(PV_CASE, &(yylsp[(1) - (4)]), &(yylsp[(3) - (4)])); /* XXX 3 or 4 ? */
                (yyval.pval)->u1.str = (yyvsp[(2) - (4)].str);
@@ -2887,7 +2889,7 @@ yyreduce:
     break;
 
   case 123:
-#line 582 "ael.y"
+#line 584 "ael.y"
     {
                (yyval.pval) = npval2(PV_DEFAULT, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));
                (yyval.pval)->u1.str = NULL;
@@ -2895,7 +2897,7 @@ yyreduce:
     break;
 
   case 124:
-#line 586 "ael.y"
+#line 588 "ael.y"
     {
                (yyval.pval) = npval2(PV_PATTERN, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)])); /* XXX@3 or @4 ? */
                (yyval.pval)->u1.str = (yyvsp[(2) - (4)].str);
@@ -2903,27 +2905,27 @@ yyreduce:
     break;
 
   case 125:
-#line 592 "ael.y"
+#line 594 "ael.y"
     { (yyval.pval) = NULL; ;}
     break;
 
   case 126:
-#line 593 "ael.y"
+#line 595 "ael.y"
     { (yyval.pval) = linku1((yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval)); ;}
     break;
 
   case 127:
-#line 596 "ael.y"
+#line 598 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 128:
-#line 597 "ael.y"
+#line 599 "ael.y"
     { (yyval.pval)=(yyvsp[(1) - (1)].pval);;}
     break;
 
   case 129:
-#line 598 "ael.y"
+#line 600 "ael.y"
     {
                (yyval.pval) = npval2(PV_CATCH, &(yylsp[(1) - (5)]), &(yylsp[(5) - (5)]));
                (yyval.pval)->u1.str = (yyvsp[(2) - (5)].str);
@@ -2931,47 +2933,47 @@ yyreduce:
     break;
 
   case 130:
-#line 604 "ael.y"
+#line 606 "ael.y"
     {
                (yyval.pval) = npval2(PV_SWITCHES, &(yylsp[(1) - (4)]), &(yylsp[(2) - (4)]));
                (yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval); set_dads((yyval.pval),(yyvsp[(3) - (4)].pval));;}
     break;
 
   case 131:
-#line 609 "ael.y"
+#line 611 "ael.y"
     {
                (yyval.pval) = npval2(PV_ESWITCHES, &(yylsp[(1) - (4)]), &(yylsp[(2) - (4)]));
                (yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval); set_dads((yyval.pval),(yyvsp[(3) - (4)].pval));;}
     break;
 
   case 132:
-#line 614 "ael.y"
+#line 616 "ael.y"
     { (yyval.pval) = NULL; ;}
     break;
 
   case 133:
-#line 615 "ael.y"
+#line 617 "ael.y"
     { (yyval.pval) = linku1(nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)])), (yyvsp[(3) - (3)].pval)); ;}
     break;
 
   case 134:
-#line 616 "ael.y"
+#line 618 "ael.y"
     { char *x; asprintf(&x,"%s@%s", (yyvsp[(1) - (5)].str),(yyvsp[(3) - (5)].str)); free((yyvsp[(1) - (5)].str)); free((yyvsp[(3) - (5)].str));
                                                                          (yyval.pval) = linku1(nword(x, &(yylsp[(1) - (5)])), (yyvsp[(5) - (5)].pval));;}
     break;
 
   case 135:
-#line 618 "ael.y"
+#line 620 "ael.y"
     {(yyval.pval)=(yyvsp[(2) - (2)].pval);;}
     break;
 
   case 136:
-#line 621 "ael.y"
+#line 623 "ael.y"
     { (yyval.pval) = nword((yyvsp[(1) - (1)].str), &(yylsp[(1) - (1)])); ;}
     break;
 
   case 137:
-#line 622 "ael.y"
+#line 624 "ael.y"
     {
                (yyval.pval) = nword((yyvsp[(1) - (3)].str), &(yylsp[(1) - (3)]));
                (yyval.pval)->u2.arglist = (yyvsp[(3) - (3)].pval);
@@ -2979,36 +2981,36 @@ yyreduce:
     break;
 
   case 138:
-#line 629 "ael.y"
+#line 631 "ael.y"
     { (yyval.pval) = (yyvsp[(1) - (2)].pval); ;}
     break;
 
   case 139:
-#line 630 "ael.y"
+#line 632 "ael.y"
     { (yyval.pval) = linku1((yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval)); ;}
     break;
 
   case 140:
-#line 631 "ael.y"
+#line 633 "ael.y"
     {(yyval.pval)=(yyvsp[(1) - (2)].pval);;}
     break;
 
   case 141:
-#line 634 "ael.y"
+#line 636 "ael.y"
     {
                (yyval.pval) = npval2(PV_INCLUDES, &(yylsp[(1) - (4)]), &(yylsp[(4) - (4)]));
                (yyval.pval)->u1.list = (yyvsp[(3) - (4)].pval);set_dads((yyval.pval),(yyvsp[(3) - (4)].pval));;}
     break;
 
   case 142:
-#line 637 "ael.y"
+#line 639 "ael.y"
     {
                (yyval.pval) = npval2(PV_INCLUDES, &(yylsp[(1) - (3)]), &(yylsp[(3) - (3)]));;}
     break;
 
 
 /* Line 1270 of yacc.c.  */
-#line 3012 "ael.tab.c"
+#line 3014 "ael.tab.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -3227,7 +3229,7 @@ yyreturn:
 }
 
 
-#line 642 "ael.y"
+#line 644 "ael.y"
 
 
 static char *token_equivs1[] =
index 95b0118..02c09db 100644 (file)
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 54 "ael.y"
+#line 56 "ael.y"
 {
        int     intval;         /* integer value, typically flags */
        char    *str;           /* strings */
index a8df1cb..97558ec 100644 (file)
@@ -31,6 +31,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <string.h>
 
 #include "asterisk/logger.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
 #include "asterisk/ael_structs.h"
 
 pval * linku1(pval *head, pval *tail);
index 26206af..8b74363 100644 (file)
@@ -803,9 +803,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #define GLOB_ABORTED GLOB_ABEND
 #endif
 # include <glob.h>
-
 #include "asterisk/logger.h"
 #include "asterisk/utils.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
 #include "ael/ael.tab.h"
 #include "asterisk/ael_structs.h"
 
@@ -906,7 +907,7 @@ static void pbcwhere(const char *text, int *line, int *col )
 #define        STORE_POS
 #define        STORE_LOC
 #endif
-#line 909 "ael_lex.c"
+#line 911 "ael_lex.c"
 
 #define INITIAL 0
 #define paren 1
@@ -1145,10 +1146,10 @@ YY_DECL
        register int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-#line 187 "ael.flex"
+#line 189 "ael.flex"
 
 
-#line 1151 "ael_lex.c"
+#line 1153 "ael_lex.c"
 
     yylval = yylval_param;
 
@@ -1239,260 +1240,260 @@ do_action:    /* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 189 "ael.flex"
+#line 191 "ael.flex"
 { STORE_POS; return LC;}
        YY_BREAK
 case 2:
 YY_RULE_SETUP
-#line 190 "ael.flex"
+#line 192 "ael.flex"
 { STORE_POS; return RC;}
        YY_BREAK
 case 3:
 YY_RULE_SETUP
-#line 191 "ael.flex"
+#line 193 "ael.flex"
 { STORE_POS; return LP;}
        YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 192 "ael.flex"
+#line 194 "ael.flex"
 { STORE_POS; return RP;}
        YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 193 "ael.flex"
+#line 195 "ael.flex"
 { STORE_POS; return SEMI;}
        YY_BREAK
 case 6:
 YY_RULE_SETUP
-#line 194 "ael.flex"
+#line 196 "ael.flex"
 { STORE_POS; return EQ;}
        YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 195 "ael.flex"
+#line 197 "ael.flex"
 { STORE_POS; return COMMA;}
        YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 196 "ael.flex"
+#line 198 "ael.flex"
 { STORE_POS; return COLON;}
        YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 197 "ael.flex"
+#line 199 "ael.flex"
 { STORE_POS; return AMPER;}
        YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 198 "ael.flex"
+#line 200 "ael.flex"
 { STORE_POS; return BAR;}
        YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 199 "ael.flex"
+#line 201 "ael.flex"
 { STORE_POS; return EXTENMARK;}
        YY_BREAK
 case 12:
 YY_RULE_SETUP
-#line 200 "ael.flex"
+#line 202 "ael.flex"
 { STORE_POS; return AT;}
        YY_BREAK
 case 13:
 YY_RULE_SETUP
-#line 201 "ael.flex"
+#line 203 "ael.flex"
 {/*comment*/}
        YY_BREAK
 case 14:
 YY_RULE_SETUP
-#line 202 "ael.flex"
+#line 204 "ael.flex"
 { STORE_POS; return KW_CONTEXT;}
        YY_BREAK
 case 15:
 YY_RULE_SETUP
-#line 203 "ael.flex"
+#line 205 "ael.flex"
 { STORE_POS; return KW_ABSTRACT;}
        YY_BREAK
 case 16:
 YY_RULE_SETUP
-#line 204 "ael.flex"
+#line 206 "ael.flex"
 { STORE_POS; return KW_EXTEND;}
        YY_BREAK
 case 17:
 YY_RULE_SETUP
-#line 205 "ael.flex"
+#line 207 "ael.flex"
 { STORE_POS; return KW_MACRO;};
        YY_BREAK
 case 18:
 YY_RULE_SETUP
-#line 206 "ael.flex"
+#line 208 "ael.flex"
 { STORE_POS; return KW_GLOBALS;}
        YY_BREAK
 case 19:
 YY_RULE_SETUP
-#line 207 "ael.flex"
+#line 209 "ael.flex"
 { STORE_POS; return KW_LOCAL;}
        YY_BREAK
 case 20:
 YY_RULE_SETUP
-#line 208 "ael.flex"
+#line 210 "ael.flex"
 { STORE_POS; return KW_IGNOREPAT;}
        YY_BREAK
 case 21:
 YY_RULE_SETUP
-#line 209 "ael.flex"
+#line 211 "ael.flex"
 { STORE_POS; return KW_SWITCH;}
        YY_BREAK
 case 22:
 YY_RULE_SETUP
-#line 210 "ael.flex"
+#line 212 "ael.flex"
 { STORE_POS; return KW_IF;}
        YY_BREAK
 case 23:
 YY_RULE_SETUP
-#line 211 "ael.flex"
+#line 213 "ael.flex"
 { STORE_POS; return KW_IFTIME;}
        YY_BREAK
 case 24:
 YY_RULE_SETUP
-#line 212 "ael.flex"
+#line 214 "ael.flex"
 { STORE_POS; return KW_RANDOM;}
        YY_BREAK
 case 25:
 YY_RULE_SETUP
-#line 213 "ael.flex"
+#line 215 "ael.flex"
 { STORE_POS; return KW_REGEXTEN;}
        YY_BREAK
 case 26:
 YY_RULE_SETUP
-#line 214 "ael.flex"
+#line 216 "ael.flex"
 { STORE_POS; return KW_HINT;}
        YY_BREAK
 case 27:
 YY_RULE_SETUP
-#line 215 "ael.flex"
+#line 217 "ael.flex"
 { STORE_POS; return KW_ELSE;}
        YY_BREAK
 case 28:
 YY_RULE_SETUP
-#line 216 "ael.flex"
+#line 218 "ael.flex"
 { STORE_POS; return KW_GOTO;}
        YY_BREAK
 case 29:
 YY_RULE_SETUP
-#line 217 "ael.flex"
+#line 219 "ael.flex"
 { STORE_POS; return KW_JUMP;}
        YY_BREAK
 case 30:
 YY_RULE_SETUP
-#line 218 "ael.flex"
+#line 220 "ael.flex"
 { STORE_POS; return KW_RETURN;}
        YY_BREAK
 case 31:
 YY_RULE_SETUP
-#line 219 "ael.flex"
+#line 221 "ael.flex"
 { STORE_POS; return KW_BREAK;}
        YY_BREAK
 case 32:
 YY_RULE_SETUP
-#line 220 "ael.flex"
+#line 222 "ael.flex"
 { STORE_POS; return KW_CONTINUE;}
        YY_BREAK
 case 33:
 YY_RULE_SETUP
-#line 221 "ael.flex"
+#line 223 "ael.flex"
 { STORE_POS; return KW_FOR;}
        YY_BREAK
 case 34:
 YY_RULE_SETUP
-#line 222 "ael.flex"
+#line 224 "ael.flex"
 { STORE_POS; return KW_WHILE;}
        YY_BREAK
 case 35:
 YY_RULE_SETUP
-#line 223 "ael.flex"
+#line 225 "ael.flex"
 { STORE_POS; return KW_CASE;}
        YY_BREAK
 case 36:
 YY_RULE_SETUP
-#line 224 "ael.flex"
+#line 226 "ael.flex"
 { STORE_POS; return KW_DEFAULT;}
        YY_BREAK
 case 37:
 YY_RULE_SETUP
-#line 225 "ael.flex"
+#line 227 "ael.flex"
 { STORE_POS; return KW_PATTERN;}
        YY_BREAK
 case 38:
 YY_RULE_SETUP
-#line 226 "ael.flex"
+#line 228 "ael.flex"
 { STORE_POS; return KW_CATCH;}
        YY_BREAK
 case 39:
 YY_RULE_SETUP
-#line 227 "ael.flex"
+#line 229 "ael.flex"
 { STORE_POS; return KW_SWITCHES;}
        YY_BREAK
 case 40:
 YY_RULE_SETUP
-#line 228 "ael.flex"
+#line 230 "ael.flex"
 { STORE_POS; return KW_ESWITCHES;}
        YY_BREAK
 case 41:
 YY_RULE_SETUP
-#line 229 "ael.flex"
+#line 231 "ael.flex"
 { STORE_POS; return KW_INCLUDES;}
        YY_BREAK
 case 42:
 YY_RULE_SETUP
-#line 230 "ael.flex"
+#line 232 "ael.flex"
 { BEGIN(comment); my_col += 2; }
        YY_BREAK
 case 43:
 YY_RULE_SETUP
-#line 232 "ael.flex"
+#line 234 "ael.flex"
 { my_col += yyleng; }
        YY_BREAK
 case 44:
 /* rule 44 can match eol */
 YY_RULE_SETUP
-#line 233 "ael.flex"
+#line 235 "ael.flex"
 { ++my_lineno; my_col=1;}
        YY_BREAK
 case 45:
 YY_RULE_SETUP
-#line 234 "ael.flex"
+#line 236 "ael.flex"
 { my_col += yyleng; }
        YY_BREAK
 case 46:
 /* rule 46 can match eol */
 YY_RULE_SETUP
-#line 235 "ael.flex"
+#line 237 "ael.flex"
 { ++my_lineno; my_col=1;}
        YY_BREAK
 case 47:
 YY_RULE_SETUP
-#line 236 "ael.flex"
+#line 238 "ael.flex"
 { my_col += 2; BEGIN(INITIAL); }
        YY_BREAK
 case 48:
 /* rule 48 can match eol */
 YY_RULE_SETUP
-#line 238 "ael.flex"
+#line 240 "ael.flex"
 { my_lineno++; my_col = 1; }
        YY_BREAK
 case 49:
 YY_RULE_SETUP
-#line 239 "ael.flex"
+#line 241 "ael.flex"
 { my_col += yyleng; }
        YY_BREAK
 case 50:
 YY_RULE_SETUP
-#line 240 "ael.flex"
+#line 242 "ael.flex"
 { my_col += (yyleng*8)-(my_col%8); }
        YY_BREAK
 case 51:
 YY_RULE_SETUP
-#line 242 "ael.flex"
+#line 244 "ael.flex"
 {
                STORE_POS;
                yylval->str = strdup(yytext);
@@ -1510,7 +1511,7 @@ YY_RULE_SETUP
 case 52:
 /* rule 52 can match eol */
 YY_RULE_SETUP
-#line 258 "ael.flex"
+#line 260 "ael.flex"
 {
                if ( pbcpop(')') ) {    /* error */
                        STORE_LOC;
@@ -1536,7 +1537,7 @@ YY_RULE_SETUP
 case 53:
 /* rule 53 can match eol */
 YY_RULE_SETUP
-#line 280 "ael.flex"
+#line 282 "ael.flex"
 {
                char c = yytext[yyleng-1];
                if (c == '(')
@@ -1548,7 +1549,7 @@ YY_RULE_SETUP
 case 54:
 /* rule 54 can match eol */
 YY_RULE_SETUP
-#line 288 "ael.flex"
+#line 290 "ael.flex"
 {
                char c = yytext[yyleng-1];
                if ( pbcpop(c))  { /* error */
@@ -1573,7 +1574,7 @@ YY_RULE_SETUP
 case 55:
 /* rule 55 can match eol */
 YY_RULE_SETUP
-#line 310 "ael.flex"
+#line 312 "ael.flex"
 {
                char c = yytext[yyleng-1];
                if (c == '(')
@@ -1585,7 +1586,7 @@ YY_RULE_SETUP
 case 56:
 /* rule 56 can match eol */
 YY_RULE_SETUP
-#line 318 "ael.flex"
+#line 320 "ael.flex"
 {
                if ( pbcpop(')') ) { /* error */
                        STORE_LOC;
@@ -1613,7 +1614,7 @@ YY_RULE_SETUP
 case 57:
 /* rule 57 can match eol */
 YY_RULE_SETUP
-#line 342 "ael.flex"
+#line 344 "ael.flex"
 {
                if( parencount != 0) { /* printf("Folding in a comma!\n"); */
                        yymore();
@@ -1631,7 +1632,7 @@ YY_RULE_SETUP
 case 58:
 /* rule 58 can match eol */
 YY_RULE_SETUP
-#line 356 "ael.flex"
+#line 358 "ael.flex"
 {
                char c = yytext[yyleng-1];
                if ( pbcpop(c) ) { /* error */
@@ -1652,7 +1653,7 @@ YY_RULE_SETUP
 case 59:
 /* rule 59 can match eol */
 YY_RULE_SETUP
-#line 373 "ael.flex"
+#line 375 "ael.flex"
 {
                char c = yytext[yyleng-1];
                yymore();
@@ -1662,7 +1663,7 @@ YY_RULE_SETUP
 case 60:
 /* rule 60 can match eol */
 YY_RULE_SETUP
-#line 379 "ael.flex"
+#line 381 "ael.flex"
 {
                char c = yytext[yyleng-1];
                if ( pbcpop(c) ) { /* error */
@@ -1678,7 +1679,7 @@ YY_RULE_SETUP
 case 61:
 /* rule 61 can match eol */
 YY_RULE_SETUP
-#line 391 "ael.flex"
+#line 393 "ael.flex"
 {
                STORE_LOC;
                yylval->str = strdup(yytext);
@@ -1691,7 +1692,7 @@ YY_RULE_SETUP
 case 62:
 /* rule 62 can match eol */
 YY_RULE_SETUP
-#line 400 "ael.flex"
+#line 402 "ael.flex"
 {
                char fnamebuf[1024],*p1,*p2;
                int glob_ret;
@@ -1741,7 +1742,7 @@ case YY_STATE_EOF(paren):
 case YY_STATE_EOF(semic):
 case YY_STATE_EOF(argg):
 case YY_STATE_EOF(comment):
-#line 445 "ael.flex"
+#line 447 "ael.flex"
 {
                char fnamebuf[2048];
                if (include_stack_index > 0 && include_stack[include_stack_index-1].globbuf_pos < include_stack[include_stack_index-1].globbuf.gl_pathc-1) {
@@ -1778,10 +1779,10 @@ case YY_STATE_EOF(comment):
        YY_BREAK
 case 63:
 YY_RULE_SETUP
-#line 479 "ael.flex"
+#line 481 "ael.flex"
 ECHO;
        YY_BREAK
-#line 1784 "ael_lex.c"
+#line 1786 "ael_lex.c"
 
        case YY_END_OF_BUFFER:
                {
@@ -2906,7 +2907,7 @@ void *ael_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
 
 #define YYTABLES_NAME "yytables"
 
-#line 479 "ael.flex"
+#line 481 "ael.flex"
 
 
 
index 5679404..38748ec 100644 (file)
@@ -3963,7 +3963,7 @@ static void fix_gotos_in_extensions(struct ael_extension *exten)
 }
 
 
-void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root)
+void ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root)
 {
        pval *p,*p2;
        struct ast_context *context;
@@ -3994,7 +3994,7 @@ void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root)
                switch (p->type) {
                case PV_MACRO:
                        
-                       context = ast_context_create(local_contexts, p->u1.str, registrar);
+                       context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
                        
                        exten = new_exten();
                        exten->context = context;
@@ -4032,7 +4032,7 @@ void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root)
                        break;
                        
                case PV_CONTEXT:
-                       context = ast_context_find_or_create(local_contexts, p->u1.str, registrar);
+                       context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
                        
                        /* contexts contain: ignorepat, includes, switches, eswitches, extensions,  */
                        for (p2=p->u2.statements; p2; p2=p2->next) {
index 4c6bb11..5089ffe 100644 (file)
@@ -131,7 +131,7 @@ aelparse.c: $(ASTTOPDIR)/res/ael/ael_lex.c
 
 aelparse.o: ASTCFLAGS+=-I$(ASTTOPDIR)/res -DSTANDALONE_AEL
 
-aelparse: aelparse.o aelbison.o pbx_ael.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o pval.o extconf.o
+aelparse: aelparse.o aelbison.o pbx_ael.o hashtab.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o pval.o extconf.o
 
 astobj2.c: $(ASTTOPDIR)/main/astobj2.c
        @cp $< $@
@@ -155,7 +155,7 @@ hashtest.o: ASTCFLAGS+=-O0
 
 extconf.o: extconf.c
 
-conf2ael: conf2ael.o ast_expr2f.o ast_expr2.o aelbison.o aelparse.o pbx_ael.o pval.o extconf.o strcompat.o
+conf2ael: conf2ael.o ast_expr2f.o ast_expr2.o hashtab.o aelbison.o aelparse.o pbx_ael.o pval.o extconf.o strcompat.o
 
 testexpr2s: $(ASTTOPDIR)/main/ast_expr2f.c $(ASTTOPDIR)/main/ast_expr2.c $(ASTTOPDIR)/main/ast_expr2.h
        $(CC) -g -c -I$(ASTTOPDIR)/include -DSTANDALONE_AEL $(ASTTOPDIR)/main/ast_expr2f.c -o ast_expr2f.o
index 7f20365..24349b4 100644 (file)
@@ -19,6 +19,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/ast_expr.h"
 #include "asterisk/module.h"
 #include "asterisk/app.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
 #include "asterisk/ael_structs.h"
 #include "asterisk/extconf.h"
 
@@ -582,3 +584,34 @@ int main(int argc, char **argv)
        
     return 0;
 }
+
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
+{
+       return 0;
+}
+
+unsigned int ast_hashtab_hash_contexts(const void *obj);
+
+unsigned int ast_hashtab_hash_contexts(const void *obj)
+{
+       return 0;
+}
+
+#ifdef DEBUG_THREADS
+
+void ast_mark_lock_acquired(void *lock_addr)
+{
+}
+
+void ast_remove_lock_info(void *lock_addr)
+{
+}
+
+void ast_store_lock_info(enum ast_lock_type type, const char *filename,
+       int line_num, const char *func, const char *lock_name, void *lock_addr)
+{
+}
+
+#endif
index fa6a3cc..56856ef 100644 (file)
@@ -47,6 +47,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/config.h"
 #include "asterisk/options.h"
 #include "asterisk/callerid.h"
+#include "asterisk/lock.h"
+#include "asterisk/hashtab.h"
 #include "asterisk/ael_structs.h"
 #include "asterisk/devicestate.h"
 #include "asterisk/stringfields.h"
@@ -604,14 +606,7 @@ int ast_context_add_include2(struct ast_context *con, const char *value,
        return localized_context_add_include2(con, value,registrar);
 }
 
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
-{
-       printf("Creating context %s, registrar=%s\n", name, registrar);
-       
-       return localized_context_create(extcontexts, name, registrar);
-}
-
-struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
 {
        printf("find/Creating context %s, registrar=%s\n", name, registrar);
        
@@ -658,9 +653,9 @@ int ast_context_verify_includes(struct ast_context *con)
        return  localized_context_verify_includes(con);
 }
 
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar);
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar);
 
-void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
+void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
 {
        localized_merge_contexts_and_delete(extcontexts, registrar);
 }
@@ -688,3 +683,33 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
        return localized_find_extension(bypass, q, context, exten, priority, label, callerid, action);
 }
 
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
+
+int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
+{
+       return 0;
+}
+
+unsigned int ast_hashtab_hash_contexts(const void *obj);
+
+unsigned int ast_hashtab_hash_contexts(const void *obj)
+{
+       return 0;
+}
+
+#ifdef DEBUG_THREADS
+
+void ast_mark_lock_acquired(void *lock_addr)
+{
+}
+
+void ast_remove_lock_info(void *lock_addr)
+{
+}
+
+void ast_store_lock_info(enum ast_lock_type type, const char *filename,
+       int line_num, const char *func, const char *lock_name, void *lock_addr)
+{
+}
+
+#endif
index 5d4b21e..9903ff2 100644 (file)
@@ -23,6 +23,7 @@
  * for operations outside of asterisk. A huge, awful hack.
  *
  */
+#undef DEBUG_THREADS
 
 #include "asterisk/compat.h"
 #include "asterisk/paths.h"    /* we use AST_CONFIG_DIR */
@@ -65,10 +66,9 @@ struct ast_channel
 #include "asterisk/inline_api.h"
 #include "asterisk/endian.h"
 #include "asterisk/ast_expr.h"
-#include "asterisk/ael_structs.h"
-#include "asterisk/pval.h"
 
 /* logger.h */
+
 #define EVENTLOG "event_log"
 #define        QUEUELOG        "queue_log"
 
@@ -147,1712 +147,1716 @@ void ast_console_toggle_mute(int fd);
 #define __LOG_DTMF  6
 #define LOG_DTMF    __LOG_DTMF, _A_
 
-/* from utils.h */
-
-static unsigned int __unsigned_int_flags_dummy;
+/* lock.h */
 
-struct ast_flags {  /* stolen from utils.h */
-       unsigned int flags;
-};
-#define ast_test_flag(p,flag)          ({ \
-                                       typeof ((p)->flags) __p = (p)->flags; \
-                                       typeof (__unsigned_int_flags_dummy) __x = 0; \
-                                       (void) (&__p == &__x); \
-                                       ((p)->flags & (flag)); \
-                                       })
+#ifndef        HAVE_MTX_PROFILE
+#define        __MTX_PROF(a)   return pthread_mutex_lock((a))
+#else
+#define        __MTX_PROF(a)   do {                    \
+       int i;                                  \
+       /* profile only non-blocking events */  \
+       ast_mark(mtx_prof, 1);                  \
+       i = pthread_mutex_trylock((a));         \
+       ast_mark(mtx_prof, 0);                  \
+       if (!i)                                 \
+               return i;                       \
+       else                                    \
+               return pthread_mutex_lock((a)); \
+       } while (0)
+#endif /* HAVE_MTX_PROFILE */
 
-#define ast_set2_flag(p,value,flag)    do { \
-                                       typeof ((p)->flags) __p = (p)->flags; \
-                                       typeof (__unsigned_int_flags_dummy) __x = 0; \
-                                       (void) (&__p == &__x); \
-                                       if (value) \
-                                               (p)->flags |= (flag); \
-                                       else \
-                                               (p)->flags &= ~(flag); \
-                                       } while (0)
+#define AST_PTHREADT_NULL (pthread_t) -1
+#define AST_PTHREADT_STOP (pthread_t) -2
 
+#if defined(SOLARIS) || defined(BSD)
+#define AST_MUTEX_INIT_W_CONSTRUCTORS
+#endif /* SOLARIS || BSD */
 
-#ifdef __AST_DEBUG_MALLOC
-static void ast_free(void *ptr) attribute_unused;
-static void ast_free(void *ptr)
-{
-       free(ptr);
-}
+/* Asterisk REQUIRES recursive (not error checking) mutexes
+   and will not run without them. */
+#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
+#define PTHREAD_MUTEX_INIT_VALUE       PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+#define AST_MUTEX_KIND                 PTHREAD_MUTEX_RECURSIVE_NP
 #else
-#define ast_free free
-#endif
-
-#ifndef __AST_DEBUG_MALLOC
-
-#define MALLOC_FAILURE_MSG \
-       ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
-/*!
- * \brief A wrapper for malloc()
- *
- * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * The argument and return value are the same as malloc()
- */
-#define ast_malloc(len) \
-       _ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define PTHREAD_MUTEX_INIT_VALUE       PTHREAD_MUTEX_INITIALIZER
+#define AST_MUTEX_KIND                 PTHREAD_MUTEX_RECURSIVE
+#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
 
-AST_INLINE_API(
-void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, const char *func),
-{
-       void *p;
+#ifdef DEBUG_THREADS
 
-       if (!(p = malloc(len)))
-               MALLOC_FAILURE_MSG;
+#define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
 
-       return p;
-}
-)
+#ifdef THREAD_CRASH
+#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
+#else
+#define DO_THREAD_CRASH do { } while (0)
+#endif
 
-/*!
- * \brief A wrapper for calloc()
- *
- * ast_calloc() is a wrapper for calloc() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * The arguments and return value are the same as calloc()
- */
-#define ast_calloc(num, len) \
-       _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
 
-AST_INLINE_API(
-void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func),
-{
-       void *p;
+#define AST_MAX_REENTRANCY 10
 
-       if (!(p = calloc(num, len)))
-               MALLOC_FAILURE_MSG;
+struct ast_mutex_info {
+       pthread_mutex_t mutex;
+       /*! Track which thread holds this lock */
+       unsigned int track:1;
+       const char *file[AST_MAX_REENTRANCY];
+       int lineno[AST_MAX_REENTRANCY];
+       int reentrancy;
+       const char *func[AST_MAX_REENTRANCY];
+       pthread_t thread[AST_MAX_REENTRANCY];
+};
 
-       return p;
-}
-)
+typedef struct ast_mutex_info ast_mutex_t;
 
-/*!
- * \brief A wrapper for calloc() for use in cache pools
- *
- * ast_calloc_cache() is a wrapper for calloc() that will generate an Asterisk log
- * message in the case that the allocation fails. When memory debugging is in use,
- * the memory allocated by this function will be marked as 'cache' so it can be
- * distinguished from normal memory allocations.
- *
- * The arguments and return value are the same as calloc()
- */
-#define ast_calloc_cache(num, len) \
-       _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+typedef pthread_cond_t ast_cond_t;
 
-/*!
- * \brief A wrapper for realloc()
- *
- * ast_realloc() is a wrapper for realloc() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * The arguments and return value are the same as realloc()
- */
-#define ast_realloc(p, len) \
-       _ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+static pthread_mutex_t empty_mutex;
 
-AST_INLINE_API(
-void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
+static void __attribute__((constructor)) init_empty_mutex(void)
 {
-       void *newp;
-
-       if (!(newp = realloc(p, len)))
-               MALLOC_FAILURE_MSG;
-
-       return newp;
+       memset(&empty_mutex, 0, sizeof(empty_mutex));
 }
-)
-
-/*!
- * \brief A wrapper for strdup()
- *
- * ast_strdup() is a wrapper for strdup() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * ast_strdup(), unlike strdup(), can safely accept a NULL argument. If a NULL
- * argument is provided, ast_strdup will return NULL without generating any
- * kind of error log message.
- *
- * The argument and return value are the same as strdup()
- */
-#define ast_strdup(str) \
-       _ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-AST_INLINE_API(
-char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func),
+static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
+                                               const char *mutex_name, ast_mutex_t *t,
+                                               pthread_mutexattr_t *attr) 
 {
-       char *newstr = NULL;
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+       int canlog = strcmp(filename, "logger.c");
 
-       if (str) {
-               if (!(newstr = strdup(str)))
-                       MALLOC_FAILURE_MSG;
+       if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               if ((t->mutex) != (empty_mutex)) {
+                       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
+                                          filename, lineno, func, mutex_name);
+                       __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
+                                          t->file[0], t->lineno[0], t->func[0], mutex_name);
+                       DO_THREAD_CRASH;
+                       return 0;
+               }
        }
+#endif
 
-       return newstr;
-}
-)
+       t->file[0] = filename;
+       t->lineno[0] = lineno;
+       t->func[0] = func;
+       t->thread[0]  = 0;
+       t->reentrancy = 0;
 
-/*!
- * \brief A wrapper for strndup()
- *
- * ast_strndup() is a wrapper for strndup() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * ast_strndup(), unlike strndup(), can safely accept a NULL argument for the
- * string to duplicate. If a NULL argument is provided, ast_strdup will return  
- * NULL without generating any kind of error log message.
- *
- * The arguments and return value are the same as strndup()
- */
-#define ast_strndup(str, len) \
-       _ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+       return pthread_mutex_init(&t->mutex, attr);
+}
 
-AST_INLINE_API(
-char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
+static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
+                                          const char *mutex_name, ast_mutex_t *t)
 {
-       char *newstr = NULL;
+       static pthread_mutexattr_t  attr;
 
-       if (str) {
-               if (!(newstr = strndup(str, len)))
-                       MALLOC_FAILURE_MSG;
-       }
+       pthread_mutexattr_init(&attr);
+       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
 
-       return newstr;
+       return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
 }
-)
-
-/*!
- * \brief A wrapper for asprintf()
- *
- * ast_asprintf() is a wrapper for asprintf() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * The arguments and return value are the same as asprintf()
- */
-#define ast_asprintf(ret, fmt, ...) \
-       _ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
+#define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
 
-AST_INLINE_API(
-int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...),
+static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
+                                               const char *mutex_name, ast_mutex_t *t)
 {
        int res;
-       va_list ap;
+       int canlog = strcmp(filename, "logger.c");
 
-       va_start(ap, fmt);
-       if ((res = vasprintf(ret, fmt, ap)) == -1)
-               MALLOC_FAILURE_MSG;
-       va_end(ap);
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+                                  filename, lineno, func, mutex_name);
+       }
+#endif
+
+       res = pthread_mutex_trylock(&t->mutex);
+       switch (res) {
+       case 0:
+               pthread_mutex_unlock(&t->mutex);
+               break;
+       case EINVAL:
+               __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
+                                 filename, lineno, func, mutex_name);
+               break;
+       case EBUSY:
+               __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
+                                  filename, lineno, func, mutex_name);
+               __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
+                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+               break;
+       }
+
+       if ((res = pthread_mutex_destroy(&t->mutex)))
+               __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
+                                  filename, lineno, func, strerror(res));
+#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+       else
+               t->mutex = PTHREAD_MUTEX_INIT_VALUE;
+#endif
+       t->file[0] = filename;
+       t->lineno[0] = lineno;
+       t->func[0] = func;
 
        return res;
 }
-)
-
-/*!
- * \brief A wrapper for vasprintf()
- *
- * ast_vasprintf() is a wrapper for vasprintf() that will generate an Asterisk log
- * message in the case that the allocation fails.
- *
- * The arguments and return value are the same as vasprintf()
- */
-#define ast_vasprintf(ret, fmt, ap) \
-       _ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
 
-AST_INLINE_API(
-int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, va_list ap),
+static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
+                                           const char* mutex_name, ast_mutex_t *t)
 {
        int res;
+       int canlog = strcmp(filename, "logger.c");
 
-       if ((res = vasprintf(ret, fmt, ap)) == -1)
-               MALLOC_FAILURE_MSG;
-
-       return res;
-}
-)
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
+       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+                                filename, lineno, func, mutex_name);
+               ast_mutex_init(t);
+       }
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
+#ifdef DETECT_DEADLOCKS
+       {
+               time_t seconds = time(NULL);
+               time_t current;
+               do {
+#ifdef HAVE_MTX_PROFILE
+                       ast_mark(mtx_prof, 1);
+#endif
+                       res = pthread_mutex_trylock(&t->mutex);
+#ifdef HAVE_MTX_PROFILE
+                       ast_mark(mtx_prof, 0);
+#endif
+                       if (res == EBUSY) {
+                               current = time(NULL);
+                               if ((current - seconds) && (!((current - seconds) % 5))) {
+                                       __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
+                                                          filename, lineno, func, (int)(current - seconds), mutex_name);
+                                       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+                                                          t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
+                                                          t->func[t->reentrancy-1], mutex_name);
+                               }
+                               usleep(200);
+                       }
+               } while (res == EBUSY);
+       }
 #else
+#ifdef HAVE_MTX_PROFILE
+       ast_mark(mtx_prof, 1);
+       res = pthread_mutex_trylock(&t->mutex);
+       ast_mark(mtx_prof, 0);
+       if (res)
+#endif
+       res = pthread_mutex_lock(&t->mutex);
+#endif /* DETECT_DEADLOCKS */
 
-/* If astmm is in use, let it handle these.  Otherwise, it will report that
-   all allocations are coming from this header file */
+       if (!res) {
+               if (t->reentrancy < AST_MAX_REENTRANCY) {
+                       t->file[t->reentrancy] = filename;
+                       t->lineno[t->reentrancy] = lineno;
+                       t->func[t->reentrancy] = func;
+                       t->thread[t->reentrancy] = pthread_self();
+                       t->reentrancy++;
+               } else {
+                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+                                                          filename, lineno, func, mutex_name);
+               }
+       } else {
+               __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
+                                  filename, lineno, func, strerror(errno));
+               DO_THREAD_CRASH;
+       }
 
-#define ast_malloc(a)          malloc(a)
-#define ast_calloc(a,b)                calloc(a,b)
-#define ast_realloc(a,b)       realloc(a,b)
-#define ast_strdup(a)          strdup(a)
-#define ast_strndup(a,b)       strndup(a,b)
-#define ast_asprintf(a,b,c)    asprintf(a,b,c)
-#define ast_vasprintf(a,b,c)   vasprintf(a,b,c)
+       return res;
+}
 
-#endif /* AST_DEBUG_MALLOC */
+static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
+                                              const char* mutex_name, ast_mutex_t *t)
+{
+       int res;
+       int canlog = strcmp(filename, "logger.c");
 
-#if !defined(ast_strdupa) && defined(__GNUC__)
-/*!
-  \brief duplicate a string in memory from the stack
-  \param s The string to duplicate
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
+       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+                                  filename, lineno, func, mutex_name);
+               ast_mutex_init(t);
+       }
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-  This macro will duplicate the given string.  It returns a pointer to the stack
-  allocatted memory for the new string.
-*/
-#define ast_strdupa(s)                                                    \
-       (__extension__                                                    \
-       ({                                                                \
-               const char *__old = (s);                                  \
-               size_t __len = strlen(__old) + 1;                         \
-               char *__new = __builtin_alloca(__len);                    \
-               memcpy (__new, __old, __len);                             \
-               __new;                                                    \
-       }))
-#endif
+       if (!(res = pthread_mutex_trylock(&t->mutex))) {
+               if (t->reentrancy < AST_MAX_REENTRANCY) {
+                       t->file[t->reentrancy] = filename;
+                       t->lineno[t->reentrancy] = lineno;
+                       t->func[t->reentrancy] = func;
+                       t->thread[t->reentrancy] = pthread_self();
+                       t->reentrancy++;
+               } else {
+                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+                                          filename, lineno, func, mutex_name);
+               }
+       } else {
+               __ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n",
+                                   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+       }
 
+       return res;
+}
 
-/* from config.c */
+static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
+                                            const char *mutex_name, ast_mutex_t *t)
+{
+       int res;
+       int canlog = strcmp(filename, "logger.c");
 
-#define MAX_NESTED_COMMENTS 128
-#define COMMENT_START ";--"
-#define COMMENT_END "--;"
-#define COMMENT_META ';'
-#define COMMENT_TAG '-'
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+                                  filename, lineno, func, mutex_name);
+       }
+#endif
 
-static char *extconfig_conf = "extconfig.conf";
+       if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
+               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+                                  filename, lineno, func, mutex_name);
+               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+               DO_THREAD_CRASH;
+       }
 
-/*! 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 */
+       if (--t->reentrancy < 0) {
+               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
+                                  filename, lineno, func, mutex_name);
+               t->reentrancy = 0;
+       }
 
-static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
-static int  lline_buffer_size;
+       if (t->reentrancy < AST_MAX_REENTRANCY) {
+               t->file[t->reentrancy] = NULL;
+               t->lineno[t->reentrancy] = 0;
+               t->func[t->reentrancy] = NULL;
+               t->thread[t->reentrancy] = 0;
+       }
 
-#define CB_INCR 250
+       if ((res = pthread_mutex_unlock(&t->mutex))) {
+               __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
+                                  filename, lineno, func, strerror(res));
+               DO_THREAD_CRASH;
+       }
 
-struct ast_comment {
-       struct ast_comment *next;
-       char cmt[0];
-};
+       return res;
+}
 
-static void CB_INIT(void)
+static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
+                                 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
 {
-       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)
-                       return;
-               lline_buffer[0] = 0;
-               lline_buffer_size = CB_INCR;
-       } else {
-               comment_buffer[0] = 0;
-               lline_buffer[0] = 0;
-       }
+       return pthread_cond_init(cond, cond_attr);
 }
 
-static void  CB_ADD(char *str)
+static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
+                                   const char *cond_name, ast_cond_t *cond)
 {
-       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)
-                       return;
-               comment_buffer_size += CB_INCR+siz+1;
-       }
-       strcat(comment_buffer,str);
+       return pthread_cond_signal(cond);
 }
 
-static void  CB_ADD_LEN(char *str, int len)
+static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
+                                      const char *cond_name, ast_cond_t *cond)
 {
-       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)
-                       return;
-               comment_buffer_size += CB_INCR+len+1;
-       }
-       strncat(comment_buffer,str,len); /* safe */
-       comment_buffer[cbl+len-1] = 0;
+       return pthread_cond_broadcast(cond);
 }
 
-static void  LLB_ADD(char *str)
+static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
+                                    const char *cond_name, ast_cond_t *cond)
 {
-       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) 
-                       return;
-               lline_buffer_size += CB_INCR + siz + 1;
-       }
-       strcat(lline_buffer,str);
-}
-
-static void CB_RESET(void )  
-{ 
-       comment_buffer[0] = 0; 
-       lline_buffer[0] = 0;
+       return pthread_cond_destroy(cond);
 }
-               
-/*! \brief Keep track of how many threads are currently trying to wait*() on
- *  a child process */
-static unsigned int safe_system_level = 0;
-static void *safe_system_prev_handler;
 
-/*! \brief NULL handler so we can collect the child exit status */
-static void null_sig_handler(int signal)
+static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
+                                 const char *cond_name, const char *mutex_name,
+                                 ast_cond_t *cond, ast_mutex_t *t)
 {
+       int res;
+       int canlog = strcmp(filename, "logger.c");
 
-}
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+                                  filename, lineno, func, mutex_name);
+       }
+#endif
 
-void ast_replace_sigchld(void);
+       if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
+               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+                                  filename, lineno, func, mutex_name);
+               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+               DO_THREAD_CRASH;
+       }
 
-void ast_replace_sigchld(void)
-{
-       unsigned int level;
+       if (--t->reentrancy < 0) {
+               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
+                                  filename, lineno, func, mutex_name);
+               t->reentrancy = 0;
+       }
 
-       level = safe_system_level++;
+       if (t->reentrancy < AST_MAX_REENTRANCY) {
+               t->file[t->reentrancy] = NULL;
+               t->lineno[t->reentrancy] = 0;
+               t->func[t->reentrancy] = NULL;
+               t->thread[t->reentrancy] = 0;
+       }
 
-       /* only replace the handler if it has not already been done */
-       if (level == 0)
-               safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
+       if ((res = pthread_cond_wait(cond, &t->mutex))) {
+               __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
+                                  filename, lineno, func, strerror(res));
+               DO_THREAD_CRASH;
+       } else {
+               if (t->reentrancy < AST_MAX_REENTRANCY) {
+                       t->file[t->reentrancy] = filename;
+                       t->lineno[t->reentrancy] = lineno;
+                       t->func[t->reentrancy] = func;
+                       t->thread[t->reentrancy] = pthread_self();
+                       t->reentrancy++;
+               } else {
+                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+                                                          filename, lineno, func, mutex_name);
+               }
+       }
 
+       return res;
 }
 
-void ast_unreplace_sigchld(void);
-
-void ast_unreplace_sigchld(void)
+static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
+                                      const char *cond_name, const char *mutex_name, ast_cond_t *cond,
+                                      ast_mutex_t *t, const struct timespec *abstime)
 {
-       unsigned int level;
+       int res;
+       int canlog = strcmp(filename, "logger.c");
 
-       level = --safe_system_level;
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+                                  filename, lineno, func, mutex_name);
+       }
+#endif
 
-       /* only restore the handler if we are the last one */
-       if (level == 0)
-               signal(SIGCHLD, safe_system_prev_handler);
+       if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
+               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+                                  filename, lineno, func, mutex_name);
+               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+               DO_THREAD_CRASH;
+       }
+
+       if (--t->reentrancy < 0) {
+               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
+                                  filename, lineno, func, mutex_name);
+               t->reentrancy = 0;
+       }
+
+       if (t->reentrancy < AST_MAX_REENTRANCY) {
+               t->file[t->reentrancy] = NULL;
+               t->lineno[t->reentrancy] = 0;
+               t->func[t->reentrancy] = NULL;
+               t->thread[t->reentrancy] = 0;
+       }
+
+       if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
+               __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
+                                  filename, lineno, func, strerror(res));
+               DO_THREAD_CRASH;
+       } else {
+               if (t->reentrancy < AST_MAX_REENTRANCY) {
+                       t->file[t->reentrancy] = filename;
+                       t->lineno[t->reentrancy] = lineno;
+                       t->func[t->reentrancy] = func;
+                       t->thread[t->reentrancy] = pthread_self();
+                       t->reentrancy++;
+               } else {
+                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+                                                          filename, lineno, func, mutex_name);
+               }
+       }
 
+       return res;
 }
 
-int ast_safe_system(const char *s);
+#define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
+#define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
+#define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
+#define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
+#define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
+#define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
+#define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
+#define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
+#define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
+#define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
 
-int ast_safe_system(const char *s)
+#else /* !DEBUG_THREADS */
+
+
+typedef pthread_mutex_t ast_mutex_t;
+
+#define AST_MUTEX_INIT_VALUE   ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
+
+static inline int ast_mutex_init(ast_mutex_t *pmutex)
 {
-       pid_t pid;
-#ifdef HAVE_WORKING_FORK
-       int x;
-#endif
-       int res;
-       struct rusage rusage;
-       int status;
+       pthread_mutexattr_t attr;
 
-#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
-       ast_replace_sigchld();
+       pthread_mutexattr_init(&attr);
+       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
 
-#ifdef HAVE_WORKING_FORK
-       pid = fork();
-#else
-       pid = vfork();
-#endif 
+       return pthread_mutex_init(pmutex, &attr);
+}
 
-       if (pid == 0) {
-#ifdef HAVE_WORKING_FORK
-               /* Close file descriptors and launch system command */
-               for (x = STDERR_FILENO + 1; x < 4096; x++)
-                       close(x);
-#endif
-               execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
-               _exit(1);
-       } else if (pid > 0) {
-               for(;;) {
-                       res = wait4(pid, &status, 0, &rusage);
-                       if (res > -1) {
-                               res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
-                               break;
-                       } else if (errno != EINTR) 
-                               break;
-               }
-       } else {
-               ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
-               res = -1;
-       }
+#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
 
-       ast_unreplace_sigchld();
-#else
-       res = -1;
-#endif
+static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
+{
+       return pthread_mutex_unlock(pmutex);
+}
 
-       return res;
+static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
+{
+       return pthread_mutex_destroy(pmutex);
 }
 
-static struct ast_comment *ALLOC_COMMENT(const char *buffer)
-{ 
-       struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
-       strcpy(x->cmt, buffer);
-       return x;
+static inline int ast_mutex_lock(ast_mutex_t *pmutex)
+{
+       __MTX_PROF(pmutex);
 }
 
-static struct ast_config_map {
-       struct ast_config_map *next;
-       char *name;
-       char *driver;
-       char *database;
-       char *table;
-       char stuff[0];
-} *config_maps = NULL;
+static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
+{
+       return pthread_mutex_trylock(pmutex);
+}
 
-static struct ast_config_engine *config_engine_list;
+typedef pthread_cond_t ast_cond_t;
 
-#define MAX_INCLUDE_LEVEL 10
+static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
+{
+       return pthread_cond_init(cond, cond_attr);
+}
 
+static inline int ast_cond_signal(ast_cond_t *cond)
+{
+       return pthread_cond_signal(cond);
+}
 
-struct ast_category {
-       char name[80];
-       int ignored;                    /*!< do not let user of the config see this category */
-       int include_level;      
-    char *file;                /*!< the file name from whence this declaration was read */
-    int lineno;
-       struct ast_comment *precomments;
-       struct ast_comment *sameline;
-       struct ast_variable *root;
-       struct ast_variable *last;
-       struct ast_category *next;
-};
-
-struct ast_config {
-       struct ast_category *root;
-       struct ast_category *last;
-       struct ast_category *current;
-       struct ast_category *last_browse;               /*!< used to cache the last category supplied via category_browse */
-       int include_level;
-       int max_include_level;
-    struct ast_config_include *includes;  /*!< a list of inclusions, which should describe the entire tree */
-};
-
-struct ast_config_include {
-       char *include_location_file;     /*!< file name in which the include occurs */
-       int  include_location_lineno;    /*!< lineno where include occurred */
-       int  exec;                       /*!< set to non-zero if itsa #exec statement */
-       char *exec_file;                 /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
-       char *included_file;             /*!< file name included */
-       int inclusion_count;             /*!< if the file is included more than once, a running count thereof -- but, worry not,
-                                                                          we explode the instances and will include those-- so all entries will be unique */
-       int output;                      /*!< a flag to indicate if the inclusion has been output */
-       struct ast_config_include *next; /*!< ptr to next inclusion in the list */
-};
-
-typedef struct ast_config *config_load_func(const char *database, const char *table, const char *configfile, struct ast_config *config, int withcomments, const char *suggested_include_file);
-typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
-typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
-typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
-
-/*! \brief Configuration engine structure, used to define realtime drivers */
-struct ast_config_engine {
-       char *name;
-       config_load_func *load_func;
-       realtime_var_get *realtime_func;
-       realtime_multi_get *realtime_multi_func;
-       realtime_update *update_func;
-       struct ast_config_engine *next;
-};
-
-static struct ast_config_engine *config_engine_list;
-
-/* taken from strings.h */
-
-static force_inline int ast_strlen_zero(const char *s)
+static inline int ast_cond_broadcast(ast_cond_t *cond)
 {
-       return (!s || (*s == '\0'));
+       return pthread_cond_broadcast(cond);
 }
 
-#define S_OR(a, b)     (!ast_strlen_zero(a) ? (a) : (b))
-
-AST_INLINE_API(
-void ast_copy_string(char *dst, const char *src, size_t size),
+static inline int ast_cond_destroy(ast_cond_t *cond)
 {
-       while (*src && size) {
-               *dst++ = *src++;
-               size--;
-       }
-       if (__builtin_expect(!size, 0))
-               dst--;
-       *dst = '\0';
+       return pthread_cond_destroy(cond);
 }
-)
 
-AST_INLINE_API(
-char *ast_skip_blanks(const char *str),
+static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
 {
-       while (*str && *str < 33)
-               str++;
-       return (char *)str;
+       return pthread_cond_wait(cond, t);
 }
-)
 
-/*!
-  \brief Trims trailing whitespace characters from a string.
-  \param ast_trim_blanks function being used
-  \param str the input string
-  \return a pointer to the modified string
- */
-AST_INLINE_API(
-char *ast_trim_blanks(char *str),
+static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
 {
-       char *work = str;
+       return pthread_cond_timedwait(cond, t, abstime);
+}
 
-       if (work) {
-               work += strlen(work) - 1;
-               /* It's tempting to only want to erase after we exit this loop, 
-                  but since ast_trim_blanks *could* receive a constant string
-                  (which we presumably wouldn't have to touch), we shouldn't
-                  actually set anything unless we must, and it's easier just
-                  to set each position to \0 than to keep track of a variable
-                  for it */
-               while ((work >= str) && *work < 33)
-                       *(work--) = '\0';
-       }
-       return str;
+#endif /* !DEBUG_THREADS */
+
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
+/* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
+ constructors/destructors to create/destroy mutexes.  */
+#define __AST_MUTEX_DEFINE(scope, mutex) \
+       scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
+static void  __attribute__ ((constructor)) init_##mutex(void) \
+{ \
+       ast_mutex_init(&mutex); \
+} \
+static void  __attribute__ ((destructor)) fini_##mutex(void) \
+{ \
+       ast_mutex_destroy(&mutex); \
 }
-)
+#else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
+/* By default, use static initialization of mutexes. */ 
+#define __AST_MUTEX_DEFINE(scope, mutex) \
+       scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-/*!
-  \brief Strip leading/trailing whitespace from a string.
-  \param s The string to be stripped (will be modified).
-  \return The stripped string.
+#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
+#define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
+#define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
+#define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
+#define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
+#define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
+#define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
+#define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
+#define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
+#define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
+#define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
+#define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
+#define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
 
-  This functions strips all leading and trailing whitespace
-  characters from the input string, and returns a pointer to
-  the resulting string. The string is modified in place.
-*/
-AST_INLINE_API(
-char *ast_strip(char *s),
-{
-       s = ast_skip_blanks(s);
-       if (s)
-               ast_trim_blanks(s);
-       return s;
-} 
-)
+#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
 
+#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
 
-/* from config.h */
+#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
 
-struct ast_variable {
-       char *name;
-       char *value;
-       char *file;
-       int lineno;
-       int object;             /*!< 0 for variable, 1 for object */
-       int blanklines;         /*!< Number of blanklines following entry */
-       struct ast_comment *precomments;
-       struct ast_comment *sameline;
-       struct ast_variable *next;
-       char stuff[0];
-};
+#ifndef __linux__
+#define pthread_create __use_ast_pthread_create_instead__
+#endif
 
-static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable);
-static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_include_file);
+typedef pthread_rwlock_t ast_rwlock_t;
 
-struct ast_config *localized_config_load_with_comments(const char *filename);
-static char *ast_category_browse(struct ast_config *config, const char *prev);
-static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
-static void ast_variables_destroy(struct ast_variable *v);
-static void ast_config_destroy(struct ast_config *cfg);
-static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size);
-static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file);
-void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file);
+static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
+{
+       pthread_rwlockattr_t attr;
 
-static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
+       pthread_rwlockattr_init(&attr);
 
-static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename) 
+#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
+       pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
+#endif
+
+       return pthread_rwlock_init(prwlock, &attr);
+}
+
+static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
 {
-       struct ast_variable *variable;
-       int name_len = strlen(name) + 1;        
+       return pthread_rwlock_destroy(prwlock);
+}
 
-       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->value + strlen(value) + 1;           
-               strcpy(variable->name,name);
-               strcpy(variable->value,value);
-               strcpy(variable->file,filename);
-       }
+static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
+{
+       return pthread_rwlock_unlock(prwlock);
+}
 
-       return variable;
+static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
+{
+       return pthread_rwlock_rdlock(prwlock);
 }
 
-static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
+static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
 {
-       /* a file should be included ONCE. Otherwise, if one of the instances is changed,
-       then all be changed. -- how do we know to include it? -- Handling modified 
-       instances is possible, I'd have
-       to create a new master for each instance. */
-       struct ast_config_include *inc;
-    
-       inc = ast_include_find(conf, included_file);
-       if (inc)
-       {
-               inc->inclusion_count++;
-               snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
-               ast_log(LOG_WARNING,"'%s', line %d:  Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
-       } else
-               *real_included_file_name = 0;
-       
-       inc = ast_calloc(1,sizeof(struct ast_config_include));
-       inc->include_location_file = ast_strdup(from_file);
-       inc->include_location_lineno = from_lineno;
-       if (!ast_strlen_zero(real_included_file_name))
-               inc->included_file = ast_strdup(real_included_file_name);
-       else
-               inc->included_file = ast_strdup(included_file);
-       
-       inc->exec = is_exec;
-       if (is_exec)
-               inc->exec_file = ast_strdup(exec_file);
-       
-       /* attach this new struct to the conf struct */
-       inc->next = conf->includes;
-       conf->includes = inc;
-    
-       return inc;
+       return pthread_rwlock_tryrdlock(prwlock);
 }
 
-void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
+static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
 {
-       struct ast_config_include *incl;
-       struct ast_category *cat;
-       struct ast_variable *v;
-    
-       int from_len = strlen(from_file);
-       int to_len = strlen(to_file);
-    
-       if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
-               return;
-       
-       /* the manager code allows you to read in one config file, then
-       write it back out under a different name. But, the new arrangement
-          ties output lines to the file name. So, before you try to write
-       the config file to disk, better riffle thru the data and make sure
-       the file names are changed.
-       */
-       /* file names are on categories, includes (of course), and on variables. So,
-          traverse all this and swap names */
-       
-       for (incl = conf->includes; incl; incl=incl->next) {
-               if (strcmp(incl->include_location_file,from_file) == 0) {
-                       if (from_len >= to_len)
-                               strcpy(incl->include_location_file, to_file);
-                       else {
-                               free(incl->include_location_file);
-                               incl->include_location_file = strdup(to_file);
-                       }
-               }
-       }
-       for (cat = conf->root; cat; cat = cat->next) {
-               if (strcmp(cat->file,from_file) == 0) {
-                       if (from_len >= to_len)
-                               strcpy(cat->file, to_file);
-                       else {
-                               free(cat->file);
-                               cat->file = strdup(to_file);
-                       }
-               }
-               for (v = cat->root; v; v = v->next) {
-                       if (strcmp(v->file,from_file) == 0) {
-                               if (from_len >= to_len)
-                                       strcpy(v->file, to_file);
-                               else {
-                                       free(v->file);
-                                       v->file = strdup(to_file);
-                               }
-                       }
-               }
-       }
+       return pthread_rwlock_wrlock(prwlock);
 }
 
-static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
+static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
 {
-       struct ast_config_include *x;
-       for (x=conf->includes;x;x=x->next)
-       {
-               if (strcmp(x->included_file,included_file) == 0)
-                       return x;
-       }
-       return 0;
+       return pthread_rwlock_trywrlock(prwlock);
 }
 
+/* Statically declared read/write locks */
 
-static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
-
-static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
-{
-       if (!variable)
-               return;
-       if (category->last)
-               category->last->next = variable;
-       else
-               category->root = variable;
-       category->last = variable;
-       while (category->last->next)
-               category->last = category->last->next;
+#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
+#define __AST_RWLOCK_DEFINE(scope, rwlock) \
+        scope ast_rwlock_t rwlock; \
+static void  __attribute__ ((constructor)) init_##rwlock(void) \
+{ \
+        ast_rwlock_init(&rwlock); \
+} \
+static void  __attribute__ ((destructor)) fini_##rwlock(void) \
+{ \
+        ast_rwlock_destroy(&rwlock); \
 }
+#else
+#define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
+#define __AST_RWLOCK_DEFINE(scope, rwlock) \
+        scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
+#endif
 
-static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
-
-static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
-{
-       struct ast_category *cat;
+#define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
 
-       /* try exact match first, then case-insensitive match */
-       for (cat = config->root; cat; cat = cat->next) {
-               if (cat->name == category_name && (ignored || !cat->ignored))
-                       return cat;
-       }
+/*
+ * Initial support for atomic instructions.
+ * For platforms that have it, use the native cpu instruction to
+ * implement them. For other platforms, resort to a 'slow' version
+ * (defined in utils.c) that protects the atomic instruction with
+ * a single lock.
+ * The slow versions is always available, for testing purposes,
+ * as ast_atomic_fetchadd_int_slow()
+ */
 
-       for (cat = config->root; cat; cat = cat->next) {
-               if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
-                       return cat;
-       }
+#if defined(HAVE_OSX_ATOMICS)
+#include "libkern/OSAtomic.h"
+#endif
 
-       return NULL;
-}
+/*! \brief Atomically add v to *p and return * the previous value of *p.
+ * This can be used to handle reference counts, and the return value
+ * can be used to generate unique identifiers.
+ */
 
-static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
+#if defined(HAVE_GCC_ATOMICS)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
 {
-       return category_get(config, category_name, 0);
+       return __sync_fetch_and_add(p, v);
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+       return OSAtomicAdd32(v, (int32_t *) p);
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+       return OSAtomicAdd64(v, (int64_t *) p);
+#elif defined (__i386__) || defined(__x86_64__)
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+       __asm __volatile (
+       "       lock   xaddl   %0, %1 ;        "
+       : "+r" (v),                     /* 0 (result) */   
+         "=m" (*p)                     /* 1 */
+       : "m" (*p));                    /* 2 */
+       return (v);
+})
+#else
+static int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
+{
+       int ret;
+       ret = *p;
+       *p += v;
+       return ret;
 }
+AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
+{
+       return ast_atomic_fetchadd_int_slow(p, v);
+})
+#endif
 
-static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
+/*! \brief decrement *p by 1 and return true if the variable has reached 0.
+ * Useful e.g. to check if a refcount has reached 0.
+ */
+#if defined(HAVE_GCC_ATOMICS)
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
 {
-       struct ast_category *cat = NULL;
+       return __sync_sub_and_fetch(p, 1) == 0;
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+       return OSAtomicAdd32( -1, (int32_t *) p) == 0;
+})
+#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+       return OSAtomicAdd64( -1, (int64_t *) p) == 0;
+#else
+AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
+{
+       int a = ast_atomic_fetchadd_int(p, -1);
+       return a == 1; /* true if the value is 0 now (so it was 1 previously) */
+})
+#endif
 
-       if (category && config->last_browse && (config->last_browse->name == category))
-               cat = config->last_browse;
-       else
-               cat = ast_category_get(config, category);
+#ifndef DEBUG_CHANNEL_LOCKS
+/*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
+       in the Makefile, print relevant output for debugging */
+#define ast_channel_lock(x)            ast_mutex_lock(&x->lock)
+/*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
+       in the Makefile, print relevant output for debugging */
+#define ast_channel_unlock(x)          ast_mutex_unlock(&x->lock)
+/*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
+       in the Makefile, print relevant output for debugging */
+#define ast_channel_trylock(x)         ast_mutex_trylock(&x->lock)
+#else
 
-       return (cat) ? cat->root : NULL;
-}
+/*! \brief Lock AST channel (and print debugging output)
+\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
+int ast_channel_lock(struct ast_channel *chan);
 
-static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
-{
-       struct ast_variable *v;
+/*! \brief Unlock AST channel (and print debugging output)
+\note You need to enable DEBUG_CHANNEL_LOCKS for this function
+*/
+int ast_channel_unlock(struct ast_channel *chan);
 
-       if (category) {
-               for (v = ast_variable_browse(config, category); v; v = v->next) {
-                       if (!strcasecmp(variable, v->name))
-                               return v->value;
-               }
-       } else {
-               struct ast_category *cat;
+/*! \brief Lock AST channel (and print debugging output)
+\note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
+int ast_channel_trylock(struct ast_channel *chan);
+#endif
 
-               for (cat = config->root; cat; cat = cat->next)
-                       for (v = cat->root; v; v = v->next)
-                               if (!strcasecmp(variable, v->name))
-                                       return v->value;
-       }
 
-       return NULL;
-}
+#include "asterisk/hashtab.h"
+#include "asterisk/ael_structs.h"
+#include "asterisk/pval.h"
 
-static struct ast_variable *variable_clone(const struct ast_variable *old)
-{
-       struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
+/* from utils.h */
 
-       if (new) {
-               new->lineno = old->lineno;
-               new->object = old->object;
-               new->blanklines = old->blanklines;
-               /* TODO: clone comments? */
-       }
+static unsigned int __unsigned_int_flags_dummy;
 
-       return new;
-}
-static void ast_variables_destroy(struct ast_variable *v)
-{
-       struct ast_variable *vn;
+struct ast_flags {  /* stolen from utils.h */
+       unsigned int flags;
+};
+#define ast_test_flag(p,flag)          ({ \
+                                       typeof ((p)->flags) __p = (p)->flags; \
+                                       typeof (__unsigned_int_flags_dummy) __x = 0; \
+                                       (void) (&__p == &__x); \
+                                       ((p)->flags & (flag)); \
+                                       })
 
-       while (v) {
-               vn = v;
-               v = v->next;
-               free(vn);
-       }
+#define ast_set2_flag(p,value,flag)    do { \
+                                       typeof ((p)->flags) __p = (p)->flags; \
+                                       typeof (__unsigned_int_flags_dummy) __x = 0; \
+                                       (void) (&__p == &__x); \
+                                       if (value) \
+                                               (p)->flags |= (flag); \
+                                       else \
+                                               (p)->flags &= ~(flag); \
+                                       } while (0)
+
+
+#ifdef __AST_DEBUG_MALLOC
+static void ast_free(void *ptr) attribute_unused;
+static void ast_free(void *ptr)
+{
+       free(ptr);
 }
+#else
+#define ast_free free
+#endif
 
-static void ast_includes_destroy(struct ast_config_include *incls)
+#ifndef __AST_DEBUG_MALLOC
+
+#define MALLOC_FAILURE_MSG \
+       ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
+/*!
+ * \brief A wrapper for malloc()
+ *
+ * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The argument and return value are the same as malloc()
+ */
+#define ast_malloc(len) \
+       _ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+AST_INLINE_API(
+void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, const char *func),
 {
-       struct ast_config_include *incl,*inclnext;
-    
-       for (incl=incls; incl; incl = inclnext) {
-               inclnext = incl->next;
-               if (incl->include_location_file)
-                       free(incl->include_location_file);
-               if (incl->exec_file)
-                       free(incl->exec_file);
-               if (incl->included_file)
-                       free(incl->included_file);
-               free(incl);
-       }
+       void *p;
+
+       if (!(p = malloc(len)))
+               MALLOC_FAILURE_MSG;
+
+       return p;
 }
+)
 
-static void ast_config_destroy(struct ast_config *cfg)
+/*!
+ * \brief A wrapper for calloc()
+ *
+ * ast_calloc() is a wrapper for calloc() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as calloc()
+ */
+#define ast_calloc(num, len) \
+       _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+AST_INLINE_API(
+void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func),
 {
-       struct ast_category *cat, *catn;
+       void *p;
 
-       if (!cfg)
-               return;
+       if (!(p = calloc(num, len)))
+               MALLOC_FAILURE_MSG;
 
-       ast_includes_destroy(cfg->includes);
-       
-       cat = cfg->root;
-       while (cat) {
-               ast_variables_destroy(cat->root);
-               catn = cat;
-               cat = cat->next;
-               free(catn);
-       }
-       free(cfg);
+       return p;
 }
+)
 
+/*!
+ * \brief A wrapper for calloc() for use in cache pools
+ *
+ * ast_calloc_cache() is a wrapper for calloc() that will generate an Asterisk log
+ * message in the case that the allocation fails. When memory debugging is in use,
+ * the memory allocated by this function will be marked as 'cache' so it can be
+ * distinguished from normal memory allocations.
+ *
+ * The arguments and return value are the same as calloc()
+ */
+#define ast_calloc_cache(num, len) \
+       _ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-/* options.h declars ast_options extern; I need it static? */
+/*!
+ * \brief A wrapper for realloc()
+ *
+ * ast_realloc() is a wrapper for realloc() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as realloc()
+ */
+#define ast_realloc(p, len) \
+       _ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-#define AST_CACHE_DIR_LEN      512
-#define AST_FILENAME_MAX       80
+AST_INLINE_API(
+void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
+{
+       void *newp;
 
-/*! \ingroup main_options */
-enum ast_option_flags {
-       /*! Allow \#exec in config files */
-       AST_OPT_FLAG_EXEC_INCLUDES = (1 << 0),
-       /*! Do not fork() */
-       AST_OPT_FLAG_NO_FORK = (1 << 1),
-       /*! Keep quiet */
-       AST_OPT_FLAG_QUIET = (1 << 2),
-       /*! Console mode */
-       AST_OPT_FLAG_CONSOLE = (1 << 3),
-       /*! Run in realtime Linux priority */
-       AST_OPT_FLAG_HIGH_PRIORITY = (1 << 4),
-       /*! Initialize keys for RSA authentication */
-       AST_OPT_FLAG_INIT_KEYS = (1 << 5),
-       /*! Remote console */
-       AST_OPT_FLAG_REMOTE = (1 << 6),
-       /*! Execute an asterisk CLI command upon startup */
-       AST_OPT_FLAG_EXEC = (1 << 7),
-       /*! Don't use termcap colors */
-       AST_OPT_FLAG_NO_COLOR = (1 << 8),
-       /*! Are we fully started yet? */
-       AST_OPT_FLAG_FULLY_BOOTED = (1 << 9),
-       /*! Trascode via signed linear */
-       AST_OPT_FLAG_TRANSCODE_VIA_SLIN = (1 << 10),
-       /*! Enable priority jumping in applications */
-       AST_OPT_FLAG_PRIORITY_JUMPING = (1 << 11),
-       /*! Dump core on a seg fault */
-       AST_OPT_FLAG_DUMP_CORE = (1 << 12),
-       /*! Cache sound files */
-       AST_OPT_FLAG_CACHE_RECORD_FILES = (1 << 13),
-       /*! Display timestamp in CLI verbose output */
-       AST_OPT_FLAG_TIMESTAMP = (1 << 14),
-       /*! Override config */
-       AST_OPT_FLAG_OVERRIDE_CONFIG = (1 << 15),
-       /*! Reconnect */
-       AST_OPT_FLAG_RECONNECT = (1 << 16),
-       /*! Transmit Silence during Record() */
-       AST_OPT_FLAG_TRANSMIT_SILENCE = (1 << 17),
-       /*! Suppress some warnings */
-       AST_OPT_FLAG_DONT_WARN = (1 << 18),
-       /*! End CDRs before the 'h' extension */
-       AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN = (1 << 19),
-       /*! Use Zaptel Timing for generators if available */
-       AST_OPT_FLAG_INTERNAL_TIMING = (1 << 20),
-       /*! Always fork, even if verbose or debug settings are non-zero */
-       AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
-       /*! Disable log/verbose output to remote consoles */
-       AST_OPT_FLAG_MUTE = (1 << 22)
-};
+       if (!(newp = realloc(p, len)))
+               MALLOC_FAILURE_MSG;
 
-/*! These are the options that set by default when Asterisk starts */
-#define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
+       return newp;
+}
+)
 
-#define ast_opt_exec_includes          ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
-#define ast_opt_no_fork                        ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)
-#define ast_opt_quiet                  ast_test_flag(&ast_options, AST_OPT_FLAG_QUIET)
-#define ast_opt_console                        ast_test_flag(&ast_options, AST_OPT_FLAG_CONSOLE)
-#define ast_opt_high_priority          ast_test_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY)
-#define ast_opt_init_keys              ast_test_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS)
-#define ast_opt_remote                 ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)
-#define ast_opt_exec                   ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC)
-#define ast_opt_no_color               ast_test_flag(&ast_options, AST_OPT_FLAG_NO_COLOR)
-#define ast_fully_booted               ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)
-#define ast_opt_transcode_via_slin     ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN)
-#define ast_opt_priority_jumping       ast_test_flag(&ast_options, AST_OPT_FLAG_PRIORITY_JUMPING)
-#define ast_opt_dump_core              ast_test_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE)
-#define ast_opt_cache_record_files     ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
-#define ast_opt_timestamp              ast_test_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP)
-#define ast_opt_override_config                ast_test_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG)
-#define ast_opt_reconnect              ast_test_flag(&ast_options, AST_OPT_FLAG_RECONNECT)
-#define ast_opt_transmit_silence       ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
-#define ast_opt_dont_warn              ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
-#define ast_opt_end_cdr_before_h_exten ast_test_flag(&ast_options, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN)
-#define ast_opt_internal_timing                ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING)
-#define ast_opt_always_fork            ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
-#define ast_opt_mute                   ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
+/*!
+ * \brief A wrapper for strdup()
+ *
+ * ast_strdup() is a wrapper for strdup() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * ast_strdup(), unlike strdup(), can safely accept a NULL argument. If a NULL
+ * argument is provided, ast_strdup will return NULL without generating any
+ * kind of error log message.
+ *
+ * The argument and return value are the same as strdup()
+ */
+#define ast_strdup(str) \
+       _ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
-/*  IN CONFLICT: extern int option_verbose; */
-/*  IN CONFLICT: extern int option_debug;      */      /*!< Debugging */
-extern int option_maxcalls;            /*!< Maximum number of simultaneous channels */
-extern double option_maxload;
-extern char defaultlanguage[];
+AST_INLINE_API(
+char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func),
+{
+       char *newstr = NULL;
 
-extern time_t ast_startuptime;
-extern time_t ast_lastreloadtime;
-extern pid_t ast_mainpid;
+       if (str) {
+               if (!(newstr = strdup(str)))
+                       MALLOC_FAILURE_MSG;
+       }
 
-extern char record_cache_dir[AST_CACHE_DIR_LEN];
-extern char debug_filename[AST_FILENAME_MAX];
+       return newstr;
+}
+)
 
-extern int ast_language_is_prefix;
+/*!
+ * \brief A wrapper for strndup()
+ *
+ * ast_strndup() is a wrapper for strndup() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * ast_strndup(), unlike strndup(), can safely accept a NULL argument for the
+ * string to duplicate. If a NULL argument is provided, ast_strdup will return  
+ * NULL without generating any kind of error log message.
+ *
+ * The arguments and return value are the same as strndup()
+ */
+#define ast_strndup(str, len) \
+       _ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
+AST_INLINE_API(
+char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
+{
+       char *newstr = NULL;
 
+       if (str) {
+               if (!(newstr = strndup(str, len)))
+                       MALLOC_FAILURE_MSG;
+       }
 
-/* lock.h */
+       return newstr;
+}
+)
 
-#ifndef        HAVE_MTX_PROFILE
-#define        __MTX_PROF(a)   return pthread_mutex_lock((a))
-#else
-#define        __MTX_PROF(a)   do {                    \
-       int i;                                  \
-       /* profile only non-blocking events */  \
-       ast_mark(mtx_prof, 1);                  \
-       i = pthread_mutex_trylock((a));         \
-       ast_mark(mtx_prof, 0);                  \
-       if (!i)                                 \
-               return i;                       \
-       else                                    \
-               return pthread_mutex_lock((a)); \
-       } while (0)
-#endif /* HAVE_MTX_PROFILE */
+/*!
+ * \brief A wrapper for asprintf()
+ *
+ * ast_asprintf() is a wrapper for asprintf() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as asprintf()
+ */
+#define ast_asprintf(ret, fmt, ...) \
+       _ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
 
-#define AST_PTHREADT_NULL (pthread_t) -1
-#define AST_PTHREADT_STOP (pthread_t) -2
+AST_INLINE_API(
+int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...),
+{
+       int res;
+       va_list ap;
 
-#if defined(SOLARIS) || defined(BSD)
-#define AST_MUTEX_INIT_W_CONSTRUCTORS
-#endif /* SOLARIS || BSD */
+       va_start(ap, fmt);
+       if ((res = vasprintf(ret, fmt, ap)) == -1)
+               MALLOC_FAILURE_MSG;
+       va_end(ap);
 
-/* Asterisk REQUIRES recursive (not error checking) mutexes
-   and will not run without them. */
-#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
-#define PTHREAD_MUTEX_INIT_VALUE       PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
-#define AST_MUTEX_KIND                 PTHREAD_MUTEX_RECURSIVE_NP
-#else
-#define PTHREAD_MUTEX_INIT_VALUE       PTHREAD_MUTEX_INITIALIZER
-#define AST_MUTEX_KIND                 PTHREAD_MUTEX_RECURSIVE
-#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
+       return res;
+}
+)
 
-#ifdef DEBUG_THREADS
+/*!
+ * \brief A wrapper for vasprintf()
+ *
+ * ast_vasprintf() is a wrapper for vasprintf() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as vasprintf()
+ */
+#define ast_vasprintf(ret, fmt, ap) \
+       _ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
 
-#define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
+AST_INLINE_API(
+int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, va_list ap),
+{
+       int res;
+
+       if ((res = vasprintf(ret, fmt, ap)) == -1)
+               MALLOC_FAILURE_MSG;
+
+       return res;
+}
+)
 
-#ifdef THREAD_CRASH
-#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
 #else
-#define DO_THREAD_CRASH do { } while (0)
+
+/* If astmm is in use, let it handle these.  Otherwise, it will report that
+   all allocations are coming from this header file */
+
+#define ast_malloc(a)          malloc(a)
+#define ast_calloc(a,b)                calloc(a,b)
+#define ast_realloc(a,b)       realloc(a,b)
+#define ast_strdup(a)          strdup(a)
+#define ast_strndup(a,b)       strndup(a,b)
+#define ast_asprintf(a,b,c)    asprintf(a,b,c)
+#define ast_vasprintf(a,b,c)   vasprintf(a,b,c)
+
+#endif /* AST_DEBUG_MALLOC */
+
+#if !defined(ast_strdupa) && defined(__GNUC__)
+/*!
+  \brief duplicate a string in memory from the stack
+  \param s The string to duplicate
+
+  This macro will duplicate the given string.  It returns a pointer to the stack
+  allocatted memory for the new string.
+*/
+#define ast_strdupa(s)                                                    \
+       (__extension__                                                    \
+       ({                                                                \
+               const char *__old = (s);                                  \
+               size_t __len = strlen(__old) + 1;                         \
+               char *__new = __builtin_alloca(__len);                    \
+               memcpy (__new, __old, __len);                             \
+               __new;                                                    \
+       }))
 #endif
 
-#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
 
-#define AST_MAX_REENTRANCY 10
+/* from config.c */
 
-struct ast_mutex_info {
-       pthread_mutex_t mutex;
-       /*! Track which thread holds this lock */
-       unsigned int track:1;
-       const char *file[AST_MAX_REENTRANCY];
-       int lineno[AST_MAX_REENTRANCY];
-       int reentrancy;
-       const char *func[AST_MAX_REENTRANCY];
-       pthread_t thread[AST_MAX_REENTRANCY];
-};
+#define MAX_NESTED_COMMENTS 128
+#define COMMENT_START ";--"
+#define COMMENT_END "--;"
+#define COMMENT_META ';'
+#define COMMENT_TAG '-'
 
-typedef struct ast_mutex_info ast_mutex_t;
+static char *extconfig_conf = "extconfig.conf";
 
-typedef pthread_cond_t ast_cond_t;
+/*! 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 pthread_mutex_t empty_mutex;
+static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
+static int  lline_buffer_size;
 
-static void __attribute__((constructor)) init_empty_mutex(void)
+#define CB_INCR 250
+
+struct ast_comment {
+       struct ast_comment *next;
+       char cmt[0];
+};
+
+static void CB_INIT(void)
 {
-       memset(&empty_mutex, 0, sizeof(empty_mutex));
+       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)
+                       return;
+               lline_buffer[0] = 0;
+               lline_buffer_size = CB_INCR;
+       } else {
+               comment_buffer[0] = 0;
+               lline_buffer[0] = 0;
+       }
 }
 
-static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
-                                               const char *mutex_name, ast_mutex_t *t,
-                                               pthread_mutexattr_t *attr) 
+static void  CB_ADD(char *str)
 {
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-       int canlog = strcmp(filename, "logger.c");
+       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)
+                       return;
+               comment_buffer_size += CB_INCR+siz+1;
+       }
+       strcat(comment_buffer,str);
+}
 
-       if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               if ((t->mutex) != (empty_mutex)) {
-                       __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
-                                          filename, lineno, func, mutex_name);
-                       __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
-                                          t->file[0], t->lineno[0], t->func[0], mutex_name);
-                       DO_THREAD_CRASH;
-                       return 0;
-               }
+static void  CB_ADD_LEN(char *str, int len)
+{
+       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)
+                       return;
+               comment_buffer_size += CB_INCR+len+1;
        }
-#endif
+       strncat(comment_buffer,str,len); /* safe */
+       comment_buffer[cbl+len-1] = 0;
+}
+
+static void  LLB_ADD(char *str)
+{
+       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) 
+                       return;
+               lline_buffer_size += CB_INCR + siz + 1;
+       }
+       strcat(lline_buffer,str);
+}
 
-       t->file[0] = filename;
-       t->lineno[0] = lineno;
-       t->func[0] = func;
-       t->thread[0]  = 0;
-       t->reentrancy = 0;
+static void CB_RESET(void )  
+{ 
+       comment_buffer[0] = 0; 
+       lline_buffer[0] = 0;
+}
+               
+/*! \brief Keep track of how many threads are currently trying to wait*() on
+ *  a child process */
+static unsigned int safe_system_level = 0;
+static void *safe_system_prev_handler;
+
+/*! \brief NULL handler so we can collect the child exit status */
+static void null_sig_handler(int signal)
+{
 
-       return pthread_mutex_init(&t->mutex, attr);
 }
 
-static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
-                                          const char *mutex_name, ast_mutex_t *t)
+void ast_replace_sigchld(void);
+
+void ast_replace_sigchld(void)
 {
-       static pthread_mutexattr_t  attr;
+       unsigned int level;
 
-       pthread_mutexattr_init(&attr);
-       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
+       level = safe_system_level++;
+
+       /* only replace the handler if it has not already been done */
+       if (level == 0)
+               safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
 
-       return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
 }
-#define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
 
-static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
-                                               const char *mutex_name, ast_mutex_t *t)
-{
-       int res;
-       int canlog = strcmp(filename, "logger.c");
+void ast_unreplace_sigchld(void);
 
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                  filename, lineno, func, mutex_name);
-       }
-#endif
+void ast_unreplace_sigchld(void)
+{
+       unsigned int level;
 
-       res = pthread_mutex_trylock(&t->mutex);
-       switch (res) {
-       case 0:
-               pthread_mutex_unlock(&t->mutex);
-               break;
-       case EINVAL:
-               __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
-                                 filename, lineno, func, mutex_name);
-               break;
-       case EBUSY:
-               __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
-                                  filename, lineno, func, mutex_name);
-               __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
-                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
-               break;
-       }
+       level = --safe_system_level;
 
-       if ((res = pthread_mutex_destroy(&t->mutex)))
-               __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
-                                  filename, lineno, func, strerror(res));
-#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
-       else
-               t->mutex = PTHREAD_MUTEX_INIT_VALUE;
-#endif
-       t->file[0] = filename;
-       t->lineno[0] = lineno;
-       t->func[0] = func;
+       /* only restore the handler if we are the last one */
+       if (level == 0)
+               signal(SIGCHLD, safe_system_prev_handler);
 
-       return res;
 }
 
-static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
-                                           const char* mutex_name, ast_mutex_t *t)
+int ast_safe_system(const char *s);
+
+int ast_safe_system(const char *s)
 {
+       pid_t pid;
+#ifdef HAVE_WORKING_FORK
+       int x;
+#endif
        int res;
-       int canlog = strcmp(filename, "logger.c");
+       struct rusage rusage;
+       int status;
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                filename, lineno, func, mutex_name);
-               ast_mutex_init(t);
-       }
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
+       ast_replace_sigchld();
 
-#ifdef DETECT_DEADLOCKS
-       {
-               time_t seconds = time(NULL);
-               time_t current;
-               do {
-#ifdef HAVE_MTX_PROFILE
-                       ast_mark(mtx_prof, 1);
-#endif
-                       res = pthread_mutex_trylock(&t->mutex);
-#ifdef HAVE_MTX_PROFILE
-                       ast_mark(mtx_prof, 0);
-#endif
-                       if (res == EBUSY) {
-                               current = time(NULL);
-                               if ((current - seconds) && (!((current - seconds) % 5))) {
-                                       __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
-                                                          filename, lineno, func, (int)(current - seconds), mutex_name);
-                                       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-                                                          t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
-                                                          t->func[t->reentrancy-1], mutex_name);
-                               }
-                               usleep(200);
-                       }
-               } while (res == EBUSY);
-       }
+#ifdef HAVE_WORKING_FORK
+       pid = fork();
 #else
-#ifdef HAVE_MTX_PROFILE
-       ast_mark(mtx_prof, 1);
-       res = pthread_mutex_trylock(&t->mutex);
-       ast_mark(mtx_prof, 0);
-       if (res)
-#endif
-       res = pthread_mutex_lock(&t->mutex);
-#endif /* DETECT_DEADLOCKS */
+       pid = vfork();
+#endif 
 
-       if (!res) {
-               if (t->reentrancy < AST_MAX_REENTRANCY) {
-                       t->file[t->reentrancy] = filename;
-                       t->lineno[t->reentrancy] = lineno;
-                       t->func[t->reentrancy] = func;
-                       t->thread[t->reentrancy] = pthread_self();
-                       t->reentrancy++;
-               } else {
-                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-                                                          filename, lineno, func, mutex_name);
+       if (pid == 0) {
+#ifdef HAVE_WORKING_FORK
+               /* Close file descriptors and launch system command */
+               for (x = STDERR_FILENO + 1; x < 4096; x++)
+                       close(x);
+#endif
+               execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
+               _exit(1);
+       } else if (pid > 0) {
+               for(;;) {
+                       res = wait4(pid, &status, 0, &rusage);
+                       if (res > -1) {
+                               res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+                               break;
+                       } else if (errno != EINTR) 
+                               break;
                }
        } else {
-               __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
-                                  filename, lineno, func, strerror(errno));
-               DO_THREAD_CRASH;
+               ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
+               res = -1;
        }
 
+       ast_unreplace_sigchld();
+#else
+       res = -1;
+#endif
+
        return res;
 }
 
-static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
-                                              const char* mutex_name, ast_mutex_t *t)
-{
-       int res;
-       int canlog = strcmp(filename, "logger.c");
+static struct ast_comment *ALLOC_COMMENT(const char *buffer)
+{ 
+       struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
+       strcpy(x->cmt, buffer);
+       return x;
+}
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                  filename, lineno, func, mutex_name);
-               ast_mutex_init(t);
-       }
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+static struct ast_config_map {
+       struct ast_config_map *next;
+       char *name;
+       char *driver;
+       char *database;
+       char *table;
+       char stuff[0];
+} *config_maps = NULL;
 
-       if (!(res = pthread_mutex_trylock(&t->mutex))) {
-               if (t->reentrancy < AST_MAX_REENTRANCY) {
-                       t->file[t->reentrancy] = filename;
-                       t->lineno[t->reentrancy] = lineno;
-                       t->func[t->reentrancy] = func;
-                       t->thread[t->reentrancy] = pthread_self();
-                       t->reentrancy++;
-               } else {
-                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-                                          filename, lineno, func, mutex_name);
-               }
-       } else {
-               __ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n",
-                                   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
-       }
+static struct ast_config_engine *config_engine_list;
 
-       return res;
-}
+#define MAX_INCLUDE_LEVEL 10
 
-static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
-                                            const char *mutex_name, ast_mutex_t *t)
-{
-       int res;
-       int canlog = strcmp(filename, "logger.c");
 
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                  filename, lineno, func, mutex_name);
-       }
-#endif
+struct ast_category {
+       char name[80];
+       int ignored;                    /*!< do not let user of the config see this category */
+       int include_level;      
+    char *file;                /*!< the file name from whence this declaration was read */
+    int lineno;
+       struct ast_comment *precomments;
+       struct ast_comment *sameline;
+       struct ast_variable *root;
+       struct ast_variable *last;
+       struct ast_category *next;
+};
+
+struct ast_config {
+       struct ast_category *root;
+       struct ast_category *last;
+       struct ast_category *current;
+       struct ast_category *last_browse;               /*!< used to cache the last category supplied via category_browse */
+       int include_level;
+       int max_include_level;
+    struct ast_config_include *includes;  /*!< a list of inclusions, which should describe the entire tree */
+};
 
-       if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
-               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
-                                  filename, lineno, func, mutex_name);
-               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
-               DO_THREAD_CRASH;
-       }
+struct ast_config_include {
+       char *include_location_file;     /*!< file name in which the include occurs */
+       int  include_location_lineno;    /*!< lineno where include occurred */
+       int  exec;                       /*!< set to non-zero if itsa #exec statement */
+       char *exec_file;                 /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
+       char *included_file;             /*!< file name included */
+       int inclusion_count;             /*!< if the file is included more than once, a running count thereof -- but, worry not,
+                                                                          we explode the instances and will include those-- so all entries will be unique */
+       int output;                      /*!< a flag to indicate if the inclusion has been output */
+       struct ast_config_include *next; /*!< ptr to next inclusion in the list */
+};
 
-       if (--t->reentrancy < 0) {
-               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-                                  filename, lineno, func, mutex_name);
-               t->reentrancy = 0;
-       }
+typedef struct ast_config *config_load_func(const char *database, const char *table, const char *configfile, struct ast_config *config, int withcomments, const char *suggested_include_file);
+typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
+typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
+typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
 
-       if (t->reentrancy < AST_MAX_REENTRANCY) {
-               t->file[t->reentrancy] = NULL;
-               t->lineno[t->reentrancy] = 0;
-               t->func[t->reentrancy] = NULL;
-               t->thread[t->reentrancy] = 0;
-       }
+/*! \brief Configuration engine structure, used to define realtime drivers */
+struct ast_config_engine {
+       char *name;
+       config_load_func *load_func;
+       realtime_var_get *realtime_func;
+       realtime_multi_get *realtime_multi_func;
+       realtime_update *update_func;
+       struct ast_config_engine *next;
+};
 
-       if ((res = pthread_mutex_unlock(&t->mutex))) {
-               __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", 
-                                  filename, lineno, func, strerror(res));
-               DO_THREAD_CRASH;
-       }
+static struct ast_config_engine *config_engine_list;
 
-       return res;
-}
+/* taken from strings.h */
 
-static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
-                                 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
+static force_inline int ast_strlen_zero(const char *s)
 {
-       return pthread_cond_init(cond, cond_attr);
+       return (!s || (*s == '\0'));
 }
 
-static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
-                                   const char *cond_name, ast_cond_t *cond)
-{
-       return pthread_cond_signal(cond);
-}
+#define S_OR(a, b)     (!ast_strlen_zero(a) ? (a) : (b))
 
-static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
-                                      const char *cond_name, ast_cond_t *cond)
+AST_INLINE_API(
+void ast_copy_string(char *dst, const char *src, size_t size),
 {
-       return pthread_cond_broadcast(cond);
+       while (*src && size) {
+               *dst++ = *src++;
+               size--;
+       }
+       if (__builtin_expect(!size, 0))
+               dst--;
+       *dst = '\0';
 }
+)
 
-static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
-                                    const char *cond_name, ast_cond_t *cond)
+AST_INLINE_API(
+char *ast_skip_blanks(const char *str),
 {
-       return pthread_cond_destroy(cond);
+       while (*str && *str < 33)
+               str++;
+       return (char *)str;
 }
+)
 
-static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
-                                 const char *cond_name, const char *mutex_name,
-                                 ast_cond_t *cond, ast_mutex_t *t)
+/*!
+  \brief Trims trailing whitespace characters from a string.
+  \param ast_trim_blanks function being used
+  \param str the input string
+  \return a pointer to the modified string
+ */
+AST_INLINE_API(
+char *ast_trim_blanks(char *str),
 {
-       int res;
-       int canlog = strcmp(filename, "logger.c");
-
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                  filename, lineno, func, mutex_name);
-       }
-#endif
-
-       if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
-               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
-                                  filename, lineno, func, mutex_name);
-               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
-               DO_THREAD_CRASH;
-       }
-
-       if (--t->reentrancy < 0) {
-               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-                                  filename, lineno, func, mutex_name);
-               t->reentrancy = 0;
-       }
-
-       if (t->reentrancy < AST_MAX_REENTRANCY) {
-               t->file[t->reentrancy] = NULL;
-               t->lineno[t->reentrancy] = 0;
-               t->func[t->reentrancy] = NULL;
-               t->thread[t->reentrancy] = 0;
-       }
+       char *work = str;
 
-       if ((res = pthread_cond_wait(cond, &t->mutex))) {
-               __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
-                                  filename, lineno, func, strerror(res));
-               DO_THREAD_CRASH;
-       } else {
-               if (t->reentrancy < AST_MAX_REENTRANCY) {
-                       t->file[t->reentrancy] = filename;
-                       t->lineno[t->reentrancy] = lineno;
-                       t->func[t->reentrancy] = func;
-                       t->thread[t->reentrancy] = pthread_self();
-                       t->reentrancy++;
-               } else {
-                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-                                                          filename, lineno, func, mutex_name);
-               }
+       if (work) {
+               work += strlen(work) - 1;
+               /* It's tempting to only want to erase after we exit this loop, 
+                  but since ast_trim_blanks *could* receive a constant string
+                  (which we presumably wouldn't have to touch), we shouldn't
+                  actually set anything unless we must, and it's easier just
+                  to set each position to \0 than to keep track of a variable
+                  for it */
+               while ((work >= str) && *work < 33)
+                       *(work--) = '\0';
        }
-
-       return res;
+       return str;
 }
+)
 
-static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
-                                      const char *cond_name, const char *mutex_name, ast_cond_t *cond,
-                                      ast_mutex_t *t, const struct timespec *abstime)
-{
-       int res;
-       int canlog = strcmp(filename, "logger.c");
-
-#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
-       if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
-               __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
-                                  filename, lineno, func, mutex_name);
-       }
-#endif
-
-       if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
-               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
-                                  filename, lineno, func, mutex_name);
-               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-                                  t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
-               DO_THREAD_CRASH;
-       }
-
-       if (--t->reentrancy < 0) {
-               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-                                  filename, lineno, func, mutex_name);
-               t->reentrancy = 0;
-       }
-
-       if (t->reentrancy < AST_MAX_REENTRANCY) {
-               t->file[t->reentrancy] = NULL;
-               t->lineno[t->reentrancy] = 0;
-               t->func[t->reentrancy] = NULL;
-               t->thread[t->reentrancy] = 0;
-       }
+/*!
+  \brief Strip leading/trailing whitespace from a string.
+  \param s The string to be stripped (will be modified).
+  \return The stripped string.
 
-       if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
-               __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", 
-                                  filename, lineno, func, strerror(res));
-               DO_THREAD_CRASH;
-       } else {
-               if (t->reentrancy < AST_MAX_REENTRANCY) {
-                       t->file[t->reentrancy] = filename;
-                       t->lineno[t->reentrancy] = lineno;
-                       t->func[t->reentrancy] = func;
-                       t->thread[t->reentrancy] = pthread_self();
-                       t->reentrancy++;
-               } else {
-                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-                                                          filename, lineno, func, mutex_name);
-               }
-       }
+  This functions strips all leading and trailing whitespace
+  characters from the input string, and returns a pointer to
+  the resulting string. The string is modified in place.
+*/
+AST_INLINE_API(
+char *ast_strip(char *s),
+{
+       s = ast_skip_blanks(s);
+       if (s)
+               ast_trim_blanks(s);
+       return s;
+} 
+)
 
-       return res;
-}
 
-#define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
-#define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
-#define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
-#define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
-#define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
+/* from config.h */
 
-#else /* !DEBUG_THREADS */
+struct ast_variable {
+       char *name;
+       char *value;
+       char *file;
+       int lineno;
+       int object;             /*!< 0 for variable, 1 for object */
+       int blanklines;         /*!< Number of blanklines following entry */
+       struct ast_comment *precomments;
+       struct ast_comment *sameline;
+       struct ast_variable *next;
+       char stuff[0];
+};
 
+static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable);
+static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_include_file);
 
-typedef pthread_mutex_t ast_mutex_t;
+struct ast_config *localized_config_load_with_comments(const char *filename);
+static char *ast_category_browse(struct ast_config *config, const char *prev);
+static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
+static void ast_variables_destroy(struct ast_variable *v);
+static void ast_config_destroy(struct ast_config *cfg);
+static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size);
+static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file);
+void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file);
 
-#define AST_MUTEX_INIT_VALUE   ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
+static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
 
-static inline int ast_mutex_init(ast_mutex_t *pmutex)
+static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename) 
 {
-       pthread_mutexattr_t attr;
+       struct ast_variable *variable;
+       int name_len = strlen(name) + 1;        
 
-       pthread_mutexattr_init(&attr);
-       pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
+       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->value + strlen(value) + 1;           
+               strcpy(variable->name,name);
+               strcpy(variable->value,value);
+               strcpy(variable->file,filename);
+       }
 
-       return pthread_mutex_init(pmutex, &attr);
+       return variable;
 }
 
-#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
-
-static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
+static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
 {
-       return pthread_mutex_unlock(pmutex);
+       /* a file should be included ONCE. Otherwise, if one of the instances is changed,
+       then all be changed. -- how do we know to include it? -- Handling modified 
+       instances is possible, I'd have
+       to create a new master for each instance. */
+       struct ast_config_include *inc;
+    
+       inc = ast_include_find(conf, included_file);
+       if (inc)
+       {
+               inc->inclusion_count++;
+               snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
+               ast_log(LOG_WARNING,"'%s', line %d:  Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
+       } else
+               *real_included_file_name = 0;
+       
+       inc = ast_calloc(1,sizeof(struct ast_config_include));
+       inc->include_location_file = ast_strdup(from_file);
+       inc->include_location_lineno = from_lineno;
+       if (!ast_strlen_zero(real_included_file_name))
+               inc->included_file = ast_strdup(real_included_file_name);
+       else
+               inc->included_file = ast_strdup(included_file);
+       
+       inc->exec = is_exec;
+       if (is_exec)
+               inc->exec_file = ast_strdup(exec_file);
+       
+       /* attach this new struct to the conf struct */
+       inc->next = conf->includes;
+       conf->includes = inc;
+    
+       return inc;
 }
 
-static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
+void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
 {
-       return pthread_mutex_destroy(pmutex);
+       struct ast_config_include *incl;
+       struct ast_category *cat;
+       struct ast_variable *v;
+    
+       int from_len = strlen(from_file);
+       int to_len = strlen(to_file);
+    
+       if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
+               return;
+       
+       /* the manager code allows you to read in one config file, then
+       write it back out under a different name. But, the new arrangement
+          ties output lines to the file name. So, before you try to write
+       the config file to disk, better riffle thru the data and make sure
+       the file names are changed.
+       */
+       /* file names are on categories, includes (of course), and on variables. So,
+          traverse all this and swap names */
+       
+       for (incl = conf->includes; incl; incl=incl->next) {
+               if (strcmp(incl->include_location_file,from_file) == 0) {
+                       if (from_len >= to_len)
+                               strcpy(incl->include_location_file, to_file);
+                       else {
+                               free(incl->include_location_file);
+                               incl->include_location_file = strdup(to_file);
+                       }
+               }
+       }
+       for (cat = conf->root; cat; cat = cat->next) {
+               if (strcmp(cat->file,from_file) == 0) {
+                       if (from_len >= to_len)
+                               strcpy(cat->file, to_file);
+                       else {
+                               free(cat->file);
+                               cat->file = strdup(to_file);
+                       }
+               }
+               for (v = cat->root; v; v = v->next) {
+                       if (strcmp(v->file,from_file) == 0) {
+                               if (from_len >= to_len)
+                                       strcpy(v->file, to_file);
+                               else {
+                                       free(v->file);
+                                       v->file = strdup(to_file);
+                               }
+                       }
+               }
+       }
 }
 
-static inline int ast_mutex_lock(ast_mutex_t *pmutex)
+static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
 {
-       __MTX_PROF(pmutex);
+       struct ast_config_include *x;
+       for (x=conf->includes;x;x=x->next)
+       {
+               if (strcmp(x->included_file,included_file) == 0)
+                       return x;
+       }
+       return 0;
 }
 
-static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
-{
-       return pthread_mutex_trylock(pmutex);
-}
 
-typedef pthread_cond_t ast_cond_t;
+static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
 
-static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
+static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
 {
-       return pthread_cond_init(cond, cond_attr);
+       if (!variable)
+               return;
+       if (category->last)
+               category->last->next = variable;
+       else
+               category->root = variable;
+       category->last = variable;
+       while (category->last->next)
+               category->last = category->last->next;
 }
 
-static inline int ast_cond_signal(ast_cond_t *cond)
-{
-       return pthread_cond_signal(cond);
-}
+static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
 
-static inline int ast_cond_broadcast(ast_cond_t *cond)
+static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
 {
-       return pthread_cond_broadcast(cond);
-}
+       struct ast_category *cat;
 
-static inline int ast_cond_destroy(ast_cond_t *cond)
-{
-       return pthread_cond_destroy(cond);
+       /* try exact match first, then case-insensitive match */
+       for (cat = config->root; cat; cat = cat->next) {
+               if (cat->name == category_name && (ignored || !cat->ignored))
+                       return cat;
+       }
+
+       for (cat = config->root; cat; cat = cat->next) {
+               if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
+                       return cat;
+       }
+
+       return NULL;
 }
 
-static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
+static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
 {
-       return pthread_cond_wait(cond, t);
+       return category_get(config, category_name, 0);
 }
 
-static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
+static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
 {
-       return pthread_cond_timedwait(cond, t, abstime);
-}
+       struct ast_category *cat = NULL;
 
-#endif /* !DEBUG_THREADS */
+       if (category && config->last_browse && (config->last_browse->name == category))
+               cat = config->last_browse;
+       else
+               cat = ast_category_get(config, category);
 
-#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
-/* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
- constructors/destructors to create/destroy mutexes.  */
-#define __AST_MUTEX_DEFINE(scope, mutex) \
-       scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
-static void  __attribute__ ((constructor)) init_##mutex(void) \
-{ \
-       ast_mutex_init(&mutex); \
-} \
-static void  __attribute__ ((destructor)) fini_##mutex(void) \
-{ \
-       ast_mutex_destroy(&mutex); \
+       return (cat) ? cat->root : NULL;
 }
-#else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
-/* By default, use static initialization of mutexes. */ 
-#define __AST_MUTEX_DEFINE(scope, mutex) \
-       scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
-#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
-
-#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
-#define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
-#define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
-#define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
-#define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
-#define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
-#define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
-#define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
-#define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
-#define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
-#define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
-#define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
-#define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
-
-#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
-
-#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
-
-#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
 
-#ifndef __linux__
-#define pthread_create __use_ast_pthread_create_instead__
-#endif
-
-typedef pthread_rwlock_t ast_rwlock_t;
-
-static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
+static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
 {
-       pthread_rwlockattr_t attr;
+       struct ast_variable *v;
 
-       pthread_rwlockattr_init(&attr);
+       if (category) {
+               for (v = ast_variable_browse(config, category); v; v = v->next) {
+                       if (!strcasecmp(variable, v->name))
+                               return v->value;
+               }
+       } else {
+               struct ast_category *cat;
 
-#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
-       pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
-#endif
+               for (cat = config->root; cat; cat = cat->next)
+                       for (v = cat->root; v; v = v->next)
+                               if (!strcasecmp(variable, v->name))
+                                       return v->value;
+       }
 
-       return pthread_rwlock_init(prwlock, &attr);
+       return NULL;
 }
 
-static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
+static struct ast_variable *variable_clone(const struct ast_variable *old)
 {
-       return pthread_rwlock_destroy(prwlock);
-}
+       struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
+
+       if (new) {
+               new->lineno = old->lineno;
+               new->object = old->object;
+               new->blanklines = old->blanklines;
+               /* TODO: clone comments? */
+       }
 
-static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
-{
-       return pthread_rwlock_unlock(prwlock);
+       return new;
 }
-
-static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
+static void ast_variables_destroy(struct ast_variable *v)
 {
-       return pthread_rwlock_rdlock(prwlock);
-}
+       struct ast_variable *vn;
 
-static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
-{
-       return pthread_rwlock_tryrdlock(prwlock);
+       while (v) {
+               vn = v;
+               v = v->next;
+               free(vn);
+       }
 }
 
-static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
+static void ast_includes_destroy(struct ast_config_include *incls)
 {
-       return pthread_rwlock_wrlock(prwlock);
+       struct ast_config_include *incl,*inclnext;
+    
+       for (incl=incls; incl; incl = inclnext) {
+               inclnext = incl->next;
+               if (incl->include_location_file)
+                       free(incl->include_location_file);
+               if (incl->exec_file)
+                       free(incl->exec_file);
+               if (incl->included_file)
+                       free(incl->included_file);
+               free(incl);
+       }
 }
 
-static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
+static void ast_config_destroy(struct ast_config *cfg)
 {
-       return pthread_rwlock_trywrlock(prwlock);
-}
+       struct ast_category *cat, *catn;
 
-/* Statically declared read/write locks */
+       if (!cfg)
+               return;
 
-#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
-#define __AST_RWLOCK_DEFINE(scope, rwlock) \
-        scope ast_rwlock_t rwlock; \
-static void  __attribute__ ((constructor)) init_##rwlock(void) \
-{ \
-        ast_rwlock_init(&rwlock); \
-} \
-static void  __attribute__ ((destructor)) fini_##rwlock(void) \
-{ \
-        ast_rwlock_destroy(&rwlock); \
+       ast_includes_destroy(cfg->includes);
+       
+       cat = cfg->root;
+       while (cat) {
+               ast_variables_destroy(cat->root);
+               catn = cat;
+               cat = cat->next;
+               free(catn);
+       }
+       free(cfg);
 }
-#else
-#define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
-#define __AST_RWLOCK_DEFINE(scope, rwlock) \
-        scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
-#endif
 
-#define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
 
-/*
- * Initial support for atomic instructions.
- * For platforms that have it, use the native cpu instruction to
- * implement them. For other platforms, resort to a 'slow' version
- * (defined in utils.c) that protects the atomic instruction with
- * a single lock.
- * The slow versions is always available, for testing purposes,
- * as ast_atomic_fetchadd_int_slow()
- */
+/* options.h declars ast_options extern; I need it static? */
 
-#if defined(HAVE_OSX_ATOMICS)
-#include "libkern/OSAtomic.h"
-#endif
+#define AST_CACHE_DIR_LEN      512
+#define AST_FILENAME_MAX       80
 
-/*! \brief Atomically add v to *p and return * the previous value of *p.
- * This can be used to handle reference counts, and the return value
- * can be used to generate unique identifiers.
- */
+/*! \ingroup main_options */
+enum ast_option_flags {
+       /*! Allow \#exec in config files */
+       AST_OPT_FLAG_EXEC_INCLUDES = (1 << 0),
+       /*! Do not fork() */
+       AST_OPT_FLAG_NO_FORK = (1 << 1),
+       /*! Keep quiet */
+       AST_OPT_FLAG_QUIET = (1 << 2),
+       /*! Console mode */
+       AST_OPT_FLAG_CONSOLE = (1 << 3),
+       /*! Run in realtime Linux priority */
+       AST_OPT_FLAG_HIGH_PRIORITY = (1 << 4),
+       /*! Initialize keys for RSA authentication */
+       AST_OPT_FLAG_INIT_KEYS = (1 << 5),
+       /*! Remote console */
+       AST_OPT_FLAG_REMOTE = (1 << 6),
+       /*! Execute an asterisk CLI command upon startup */
+       AST_OPT_FLAG_EXEC = (1 << 7),
+       /*! Don't use termcap colors */
+       AST_OPT_FLAG_NO_COLOR = (1 << 8),
+       /*! Are we fully started yet? */
+       AST_OPT_FLAG_FULLY_BOOTED = (1 << 9),
+       /*! Trascode via signed linear */
+       AST_OPT_FLAG_TRANSCODE_VIA_SLIN = (1 << 10),
+       /*! Enable priority jumping in applications */
+       AST_OPT_FLAG_PRIORITY_JUMPING = (1 << 11),
+       /*! Dump core on a seg fault */
+       AST_OPT_FLAG_DUMP_CORE = (1 << 12),
+       /*! Cache sound files */
+       AST_OPT_FLAG_CACHE_RECORD_FILES = (1 << 13),
+       /*! Display timestamp in CLI verbose output */
+       AST_OPT_FLAG_TIMESTAMP = (1 << 14),
+       /*! Override config */
+       AST_OPT_FLAG_OVERRIDE_CONFIG = (1 << 15),
+       /*! Reconnect */
+       AST_OPT_FLAG_RECONNECT = (1 << 16),
+       /*! Transmit Silence during Record() */
+       AST_OPT_FLAG_TRANSMIT_SILENCE = (1 << 17),
+       /*! Suppress some warnings */
+       AST_OPT_FLAG_DONT_WARN = (1 << 18),
+       /*! End CDRs before the 'h' extension */
+       AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN = (1 << 19),
+       /*! Use Zaptel Timing for generators if available */
+       AST_OPT_FLAG_INTERNAL_TIMING = (1 << 20),
+       /*! Always fork, even if verbose or debug settings are non-zero */
+       AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
+       /*! Disable log/verbose output to remote consoles */
+       AST_OPT_FLAG_MUTE = (1 << 22)
+};
 
-#if defined(HAVE_GCC_ATOMICS)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       return __sync_fetch_and_add(p, v);
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       return OSAtomicAdd32(v, (int32_t *) p);
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       return OSAtomicAdd64(v, (int64_t *) p);
-#elif defined (__i386__) || defined(__x86_64__)
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       __asm __volatile (
-       "       lock   xaddl   %0, %1 ;        "
-       : "+r" (v),                     /* 0 (result) */   
-         "=m" (*p)                     /* 1 */
-       : "m" (*p));                    /* 2 */
-       return (v);
-})
-#else
-static int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
-{
-       int ret;
-       ret = *p;
-       *p += v;
-       return ret;
-}
-AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
-{
-       return ast_atomic_fetchadd_int_slow(p, v);
-})
-#endif
+/*! These are the options that set by default when Asterisk starts */
+#define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
 
-/*! \brief decrement *p by 1 and return true if the variable has reached 0.
- * Useful e.g. to check if a refcount has reached 0.
- */
-#if defined(HAVE_GCC_ATOMICS)
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
-       return __sync_sub_and_fetch(p, 1) == 0;
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
-       return OSAtomicAdd32( -1, (int32_t *) p) == 0;
-})
-#elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
-       return OSAtomicAdd64( -1, (int64_t *) p) == 0;
-#else
-AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
-{
-       int a = ast_atomic_fetchadd_int(p, -1);
-       return a == 1; /* true if the value is 0 now (so it was 1 previously) */
-})
-#endif
+#define ast_opt_exec_includes          ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
+#define ast_opt_no_fork                        ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)
+#define ast_opt_quiet                  ast_test_flag(&ast_options, AST_OPT_FLAG_QUIET)
+#define ast_opt_console                        ast_test_flag(&ast_options, AST_OPT_FLAG_CONSOLE)
+#define ast_opt_high_priority          ast_test_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY)
+#define ast_opt_init_keys              ast_test_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS)
+#define ast_opt_remote                 ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)
+#define ast_opt_exec                   ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC)
+#define ast_opt_no_color               ast_test_flag(&ast_options, AST_OPT_FLAG_NO_COLOR)
+#define ast_fully_booted               ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)
+#define ast_opt_transcode_via_slin     ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN)
+#define ast_opt_priority_jumping       ast_test_flag(&ast_options, AST_OPT_FLAG_PRIORITY_JUMPING)
+#define ast_opt_dump_core              ast_test_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE)
+#define ast_opt_cache_record_files     ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
+#define ast_opt_timestamp              ast_test_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP)
+#define ast_opt_override_config                ast_test_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG)
+#define ast_opt_reconnect              ast_test_flag(&ast_options, AST_OPT_FLAG_RECONNECT)
+#define ast_opt_transmit_silence       ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
+#define ast_opt_dont_warn              ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
+#define ast_opt_end_cdr_before_h_exten ast_test_flag(&ast_options, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN)
+#define ast_opt_internal_timing                ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING)
+#define ast_opt_always_fork            ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
+#define ast_opt_mute                   ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
 
-#ifndef DEBUG_CHANNEL_LOCKS
-/*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined 
-       in the Makefile, print relevant output for debugging */
-#define ast_channel_lock(x)            ast_mutex_lock(&x->lock)
-/*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined 
-       in the Makefile, print relevant output for debugging */
-#define ast_channel_unlock(x)          ast_mutex_unlock(&x->lock)
-/*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined 
-       in the Makefile, print relevant output for debugging */
-#define ast_channel_trylock(x)         ast_mutex_trylock(&x->lock)
-#else
+/*  IN CONFLICT: extern int option_verbose; */
+/*  IN CONFLICT: extern int option_debug;      */      /*!< Debugging */
+extern int option_maxcalls;            /*!< Maximum number of simultaneous channels */
+extern double option_maxload;
+extern char defaultlanguage[];
 
-/*! \brief Lock AST channel (and print debugging output)
-\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
-int ast_channel_lock(struct ast_channel *chan);
+extern time_t ast_startuptime;
+extern time_t ast_lastreloadtime;
+extern pid_t ast_mainpid;
 
-/*! \brief Unlock AST channel (and print debugging output)
-\note You need to enable DEBUG_CHANNEL_LOCKS for this function
-*/
-int ast_channel_unlock(struct ast_channel *chan);
+extern char record_cache_dir[AST_CACHE_DIR_LEN];
+extern char debug_filename[AST_FILENAME_MAX];
+
+extern int ast_language_is_prefix;
 
-/*! \brief Lock AST channel (and print debugging output)
-\note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
-int ast_channel_trylock(struct ast_channel *chan);
-#endif
 
 
 /* linkedlists.h */