[asterisk-commits] murf: branch murf/bug_7638 r58959 - in /team/murf/bug_7638: main/ pbx/ utils/

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Thu Mar 15 20:44:47 MST 2007


Author: murf
Date: Thu Mar 15 22:44:47 2007
New Revision: 58959

URL: http://svn.digium.com/view/asterisk?view=rev&rev=58959
Log:
OK! I got an app to compile and link. Now on to conf2ael; I have to refactor it to use the stuff in extconf.c; I may need access to more funcs there.

Modified:
    team/murf/bug_7638/main/pval.c
    team/murf/bug_7638/pbx/pbx_ael.c
    team/murf/bug_7638/utils/Makefile
    team/murf/bug_7638/utils/ael_main.c
    team/murf/bug_7638/utils/conf2ael.c
    team/murf/bug_7638/utils/extconf.c

Modified: team/murf/bug_7638/main/pval.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/main/pval.c?view=diff&rev=58959&r1=58958&r2=58959
==============================================================================
--- team/murf/bug_7638/main/pval.c (original)
+++ team/murf/bug_7638/main/pval.c Thu Mar 15 22:44:47 2007
@@ -51,11 +51,13 @@
 #endif
 
 static char expr_output[2096];
+#define AST_PBX_MAX_STACK  128
 
 /* these functions are in ../ast_expr2.fl */
 
 static int errs, warns;
 static int notes;
+static int extensions_dot_conf_loaded = 0;
 static char *registrar = "pbx_ael";
 
 static pval *current_db;
@@ -100,6 +102,51 @@
 static void remove_spaces_before_equals(char *str);
 static void substitute_commas(char *str);
 
+/*!
+ * When looking up extensions, we can have different requests
+ * identified by the 'action' argument, as follows.
+ * Note that the coding is such that the low 4 bits are the
+ * third argument to extension_match_core.
+ */
+enum ext_match_t {
+	E_MATCHMORE = 	0x00,	/* extension can match but only with more 'digits' */
+	E_CANMATCH =	0x01,	/* extension can match with or without more 'digits' */
+	E_MATCH =	0x02,	/* extension is an exact match */
+	E_MATCH_MASK =	0x03,	/* mask for the argument to extension_match_core() */
+	E_SPAWN =	0x12,	/* want to spawn an extension. Requires exact match */
+	E_FINDLABEL =	0x22	/* returns the priority for a given label. Requires exact match */
+};
+
+#define STATUS_NO_CONTEXT	1
+#define STATUS_NO_EXTENSION	2
+#define STATUS_NO_PRIORITY	3
+#define STATUS_NO_LABEL		4
+#define STATUS_SUCCESS		5
+
+/* request and result for pbx_find_extension */
+struct pbx_find_info {
+#if 0
+	const char *context;
+	const char *exten;
+	int priority;
+#endif
+
+	char *incstack[AST_PBX_MAX_STACK];      /* filled during the search */
+	int stacklen;                   /* modified during the search */
+	int status;                     /* set on return */
+	struct ast_switch *swo;         /* set on return */
+	const char *data;               /* set on return */
+	const char *foundcontext;       /* set on return */
+};
+
+struct ast_exten *external_find_extension(struct ast_context *bypass, 
+										  struct pbx_find_info *q,
+										  const char *context, 
+										  const char *exten, 
+										  int priority,
+										  const char *label, 
+										  const char *callerid, 
+										  enum ext_match_t action);
 
 
 /* I am adding this code to substitute commas with vertbars in the args to apps */
@@ -1330,11 +1377,19 @@
 					}
 				} else {
 					/* here is where code would go to check for target existence in extensions.conf files */
-					extern int this_target_in_extensions_dot_conf(char *context, char *exten, char *label);
+					struct pbx_find_info pfiq;
+					extern int localized_pbx_load_module(void);
 					
-					if (!this_target_in_extensions_dot_conf(first->u1.str, second->u1.str, third->u1.str))
-						ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto:  no context %s could be found that matches the goto target!\n",
-								item->filename, item->startline, item->endline, item->u1.list->u1.str);
+					if (!extensions_dot_conf_loaded)
+						localized_pbx_load_module();
+
+					external_find_extension(NULL, &pfiq, first->u1.str, second->u1.str, atoi(third->u1.str),
+											atoi(third->u1.str) ? NULL : third->u1.str, NULL, 
+											atoi(third->u1.str) ? E_MATCH : E_FINDLABEL);
+					
+					if (pfiq.status != STATUS_SUCCESS)
+						ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto:  Couldn't find goto target %s|%s|%s, not even in extensions.conf!\n",
+								item->filename, item->startline, item->endline, first->u1.str, second->u1.str, third->u1.str);
 					warns++;
 				}
 			} else {
@@ -2894,6 +2949,10 @@
 			str++;
 	}
 }
+
+/* =============================================================================================== */
+/* "CODE" GENERATOR -- Convert the AEL representation to asterisk extension language */
+/* =============================================================================================== */
 
 static void gen_match_to_pattern(char *pattern, char *result)
 {

Modified: team/murf/bug_7638/pbx/pbx_ael.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/pbx/pbx_ael.c?view=diff&rev=58959&r1=58958&r2=58959
==============================================================================
--- team/murf/bug_7638/pbx/pbx_ael.c (original)
+++ team/murf/bug_7638/pbx/pbx_ael.c Thu Mar 15 22:44:47 2007
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2007, Digium, Inc.
+ * Copyright (C) 2006, Digium, Inc.
  *
  * Steve Murphy <murf at parsetree.com>
  *
@@ -38,37 +38,113 @@
 
 #include "asterisk/pbx.h"
 #include "asterisk/config.h"
-#include "asterisk/options.h"
 #include "asterisk/module.h"
 #include "asterisk/logger.h"
 #include "asterisk/cli.h"
 #include "asterisk/app.h"
 #include "asterisk/callerid.h"
 #include "asterisk/ael_structs.h"
+#ifdef AAL_ARGCHECK
+#include "asterisk/argdesc.h"
+#endif
+
+/* these functions are in ../ast_expr2.fl */
 
 #define DEBUG_READ   (1 << 0)
 #define DEBUG_TOKENS (1 << 1)
 #define DEBUG_MACROS (1 << 2)
 #define DEBUG_CONTEXTS (1 << 3)
 
+static char *config = "extensions.ael";
 static char *registrar = "pbx_ael";
 static int pbx_load_module(void);
-#define AST_MODULE "pbx_ael"
-
-void ael2_semantic_check(pval *item, int *arg_errs, int *arg_warns, int *arg_notes);
+
+#ifndef AAL_ARGCHECK
+/* for the time being, short circuit all the AAL related structures
+   without permanently removing the code; after/during the AAL 
+   development, this code can be properly re-instated 
+*/
+
+#endif
+
+#ifdef AAL_ARGCHECK
+int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
+int option_matches( struct argdesc *should, pval *is, struct argapp *app);
+int ael_is_funcname(char *name);
+#endif
+
+int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
+void check_pval(pval *item, struct argapp *apps, int in_globals);
+void check_pval_item(pval *item, struct argapp *apps, int in_globals);
+void check_switch_expr(pval *item, struct argapp *apps);
+void ast_expr_register_extra_error_info(char *errmsg);
+void ast_expr_clear_extra_error_info(void);
+int  ast_expr(char *expr, char *buf, int length);
+struct pval *find_macro(char *name);
+struct pval *find_context(char *name);
+struct pval *find_context(char *name);
+struct pval *find_macro(char *name);
+struct ael_priority *new_prio(void);
+struct ael_extension *new_exten(void);
+void linkprio(struct ael_extension *exten, struct ael_priority *prio);
+void destroy_extensions(struct ael_extension *exten);
+void set_priorities(struct ael_extension *exten);
+void add_extensions(struct ael_extension *exten);
 void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root);
 void destroy_pval(pval *item);
+void destroy_pval_item(pval *item);
+int is_float(char *arg );
+int is_int(char *arg );
+int is_empty(char *arg);
 
 static int aeldebug = 0;
 
 /* interface stuff */
 
 /* if all the below are static, who cares if they are present? */
-extern int do_pbx_load_module(void);
 
 static int pbx_load_module(void)
 {
-	return do_pbx_load_module();
+	int errs, sem_err, sem_warn, sem_note;
+	char *rfilename;
+	struct ast_context *local_contexts=NULL, *con;
+	struct pval *parse_tree;
+
+	ast_log(LOG_NOTICE, "Starting AEL load process.\n");
+	if (config[0] == '/')
+		rfilename = (char *)config;
+	else {
+		rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
+		sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
+	}
+	ast_log(LOG_NOTICE, "AEL load process: calculated config file name '%s'.\n", rfilename);
+
+	if (access(rfilename,R_OK) != 0) {
+		ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
+		return AST_MODULE_LOAD_DECLINE;
+	}
+	
+	parse_tree = ael2_parse(rfilename, &errs);
+	ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
+	ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
+	if (errs == 0 && sem_err == 0) {
+		ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
+		ast_compile_ael2(&local_contexts, parse_tree);
+		ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
+		
+		ast_merge_contexts_and_delete(&local_contexts, registrar);
+		ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
+		for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
+			ast_context_verify_includes(con);
+		ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
+	} else {
+		ast_log(LOG_ERROR, "Sorry, but %d syntax errors and %d semantic errors were detected. It doesn't make sense to compile.\n", errs, sem_err);
+		destroy_pval(parse_tree); /* free up the memory */
+		return AST_MODULE_LOAD_FAILURE;
+	}
+	destroy_pval(parse_tree); /* free up the memory */
+	
+	return AST_MODULE_LOAD_SUCCESS;
 }
 
 /* CLI interface */
@@ -150,6 +226,16 @@
 {
 	return pbx_load_module();
 }
+
+#ifdef STANDALONE_AEL
+#define AST_MODULE "ael"
+int ael_external_load_module(void);
+int ael_external_load_module(void)
+{
+        pbx_load_module();
+        return 1;
+}
+#endif
 
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
 		.load = load_module,
@@ -158,3 +244,6 @@
 	       );
 
 
+
+
+

Modified: team/murf/bug_7638/utils/Makefile
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/utils/Makefile?view=diff&rev=58959&r1=58958&r2=58959
==============================================================================
--- team/murf/bug_7638/utils/Makefile (original)
+++ team/murf/bug_7638/utils/Makefile Thu Mar 15 22:44:47 2007
@@ -110,11 +110,9 @@
 
 aelparse: aelparse.o aelbison.o pbx_ael.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o pval.o extconf.o
 
-config_external.o : config_external.c
-
 extconf.o : extconf.c
 
-conf2ael: conf2ael.o config_external.o ast_expr2f.o ast_expr2.o aelbison.o aelparse.o pbx_ael.o pval.o extconf.o
+conf2ael: conf2ael.o ast_expr2f.o ast_expr2.o aelbison.o aelparse.o pbx_ael.o pval.o extconf.o
 
 
 testexpr2s: ../main/ast_expr2f.c ../main/ast_expr2.c ../main/ast_expr2.h

Modified: team/murf/bug_7638/utils/ael_main.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/utils/ael_main.c?view=diff&rev=58959&r1=58958&r2=58959
==============================================================================
--- team/murf/bug_7638/utils/ael_main.c (original)
+++ team/murf/bug_7638/utils/ael_main.c Thu Mar 15 22:44:47 2007
@@ -105,6 +105,18 @@
 static int FIRST_TIME = 0;
 static FILE *dumpfile;
 
+void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
+{
+	        va_list vars;
+		        va_start(vars,fmt);
+			
+			        printf("LOG: lev:%d file:%s  line:%d func: %s  ",
+						                   level, file, line, function);
+				        vprintf(fmt, vars);
+					        fflush(stdout);
+						        va_end(vars);
+}
+
 struct ast_app *pbx_findapp(const char *app)
 {
 	return (struct ast_app*)1; /* so as not to trigger an error */
@@ -350,10 +362,23 @@
 		printf("Executed ast_context_verify_includes();\n");
 }
 
+struct ast_context * ast_walk_contexts(void)
+{
+	if(!no_comp)
+		printf("Executed ast_walk_contexts();\n");
+	return 0;
+}
+
 void ast_cli_unregister_multiple(void)
 {
 	if(!no_comp)
 		printf("Executed ast_cli_unregister_multiple();\n");
+}
+
+void ast_context_destroy(void)
+{
+	if( !no_comp)
+		printf("Executed ast_context_destroy();\n");
 }
 
 void filter_leading_space_from_exprs(char *str)
@@ -396,14 +421,6 @@
 extern struct module_symbols mod_data;
 int ael_external_load_module(void);
 
-
-#define AST_MODULE "ael"
-int ael_external_load_module(void);
-int ael_external_load_module(void)
-{
-        do_pbx_load_module();
-        return 1;
-}
 
 int main(int argc, char **argv)
 {

Modified: team/murf/bug_7638/utils/conf2ael.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/utils/conf2ael.c?view=diff&rev=58959&r1=58958&r2=58959
==============================================================================
--- team/murf/bug_7638/utils/conf2ael.c (original)
+++ team/murf/bug_7638/utils/conf2ael.c Thu Mar 15 22:44:47 2007
@@ -58,6 +58,17 @@
 int pbx_load_config(const char *config_file);
 void get_start_stop(unsigned int *word, int bitsperword, int totalbits, int *start, int *end);
 int all_bits_set(unsigned int *word, int bitsperword, int totalbits);
+void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
+{
+	        va_list vars;
+		        va_start(vars,fmt);
+			
+			        printf("LOG: lev:%d file:%s  line:%d func: %s  ",
+						                   level, file, line, function);
+				        vprintf(fmt, vars);
+					        fflush(stdout);
+						        va_end(vars);
+}
 
 extern char *days[];
 extern char *months[];

Modified: team/murf/bug_7638/utils/extconf.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/utils/extconf.c?view=diff&rev=58959&r1=58958&r2=58959
==============================================================================
--- team/murf/bug_7638/utils/extconf.c (original)
+++ team/murf/bug_7638/utils/extconf.c Thu Mar 15 22:44:47 2007
@@ -664,15 +664,15 @@
 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);
 
-static struct ast_config *ast_config_load_with_comments(const char *filename);
+struct ast_config *localized_config_load_with_comments(const char *filename);
 static char *ast_category_browse(struct ast_config *config, const char *prev);
-struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
+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);
 
-struct ast_variable *ast_variable_new(const char *name, const char *value);
-
-struct ast_variable *ast_variable_new(const char *name, const char *value) 
+static struct ast_variable *ast_variable_new(const char *name, const char *value);
+
+static struct ast_variable *ast_variable_new(const char *name, const char *value) 
 {
 	struct ast_variable *variable;
 	int name_len = strlen(name) + 1;	
@@ -687,9 +687,9 @@
 	return variable;
 }
 
-void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
-
-void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
+static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
+
+static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
 {
 	if (!variable)
 		return;
@@ -700,6 +700,43 @@
 	category->last = variable;
 	while (category->last->next)
 		category->last = category->last->next;
+}
+
+static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
+
+static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
+{
+	struct ast_category *cat;
+
+	/* try exact match first, then case-insensitive match */
+	for (cat = config->root; cat; cat = cat->next) {
+		if (cat->name == category_name && (ignored || !cat->ignored))
+			return cat;
+	}
+
+	for (cat = config->root; cat; cat = cat->next) {
+		if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
+			return cat;
+	}
+
+	return NULL;
+}
+
+static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
+{
+	return category_get(config, category_name, 0);
+}
+
+static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
+{
+	struct ast_category *cat = NULL;
+
+	if (category && config->last_browse && (config->last_browse->name == category))
+		cat = config->last_browse;
+	else
+		cat = ast_category_get(config, category);
+
+	return (cat) ? cat->root : NULL;
 }
 
 static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
@@ -2323,8 +2360,8 @@
 
 AST_LIST_HEAD_NOLOCK(varshead, ast_var_t);
 
+AST_RWLOCK_DEFINE_STATIC(globalslock);
 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
-
 
 
 /* IN CONFLICT: struct ast_var_t *ast_var_assign(const char *name, const char *value); */
@@ -2382,7 +2419,7 @@
 };
 
 
-extern char *config; /* define this where you define main */
+static char *config = "extensions.ael";
 static char *registrar = "conf2ael";
 static char userscontext[AST_MAX_EXTENSION] = "default";
 static int static_config = 0;
@@ -2391,8 +2428,7 @@
 static int clearglobalvars_config = 0;
 /*! Go no deeper than this through includes (not counting loops) */
 #define AST_PBX_MAX_STACK	128
-static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
-void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
+static void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count);
 
 
 /* taken from strings.h */
@@ -2783,39 +2819,6 @@
 #endif
 
 
-static struct ast_custom_function *ast_custom_function_find(const char *name)
-{
-	struct ast_custom_function *acf = NULL;
-
-	AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
-		if (!strcmp(name, acf->name))
-			break;
-	}
-
-	return acf;
-}
-
-
-/*! \brief return a pointer to the arguments of the function,
- * and terminates the function name with '\\0'
- */
-static char *func_args(const char *function)
-{
-	char *args = strchr(function, '(');
-
-	if (!args)
-		ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
-	else {
-		char *p;
-		*args++ = '\0';
-		if ((p = strrchr(args, ')')) )
-			*p = '\0';
-		else
-			ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
-	}
-	return args;
-}
-
 static struct ast_var_t *ast_var_assign(const char *name, const char *value)
 {	
 	struct ast_var_t *var;
@@ -2840,61 +2843,13 @@
 }
 
 
+/* chopped this one off at the knees! */
 static int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
 {
-	char *args = func_args(function);
-	struct ast_custom_function *acfptr = ast_custom_function_find(function);
-
-	if (acfptr == NULL)
-		ast_log(LOG_ERROR, "Function %s not registered\n", function);
-	else if (!acfptr->write)
-		ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
-	else
-		return acfptr->write(chan, function, args, value);
+
+	ast_log(LOG_ERROR, "Function %s not registered\n", function);
 
 	return -1;
-}
-
-static unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
-{
-	int argc;
-	char *scan;
-	int paren = 0, quote = 0;
-
-	if (!buf || !array || !arraylen)
-		return 0;
-
-	memset(array, 0, arraylen * sizeof(*array));
-
-	scan = buf;
-
-	for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
-		array[argc] = scan;
-		for (; *scan; scan++) {
-			if (*scan == '(')
-				paren++;
-			else if (*scan == ')') {
-				if (paren)
-					paren--;
-			} else if (*scan == '"' && delim != '"') {
-				quote = quote ? 0 : 1;
-				/* Remove quote character from argument */
-				memmove(scan, scan + 1, strlen(scan));
-				scan--;
-			} else if (*scan == '\\') {
-				/* Literal character, don't parse */
-				memmove(scan, scan + 1, strlen(scan));
-			} else if ((*scan == delim) && !paren && !quote) {
-				*scan++ = '\0';
-				break;
-			}
-		}
-	}
-
-	if (*scan)
-		array[argc++] = scan;
-
-	return argc;
 }
 
 static void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
@@ -3146,29 +3101,9 @@
 	return category;
 }
 
-static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
-
-static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
-{
-	struct ast_category *cat;
-
-	/* try exact match first, then case-insensitive match */
-	for (cat = config->root; cat; cat = cat->next) {
-		if (cat->name == category_name && (ignored || !cat->ignored))
-			return cat;
-	}
-
-	for (cat = config->root; cat; cat = cat->next) {
-		if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
-			return cat;
-	}
-
-	return NULL;
-}
-
-static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name);
-
-static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
+struct ast_category *localized_category_get(const struct ast_config *config, const char *category_name);
+
+struct ast_category *localized_category_get(const struct ast_config *config, const char *category_name)
 {
 	return category_get(config, category_name, 0);
 }
@@ -3647,9 +3582,9 @@
 	return config;
 }
 
-static struct ast_config *ast_config_load(const char *filename);
-
-static struct ast_config *ast_config_load(const char *filename)
+struct ast_config *localized_config_load(const char *filename);
+
+struct ast_config *localized_config_load(const char *filename)
 {
 	struct ast_config *cfg;
 	struct ast_config *result;
@@ -3665,7 +3600,9 @@
 	return result;
 }
 
-static struct ast_config *ast_config_load_with_comments(const char *filename)
+struct ast_config *localized_config_load_with_comments(const char *filename);
+
+struct ast_config *localized_config_load_with_comments(const char *filename)
 {
 	struct ast_config *cfg;
 	struct ast_config *result;
@@ -3722,13 +3659,6 @@
 
 
 
-static int bit_at(unsigned int *word, int bitsperword, int bitnum);
-
-static int bit_at(unsigned int *word, int bitsperword, int bitnum)
-{
-	return word[bitnum/bitsperword] & (1 << (bitnum % bitsperword));
-}
-
 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat);
 
 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
@@ -3737,9 +3667,9 @@
 	cfg->current = (struct ast_category *) cat;
 }
 
-static int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator);
-
-static int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
+int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator);
+
+int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
 {
 	FILE *f;
 	char fn[256];
@@ -4738,11 +4668,6 @@
 	return ast_rwlock_wrlock(&conlock);
 }
 
-static int ast_rdlock_contexts(void)
-{
-	return ast_rwlock_rdlock(&conlock);
-}
-
 static int ast_unlock_contexts(void)
 {
 	return ast_rwlock_unlock(&conlock);
@@ -4751,11 +4676,6 @@
 static int ast_wrlock_context(struct ast_context *con)
 {
 	return ast_rwlock_wrlock(&con->lock);
-}
-
-static int ast_rdlock_context(struct ast_context *con)
-{
-	return ast_rwlock_rdlock(&con->lock);
 }
 
 static int ast_unlock_context(struct ast_context *con)
@@ -5091,15 +5011,351 @@
 	return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
 }
 
-static struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
-{
-	return __ast_context_create(extcontexts, name, registrar, 0);
-}
-
 static struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
 {
 	return __ast_context_create(extcontexts, name, registrar, 1);
 }
+
+
+/* chopped this one off at the knees */
+static int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
+{
+	ast_log(LOG_ERROR, "Function %s not registered\n", function);
+	return -1;
+}
+
+/*! \brief extract offset:length from variable name.
+ * Returns 1 if there is a offset:length part, which is
+ * trimmed off (values go into variables)
+ */
+static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
+{
+	int parens=0;
+
+	*offset = 0;
+	*length = INT_MAX;
+	*isfunc = 0;
+	for (; *var; var++) {
+		if (*var == '(') {
+			(*isfunc)++;
+			parens++;
+		} else if (*var == ')') {
+			parens--;
+		} else if (*var == ':' && parens == 0) {
+			*var++ = '\0';
+			sscanf(var, "%d:%d", offset, length);
+			return 1; /* offset:length valid */
+		}
+	}
+	return 0;
+}
+
+static const char *ast_var_value(const struct ast_var_t *var)
+{
+	return (var ? var->value : NULL);
+}
+
+/*! \brief takes a substring. It is ok to call with value == workspace.
+ *
+ * offset < 0 means start from the end of the string and set the beginning
+ *   to be that many characters back.
+ * length is the length of the substring.  A value less than 0 means to leave
+ * that many off the end.
+ * Always return a copy in workspace.
+ */
+static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
+{
+	char *ret = workspace;
+	int lr;	/* length of the input string after the copy */
+
+	ast_copy_string(workspace, value, workspace_len); /* always make a copy */
+
+	lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
+
+	/* Quick check if no need to do anything */
+	if (offset == 0 && length >= lr)	/* take the whole string */
+		return ret;
+
+	if (offset < 0)	{	/* translate negative offset into positive ones */
+		offset = lr + offset;
+		if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
+			offset = 0;
+	}
+
+	/* too large offset result in empty string so we know what to return */
+	if (offset >= lr)
+		return ret + lr;	/* the final '\0' */
+
+	ret += offset;		/* move to the start position */
+	if (length >= 0 && length < lr - offset)	/* truncate if necessary */
+		ret[length] = '\0';
+	else if (length < 0) {
+		if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
+			ret[lr + length - offset] = '\0';
+		else
+			ret[0] = '\0';
+	}
+
+	return ret;
+}
+
+/*! \brief  Support for Asterisk built-in variables in the dialplan
+\note	See also
+	- \ref AstVar	Channel variables
+	- \ref AstCauses The HANGUPCAUSE variable
+ */
+static void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
+{
+	const char not_found = '\0';
+	char *tmpvar;
+	const char *s;	/* the result */
+	int offset, length;
+	int i, need_substring;
+	struct varshead *places[2] = { headp, &globals };	/* list of places where we may look */
+	
+	/*
+	 * Make a copy of var because parse_variable_name() modifies the string.
+	 * Then if called directly, we might need to run substring() on the result;
+	 * remember this for later in 'need_substring', 'offset' and 'length'
+	 */
+	tmpvar = ast_strdupa(var);	/* parse_variable_name modifies the string */
+	need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
+	
+	/*
+	 * Look first into predefined variables, then into variable lists.
+	 * Variable 's' points to the result, according to the following rules:
+	 * s == &not_found (set at the beginning) means that we did not find a
+	 *	matching variable and need to look into more places.
+	 * If s != &not_found, s is a valid result string as follows:
+	 * s = NULL if the variable does not have a value;
+	 *	you typically do this when looking for an unset predefined variable.
+	 * s = workspace if the result has been assembled there;
+	 *	typically done when the result is built e.g. with an snprintf(),
+	 *	so we don't need to do an additional copy.
+	 * s != workspace in case we have a string, that needs to be copied
+	 *	(the ast_copy_string is done once for all at the end).
+	 *	Typically done when the result is already available in some string.
+	 */
+	s = &not_found;	/* default value */
+	if (s == &not_found) { /* look for more */
+		if (!strcmp(var, "EPOCH")) {
+			snprintf(workspace, workspacelen, "%u",(int)time(NULL));
+		}
+		
+		s = workspace;
+	}
+	/* if not found, look into chanvars or global vars */
+	for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
+		struct ast_var_t *variables;
+		if (!places[i])
+			continue;
+		if (places[i] == &globals)
+			ast_rwlock_rdlock(&globalslock);
+		AST_LIST_TRAVERSE(places[i], variables, entries) {
+			if (strcasecmp(ast_var_name(variables), var)==0) {
+				s = ast_var_value(variables);
+				break;
+			}
+		}
+		if (places[i] == &globals)
+			ast_rwlock_unlock(&globalslock);
+	}
+	if (s == &not_found || s == NULL)
+		*ret = NULL;
+	else {
+		if (s != workspace)
+			ast_copy_string(workspace, s, workspacelen);
+		*ret = workspace;
+		if (need_substring)
+			*ret = substring(*ret, offset, length, workspace, workspacelen);
+	}
+}
+
+static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
+{
+	/* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
+	   zero-filled */
+	char *cp4;
+	const char *tmp, *whereweare;
+	int length, offset, offset2, isfunction;
+	char *workspace = NULL;
+	char *ltmp = NULL, *var = NULL;
+	char *nextvar, *nextexp, *nextthing;
+	char *vars, *vare;
+	int pos, brackets, needsub, len;
+
+	whereweare=tmp=cp1;
+	while (!ast_strlen_zero(whereweare) && count) {
+		/* Assume we're copying the whole remaining string */
+		pos = strlen(whereweare);
+		nextvar = NULL;
+		nextexp = NULL;
+		nextthing = strchr(whereweare, '$');
+		if (nextthing) {
+			switch (nextthing[1]) {
+			case '{':
+				nextvar = nextthing;
+				pos = nextvar - whereweare;
+				break;
+			case '[':
+				nextexp = nextthing;
+				pos = nextexp - whereweare;
+				break;
+			}
+		}
+
+		if (pos) {
+			/* Can't copy more than 'count' bytes */
+			if (pos > count)
+				pos = count;
+
+			/* Copy that many bytes */
+			memcpy(cp2, whereweare, pos);
+
+			count -= pos;
+			cp2 += pos;
+			whereweare += pos;
+		}
+
+		if (nextvar) {
+			/* We have a variable.  Find the start and end, and determine
+			   if we are going to have to recursively call ourselves on the
+			   contents */
+			vars = vare = nextvar + 2;
+			brackets = 1;
+			needsub = 0;
+
+			/* Find the end of it */
+			while (brackets && *vare) {
+				if ((vare[0] == '$') && (vare[1] == '{')) {
+					needsub++;
+				} else if (vare[0] == '{') {
+					brackets++;
+				} else if (vare[0] == '}') {
+					brackets--;
+				} else if ((vare[0] == '$') && (vare[1] == '['))
+					needsub++;
+				vare++;
+			}
+			if (brackets)
+				ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
+			len = vare - vars - 1;
+
+			/* Skip totally over variable string */
+			whereweare += (len + 3);
+
+			if (!var)
+				var = alloca(VAR_BUF_SIZE);
+
+			/* Store variable name (and truncate) */
+			ast_copy_string(var, vars, len + 1);
+
+			/* Substitute if necessary */
+			if (needsub) {
+				if (!ltmp)
+					ltmp = alloca(VAR_BUF_SIZE);
+
+				memset(ltmp, 0, VAR_BUF_SIZE);
+				pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
+				vars = ltmp;
+			} else {
+				vars = var;
+			}
+
+			if (!workspace)
+				workspace = alloca(VAR_BUF_SIZE);
+
+			workspace[0] = '\0';
+
+			parse_variable_name(vars, &offset, &offset2, &isfunction);
+			if (isfunction) {
+				/* Evaluate function */
+				cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
+				if (option_debug)
+					ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
+			} else {
+				/* Retrieve variable value */
+				pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
+			}
+			if (cp4) {
+				cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
+
+				length = strlen(cp4);
+				if (length > count)
+					length = count;
+				memcpy(cp2, cp4, length);
+				count -= length;
+				cp2 += length;
+			}
+		} else if (nextexp) {
+			/* We have an expression.  Find the start and end, and determine
+			   if we are going to have to recursively call ourselves on the
+			   contents */
+			vars = vare = nextexp + 2;
+			brackets = 1;
+			needsub = 0;
+
+			/* Find the end of it */
+			while (brackets && *vare) {
+				if ((vare[0] == '$') && (vare[1] == '[')) {
+					needsub++;
+					brackets++;
+					vare++;
+				} else if (vare[0] == '[') {
+					brackets++;
+				} else if (vare[0] == ']') {
+					brackets--;
+				} else if ((vare[0] == '$') && (vare[1] == '{')) {
+					needsub++;
+					vare++;
+				}
+				vare++;
+			}
+			if (brackets)
+				ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
+			len = vare - vars - 1;
+
+			/* Skip totally over expression */
+			whereweare += (len + 3);
+
+			if (!var)
+				var = alloca(VAR_BUF_SIZE);
+
+			/* Store variable name (and truncate) */
+			ast_copy_string(var, vars, len + 1);
+
+			/* Substitute if necessary */
+			if (needsub) {
+				if (!ltmp)
+					ltmp = alloca(VAR_BUF_SIZE);
+
+				memset(ltmp, 0, VAR_BUF_SIZE);
+				pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
+				vars = ltmp;
+			} else {
+				vars = var;
+			}
+
+			length = ast_expr(vars, cp2, count);
+
+			if (length) {
+				if (option_debug)
+					ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
+				count -= length;
+				cp2 += length;
+			}
+		} else
+			break;
+	}
+}
+
+static void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
+{
+	pbx_substitute_variables_helper_full(c, NULL, cp1, cp2, count);
+}
+
+
+static int pbx_load_config(const char *config_file);
 
 static int pbx_load_config(const char *config_file)
 {
@@ -5113,7 +5369,7 @@
 	const char *cxt;
 	const char *aft;
 
-	cfg = ast_config_load(config_file);
+	cfg = localized_config_load(config_file);
 	if (!cfg)
 		return 0;
 
@@ -5326,7 +5582,9 @@
 	}
 }
 
-static void ast_context_destroy(struct ast_context *con, const char *registrar)
+void localized_context_destroy(struct ast_context *con, const char *registrar);
+
+void localized_context_destroy(struct ast_context *con, const char *registrar)
 {
 	ast_wrlock_contexts();
 	__ast_context_destroy(con,registrar);
@@ -5393,7 +5651,9 @@
 	return res;
 }
 
-static int pbx_load_module(void)
+int localized_pbx_load_module(void);
+
+int localized_pbx_load_module(void)
 {
 	struct ast_context *con;
 



More information about the asterisk-commits mailing list