[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