[asterisk-commits] twilson: branch twilson/config_work r365689 - in /team/twilson/config_work: a...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue May 8 14:22:20 CDT 2012
Author: twilson
Date: Tue May 8 14:22:16 2012
New Revision: 365689
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=365689
Log:
Update some documentation, a little cleanup work.
Still need to document a couple of the macros, do a little macro cleanup,
and add some overview stuff I've been working on.
Modified:
team/twilson/config_work/apps/app_skel.c
team/twilson/config_work/include/asterisk/config_options.h
team/twilson/config_work/main/config_options.c
Modified: team/twilson/config_work/apps/app_skel.c
URL: http://svnview.digium.com/svn/asterisk/team/twilson/config_work/apps/app_skel.c?view=diff&rev=365689&r1=365688&r2=365689
==============================================================================
--- team/twilson/config_work/apps/app_skel.c (original)
+++ team/twilson/config_work/apps/app_skel.c Tue May 8 14:22:16 2012
@@ -146,12 +146,10 @@
static int skel_apply_config(void);
-static struct aco_info cfg_info = {
- .module = AST_MODULE,
+CONFIG_INFO_STANDARD(cfg_info,
.filename = "app_skel.conf",
.apply_config = skel_apply_config,
-/* .preload = { "general", SENTINEL }, */
-};
+);
static void skel_global_config_destructor(void *obj)
{
Modified: team/twilson/config_work/include/asterisk/config_options.h
URL: http://svnview.digium.com/svn/asterisk/team/twilson/config_work/include/asterisk/config_options.h?view=diff&rev=365689&r1=365688&r2=365689
==============================================================================
--- team/twilson/config_work/include/asterisk/config_options.h (original)
+++ team/twilson/config_work/include/asterisk/config_options.h Tue May 8 14:22:16 2012
@@ -34,6 +34,7 @@
#include "asterisk/astobj2.h"
struct aco_option;
+struct aco_type;
enum aco_type_t {
GLOBAL_OBJ,
@@ -46,21 +47,117 @@
CONTEXT_ALLOW,
};
+/* Callback functions for option parsing via aco_process_config() */
+
+/*! \brief Allocate a configurable ao2 object
+ * \param category The config category the object is being generated for
+ * \retval NULL error
+ * \retval non-NULL a new configurable ao2 object
+ */
typedef void *(*aco_type_alloc)(const char *category);
+
+/*! \brief Allocate scontainers for a configurable object and its non-config-related state
+ * \param newpvts The new private container
+ * \param newcfgs The new config container
+ * \retval 0 success
+ * \retval -1 failure
+ */
typedef int (*aco_type_containers_alloc)(struct ao2_container **newpvts, struct ao2_container **newcfgs);
+
+/*! \brief Find an existing private or create a new one
+ * \param context The context associated with the private
+ * \retval NULL error
+ * \retval non-NULL a referenced ao2 private object
+ */
typedef void *(*aco_type_find_or_create_pvt)(const char *context);
+
+/*! \brief Find a private given a context and container of privates
+ * \param container The container to search for the private
+ * \param context The context associated with the private
+ * \retval NULL error
+ * \retval non-NULL a referenced ao2 private object
+ */
typedef void *(*aco_type_find_pvt)(struct ao2_container *newcontainer, const char *context);
+
+/*! \brief Callback function that is called after a config object is initialized with defaults
+ *
+ * \note This callback is called during config processing after a new config is allocated and
+ * and defaults applied but before values from the config are read. This callback could be used
+ * to merge in settings inherited from the global settings if necessary, despite that being a
+ * bad thing to do!
+ *
+ * \param newcfg The newly allocated config object with defaults populated
+ * \retval 0 succes, continue processing
+ * \retval non-zero failure, stop processing
+ */
typedef int (*aco_type_post_cfg_init)(void *newcfg);
+
+/*! \brief Callback function that is called after config processing, but before linking
+ *
+ * \note This callback is called after config processing, but before linking the object
+ * in the config container. This callback can be used to verify that all settings make
+ * sense together, that required options have been set, etc.
+ *
+ * \param newcfg The newly configured object
+ * \retval 0 success, continue processing
+ * \retval non-zero failure, stop processing
+ */
typedef int (*aco_type_prelink)(void *newcfg);
-struct aco_type;
-
-struct ao2_container *aco_type_container_new(void);
+/*! \brief Allocate a container for aco_types
+ *
+ * \note If using aco_process_config, this function is unnecessary as calling aco_info_init
+ * will take care of allocating a container for aco_types in the aco_info struct. This is
+ * made public in case manual config processing is needed.
+ *
+ * \retval NULL error
+ * \retval non-NULL a new ao2 container for storing aco_type objects
+ */
+struct ao2_container *aco_type_container_alloc(void);
+
+/*! \brief Allocate a global config type
+ *
+ * \note Use this to allocate global config types. These types are for configs that
+ * are unique and not linked in a container
+ *
+ * \param name A unique identifier for this type
+ * \param op Whether the following context regex is a whitelist or blacklist
+ * \param context A regular expression for matching contexts to be allowed or denied
+ * \param alloc An allocation function for ao2 object associated with this type
+ *
+ * \retval NULL error
+ * \retval non-NULL A new global aco_type handle
+ */
struct aco_type *aco_type_global_alloc(const char *name, enum aco_context_op op, const char *context, aco_type_alloc alloc);
+
+/*! \brief Allocate a global config type
+ *
+ * \note Use this to allocate private config types. These types are for configs that
+ * are defined multiple times and stored in an ao2 container.
+ *
+ * \param name A unique identifier for this type
+ * \param op Whether the following context regex is a whitelist or blacklist
+ * \param context A regular expression for matching contexts to be allowed or denied
+ * \param matchfield An option name to match for this type (i.e. a 'type'-like column)
+ * \param matchvalue The value of the option to require for matching (i.e. 'peer' for type= in sip.conf)
+ * \param alloc An allocation function for ao2 object associated with this type
+ * \param containers_alloc A callback function for allocating both a config object and its associated private
+ * \param find_or_create_pvt A callback function to find an existing private, or create a new one if it doesn't exist
+ * \param find_pvt A callback function to find an existing private in a particular container
+ * \param post_cfg_init An optional callback function that is called after defaults are applied, but before config processing
+ * \param prelink An optional callback function that is called after config processing, but before applying changes
+ *
+ * \retval NULL error
+ * \retval non-NULL A new private aco_type handle
+ */
struct aco_type *aco_type_private_alloc(const char *name, enum aco_context_op op, const char *context, const char *matchfield, const char *matchvalue,
aco_type_alloc alloc, aco_type_containers_alloc containers_alloc, aco_type_find_or_create_pvt find_or_create_pvt,
aco_type_find_pvt find_pvt, aco_type_post_cfg_init post_cfg_init, aco_type_prelink prelink);
+/*! \brief A callback function for applying the config changes
+ * \retval 0 Success
+ * \retval non-zero Failure. Changes not applied
+ */
typedef int (*aco_apply_config)(void);
struct aco_info {
@@ -69,23 +166,98 @@
struct ao2_container *opts;
struct ao2_container *objs;
aco_apply_config apply_config;
- const char *preload[]; /* Use a sentinel! */
+ const char *preload[]; /* Use a sentinel! Even if preload is empty! */
};
+/*! \def CONFIG_INFO_STANDARD
+ * \brief Declare an aco_info struct with default module and preload values
+ * \param name The name of the struct
+ * Example:
+ * \code
+ * CONFIG_INFO_STANDARD(cfg_info,
+ * .filename = "app_skel.conf",
+ * .apply_config = skel_apply_config,
+ * );
+ * ...
+ * if (aco_info_init(&cfg_info)) {
+ * return AST_MODULE_LOAD_DECLINE;
+ * }
+ * ...
+ * aco_info_destroy(&cfg_info);
+ * \endcode
+ */
+#define CONFIG_INFO_STANDARD(name, ...) \
+static struct aco_info name = { \
+ .module = AST_MODULE, \
+ .preload = { SENTINEL, }, \
+ __VA_ARGS__ \
+};
+
+/*! \brief Initialize an aco_info structure
+ * \note aco_info_destroy must be called if this succeeds
+ * \param info The address of an aco_info struct to initialize
+ * \retval 0 Success
+ * \retval non-zero Failure
+ */
int aco_info_init(struct aco_info *info);
+
+/*! \brief Destroy an initialized aco_info struct
+ * \param info The address of the aco_info struct to destroy
+ */
void aco_info_destroy(struct aco_info *info);
+
+/*! \brief Register an aco_type with an aco_info struct
+ * \param info The address of the aco_info struct to register the aco_info with
+ * \param obj The aco_type to register
+ * \retval 0 Success
+ * \retval non-zero Failure
+ */
int aco_type_register(struct aco_info *info, struct aco_type *obj);
+
+/*! \brief Find an aco_type registered to an aco_info by name
+ * \param info The aco_info containing the aco_type
+ * \param name The unique name of the aco_type to find
+ * \retval NULL aco_type not found
+ * \retval non-NULL A referenced pointer to the aco_type
+ */
struct aco_type *aco_type_find(struct aco_info *info, const char *name);
+/*! \brief Get the specified global config after processing
+ * \note This function is most likely used in the apply_config callback
+ * \param info The aco_info to query for the global config object
+ * \param name The unique name of the aco_type associated with the config
+ * \retval NULL Not found.
+ * \retval non-NULL A referenced pointer to the newly configured global config object
+ */
void *aco_info_new_global_get(struct aco_info *info, const char *name);
+
+/*! \brief Get the specified private container after config processing
+ * \note This function is most likely used in the apply_config callback. The container
+ * will be a mix of new and existing privates that can be swapped out with the existing
+ * live container of privates.
+ * \param info The aco_info to query for the container of privates
+ * \param name The unique name of the aco_type associated with the privates
+ * \retval NULL Not found.
+ * \retval non-NULL A referenced pointer to the newly configured container of privates
+ */
struct ao2_container *aco_info_new_privates_get(struct aco_info *info, const char *name);
+
+/*! \brief Get the specified private config container after config processing
+ * \note This function is most likely used in the apply_config callback. The container
+ * will be of new privates configs that can be swapped out with the existing
+ * live container of private configs.
+ * \param info The aco_info to query for the container of private configs
+ * \param name The unique name of the aco_type associated with the private configs
+ * \retval NULL Not found.
+ * \retval non-NULL A referenced pointer to the newly configured container of private configs
+ */
struct ao2_container *aco_info_new_configs_get(struct aco_info *info, const char *name);
/*! \brief The option types with default handlers
*
- * aco_option_register takes an option type which is used
- * to look up the handler for that type. Each type requires field
- * names for specific types in the struct being configured. Each
+ * \note aco_option_register takes an option type which is used
+ * to look up the handler for that type. Each non-custom type requires
+ * field names for specific types in the struct being configured. Each
* option below is commented with the field types, *in the order
* they must be passed* to aco_option_register. The fields
* are located in the args array in the ast_config_option passed to
@@ -114,7 +286,7 @@
typedef int (*aco_option_handler)(const struct aco_option *opt, struct ast_variable *var, void *obj);
/*! \brief Allocate a container to hold config options */
-struct ao2_container *aco_option_container_new(void);
+struct ao2_container *aco_option_container_alloc(void);
/*! \brief Find a config option that can handle the option \a name in \a context
* \param container The container of options to search
@@ -137,7 +309,7 @@
* \param reload Whether or not this is a reload
*
* \retval 0 Success
- * \retval 1 Failure
+ * \retval -1 Failure
*/
int aco_process_config(struct aco_info *info, int reload);
@@ -270,8 +442,22 @@
#define ARGMAP_8(func, func_arg, in, x, ...)\
ARGMAP_7(func, func_arg, ARGIFY(in, func(func_arg, x)), __VA_ARGS__)
-/*! \brief Results in the number of arguments passed to it
- * \note currently only up to 8, but expanding is easy
+/* \def VA_NARGS(...)
+ * \brief Results in the number of arguments passed to it
+ * \note Currently only up to 8, but expanding is easy. This macro basically counts
+ * commas + 1. To visualize:
+ *
+ * VA_NARGS(one, two, three) -> v
+ * VA_NARGS1(one, two, three, 8, 7, 6, 5, 4, 3, 2, 1, 0) ->
+ * VA_NARGS1( _1, _2, _3, _4, _5, _6, _7, _8, N, ... ) N -> 3
+ *
+ * Note that VA_NARGS *does not* work when there are no arguments passed. Pasting an empty
+ * __VA_ARGS__ with a comma like ", ##__VA_ARGS__" will delete the leading comma, but it
+ * does not work when __VA_ARGS__ is the first argument. Instead, 1 is returned instead of 0:
+ *
+ * VA_NARGS() -> v
+ * VA_NARGS1( , 8, 7, 6, 5, 4, 3, 2, 1, 0) ->
+ * VA_NARGS1(_1, _2, _3, _4, _5, _6, _7, _8, N) -> 1
*/
#define VA_NARGS(...) VA_NARGS1(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define VA_NARGS1(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
@@ -283,7 +469,6 @@
#define POP(...) POP1(__VA_ARGS__)
#define POP1(x, ...) __VA_ARGS__
-
#if defined(__cplusplus) || defined(c_plusplus)
}
Modified: team/twilson/config_work/main/config_options.c
URL: http://svnview.digium.com/svn/asterisk/team/twilson/config_work/main/config_options.c?view=diff&rev=365689&r1=365688&r2=365689
==============================================================================
--- team/twilson/config_work/main/config_options.c (original)
+++ team/twilson/config_work/main/config_options.c Tue May 8 14:22:16 2012
@@ -208,7 +208,7 @@
return ao2_callback_data(container, OBJ_KEY, find_option_cb, (void *) name, (void *) cat);
}
-struct ao2_container *aco_option_container_new(void)
+struct ao2_container *aco_option_container_alloc(void)
{
return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
}
@@ -264,7 +264,7 @@
return 0;
}
-static int config_opt_obj_context_cmp(void *obj, void *arg, void *data, int flags)
+static int type_context_cmp(void *obj, void *arg, void *data, int flags)
{
struct aco_type *match = obj;
const char *context = arg;
@@ -292,7 +292,7 @@
static struct aco_type *internal_aco_type_find(struct ao2_container *container, struct ast_config *cfg, const char *context)
{
- return ao2_callback_data(container, 0, config_opt_obj_context_cmp, (void *) context, (void *) cfg);
+ return ao2_callback_data(container, 0, type_context_cmp, (void *) context, (void *) cfg);
}
static int is_preload(struct aco_info *info, const char *cat)
@@ -479,10 +479,10 @@
int aco_info_init(struct aco_info *info)
{
- if (!(info->opts = aco_option_container_new())) {
- return -1;
- }
- if (!(info->objs = aco_type_container_new())) {
+ if (!(info->opts = aco_option_container_alloc())) {
+ return -1;
+ }
+ if (!(info->objs = aco_type_container_alloc())) {
ao2_ref(info->opts, -1);
info->opts = NULL;
return -1;
@@ -541,23 +541,23 @@
return 0;
}
-static int config_opt_obj_hash(const void *obj, const int flags)
+static int type_hash(const void *obj, const int flags)
{
const struct aco_type *object = obj;
const char *name = (flags & OBJ_KEY) ? obj : object->name;
return ast_str_case_hash(name);
}
-static int config_opt_obj_cmp(void *obj, void *arg, int flags)
+static int type_cmp(void *obj, void *arg, int flags)
{
struct aco_type *obj1 = obj, *obj2 = arg;
const char *name = (flags & OBJ_KEY) ? arg : obj2->name;
return strcasecmp(obj1->name, name) ? 0 : CMP_STOP | CMP_MATCH;
}
-struct ao2_container *aco_type_container_new(void)
-{
- return ao2_container_alloc(7, config_opt_obj_hash, config_opt_obj_cmp);
+struct ao2_container *aco_type_container_alloc(void)
+{
+ return ao2_container_alloc(3, type_hash, type_cmp);
}
static void config_obj_destructor(void *o)
More information about the asterisk-commits
mailing list