[asterisk-commits] twilson: branch twilson/config_work r361853 - in /team/twilson/config_work: a...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Apr 10 16:32:46 CDT 2012
Author: twilson
Date: Tue Apr 10 16:32:42 2012
New Revision: 361853
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=361853
Log:
Backup of work
TODO: docs, file headers, handling required fields, etc.
Added:
team/twilson/config_work/configs/app_skel.conf.sample (with props)
team/twilson/config_work/include/asterisk/config_options.h (with props)
team/twilson/config_work/main/config_options.c (with props)
Modified:
team/twilson/config_work/apps/app_skel.c
team/twilson/config_work/include/asterisk/stringfields.h
team/twilson/config_work/include/asterisk/utils.h
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=361853&r1=361852&r2=361853
==============================================================================
--- team/twilson/config_work/apps/app_skel.c (original)
+++ team/twilson/config_work/apps/app_skel.c Tue Apr 10 16:32:42 2012
@@ -15,7 +15,7 @@
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*
- * Please follow coding guidelines
+ * Please follow coding guidelines
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
*/
@@ -24,8 +24,8 @@
* \brief Skeleton application
*
* \author\verbatim <Your Name Here> <<Your Email Here>> \endverbatim
- *
- * This is a skeleton for development of an Asterisk application
+ *
+ * This is a skeleton for development of an Asterisk application
* \ingroup applications
*/
@@ -44,6 +44,13 @@
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
+#include "asterisk/config.h"
+#include "asterisk/config_options.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/acl.h"
+#include "asterisk/netsock2.h"
+#include "asterisk/strings.h"
+#include "asterisk/cli.h"
/*** DOCUMENTATION
<application name="Skel" language="en_US">
@@ -67,7 +74,7 @@
</parameter>
</syntax>
<description>
- <para>This application is a template to build other applications from.
+ <para>This application is a template to build other applications from.
It shows you the basic structure to create your own Asterisk applications.</para>
</description>
</application>
@@ -94,6 +101,126 @@
AST_APP_OPTION_ARG('c', OPTION_C, OPTION_ARG_C),
});
+struct skel_global_config {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(foo);
+ AST_STRING_FIELD(bar);
+ AST_STRING_FIELD(baz);
+ );
+ int blah;
+ struct ast_sockaddr bindaddr;
+};
+
+struct skel_pvt_config {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(name);
+ AST_STRING_FIELD(description);
+ );
+ struct ast_codec_pref prefs;
+ struct ast_format_cap *caps;
+ struct ast_ha *permit;
+};
+
+struct skel_pvt {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(name);
+ );
+ size_t non_config_state;
+};
+
+enum {
+ GLOBAL_OPTIONS = 0,
+ PVT_CFG_CONTAINER,
+ PVT_CONTAINER,
+
+ /* Must be declared last */
+ NUM_GLOBAL_OBJECTS,
+};
+
+static AO2_GLOBAL_OBJ_STATIC(global_config, NUM_GLOBAL_OBJECTS);
+AST_MUTEX_DEFINE_STATIC(global_config_transaction);
+
+static struct ao2_container *config_opts;
+
+static void skel_global_config_destructor(void *obj)
+{
+ struct skel_global_config *cfg = obj;
+ ast_string_field_free_memory(cfg);
+}
+
+static void skel_pvt_destructor(void *obj)
+{
+ struct skel_pvt *pvt = obj;
+ ast_string_field_free_memory(pvt);
+}
+
+static int skel_pvt_hash(const void *obj, const int flags)
+{
+ const struct skel_pvt *pvt = obj;
+ const char *name = (flags & OBJ_KEY) ? obj : pvt->name;
+ return ast_str_case_hash(name);
+}
+
+static int skel_pvt_cmp(void *obj, void *arg, int flags)
+{
+ struct skel_pvt *one = obj, *two = arg;
+ const char *match = (flags & OBJ_KEY) ? arg : two->name;
+ return strcasecmp(one->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
+}
+
+static void skel_pvt_config_destructor(void *obj)
+{
+ struct skel_pvt_config *cfg = obj;
+ ast_string_field_free_memory(cfg);
+}
+
+static int skel_pvt_config_hash(const void *obj, const int flags)
+{
+ const struct skel_pvt_config *cfg = obj;
+ const char *name = (flags & OBJ_KEY) ? obj : cfg->name;
+ /* make this and others work with OBJ_KEY */
+ return ast_str_case_hash(name);
+}
+
+static int skel_pvt_config_cmp(void *obj, void *arg, int flags)
+{
+ struct skel_pvt_config *one = obj, *two = arg;
+ const char *match = (flags & OBJ_KEY) ? arg : two->name;
+ return strcasecmp(one->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
+}
+
+static void ao2_cleanup(void *obj)
+{
+ if (obj) {
+ ao2_ref(obj, -1);
+ }
+}
+
+static void apply_config(struct skel_global_config *new_global, struct ao2_container *new_pvt_container, struct ao2_container *new_cfg_container)
+{
+ void *old;
+ void *array[NUM_GLOBAL_OBJECTS];
+ int i;
+
+ array[GLOBAL_OPTIONS] = new_global;
+ array[PVT_CONTAINER] = new_pvt_container;
+ array[PVT_CFG_CONTAINER] = new_cfg_container;
+
+ /* Instead of having a global lock here, I would prefer an ao2 global obj API
+ * function that allows the entire array to be swapped out with its intenral
+ * lock held. */
+ ast_mutex_lock(&global_config_transaction);
+ for (i = 0; i < NUM_GLOBAL_OBJECTS; i++) {
+ if ((old = ao2_global_obj_replace(global_config, i, array[i]))) {
+ /* There was an existing config */
+ ao2_ref(old, -1);
+ }
+ ao2_ref(array[i], -1);
+ }
+ ast_mutex_unlock(&global_config_transaction);
+
+ ast_log(LOG_NOTICE, "Succesfully applied config!\n");
+}
static int app_exec(struct ast_channel *chan, const char *data)
{
@@ -140,15 +267,329 @@
return res;
}
+static struct skel_pvt *new_pvt(const char *name)
+{
+ struct skel_pvt *pvt;
+
+ if (!(pvt = ao2_alloc(sizeof(*pvt), skel_pvt_destructor))) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(pvt, 128)) {
+ ao2_ref(pvt, -1);
+ return NULL;
+ }
+ ast_string_field_set(pvt, name, name);
+ return pvt;
+}
+
+static struct skel_pvt_config *new_pvt_cfg(struct ast_config *cfg, const char *cat)
+{
+ struct skel_pvt_config *pvtcfg;
+ struct ast_variable *var;
+
+ if (!(pvtcfg = ao2_alloc(sizeof(*pvtcfg), skel_pvt_config_destructor))) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(pvtcfg, 128)) {
+ ao2_ref(pvtcfg, -1);
+ return NULL;
+ }
+
+ if (!(pvtcfg->caps = ast_format_cap_alloc_nolock())) {
+ ao2_ref(pvtcfg, -1);
+ return NULL;
+ }
+
+ ast_string_field_set(pvtcfg, name, cat);
+
+ if (ast_config_option_set_defaults(config_opts, cat, pvtcfg)) {
+ ao2_ref(pvtcfg, -1);
+ return NULL;
+ }
+
+ for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
+ if (ast_config_parse_category_options(config_opts, cfg, cat, pvtcfg)) {
+ ast_log(LOG_WARNING, "Config parsing failed at lineno %d, %s=%s\n", var->lineno, var->name, var->value);
+ ao2_ref(pvtcfg, -1);
+ return NULL;
+ }
+ }
+
+ return pvtcfg;
+}
+
+static int process_pvt_config_options(struct ast_config *cfg, struct ao2_container *newpvts, struct ao2_container *newcfgs) {
+ RAII_VAR(struct ao2_container *, pvt_container, ao2_global_obj_ref(global_config, PVT_CONTAINER), ao2_cleanup);
+ const char *cat = NULL;
+
+ /* It is ok if pvt_container is NULL, it just means this is our first load */
+
+ while ((cat = ast_category_browse(cfg, cat))) {
+ struct skel_pvt *tmppvt;
+ struct skel_pvt_config *tmpcfg;
+
+ if (!strcasecmp(cat, "general")) {
+ continue;
+ }
+
+ if (!(pvt_container && (tmppvt = ao2_find(pvt_container, cat, OBJ_KEY))) && !(tmppvt = new_pvt(cat))) {
+ /* Since we will be replacing the whole private container, bail out on errors instead of just
+ * skipping privates with config errors */
+ ast_log(LOG_WARNING, "Could not create pvt '%s,' ignoring all private config changes.\n", cat);
+ return -1;
+ }
+
+ if (!(tmpcfg = new_pvt_cfg(cfg, cat))) {
+ ao2_ref(tmppvt, -1);
+ return -1;
+ }
+ /* We have a valid pvt/cfg, link 'em */
+ ao2_link(newpvts, tmppvt);
+ ao2_ref(tmppvt, -1);
+ ao2_link(newcfgs, tmpcfg);
+ ao2_ref(tmpcfg, -1);
+ }
+
+ return 0;
+}
+
+static struct skel_global_config *new_global_config(void)
+{
+ struct skel_global_config *cfg;
+
+ /* Allocate/initialize memory */
+ if (!(cfg = ao2_alloc(sizeof(*cfg), skel_global_config_destructor))) {
+ return NULL;
+ }
+
+ if (ast_string_field_init(cfg, 128)) {
+ ao2_ref(cfg, -1);
+ return NULL;
+ }
+
+ /* Set defaults */
+ if (ast_config_option_set_defaults(config_opts, "general", cfg)) {
+ ao2_ref(cfg, -1);
+ return NULL;
+ }
+
+ return cfg;
+}
+
+static struct skel_global_config *process_global_config_options(struct ast_config *cfg)
+{
+ struct skel_global_config *skelcfg;
+
+ if (!(skelcfg = new_global_config())) {
+ return NULL;
+ }
+
+ if (ast_config_parse_category_options(config_opts, cfg, "general", skelcfg)) {
+ ao2_ref(skelcfg, -1);
+ return NULL;
+ }
+
+ return skelcfg;
+}
+
+static int process_config(int reload)
+{
+ struct ast_config *cfg;
+ struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
+ static const char *cfg_file = "app_skel.conf";
+ struct skel_global_config *new_global_config = NULL;
+ struct ao2_container *new_pvt_container = NULL;
+ struct ao2_container *new_cfg_container = NULL;
+
+ if (!(cfg = ast_config_load(cfg_file, cfg_flags))) {
+ ast_log(LOG_ERROR, "Unable to load config file '%s'\n", cfg_file);
+ return -1;
+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
+ ast_debug(1, "%s was unchanged\n", cfg_file);
+ return 0;
+ } else if (cfg == CONFIG_STATUS_FILEINVALID) {
+ ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n", cfg_file);
+ return -1;
+ } else if (cfg == CONFIG_STATUS_FILEMISSING) {
+ ast_log(LOG_ERROR, "%s is missing! Cannot load %s\n", cfg_file, AST_MODULE);
+ return -1;
+ }
+
+ /* If either [general] or individual parsing fails, refuse to load or make any changes.
+ * If no settings from [general] filter down into settings for individual private
+ * structures, then treating the two settings as separate cases would be fine. Note
+ * that since we replace the entire private container, it is important that we verify
+ * that there are no errors in *any* of the private configurations before replacing
+ * the existing container */
+ if (!(new_global_config = process_global_config_options(cfg))) {
+ goto error;
+ }
+
+ if (!(new_pvt_container = ao2_container_alloc(17, skel_pvt_hash, skel_pvt_cmp))) {
+ goto error;
+ }
+ if (!(new_cfg_container = ao2_container_alloc(17, skel_pvt_config_hash, skel_pvt_config_cmp))) {
+ goto error;
+ }
+
+ if (process_pvt_config_options(cfg, new_pvt_container, new_cfg_container)) {
+ goto error;
+ }
+
+ /* apply_config releases the temporary objects */
+ apply_config(new_global_config, new_pvt_container, new_cfg_container);
+
+ ast_config_destroy(cfg);
+
+ return 0;
+
+error:
+ ast_log(LOG_WARNING, "Ignoring config changes\n");
+ ast_config_destroy(cfg);
+ if (new_pvt_container) {
+ ao2_ref(new_pvt_container, -1);
+ }
+ if (new_cfg_container) {
+ ao2_ref(new_cfg_container, -1);
+ }
+ if (new_global_config) {
+ ao2_ref(new_global_config, -1);
+ }
+ return -1;
+}
+
+static char *handle_skel_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct skel_global_config *cfg;
+
+ switch(cmd) {
+ case CLI_INIT:
+ e->command = "skel show config";
+ e->usage =
+ "Usage: skel show config\n"
+ " List app_skel global config\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (!(cfg = ao2_global_obj_ref(global_config, GLOBAL_OPTIONS))) {
+ return NULL;
+ }
+
+ ast_cli(a->fd, "foo: %s\n", cfg->foo);
+ ast_cli(a->fd, "bar: %s\n", cfg->bar);
+ ast_cli(a->fd, "baz: %s\n", cfg->baz);
+ ast_cli(a->fd, "blah: %s\n", AST_CLI_YESNO(cfg->blah));
+ ast_cli(a->fd, "bindaddr: %s\n", ast_sockaddr_stringify(&cfg->bindaddr));
+
+ ao2_ref(cfg, -1);
+
+ return CLI_SUCCESS;
+}
+
+static char *handle_skel_show_pvts(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ struct ao2_container *pvts, *cfgs;
+ struct ao2_iterator iter;
+ struct skel_pvt *pvt;
+ char codec_buf[128];
+
+ switch(cmd) {
+ case CLI_INIT:
+ e->command = "skel show privates";
+ e->usage =
+ "Usage: skel show privates\n"
+ " List the app_skel privates\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ if (!(pvts = ao2_global_obj_ref(global_config, PVT_CONTAINER))) {
+ return NULL;
+ }
+ if (!(cfgs = ao2_global_obj_ref(global_config, PVT_CFG_CONTAINER))) {
+ ao2_ref(pvts, -1);
+ return NULL;
+ }
+
+#define SKEL_FORMAT "%-20.20s %-25.25s %-20.20s %-5.5s\n"
+ ast_cli(a->fd, SKEL_FORMAT, "Name", "Description", "Codecs", "ACL");
+ iter = ao2_iterator_init(pvts, 0);
+ while ((pvt = ao2_iterator_next(&iter))) {
+ struct skel_pvt_config *cfg;
+ if (!(cfg = ao2_find(cfgs, pvt->name, OBJ_KEY))) {
+ ast_log(LOG_NOTICE, "Could not find config info for %s\n", pvt->name);
+ ao2_ref(pvt, -1);
+ continue;
+ }
+ ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, cfg->caps);
+ ast_cli(a->fd, SKEL_FORMAT, pvt->name, cfg->description, codec_buf, AST_CLI_YESNO(cfg->permit != NULL));
+ ao2_ref(pvt, -1);
+ ao2_ref(cfg, -1);
+ }
+ ao2_iterator_destroy(&iter);
+#undef SKEL_FORMAT
+
+ ao2_ref(pvts, -1);
+ ao2_ref(cfgs, -1);
+
+ return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry skel_cli[] = {
+ AST_CLI_DEFINE(handle_skel_show_config, "Show app_skel global config options"),
+ AST_CLI_DEFINE(handle_skel_show_pvts, "Show app_skel private thingys"),
+};
+
+static int reload_module(void)
+{
+ if (process_config(1)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ return 0;
+}
+
static int unload_module(void)
{
+ ast_cli_unregister_multiple(skel_cli, ARRAY_LEN(skel_cli));
+ ao2_global_obj_release(global_config);
return ast_unregister_application(app);
}
static int load_module(void)
{
- return ast_register_application_xml(app, app_exec) ?
+ if (!(config_opts = ast_config_option_container_new())) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ /* General Options */
+ ast_config_option_register(config_opts, "foo", CONTEXT_ALLOW, "general", "booya", OPT_STRINGFIELD_T, struct skel_global_config, 0, foo);
+ ast_config_option_register(config_opts, "bar", CONTEXT_ALLOW, "general", NULL, OPT_STRINGFIELD_T, struct skel_global_config, 0, bar);
+ ast_config_option_register(config_opts, "baz", CONTEXT_ALLOW, "general", NULL, OPT_STRINGFIELD_T, struct skel_global_config, 0, baz);
+ ast_config_option_register(config_opts, "blah", CONTEXT_ALLOW, "general", NULL, OPT_BOOL_T, struct skel_global_config, 1, blah);
+ ast_config_option_register(config_opts, "bindaddr", CONTEXT_ALLOW, "general", "0.0.0.0:1234", OPT_SOCKADDR_T, struct skel_global_config, PARSE_PORT_REQUIRE, bindaddr);
+
+ ast_config_option_register(config_opts, "description", CONTEXT_DENY, "general", NULL, OPT_STRINGFIELD_T, struct skel_pvt_config, 0, description);
+ ast_config_option_register(config_opts, "allow", CONTEXT_DENY, "general", "ulaw,alaw", OPT_CODEC_T, struct skel_pvt_config, 1, prefs, caps);
+ ast_config_option_register(config_opts, "permit", CONTEXT_DENY, "general", NULL, OPT_ACL_T, struct skel_pvt_config, 1, permit);
+
+ if (process_config(0)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ ast_cli_register_multiple(skel_cli, ARRAY_LEN(skel_cli));
+ return ast_register_application_xml(app, app_exec) ?
AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
}
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Skeleton (sample) Application");
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Skeleton (sample) Application",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload_module,
+ .load_pri = AST_MODPRI_DEFAULT,
+);
Added: team/twilson/config_work/configs/app_skel.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/twilson/config_work/configs/app_skel.conf.sample?view=auto&rev=361853
==============================================================================
--- team/twilson/config_work/configs/app_skel.conf.sample (added)
+++ team/twilson/config_work/configs/app_skel.conf.sample Tue Apr 10 16:32:42 2012
@@ -1,0 +1,15 @@
+[general]
+foo=one
+bar=two
+baz=three
+blah=no
+bindaddr=1.2.3.4:1234
+
+[pvt1]
+description=first private
+allow=!all,ulaw,alaw
+permit=127.0.0.1/32
+
+[pvt2]
+description=second private
+allow=!all,ulaw
Propchange: team/twilson/config_work/configs/app_skel.conf.sample
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/twilson/config_work/configs/app_skel.conf.sample
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/twilson/config_work/configs/app_skel.conf.sample
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: 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=auto&rev=361853
==============================================================================
--- team/twilson/config_work/include/asterisk/config_options.h (added)
+++ team/twilson/config_work/include/asterisk/config_options.h Tue Apr 10 16:32:42 2012
@@ -1,0 +1,92 @@
+#ifndef _ASTERISK_CONFIG_OPTIONS_H
+#define _ASTERISK_CONFIG_OPTIONS_H
+
+#include "asterisk/config.h"
+#include "asterisk/astobj2.h"
+
+struct ast_config_option;
+
+enum ast_config_option_type {
+ OPT_INT_T,
+ OPT_UINT_T,
+ OPT_DOUBLE_T,
+ OPT_SOCKADDR_T,
+ OPT_STRINGFIELD_T,
+ OPT_BOOL_T,
+ OPT_ACL_T,
+ OPT_CODEC_T,
+};
+
+enum ast_config_option_context_op {
+ CONTEXT_DENY,
+ CONTEXT_ALLOW,
+};
+
+typedef int (*ast_config_option_handler)(const struct ast_config_option *opt, struct ast_variable *var, void *obj);
+
+int ast_config_option_int_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj);
+int ast_config_option_uint_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj);
+int ast_config_option_double_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj);
+int ast_config_option_sockaddr_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj);
+int ast_config_option_stringfield_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj);
+int ast_config_option_bool_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj);
+int ast_config_option_acl_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj);
+int ast_config_option_codec_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj);
+
+struct ast_config_option *__ast_config_option_build(const char *name, enum ast_config_option_context_op context_allow,
+ const char *context, const char *default_val, enum ast_config_option_type type, ast_config_option_handler handler, unsigned int flags, size_t argc, ...);
+struct ao2_container *ast_config_option_container_new(void);
+struct ast_config_option *ast_config_option_find(struct ao2_container *container, const char *name, const char *cat);
+int ast_config_parse_category_options(struct ao2_container *container, struct ast_config *cfg, const char *cat, void *obj);
+int ast_config_option_set_defaults(struct ao2_container *container, const char *context, void *obj);
+
+#define PASTE(arg1, arg2) PASTE1(arg1, arg2)
+#define PASTE1(arg1, arg2) arg1##arg2
+
+#define ARGIFY(...) __VA_ARGS__
+
+#define ARGMAP_1(func, type, in, x, ...) ARGIFY(in, func(type, x))
+#define ARGMAP_2(func, type, in, x, ...)\
+ ARGMAP_1(func, type, ARGIFY(in, func(type, x)), __VA_ARGS__)
+#define ARGMAP_3(func, type, in, x, ...)\
+ ARGMAP_2(func, type, ARGIFY(in, func(type, x)), __VA_ARGS__)
+#define ARGMAP_4(func, type, in, x, ...)\
+ ARGMAP_3(func, type, ARGIFY(in, func(type, x)), __VA_ARGS__)
+#define ARGMAP_5(func, type, in, x, ...)\
+ ARGMAP_4(func, type, ARGIFY(in, func(type, x)), __VA_ARGS__)
+#define ARGMAP_6(func, type, in, x, ...)\
+ ARGMAP_5(func, type, ARGIFY(in, func(type, x)), __VA_ARGS__)
+#define ARGMAP_7(func, type, in, x, ...)\
+ ARGMAP_6(func, type, ARGIFY(in, func(type, x)), __VA_ARGS__)
+#define ARGMAP_8(func, type, in, x, ...)\
+ ARGMAP_7(func, type, ARGIFY(in, func(type, x)), __VA_ARGS__)
+
+#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
+
+/* This is sneaky as hell. On the very first argument, we set "in" to N, the number of arguments, so
+ * that the accumulation both works properly for the first argument (since "in" can't be empty) and
+ * we get the number of arguments too */
+#define ARGMAP_(N, func, type, x, ...) PASTE(ARGMAP_, N)(func, type, N, x, __VA_ARGS__)
+#define ARGMAP(func, type, x, ...) ARGMAP_(VA_NARGS(x, ##__VA_ARGS__), func, type, x, __VA_ARGS__)
+
+#define ast_config_option_register(container, name, op, context, default_val, opt_type, struct_type, flags, ...) {\
+ struct ast_config_option *__opt; \
+ __opt = opt_type == OPT_STRINGFIELD_T ? \
+ __ast_config_option_build(name, op, context, default_val, opt_type, NULL, flags, ARGMAP(offsetof, struct_type, __VA_ARGS__, __field_mgr_pool, __field_mgr)) : \
+ __ast_config_option_build(name, op, context, default_val, opt_type, NULL, flags, ARGMAP(offsetof, struct_type, __VA_ARGS__)); \
+ if (__opt) { \
+ ao2_link(container, __opt); \
+ ao2_ref(__opt, -1); \
+ } \
+}
+
+#define ast_config_option_register_custom(container, name, op, context, default_val, opt_type, handler, flags) { \
+ struct ast_config_option *__opt = ast_config_option_build(name, op, context, default_val, opt_type, handler, flags); \
+ if (__opt) { \
+ ao2_link(container, __opt); \
+ ao2_ref(__opt, -1); \
+ } \
+}
+
+#endif /* _ASTERISK_CONFIG_OPTIONS_H */
Propchange: team/twilson/config_work/include/asterisk/config_options.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/twilson/config_work/include/asterisk/config_options.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/twilson/config_work/include/asterisk/config_options.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: team/twilson/config_work/include/asterisk/stringfields.h
URL: http://svnview.digium.com/svn/asterisk/team/twilson/config_work/include/asterisk/stringfields.h?view=diff&rev=361853&r1=361852&r2=361853
==============================================================================
--- team/twilson/config_work/include/asterisk/stringfields.h (original)
+++ team/twilson/config_work/include/asterisk/stringfields.h Tue Apr 10 16:32:42 2012
@@ -313,22 +313,24 @@
\param data String value to be copied into the field
\return nothing
*/
-#define ast_string_field_ptr_set(x, ptr, data) do { \
- const char *__d__ = (data); \
- size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1; \
- ast_string_field *__p__ = (ast_string_field *) (ptr); \
- if (__dlen__ == 1) { \
- __ast_string_field_release_active((x)->__field_mgr_pool, *__p__); \
- *__p__ = __ast_string_field_empty; \
- } else if ((__dlen__ <= AST_STRING_FIELD_ALLOCATION(*__p__)) || \
- (!__ast_string_field_ptr_grow(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__, __p__)) || \
- (*__p__ = __ast_string_field_alloc_space(&(x)->__field_mgr, &(x)->__field_mgr_pool, __dlen__))) { \
- if (*__p__ != (*ptr)) { \
- __ast_string_field_release_active((x)->__field_mgr_pool, (*ptr)); \
- } \
- memcpy(* (void **) __p__, __d__, __dlen__); \
- } \
- } while (0)
+#define ast_string_field_ptr_set(x, ptr, data) ast_string_field_ptr_set_by_fields((x)->__field_mgr_pool, (x)->__field_mgr, ptr, data)
+
+#define ast_string_field_ptr_set_by_fields(field_mgr_pool, field_mgr, ptr, data) do { \
+ const char *__d__ = (data); \
+ size_t __dlen__ = (__d__) ? strlen(__d__) + 1 : 1; \
+ ast_string_field *__p__ = (ast_string_field *) (ptr); \
+ if (__dlen__ == 1) { \
+ __ast_string_field_release_active(field_mgr_pool, *__p__); \
+ *__p__ = __ast_string_field_empty; \
+ } else if ((__dlen__ <= AST_STRING_FIELD_ALLOCATION(*__p__)) || \
+ (!__ast_string_field_ptr_grow(&field_mgr, &field_mgr_pool, __dlen__, __p__)) || \
+ (*__p__ = __ast_string_field_alloc_space(&field_mgr, &field_mgr_pool, __dlen__))) { \
+ if (*__p__ != (*ptr)) { \
+ __ast_string_field_release_active(field_mgr_pool, (*ptr)); \
+ } \
+ memcpy(* (void **) __p__, __d__, __dlen__); \
+ } \
+ } while (0)
/*!
\brief Set a field to a simple string value
Modified: team/twilson/config_work/include/asterisk/utils.h
URL: http://svnview.digium.com/svn/asterisk/team/twilson/config_work/include/asterisk/utils.h?view=diff&rev=361853&r1=361852&r2=361853
==============================================================================
--- team/twilson/config_work/include/asterisk/utils.h (original)
+++ team/twilson/config_work/include/asterisk/utils.h Tue Apr 10 16:32:42 2012
@@ -863,4 +863,8 @@
*/
char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size);
+#define RAII_VAR(vartype,varname,initval,dtor) \
+ void _dtor_ ## varname (vartype * v) { dtor(*v); } \
+ vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval)
+
#endif /* _ASTERISK_UTILS_H */
Added: team/twilson/config_work/main/config_options.c
URL: http://svnview.digium.com/svn/asterisk/team/twilson/config_work/main/config_options.c?view=auto&rev=361853
==============================================================================
--- team/twilson/config_work/main/config_options.c (added)
+++ team/twilson/config_work/main/config_options.c Tue Apr 10 16:32:42 2012
@@ -1,0 +1,247 @@
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <regex.h>
+
+#include "asterisk/config.h"
+#include "asterisk/config_options.h"
+#include "asterisk/stringfields.h"
+#include "asterisk/acl.h"
+#include "asterisk/frame.h"
+
+struct ast_config_option {
+ const char *name;
+ const char *context;
+ const char *default_val;
+ regex_t *context_regex;
+ enum ast_config_option_type type;
+ enum ast_config_option_context_op context_allow;
+ ast_config_option_handler handler;
+ unsigned int flags;
+ size_t argc;
+ size_t args[0];
+};
+
+static void config_option_destroy(void *obj)
+{
+ struct ast_config_option *opt = obj;
+ if (opt->context_regex) {
+ regfree(opt->context_regex);
+ ast_free(opt->context_regex);
+ }
+}
+
+static int (*ast_config_option_default_handlers[])(const struct ast_config_option *opt, struct ast_variable *var, void *obj) = {
+ ast_config_option_int_fn, /* OPT_INT_T */
+ ast_config_option_uint_fn, /* OPT_UINT_T */
+ ast_config_option_double_fn, /* OPT_DOUBLE_T */
+ ast_config_option_sockaddr_fn, /* OPT_SOCKADDR_T */
+ ast_config_option_stringfield_fn, /* OPT_STRINGFIELD_T */
+ ast_config_option_bool_fn, /* OPT_BOOL_T */
+ ast_config_option_acl_fn, /* OPT_ACL_T */
+ ast_config_option_codec_fn, /* OPT_CODEC_T */
+};
+
+/*
+struct ast_config_option *__ast_config_option_build(const char *name, enum ast_config_option_context_op context_allow,
+ const char *context, const char *default_val, enum ast_config_option_type type, size_t field_offset,
+ ast_config_option_handler handler, unsigned int flags, size_t field_mgr_ofst, size_t field_mgr_pool_ofst)
+*/
+struct ast_config_option *__ast_config_option_build(const char *name, enum ast_config_option_context_op context_allow,
+ const char *context, const char *default_val, enum ast_config_option_type type, ast_config_option_handler handler, unsigned int flags, size_t argc, ...)
+{
+ struct ast_config_option *opt;
+ va_list ap;
+ regex_t *regex;
+ int tmp;
+
+ if (!(regex = ast_calloc(1, sizeof(*regex)))) {
+ return NULL;
+ }
+ if ((tmp = regcomp(regex, context, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
+ char buf[80];
+ regerror(tmp, regex, buf, sizeof(buf));
+ ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", context, buf);
+ return NULL;
+ }
+
+ if (!(opt = ao2_alloc(sizeof(*opt) + argc * sizeof(opt->args[0]), config_option_destroy))) {
+ return NULL;
+ }
+
+ va_start(ap, argc);
+ for (tmp = 0; tmp < argc; tmp++) {
+ opt->args[tmp] = va_arg(ap, size_t);
+ }
+ va_end(ap);
+
+ opt->name = name;
+ opt->context_allow = context_allow;
+ opt->context = context;
+ opt->context_regex = regex;
+ opt->default_val = default_val;
+ opt->type = type;
+ opt->handler = handler;
+ opt->flags = flags;
+ opt->argc = argc;
+
+ if (!opt->handler && !(opt->handler = ast_config_option_default_handlers[opt->type])) {
+ ao2_ref(opt, -1);
+ return NULL;
+ };
+
+ return opt;
+}
+
+static int test_opt_contexts(struct ast_config_option *opt1, struct ast_config_option *opt2)
+{
+ return regexec(opt1->context_regex, opt2->context, 0, NULL, 0) ||
+ regexec(opt2->context_regex, opt1->context, 0, NULL, 0) ? -1 : 0;
+}
+
+static int config_opt_hash(const void *obj, const int flags)
+{
+ const struct ast_config_option *opt = obj;
+ const char *name = (flags & OBJ_KEY) ? obj : opt->name;
+ return ast_str_case_hash(name);
+}
+
+static int config_opt_cmp(void *obj, void *arg, int flags)
+{
+ struct ast_config_option *opt1 = obj, *opt2 = arg;
+ return strcasecmp(opt1->name, opt2->name) || opt1->context_allow != opt2->context_allow || test_opt_contexts(opt1, opt2) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+static int find_option_cb(void *obj, void *arg, void *data, int flags)
+{
+ const char *name = arg, *context = data;
+ struct ast_config_option *match = obj;
+ /* Continue if we don't match on name, or if NOT regex_matches XOR regex_should_match */
+ return strcasecmp(name, match->name) || !regexec(match->context_regex, context, 0, NULL, 0) == !match->context_allow ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+struct ast_config_option *ast_config_option_find(struct ao2_container *container, const char *name, const char *cat)
+{
+ return ao2_callback_data(container, OBJ_KEY, find_option_cb, (void *) name, (void *) cat);
+}
+
+#define CONFIG_OPT_BUCKETS 53
+struct ao2_container *ast_config_option_container_new(void)
+{
+ return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
+}
+
+int ast_config_parse_category_options(struct ao2_container *container, struct ast_config *cfg, const char *cat, void *obj)
+{
+ struct ast_variable *var;
+ struct ast_config_option *opt;
+
+ for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
+ if (!(opt = ast_config_option_find(container, var->name, cat))) {
+ ast_log(LOG_WARNING, "Could not find option suitable for category '%s' named '%s'\n", cat, var->name);
+ return -1;
+ }
+ if (!opt->handler) {
+ /* It should be impossible for an option to not have a handler */
+ ao2_ref(opt, -1);
+ return -1;
+ }
+ if (opt->handler(opt, var, obj)) {
+ ast_log(LOG_WARNING, "Error parsing %s=%s at line %d\n", var->name, var->value, var->lineno);
+ ao2_ref(opt, -1);
+ return -1;
+ }
+ ao2_ref(opt, -1);
+ }
+
+ return 0;
+}
+
+static int match_option_by_context(void *obj, void *arg, int flags)
+{
+ struct ast_config_option *match = obj;
+ const char *context = arg;
+
+ return !regexec(match->context_regex, context, 0, NULL, 0) == !match->context_allow ? 0 : CMP_MATCH;
+}
+
+int ast_config_option_set_defaults(struct ao2_container *container, const char *context, void *obj)
+{
+ struct ao2_iterator *iter;
+ struct ast_config_option *opt;
+
+ iter = ao2_callback(container, OBJ_MULTIPLE, match_option_by_context, (void *) context);
+ while ((opt = ao2_iterator_next(iter))) {
+ struct ast_variable *var;
+ if (ast_strlen_zero(opt->default_val)) {
+ continue;
+ }
+ if (!(var = ast_variable_new(opt->name, opt->default_val, ""))) {
+ ao2_ref(opt, -1);
+ ao2_iterator_destroy(iter);
+ return -1;
+ }
+ if (opt->handler(opt, var, obj)) {
+ ao2_ref(opt, -1);
+ ao2_iterator_destroy(iter);
+ ast_variables_destroy(var);
+ return -1;
+ }
+ ast_variables_destroy(var);
+ }
+ ao2_iterator_destroy(iter);
+
+ return 0;
+}
+
+/* default option handlers */
+int ast_config_option_int_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj) {
+ int *field = (int *)(obj + opt->args[0]);
+ return ast_parse_arg(var->value, PARSE_INT32 | opt->flags, field);
+}
+
+int ast_config_option_uint_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj) {
+ unsigned int *field = (unsigned int *)(obj + opt->args[0]);
+ return ast_parse_arg(var->value, PARSE_UINT32 | opt->flags, field);
+}
+int ast_config_option_double_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj) {
+ double *field = (double *)(obj + opt->args[0]);
+ return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
+}
+int ast_config_option_acl_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj) {
+ struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
+ int error = 0;
+ *ha = ast_append_ha(var->name, var->value, *ha, &error);
+ return error;
+}
+
+/* opt->args[0] = struct ast_codec_pref, opt->args[1] struct ast_format_cap * */
+int ast_config_option_codec_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj) {
+ struct ast_codec_pref *pref = (struct ast_codec_pref *)(obj + opt->args[0]);
+ struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[1]);
+ return ast_parse_allow_disallow(pref, *cap, var->value, opt->flags);
+}
+
+/* opt->args[0] = ast_string_field, opt->args[1] = field_mgr_pool, opt->args[2] = field_mgri */
+int ast_config_option_stringfield_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj)
+{
+ const char **field = (const char **)(obj + opt->args[0]);
+ struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
+ struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
+ ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
+ return 0;
+}
+
+int ast_config_option_bool_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj)
+{
+ unsigned int *field = (unsigned int *)(obj + opt->args[0]);
+ *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
+ return 0;
+}
+
+int ast_config_option_sockaddr_fn(const struct ast_config_option *opt, struct ast_variable *var, void *obj)
+{
+ struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
+ return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
+}
Propchange: team/twilson/config_work/main/config_options.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/twilson/config_work/main/config_options.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/twilson/config_work/main/config_options.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the asterisk-commits
mailing list