Skip to content
Snippets Groups Projects
extconf.c 164 KiB
Newer Older
  • Learn to ignore specific revisions
  • Steve Murphy's avatar
    Steve Murphy committed
    	return str;
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
      \brief Strip leading/trailing whitespace from a string.
      \param s The string to be stripped (will be modified).
      \return The stripped string.
    
    Steve Murphy's avatar
    Steve Murphy committed
      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;
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* from config.h */
    
    Steve Murphy's avatar
    Steve Murphy committed
    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];
    };
    
    Steve Murphy's avatar
    Steve Murphy committed
    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);
    
    Steve Murphy's avatar
    Steve Murphy committed
    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);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
    
    static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_variable *variable;
    
    	int name_len = strlen(name) + 1;
    
    	size_t value_len = strlen(value) + 1;
    	size_t filename_len = strlen(filename) + 1;
    
    	if ((variable = ast_calloc(1, name_len + value_len + filename_len + sizeof(*variable)))) {
    
    Steve Murphy's avatar
    Steve Murphy committed
    		variable->name = variable->stuff;
    
    		variable->value = variable->stuff + name_len;
    
    		variable->file = variable->value + value_len;
    
    Steve Murphy's avatar
    Steve Murphy committed
    		strcpy(variable->name,name);
    
    		ast_copy_string(variable->value, value, value_len);
    		ast_copy_string(variable->file, filename, filename_len);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return variable;
    
    Steve Murphy's avatar
    Steve Murphy committed
    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)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* 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
    
    Steve Murphy's avatar
    Steve Murphy committed
           instances is possible, I'd have
           to create a new master for each instance. */
    	struct ast_config_include *inc;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	inc->exec = is_exec;
    	if (is_exec)
    		inc->exec_file = ast_strdup(exec_file);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* attach this new struct to the conf struct */
    	inc->next = conf->includes;
    	conf->includes = inc;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return inc;
    
    Steve Murphy's avatar
    Steve Murphy committed
    void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_config_include *incl;
    	struct ast_category *cat;
    	struct ast_variable *v;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	int from_len = strlen(from_file);
    	int to_len = strlen(to_file);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
    		return;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* 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 */
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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);
    				}
    			}
    		}
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_category *cat;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* 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;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return category_get(config, category_name, 0);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_category *cat = NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (category && config->last_browse && (config->last_browse->name == category))
    		cat = config->last_browse;
    	else
    		cat = ast_category_get(config, category);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return (cat) ? cat->root : NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_variable *v;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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;
    
    Steve Murphy's avatar
    Steve Murphy committed
    		for (cat = config->root; cat; cat = cat->next)
    			for (v = cat->root; v; v = v->next)
    				if (!strcasecmp(variable, v->name))
    					return v->value;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_variable *variable_clone(const struct ast_variable *old)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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? */
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return new;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_variables_destroy(struct ast_variable *v)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_variable *vn;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	while (v) {
    		vn = v;
    		v = v->next;
    		free(vn);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_includes_destroy(struct ast_config_include *incls)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_config_include *incl,*inclnext;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_config_destroy(struct ast_config *cfg)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_category *cat, *catn;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!cfg)
    		return;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	ast_includes_destroy(cfg->includes);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	cat = cfg->root;
    	while (cat) {
    		ast_variables_destroy(cat->root);
    		catn = cat;
    		cat = cat->next;
    		free(catn);
    	}
    	free(cfg);
    
    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),
    	/*! 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() and DTMF Generation */
    	AST_OPT_FLAG_TRANSMIT_SILENCE = (1 << 17),
    	/*! Suppress some warnings */
    	AST_OPT_FLAG_DONT_WARN = (1 << 18),
    	/*! 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),
    	/*! There is a per-file debug setting */
    	AST_OPT_FLAG_DEBUG_FILE = (1 << 23),
    	/*! Terminal colors should be adjusted for a light-colored background */
    	AST_OPT_FLAG_LIGHT_BACKGROUND = (1 << 25),
    	/*! Force black background */
    	AST_OPT_FLAG_FORCE_BLACK_BACKGROUND = (1 << 27),
    };
    
    /* options.h declares ast_options extern; I need it static? */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_CACHE_DIR_LEN 	512
    #define AST_FILENAME_MAX	80
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! These are the options that set by default when Asterisk starts */
    #define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
    
    struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    #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_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)
    
    extern int option_verbose;
    extern int option_debug;		/*!< Debugging */
    
    extern int ast_option_maxcalls;		/*!< Maximum number of simultaneous channels */
    extern double ast_option_maxload;
    extern char ast_defaultlanguage[];
    
    Steve Murphy's avatar
    Steve Murphy committed
    extern pid_t ast_mainpid;
    
    Steve Murphy's avatar
    Steve Murphy committed
    extern char record_cache_dir[AST_CACHE_DIR_LEN];
    extern char debug_filename[AST_FILENAME_MAX];
    
    extern int ast_language_is_prefix;
    
    
    
    
    /* linkedlists.h */
    
    /*!
      \brief Write locks a list.
      \param head This is a pointer to the list head structure
    
      This macro attempts to place an exclusive write lock in the
      list head structure pointed to by head.
      Returns non-zero on success, 0 on failure
    */
    #define AST_RWLIST_WRLOCK(head)                                         \
            ast_rwlock_wrlock(&(head)->lock)
    
    /*!
      \brief Read locks a list.
      \param head This is a pointer to the list head structure
    
      This macro attempts to place a read lock in the
      list head structure pointed to by head.
      Returns non-zero on success, 0 on failure
    */
    #define AST_RWLIST_RDLOCK(head)                                         \
            ast_rwlock_rdlock(&(head)->lock)
    
    /*!
      \brief Attempts to unlock a read/write based list.
      \param head This is a pointer to the list head structure
    
      This macro attempts to remove a read or write lock from the
      list head structure pointed to by head. If the list
      was not locked by this thread, this macro has no effect.
    */
    #define AST_RWLIST_UNLOCK(head)                                         \
            ast_rwlock_unlock(&(head)->lock)
    
    /*!
      \brief Defines a structure to be used to hold a list of specified type.
      \param name This will be the name of the defined structure.
      \param type This is the type of each list entry.
    
      This macro creates a structure definition that can be used
      to hold a list of the entries of type \a type. It does not actually
      declare (allocate) a structure; to do that, either follow this
      macro with the desired name of the instance you wish to declare,
      or use the specified \a name to declare instances elsewhere.
    
      Example usage:
      \code
      static AST_LIST_HEAD(entry_list, entry) entries;
      \endcode
    
      This would define \c struct \c entry_list, and declare an instance of it named
      \a entries, all intended to hold a list of type \c struct \c entry.
    */
    #define AST_LIST_HEAD(name, type)					\
    struct name {								\
    	struct type *first;						\
    	struct type *last;						\
    	ast_mutex_t lock;						\
    }
    
    /*!
      \brief Defines a structure to be used to hold a read/write list of specified type.
      \param name This will be the name of the defined structure.
      \param type This is the type of each list entry.
    
      This macro creates a structure definition that can be used
      to hold a list of the entries of type \a type. It does not actually
      declare (allocate) a structure; to do that, either follow this
      macro with the desired name of the instance you wish to declare,
      or use the specified \a name to declare instances elsewhere.
    
      Example usage:
      \code
      static AST_RWLIST_HEAD(entry_list, entry) entries;
      \endcode
    
      This would define \c struct \c entry_list, and declare an instance of it named
      \a entries, all intended to hold a list of type \c struct \c entry.
    */
    #define AST_RWLIST_HEAD(name, type)                                     \
    struct name {                                                           \
            struct type *first;                                             \
            struct type *last;                                              \
            ast_rwlock_t lock;                                              \
    }
    
    /*!
      \brief Defines a structure to be used to hold a list of specified type (with no lock).
      \param name This will be the name of the defined structure.
      \param type This is the type of each list entry.
    
      This macro creates a structure definition that can be used
      to hold a list of the entries of type \a type. It does not actually
      declare (allocate) a structure; to do that, either follow this
      macro with the desired name of the instance you wish to declare,
      or use the specified \a name to declare instances elsewhere.
    
      Example usage:
      \code
      static AST_LIST_HEAD_NOLOCK(entry_list, entry) entries;
      \endcode
    
      This would define \c struct \c entry_list, and declare an instance of it named
      \a entries, all intended to hold a list of type \c struct \c entry.
    */
    #define AST_LIST_HEAD_NOLOCK(name, type)				\
    struct name {								\
    	struct type *first;						\
    	struct type *last;						\
    }
    
    /*!
      \brief Defines initial values for a declaration of AST_LIST_HEAD
    */
    #define AST_LIST_HEAD_INIT_VALUE	{		\
    	.first = NULL,					\
    	.last = NULL,					\
    	.lock = AST_MUTEX_INIT_VALUE,			\
    	}
    
    /*!
      \brief Defines initial values for a declaration of AST_RWLIST_HEAD
    */
    #define AST_RWLIST_HEAD_INIT_VALUE      {               \
            .first = NULL,                                  \
            .last = NULL,                                   \
            .lock = AST_RWLOCK_INIT_VALUE,                  \
            }
    
    /*!
      \brief Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK
    */
    #define AST_LIST_HEAD_NOLOCK_INIT_VALUE	{	\
    	.first = NULL,					\
    	.last = NULL,					\
    	}
    
    /*!
      \brief Defines a structure to be used to hold a list of specified type, statically initialized.
      \param name This will be the name of the defined structure.
      \param type This is the type of each list entry.
    
      This macro creates a structure definition that can be used
      to hold a list of the entries of type \a type, and allocates an instance
      of it, initialized to be empty.
    
      Example usage:
      \code
      static AST_LIST_HEAD_STATIC(entry_list, entry);
      \endcode
    
      This would define \c struct \c entry_list, intended to hold a list of
      type \c struct \c entry.
    */
    #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
    #define AST_LIST_HEAD_STATIC(name, type)				\
    struct name {								\
    	struct type *first;						\
    	struct type *last;						\
    	ast_mutex_t lock;						\
    } name;									\
    
    static void  __attribute__((constructor)) init_##name(void)		\
    
    static void  __attribute__((destructor)) fini_##name(void)		\
    
    {									\
            AST_LIST_HEAD_DESTROY(&name);					\
    }									\
    struct __dummy_##name
    #else
    #define AST_LIST_HEAD_STATIC(name, type)				\
    struct name {								\
    	struct type *first;						\
    	struct type *last;						\
    	ast_mutex_t lock;						\
    } name = AST_LIST_HEAD_INIT_VALUE
    #endif
    
    /*!
      \brief Defines a structure to be used to hold a read/write list of specified type, statically initialized.
      \param name This will be the name of the defined structure.
      \param type This is the type of each list entry.
    
      This macro creates a structure definition that can be used
      to hold a list of the entries of type \a type, and allocates an instance
      of it, initialized to be empty.
    
      Example usage:
      \code
      static AST_RWLIST_HEAD_STATIC(entry_list, entry);
      \endcode
    
      This would define \c struct \c entry_list, intended to hold a list of
      type \c struct \c entry.
    */
    #ifndef AST_RWLOCK_INIT_VALUE
    #define AST_RWLIST_HEAD_STATIC(name, type)                              \
    struct name {                                                           \
            struct type *first;                                             \
            struct type *last;                                              \
            ast_rwlock_t lock;                                              \
    } name;                                                                 \
    
    static void  __attribute__((constructor)) init_##name(void)            \
    
    static void  __attribute__((destructor)) fini_##name(void)             \
    
    {                                                                       \
            AST_RWLIST_HEAD_DESTROY(&name);                                 \
    }                                                                       \
    struct __dummy_##name
    #else
    #define AST_RWLIST_HEAD_STATIC(name, type)                              \
    struct name {                                                           \
            struct type *first;                                             \
            struct type *last;                                              \
            ast_rwlock_t lock;                                              \
    } name = AST_RWLIST_HEAD_INIT_VALUE
    #endif
    
    /*!
      \brief Defines a structure to be used to hold a list of specified type, statically initialized.
    
      This is the same as AST_LIST_HEAD_STATIC, except without the lock included.
    */
    #define AST_LIST_HEAD_NOLOCK_STATIC(name, type)				\
    struct name {								\
    	struct type *first;						\
    	struct type *last;						\
    } name = AST_LIST_HEAD_NOLOCK_INIT_VALUE
    
    /*!
      \brief Initializes a list head structure with a specified first entry.
      \param head This is a pointer to the list head structure
      \param entry pointer to the list entry that will become the head of the list
    
      This macro initializes a list head structure by setting the head
      entry to the supplied value and recreating the embedded lock.
    */
    #define AST_LIST_HEAD_SET(head, entry) do {				\
    	(head)->first = (entry);					\
    	(head)->last = (entry);						\
    	ast_mutex_init(&(head)->lock);					\
    } while (0)
    
    /*!
      \brief Initializes an rwlist head structure with a specified first entry.
      \param head This is a pointer to the list head structure
      \param entry pointer to the list entry that will become the head of the list
    
      This macro initializes a list head structure by setting the head
      entry to the supplied value and recreating the embedded lock.
    */
    #define AST_RWLIST_HEAD_SET(head, entry) do {                           \
            (head)->first = (entry);                                        \
            (head)->last = (entry);                                         \
            ast_rwlock_init(&(head)->lock);                                 \
    } while (0)
    
    /*!
      \brief Initializes a list head structure with a specified first entry.
      \param head This is a pointer to the list head structure
      \param entry pointer to the list entry that will become the head of the list
    
      This macro initializes a list head structure by setting the head
      entry to the supplied value.
    */
    #define AST_LIST_HEAD_SET_NOLOCK(head, entry) do {			\
    	(head)->first = (entry);					\
    	(head)->last = (entry);						\
    } while (0)
    
    /*!
      \brief Declare a forward link structure inside a list entry.
      \param type This is the type of each list entry.
    
      This macro declares a structure to be used to link list entries together.
      It must be used inside the definition of the structure named in
      \a type, as follows:
    
      \code
      struct list_entry {
      	...
      	AST_LIST_ENTRY(list_entry) list;
      }
      \endcode
    
      The field name \a list here is arbitrary, and can be anything you wish.
    */
    #define AST_LIST_ENTRY(type)						\
    struct {								\
    	struct type *next;						\
    }
    
    #define AST_RWLIST_ENTRY AST_LIST_ENTRY
    
    1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000
    /*!
      \brief Returns the first entry contained in a list.
      \param head This is a pointer to the list head structure
     */
    #define	AST_LIST_FIRST(head)	((head)->first)
    
    #define AST_RWLIST_FIRST AST_LIST_FIRST
    
    /*!
      \brief Returns the last entry contained in a list.
      \param head This is a pointer to the list head structure
     */
    #define	AST_LIST_LAST(head)	((head)->last)
    
    #define AST_RWLIST_LAST AST_LIST_LAST
    
    /*!
      \brief Returns the next entry in the list after the given entry.
      \param elm This is a pointer to the current entry.
      \param field This is the name of the field (declared using AST_LIST_ENTRY())
      used to link entries of this list together.
    */
    #define AST_LIST_NEXT(elm, field)	((elm)->field.next)
    
    #define AST_RWLIST_NEXT AST_LIST_NEXT
    
    /*!
      \brief Checks whether the specified list contains any entries.
      \param head This is a pointer to the list head structure
    
      Returns non-zero if the list has entries, zero if not.
     */
    #define	AST_LIST_EMPTY(head)	(AST_LIST_FIRST(head) == NULL)
    
    #define AST_RWLIST_EMPTY AST_LIST_EMPTY
    
    /*!
      \brief Loops over (traverses) the entries in a list.
      \param head This is a pointer to the list head structure
      \param var This is the name of the variable that will hold a pointer to the
      current list entry on each iteration. It must be declared before calling
      this macro.
      \param field This is the name of the field (declared using AST_LIST_ENTRY())
      used to link entries of this list together.
    
      This macro is use to loop over (traverse) the entries in a list. It uses a
      \a for loop, and supplies the enclosed code with a pointer to each list
      entry as it loops. It is typically used as follows:
      \code
      static AST_LIST_HEAD(entry_list, list_entry) entries;
      ...
      struct list_entry {
      	...
      	AST_LIST_ENTRY(list_entry) list;
      }
      ...
      struct list_entry *current;
      ...
      AST_LIST_TRAVERSE(&entries, current, list) {
         (do something with current here)
      }
      \endcode
      \warning If you modify the forward-link pointer contained in the \a current entry while
      inside the loop, the behavior will be unpredictable. At a minimum, the following
      macros will modify the forward-link pointer, and should not be used inside
      AST_LIST_TRAVERSE() against the entry pointed to by the \a current pointer without
      careful consideration of their consequences:
      \li AST_LIST_NEXT() (when used as an lvalue)
      \li AST_LIST_INSERT_AFTER()
      \li AST_LIST_INSERT_HEAD()
      \li AST_LIST_INSERT_TAIL()
    */
    #define AST_LIST_TRAVERSE(head,var,field) 				\
    	for((var) = (head)->first; (var); (var) = (var)->field.next)
    
    #define AST_RWLIST_TRAVERSE AST_LIST_TRAVERSE
    
    /*!
      \brief Loops safely over (traverses) the entries in a list.
      \param head This is a pointer to the list head structure
      \param var This is the name of the variable that will hold a pointer to the
      current list entry on each iteration. It must be declared before calling
      this macro.
      \param field This is the name of the field (declared using AST_LIST_ENTRY())
      used to link entries of this list together.
    
      This macro is used to safely loop over (traverse) the entries in a list. It
      uses a \a for loop, and supplies the enclosed code with a pointer to each list
      entry as it loops. It is typically used as follows:
    
      \code
      static AST_LIST_HEAD(entry_list, list_entry) entries;
      ...
      struct list_entry {
      	...
      	AST_LIST_ENTRY(list_entry) list;
      }
      ...
      struct list_entry *current;
      ...
      AST_LIST_TRAVERSE_SAFE_BEGIN(&entries, current, list) {
         (do something with current here)
      }
      AST_LIST_TRAVERSE_SAFE_END;
      \endcode
    
      It differs from AST_LIST_TRAVERSE() in that the code inside the loop can modify
      (or even free, after calling AST_LIST_REMOVE_CURRENT()) the entry pointed to by
      the \a current pointer without affecting the loop traversal.
    */
    #define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field) {				\
    	typeof((head)->first) __list_next;						\
    	typeof((head)->first) __list_prev = NULL;					\
    	typeof((head)->first) __new_prev = NULL;					\
    	for ((var) = (head)->first, __new_prev = (var),					\
    	      __list_next = (var) ? (var)->field.next : NULL;				\
    	     (var);									\
    	     __list_prev = __new_prev, (var) = __list_next,				\
    	     __new_prev = (var),							\
    	     __list_next = (var) ? (var)->field.next : NULL				\
    	    )
    
    #define AST_RWLIST_TRAVERSE_SAFE_BEGIN AST_LIST_TRAVERSE_SAFE_BEGIN
    
    /*!
      \brief Removes the \a current entry from a list during a traversal.
      \param head This is a pointer to the list head structure
      \param field This is the name of the field (declared using AST_LIST_ENTRY())
      used to link entries of this list together.
    
      \note This macro can \b only be used inside an AST_LIST_TRAVERSE_SAFE_BEGIN()
      block; it is used to unlink the current entry from the list without affecting
      the list traversal (and without having to re-traverse the list to modify the
      previous entry, if any).
     */
    #define AST_LIST_REMOVE_CURRENT(head, field)						\
    	__new_prev->field.next = NULL;							\
    	__new_prev = __list_prev;							\
    	if (__list_prev)								\
    		__list_prev->field.next = __list_next;					\
    	else										\
    		(head)->first = __list_next;						\
    	if (!__list_next)								\
    		(head)->last = __list_prev;
    
    #define AST_RWLIST_REMOVE_CURRENT AST_LIST_REMOVE_CURRENT
    
    /*!
      \brief Inserts a list entry before the current entry during a traversal.
      \param head This is a pointer to the list head structure
      \param elm This is a pointer to the entry to be inserted.
      \param field This is the name of the field (declared using AST_LIST_ENTRY())
      used to link entries of this list together.
    
      \note This macro can \b only be used inside an AST_LIST_TRAVERSE_SAFE_BEGIN()
      block.
     */
    #define AST_LIST_INSERT_BEFORE_CURRENT(head, elm, field) do {		\
    	if (__list_prev) {						\
    		(elm)->field.next = __list_prev->field.next;		\
    		__list_prev->field.next = elm;				\
    	} else {							\
    		(elm)->field.next = (head)->first;			\
    		(head)->first = (elm);					\
    	}								\
    	__new_prev = (elm);						\
    } while (0)
    
    #define AST_RWLIST_INSERT_BEFORE_CURRENT AST_LIST_INSERT_BEFORE_CURRENT
    
    /*!
      \brief Closes a safe loop traversal block.
     */
    #define AST_LIST_TRAVERSE_SAFE_END  }
    
    #define AST_RWLIST_TRAVERSE_SAFE_END AST_LIST_TRAVERSE_SAFE_END
    
    /*!
      \brief Initializes a list head structure.
      \param head This is a pointer to the list head structure
    
      This macro initializes a list head structure by setting the head
      entry to \a NULL (empty list) and recreating the embedded lock.
    */
    #define AST_LIST_HEAD_INIT(head) {					\
    	(head)->first = NULL;						\
    	(head)->last = NULL;						\
    	ast_mutex_init(&(head)->lock);					\
    }
    
    /*!
      \brief Initializes an rwlist head structure.
      \param head This is a pointer to the list head structure
    
      This macro initializes a list head structure by setting the head
      entry to \a NULL (empty list) and recreating the embedded lock.
    */
    #define AST_RWLIST_HEAD_INIT(head) {                                    \
            (head)->first = NULL;                                           \
            (head)->last = NULL;                                            \
            ast_rwlock_init(&(head)->lock);                                 \
    }
    
    /*!
      \brief Destroys an rwlist head structure.
      \param head This is a pointer to the list head structure
    
      This macro destroys a list head structure by setting the head
      entry to \a NULL (empty list) and destroying the embedded lock.
      It does not free the structure from memory.
    */
    #define AST_RWLIST_HEAD_DESTROY(head) {                                 \
            (head)->first = NULL;                                           \
            (head)->last = NULL;                                            \
            ast_rwlock_destroy(&(head)->lock);                              \
    }
    
    /*!
      \brief Initializes a list head structure.
      \param head This is a pointer to the list head structure
    
      This macro initializes a list head structure by setting the head
      entry to \a NULL (empty list). There is no embedded lock handling
      with this macro.
    */
    #define AST_LIST_HEAD_INIT_NOLOCK(head) {				\
    	(head)->first = NULL;						\
    	(head)->last = NULL;						\
    }
    
    /*!
      \brief Inserts a list entry after a given entry.
      \param head This is a pointer to the list head structure
      \param listelm This is a pointer to the entry after which the new entry should
      be inserted.
      \param elm This is a pointer to the entry to be inserted.
      \param field This is the name of the field (declared using AST_LIST_ENTRY())
      used to link entries of this list together.
     */
    #define AST_LIST_INSERT_AFTER(head, listelm, elm, field) do {		\
    	(elm)->field.next = (listelm)->field.next;			\
    	(listelm)->field.next = (elm);					\
    	if ((head)->last == (listelm))					\
    		(head)->last = (elm);					\
    } while (0)
    
    #define AST_RWLIST_INSERT_AFTER AST_LIST_INSERT_AFTER
    
    /*!
      \brief Inserts a list entry at the head of a list.
      \param head This is a pointer to the list head structure
      \param elm This is a pointer to the entry to be inserted.
      \param field This is the name of the field (declared using AST_LIST_ENTRY())
      used to link entries of this list together.
     */
    #define AST_LIST_INSERT_HEAD(head, elm, field) do {			\
    		(elm)->field.next = (head)->first;			\
    		(head)->first = (elm);					\
    		if (!(head)->last)					\
    			(head)->last = (elm);				\
    } while (0)
    
    #define AST_RWLIST_INSERT_HEAD AST_LIST_INSERT_HEAD
    
    /*!
      \brief Appends a list entry to the tail of a list.
      \param head This is a pointer to the list head structure
      \param elm This is a pointer to the entry to be appended.
      \param field This is the name of the field (declared using AST_LIST_ENTRY())
      used to link entries of this list together.
    
      Note: The link field in the appended entry is \b not modified, so if it is
      actually the head of a list itself, the entire list will be appended
      temporarily (until the next AST_LIST_INSERT_TAIL is performed).
     */
    #define AST_LIST_INSERT_TAIL(head, elm, field) do {			\
          if (!(head)->first) {						\
    		(head)->first = (elm);					\
    		(head)->last = (elm);					\
          } else {								\
    		(head)->last->field.next = (elm);			\
    		(head)->last = (elm);					\
          }									\
    } while (0)
    
    #define AST_RWLIST_INSERT_TAIL AST_LIST_INSERT_TAIL
    
    /*!
      \brief Appends a whole list to the tail of a list.
      \param head This is a pointer to the list head structure
      \param list This is a pointer to the list to be appended.
      \param field This is the name of the field (declared using AST_LIST_ENTRY())
      used to link entries of this list together.
     */
    #define AST_LIST_APPEND_LIST(head, list, field) do {			\
          if (!(head)->first) {						\
    		(head)->first = (list)->first;				\
    		(head)->last = (list)->last;				\
          } else {								\
    		(head)->last->field.next = (list)->first;		\