[asterisk-commits] murf: branch murf/bug_7638 r51894 - in /team/murf/bug_7638: include/asterisk/...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue Jan 23 20:23:44 MST 2007


Author: murf
Date: Tue Jan 23 21:23:43 2007
New Revision: 51894

URL: http://svn.digium.com/view/asterisk?view=rev&rev=51894
Log:
Refactored just about all of AEL to move things to main; conf2ael crashes now. Good time to commit!

Added:
    team/murf/bug_7638/include/asterisk/pval.h   (with props)
    team/murf/bug_7638/main/pval.c   (with props)
Modified:
    team/murf/bug_7638/include/asterisk/ael_structs.h
    team/murf/bug_7638/main/Makefile
    team/murf/bug_7638/pbx/ael/ael.tab.c
    team/murf/bug_7638/pbx/ael/ael.tab.h
    team/murf/bug_7638/pbx/ael/ael.y
    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/config_external.c

Modified: team/murf/bug_7638/include/asterisk/ael_structs.h
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/include/asterisk/ael_structs.h?view=diff&rev=51894&r1=51893&r2=51894
==============================================================================
--- team/murf/bug_7638/include/asterisk/ael_structs.h (original)
+++ team/murf/bug_7638/include/asterisk/ael_structs.h Tue Jan 23 21:23:43 2007
@@ -1,5 +1,7 @@
 #ifndef _ASTERISK_AEL_STRUCTS_H
 #define _ASTERISK_AEL_STRUCTS_H
+
+#include "pval.h"
 
 #if !defined(SOLARIS) && !defined(__CYGWIN__)
 /* #include <err.h> */
@@ -22,112 +24,10 @@
 #  endif
 
 
-typedef enum 
-{
-	PV_WORD, /* an ident, string, name, label, etc. A user-supplied string. */ /* 0 */
-	PV_MACRO,             /* 1 */
-	PV_CONTEXT,           /* 2 */
-	PV_MACRO_CALL,        /* 3 */
-	PV_APPLICATION_CALL,  /* 4 */
-	PV_CASE,              /* 5 */
-	PV_PATTERN,           /* 6 */
-	PV_DEFAULT,           /* 7 */
-	PV_CATCH,             /* 8 */
-	PV_SWITCHES,          /* 9 */
-	PV_ESWITCHES,         /* 10 */
-	PV_INCLUDES,          /* 11 */
-	PV_STATEMENTBLOCK,    /* 12 */
-	PV_VARDEC, /* you know, var=val; */  /* 13 */
-	PV_GOTO,              /* 14 */
-	PV_LABEL,             /* 15 */
-	PV_FOR,               /* 16 */
-	PV_WHILE,             /* 17 */
-	PV_BREAK,             /* 18 */
-	PV_RETURN,            /* 19 */
-	PV_CONTINUE,          /* 20 */
-	PV_IF,                /* 21 */
-	PV_IFTIME,            /* 22 */
-	PV_RANDOM,            /* 23 */
-	PV_SWITCH,            /* 24 */
-	PV_EXTENSION,         /* 25 */
-	PV_IGNOREPAT,         /* 26 */
-	PV_GLOBALS,           /* 27 */
-
-} pvaltype;
-
-/* why this horrible mess? It's always been a tradeoff-- tons of structs,
-   each storing it's specific lists of goodies, or a 'simple' single struct,
-   with lots of fields, that catches all uses at once. Either you have a long
-   list of struct names and subnames, or you have a long list of field names,
-   and where/how they are used. I'm going with a single struct, using unions
-   to reduce storage. Some simple generalizations, and a long list of types,
-   and a book about what is used with what types.... Sorry!
-*/
-
-struct pval
-{
-	pvaltype type;
-	int startline;
-	int endline;
-	int startcol;
-	int endcol;
-	char *filename;
-	
-	union
-	{
-		char *str; /* wow, used almost everywhere! */
-		struct pval *list; /* used in SWITCHES, ESWITCHES, INCLUDES, STATEMENTBLOCK, GOTO */
-		struct pval *statements;/*  used in EXTENSION */
-		char *for_init;  /* used in FOR */
-	} u1;
-	struct pval *u1_last; /* to build in-order lists -- looks like we only need one */
-	
-	union
-	{
-		struct pval *arglist; /* used in macro_call, application_call, MACRO def, also attached to PWORD, the 4 timevals for includes  */
-		struct pval *statements; /* used in case, default, catch, while's statement, CONTEXT elements, GLOBALS */
-		char *val;  /* used in VARDEC */
-		char *for_test; /* used in FOR */
-		int label_in_case; /* a boolean for LABELs */
-		struct pval *goto_target;  /* used in GOTO */
-	} u2;
-	
-	union
-	{
-		char *for_inc; /* used in FOR */
-		struct pval *else_statements; /* used in IF */
-		struct pval *macro_statements; /* used in MACRO */
-		int abstract;  /* used for context */
-		char *hints; /* used in EXTENSION */
-		int goto_target_in_case; /* used in GOTO */
-		struct ael_extension *compiled_label;
-	} u3;
-	
-	union
-	{
-		struct pval *for_statements; /* used in PV_FOR */
-		int regexten;                /* used in EXTENSION */
-	} u4;
-	
-	struct pval *next; /* the pval at the end of this ptr will ALWAYS be of the same type as this one! 
-						  EXCEPT for objects of the different types, that are in the same list, like contexts & macros, etc */
-	
-	struct pval *dad; /* the 'container' of this struct instance */
-	struct pval *prev; /* the opposite of the 'next' pointer */
-} ;
-
-
-typedef struct pval pval;
 
 #if 0
-void print_pval_list(FILE *f, pval *item, int depth);
-void print_pval(FILE *f, pval *item, int depth);
+#endif
 void ael2_semantic_check(pval *item, int *errs, int *warns, int *notes);
-struct pval *find_label_in_current_context(char *exten, char *label);
-struct pval *find_label_in_current_extension(char *label);
-int count_labels_in_current_context(char *label);
-struct pval *find_label_in_current_db(char *context, char *exten, char *label);
-#endif
 pval *npval(pvaltype type, int first_line, int last_line, int first_column, int last_column);
 pval *linku1(pval *head, pval *tail);
 void ael2_print(char *fname, pval *tree);

Added: team/murf/bug_7638/include/asterisk/pval.h
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/include/asterisk/pval.h?view=auto&rev=51894
==============================================================================
--- team/murf/bug_7638/include/asterisk/pval.h (added)
+++ team/murf/bug_7638/include/asterisk/pval.h Tue Jan 23 21:23:43 2007
@@ -1,0 +1,152 @@
+#ifndef _ASTERISK_PVAL_H
+#define _ASTERISK_PVAL_H
+
+
+typedef enum 
+{
+	PV_WORD, /* an ident, string, name, label, etc. A user-supplied string. */ /* 0 */
+	PV_MACRO,             /* 1 */
+	PV_CONTEXT,           /* 2 */
+	PV_MACRO_CALL,        /* 3 */
+	PV_APPLICATION_CALL,  /* 4 */
+	PV_CASE,              /* 5 */
+	PV_PATTERN,           /* 6 */
+	PV_DEFAULT,           /* 7 */
+	PV_CATCH,             /* 8 */
+	PV_SWITCHES,          /* 9 */
+	PV_ESWITCHES,         /* 10 */
+	PV_INCLUDES,          /* 11 */
+	PV_STATEMENTBLOCK,    /* 12 */
+	PV_VARDEC, /* you know, var=val; */  /* 13 */
+	PV_GOTO,              /* 14 */
+	PV_LABEL,             /* 15 */
+	PV_FOR,               /* 16 */
+	PV_WHILE,             /* 17 */
+	PV_BREAK,             /* 18 */
+	PV_RETURN,            /* 19 */
+	PV_CONTINUE,          /* 20 */
+	PV_IF,                /* 21 */
+	PV_IFTIME,            /* 22 */
+	PV_RANDOM,            /* 23 */
+	PV_SWITCH,            /* 24 */
+	PV_EXTENSION,         /* 25 */
+	PV_IGNOREPAT,         /* 26 */
+	PV_GLOBALS,           /* 27 */
+
+} pvaltype;
+
+/* why this horrible mess? It's always been a tradeoff-- tons of structs,
+   each storing it's specific lists of goodies, or a 'simple' single struct,
+   with lots of fields, that catches all uses at once. Either you have a long
+   list of struct names and subnames, or you have a long list of field names,
+   and where/how they are used. I'm going with a single struct, using unions
+   to reduce storage. Some simple generalizations, and a long list of types,
+   and a book about what is used with what types.... Sorry!
+*/
+
+struct pval
+{
+	pvaltype type;
+	int startline;
+	int endline;
+	int startcol;
+	int endcol;
+	char *filename;
+	
+	union
+	{
+		char *str; /* wow, used almost everywhere! */
+		struct pval *list; /* used in SWITCHES, ESWITCHES, INCLUDES, STATEMENTBLOCK, GOTO */
+		struct pval *statements;/*  used in EXTENSION */
+		char *for_init;  /* used in FOR */
+	} u1;
+	struct pval *u1_last; /* to build in-order lists -- looks like we only need one */
+	
+	union
+	{
+		struct pval *arglist; /* used in macro_call, application_call, MACRO def, also attached to PWORD, the 4 timevals for includes  */
+		struct pval *statements; /* used in case, default, catch, while's statement, CONTEXT elements, GLOBALS */
+		char *val;  /* used in VARDEC */
+		char *for_test; /* used in FOR */
+		int label_in_case; /* a boolean for LABELs */
+		struct pval *goto_target;  /* used in GOTO */
+	} u2;
+	
+	union
+	{
+		char *for_inc; /* used in FOR */
+		struct pval *else_statements; /* used in IF */
+		struct pval *macro_statements; /* used in MACRO */
+		int abstract;  /* used for context */
+		char *hints; /* used in EXTENSION */
+		int goto_target_in_case; /* used in GOTO */
+		struct ael_extension *compiled_label;
+	} u3;
+	
+	union
+	{
+		struct pval *for_statements; /* used in PV_FOR */
+		int regexten;                /* used in EXTENSION */
+	} u4;
+	
+	struct pval *next; /* the pval at the end of this ptr will ALWAYS be of the same type as this one! 
+						  EXCEPT for objects of the different types, that are in the same list, like contexts & macros, etc */
+	
+	struct pval *dad; /* the 'container' of this struct instance */
+	struct pval *prev; /* the opposite of the 'next' pointer */
+} ;
+
+
+typedef struct pval pval;
+
+#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 
+*/
+
+/* null definitions for structs passed down the infrastructure */
+struct argapp
+{
+	struct argapp *next;
+};
+
+#endif
+
+struct ast_context;
+
+#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 do_pbx_load_module(void);
+int count_labels_in_current_context(char *label);
+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);
+/* static void linkexten(struct ael_extension *exten, struct ael_extension *add);
+   static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *context ); */
+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);
+
+#endif

Propchange: team/murf/bug_7638/include/asterisk/pval.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/murf/bug_7638/include/asterisk/pval.h
------------------------------------------------------------------------------
    svn:keywords = Author Id Date Revision

Propchange: team/murf/bug_7638/include/asterisk/pval.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/murf/bug_7638/main/Makefile
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/main/Makefile?view=diff&rev=51894&r1=51893&r2=51894
==============================================================================
--- team/murf/bug_7638/main/Makefile (original)
+++ team/murf/bug_7638/main/Makefile Tue Jan 23 21:23:43 2007
@@ -20,13 +20,13 @@
 OBJS=	io.o sched.o logger.o frame.o loader.o config.o channel.o \
 	translate.o file.o pbx.o cli.o md5.o term.o \
 	ulaw.o alaw.o callerid.o fskmodem.o image.o app.o \
-	cdr.o tdd.o acl.o rtp.o udptl.o manager.o asterisk.o \
+	cdr.o pval.o tdd.o acl.o rtp.o udptl.o manager.o asterisk.o \
 	dsp.o chanvars.o indications.o autoservice.o db.o privacy.o \
 	astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
 	utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
 	netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
 	cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \
-	strcompat.o threadstorage.o
+	strcompat.o threadstorage.o ../pbx/ael/ael_lex.o ../pbx/ael/ael.tab.o
 
 # we need to link in the objects statically, not as a library, because
 # otherwise modules will not have them available if none of the static

Added: team/murf/bug_7638/main/pval.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/main/pval.c?view=auto&rev=51894
==============================================================================
--- team/murf/bug_7638/main/pval.c (added)
+++ team/murf/bug_7638/main/pval.c Tue Jan 23 21:23:43 2007
@@ -1,0 +1,5301 @@
+
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2006, Digium, Inc.
+ *
+ * Steve Murphy <murf at parsetree.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.
+ * 
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <regex.h>
+#include <sys/stat.h>
+
+#include "asterisk/pbx.h"
+#include "asterisk/config.h"
+#include "asterisk/module.h"
+#include "asterisk/logger.h"
+#include "asterisk/cli.h"
+#include "asterisk/app.h"
+#include "asterisk/callerid.h"
+#include "asterisk/pval.h"
+#include "asterisk/ael_structs.h"
+#ifdef AAL_ARGCHECK
+#include "asterisk/argdesc.h"
+#endif
+
+static char expr_output[2096];
+static char *config = "extensions.ael";
+
+/* these functions are in ../ast_expr2.fl */
+
+static int errs, warns;
+static int notes;
+static char *registrar = "pbx_ael";
+
+static pval *current_db;
+static pval *current_context;
+static pval *current_extension;
+
+static const char *match_context;
+static const char *match_exten;
+static const char *match_label;
+static int in_abstract_context;
+static int count_labels; /* true, put matcher in label counting mode */
+static int label_count;  /* labels are only meant to be counted in a context or exten */
+static int return_on_context_match;
+static pval *last_matched_label;
+struct pval *match_pval(pval *item);
+static void check_timerange(pval *p);
+static void check_dow(pval *DOW);
+static void check_day(pval *DAY);
+static void check_month(pval *MON);
+static void check_expr2_input(pval *expr, char *str);
+static int extension_matches(pval *here, const char *exten, const char *pattern);
+static void check_goto(pval *item);
+static void find_pval_goto_item(pval *item, int lev);
+static void find_pval_gotos(pval *item, int lev);
+static int check_break(pval *item);
+static int check_continue(pval *item);
+static void check_label(pval *item);
+static void check_macro_returns(pval *macro);
+
+static struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont);
+static struct pval *find_first_label_in_current_context(char *label, pval *curr_cont);
+static void print_pval_list(FILE *fin, pval *item, int depth);
+
+static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext);
+static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label);
+static pval *get_goto_target(pval *item);
+static int label_inside_case(pval *label);
+static void attach_exten(struct ael_extension **list, struct ael_extension *newmem);
+static void fix_gotos_in_extensions(struct ael_extension *exten);
+static pval *get_extension_or_contxt(pval *p);
+static pval *get_contxt(pval *p);
+static void remove_spaces_before_equals(char *str);
+static void substitute_commas(char *str);
+
+
+
+/* I am adding this code to substitute commas with vertbars in the args to apps */
+static void substitute_commas(char *str)
+{
+	char *p = str;
+	while (p && *p)
+	{
+		if (*p == ',' && ((p != str && *(p-1) != '\\')
+				|| p == str))
+			*p = '|';
+		p++;
+	}
+}
+
+
+/* PRETTY PRINTER FOR AEL:  ============================================================================= */
+
+static void print_pval(FILE *fin, pval *item, int depth)
+{
+	int i;
+	pval *lp;
+	
+	for (i=0; i<depth; i++) {
+		fprintf(fin, "\t"); /* depth == indentation */
+	}
+	
+	switch ( item->type ) {
+	case PV_WORD:
+		fprintf(fin,"%s;\n", item->u1.str); /* usually, words are encapsulated in something else */
+		break;
+		
+	case PV_MACRO:
+		fprintf(fin,"macro %s(", item->u1.str);
+		for (lp=item->u2.arglist; lp; lp=lp->next) {
+			if (lp != item->u2.arglist )
+				fprintf(fin,", ");
+			fprintf(fin,"%s", lp->u1.str);
+		}
+		fprintf(fin,") {\n");
+		print_pval_list(fin,item->u3.macro_statements,depth+1);
+		for (i=0; i<depth; i++) {
+			fprintf(fin,"\t"); /* depth == indentation */
+		}
+		fprintf(fin,"};\n\n");
+		break;
+			
+	case PV_CONTEXT:
+		if ( item->u3.abstract )
+			fprintf(fin,"abstract context %s {\n", item->u1.str);
+		else
+			fprintf(fin,"context %s {\n", item->u1.str);
+		print_pval_list(fin,item->u2.statements,depth+1);
+		for (i=0; i<depth; i++) {
+			fprintf(fin,"\t"); /* depth == indentation */
+		}
+		fprintf(fin,"};\n\n");
+		break;
+			
+	case PV_MACRO_CALL:
+		fprintf(fin,"&%s(", item->u1.str);
+		for (lp=item->u2.arglist; lp; lp=lp->next) {
+			if ( lp != item->u2.arglist )
+				fprintf(fin,", ");
+			fprintf(fin,"%s", lp->u1.str);
+		}
+		fprintf(fin,");\n");
+		break;
+			
+	case PV_APPLICATION_CALL:
+		fprintf(fin,"%s(", item->u1.str);
+		for (lp=item->u2.arglist; lp; lp=lp->next) {
+			if ( lp != item->u2.arglist )
+				fprintf(fin,",");
+			fprintf(fin,"%s", lp->u1.str);
+		}
+		fprintf(fin,");\n");
+		break;
+			
+	case PV_CASE:
+		fprintf(fin,"case %s:\n", item->u1.str);
+		print_pval_list(fin,item->u2.statements, depth+1);
+		break;
+			
+	case PV_PATTERN:
+		fprintf(fin,"pattern %s:\n", item->u1.str);
+		print_pval_list(fin,item->u2.statements, depth+1);
+		break;
+			
+	case PV_DEFAULT:
+		fprintf(fin,"default:\n");
+		print_pval_list(fin,item->u2.statements, depth+1);
+		break;
+			
+	case PV_CATCH:
+		fprintf(fin,"catch %s {\n", item->u1.str);
+		print_pval_list(fin,item->u2.statements, depth+1);
+		for (i=0; i<depth; i++) {
+			fprintf(fin,"\t"); /* depth == indentation */
+		}
+		fprintf(fin,"};\n");
+		break;
+			
+	case PV_SWITCHES:
+		fprintf(fin,"switches {\n");
+		print_pval_list(fin,item->u1.list,depth+1);
+		for (i=0; i<depth; i++) {
+			fprintf(fin,"\t"); /* depth == indentation */
+		}
+		fprintf(fin,"};\n");
+		break;
+			
+	case PV_ESWITCHES:
+		fprintf(fin,"eswitches {\n");
+		print_pval_list(fin,item->u1.list,depth+1);
+		for (i=0; i<depth; i++) {
+			fprintf(fin,"\t"); /* depth == indentation */
+		}
+		fprintf(fin,"};\n");
+		break;
+			
+	case PV_INCLUDES:
+		fprintf(fin,"includes {\n");
+		for (lp=item->u1.list; lp; lp=lp->next) {
+			for (i=0; i<depth+1; i++) {
+				fprintf(fin,"\t"); /* depth == indentation */
+			}
+			fprintf(fin,"%s", lp->u1.str); /* usually, words are encapsulated in something else */
+			if ( lp->u2.arglist )
+				fprintf(fin,"|%s|%s|%s|%s", 
+						lp->u2.arglist->u1.str,
+						lp->u2.arglist->next->u1.str,
+						lp->u2.arglist->next->next->u1.str,
+						lp->u2.arglist->next->next->next->u1.str
+					);
+			fprintf(fin,";\n"); /* usually, words are encapsulated in something else */
+		}
+		
+		print_pval_list(fin,item->u1.list,depth+1);
+		for (i=0; i<depth; i++) {
+			fprintf(fin,"\t"); /* depth == indentation */
+		}
+		fprintf(fin,"};\n");
+		break;
+			
+	case PV_STATEMENTBLOCK:
+		fprintf(fin,"{\n");
+		print_pval_list(fin,item->u1.list, depth+1);
+		for (i=0; i<depth; i++) {
+			fprintf(fin,"\t"); /* depth == indentation */
+		}
+		fprintf(fin,"}\n");
+		break;
+			
+	case PV_VARDEC:
+		fprintf(fin,"%s=%s;\n", item->u1.str, item->u2.val);
+		break;
+			
+	case PV_GOTO:
+		fprintf(fin,"goto %s", item->u1.list->u1.str);
+		if ( item->u1.list->next )
+			fprintf(fin,"|%s", item->u1.list->next->u1.str);
+		if ( item->u1.list->next && item->u1.list->next->next )
+			fprintf(fin,"|%s", item->u1.list->next->next->u1.str);
+		fprintf(fin,"\n");
+		break;
+			
+	case PV_LABEL:
+		fprintf(fin,"%s:\n", item->u1.str);
+		break;
+			
+	case PV_FOR:
+		fprintf(fin,"for (%s; %s; %s)\n", item->u1.for_init, item->u2.for_test, item->u3.for_inc);
+		print_pval_list(fin,item->u4.for_statements,depth+1);
+		break;
+			
+	case PV_WHILE:
+		fprintf(fin,"while (%s)\n", item->u1.str);
+		print_pval_list(fin,item->u2.statements,depth+1);
+		break;
+			
+	case PV_BREAK:
+		fprintf(fin,"break;\n");
+		break;
+			
+	case PV_RETURN:
+		fprintf(fin,"return;\n");
+		break;
+			
+	case PV_CONTINUE:
+		fprintf(fin,"continue;\n");
+		break;
+			
+	case PV_RANDOM:
+	case PV_IFTIME:
+	case PV_IF:
+		if ( item->type == PV_IFTIME ) {
+			
+			fprintf(fin,"ifTime ( %s|%s|%s|%s )\n", 
+					item->u1.list->u1.str, 
+					item->u1.list->next->u1.str, 
+					item->u1.list->next->next->u1.str, 
+					item->u1.list->next->next->next->u1.str
+					);
+		} else if ( item->type == PV_RANDOM ) {
+			fprintf(fin,"random ( %s )\n", item->u1.str );
+		} else
+			fprintf(fin,"if ( %s )\n", item->u1.str);
+		if ( item->u2.statements && item->u2.statements->next ) {
+			for (i=0; i<depth; i++) {
+				fprintf(fin,"\t"); /* depth == indentation */
+			}
+			fprintf(fin,"{\n");
+			print_pval_list(fin,item->u2.statements,depth+1);
+			for (i=0; i<depth; i++) {
+				fprintf(fin,"\t"); /* depth == indentation */
+			}
+			if ( item->u3.else_statements )
+				fprintf(fin,"}\n");
+			else
+				fprintf(fin,"};\n");
+		} else if (item->u2.statements ) {
+			print_pval_list(fin,item->u2.statements,depth+1);
+		} else {
+			if (item->u3.else_statements )
+				fprintf(fin, " {} ");
+			else
+				fprintf(fin, " {}; ");
+		}
+		if ( item->u3.else_statements ) {
+			for (i=0; i<depth; i++) {
+				fprintf(fin,"\t"); /* depth == indentation */
+			}
+			fprintf(fin,"else\n");
+			print_pval_list(fin,item->u3.else_statements, depth);
+		}
+		break;
+			
+	case PV_SWITCH:
+		fprintf(fin,"switch( %s ) {\n", item->u1.str);
+		print_pval_list(fin,item->u2.statements,depth+1);
+		for (i=0; i<depth; i++) {
+			fprintf(fin,"\t"); /* depth == indentation */
+		}
+		fprintf(fin,"}\n");
+		break;
+			
+	case PV_EXTENSION:
+		if ( item->u4.regexten )
+			fprintf(fin, "regexten ");
+		if ( item->u3.hints )
+			fprintf(fin,"hints(%s) ", item->u3.hints);
+		
+		fprintf(fin,"%s => \n", item->u1.str);
+		print_pval_list(fin,item->u2.statements,depth+1);
+		break;
+			
+	case PV_IGNOREPAT:
+		fprintf(fin,"ignorepat => %s\n", item->u1.str);
+		break;
+			
+	case PV_GLOBALS:
+		fprintf(fin,"globals {\n");
+		print_pval_list(fin,item->u1.statements,depth+1);
+		for (i=0; i<depth; i++) {
+			fprintf(fin,"\t"); /* depth == indentation */
+		}
+		fprintf(fin,"}\n");
+		break;
+	}
+}
+
+static void print_pval_list(FILE *fin, pval *item, int depth)
+{
+	pval *i;
+	
+	for (i=item; i; i=i->next) {
+		print_pval(fin, i, depth);
+	}
+}
+
+void ael2_print(char *fname, pval *tree)
+{
+	FILE *fin = fopen(fname,"w");
+	if ( !fin ) {
+		ast_log(LOG_ERROR, "Couldn't open %s for writing.\n", fname);
+		return;
+	}
+	print_pval_list(fin, tree, 0);
+	fclose(fin);
+}
+
+
+/* EMPTY TEMPLATE FUNCS FOR AEL TRAVERSAL:  ============================================================================= */
+
+void traverse_pval_template(pval *item, int depth);
+void traverse_pval_item_template(pval *item, int depth);
+
+
+void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy for a pretty print (indentation),
+														  but you may not need it */
+{
+	pval *lp;
+	
+	switch ( item->type ) {
+	case PV_WORD:
+		/* fields: item->u1.str == string associated with this (word). */
+		break;
+		
+	case PV_MACRO:
+		/* fields: item->u1.str     == name of macro
+		           item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
+				   item->u2.arglist->u1.str  == argument
+				   item->u2.arglist->next   == next arg
+
+				   item->u3.macro_statements == pval list of statements in macro body.
+		*/
+		for (lp=item->u2.arglist; lp; lp=lp->next) {
+		
+		}
+		traverse_pval_item_template(item->u3.macro_statements,depth+1);
+		break;
+			
+	case PV_CONTEXT:
+		/* fields: item->u1.str     == name of context
+		           item->u2.statements == pval list of statements in context body
+				   item->u3.abstract == int 1 if an abstract keyword were present
+		*/
+		traverse_pval_item_template(item->u2.statements,depth+1);
+		break;
+			
+	case PV_MACRO_CALL:
+		/* fields: item->u1.str     == name of macro to call
+		           item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
+				   item->u2.arglist->u1.str  == argument
+				   item->u2.arglist->next   == next arg
+		*/
+		for (lp=item->u2.arglist; lp; lp=lp->next) {
+		}
+		break;
+			
+	case PV_APPLICATION_CALL:
+		/* fields: item->u1.str     == name of application to call
+		           item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
+				   item->u2.arglist->u1.str  == argument
+				   item->u2.arglist->next   == next arg
+		*/
+		for (lp=item->u2.arglist; lp; lp=lp->next) {
+		}
+		break;
+			
+	case PV_CASE:
+		/* fields: item->u1.str     == value of case
+		           item->u2.statements == pval list of statements under the case
+		*/
+		traverse_pval_item_template(item->u2.statements,depth+1);
+		break;
+			
+	case PV_PATTERN:
+		/* fields: item->u1.str     == value of case
+		           item->u2.statements == pval list of statements under the case
+		*/
+		traverse_pval_item_template(item->u2.statements,depth+1);
+		break;
+			
+	case PV_DEFAULT:
+		/* fields: 
+		           item->u2.statements == pval list of statements under the case
+		*/
+		traverse_pval_item_template(item->u2.statements,depth+1);
+		break;
+			
+	case PV_CATCH:
+		/* fields: item->u1.str     == name of extension to catch
+		           item->u2.statements == pval list of statements in context body
+		*/
+		traverse_pval_item_template(item->u2.statements,depth+1);
+		break;
+			
+	case PV_SWITCHES:
+		/* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
+		*/
+		traverse_pval_item_template(item->u1.list,depth+1);
+		break;
+			
+	case PV_ESWITCHES:
+		/* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
+		*/
+		traverse_pval_item_template(item->u1.list,depth+1);
+		break;
+			
+	case PV_INCLUDES:
+		/* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
+		           item->u2.arglist  == pval list of 4 PV_WORD elements for time values
+		*/
+		traverse_pval_item_template(item->u1.list,depth+1);
+		traverse_pval_item_template(item->u2.arglist,depth+1);
+		break;
+			
+	case PV_STATEMENTBLOCK:
+		/* fields: item->u1.list     == pval list of statements in block, one per entry in the list
+		*/
+		traverse_pval_item_template(item->u1.list,depth+1);
+		break;
+			
+	case PV_VARDEC:
+		/* fields: item->u1.str     == variable name
+		           item->u2.val     == variable value to assign
+		*/
+		break;
+			
+	case PV_GOTO:
+		/* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
+		           item->u1.list->u1.str  == where the data on a PV_WORD will always be.
+		*/
+		
+		if ( item->u1.list->next )
+			;
+		if ( item->u1.list->next && item->u1.list->next->next )
+			;
+		
+		break;
+			
+	case PV_LABEL:
+		/* fields: item->u1.str     == label name
+		*/
+		break;
+			
+	case PV_FOR:
+		/* fields: item->u1.for_init     == a string containing the initalizer
+		           item->u2.for_test     == a string containing the loop test
+		           item->u3.for_inc      == a string containing the loop increment
+
+				   item->u4.for_statements == a pval list of statements in the for ()
+		*/
+		traverse_pval_item_template(item->u4.for_statements,depth+1);
+		break;
+			
+	case PV_WHILE:
+		/* fields: item->u1.str        == the while conditional, as supplied by user
+
+				   item->u2.statements == a pval list of statements in the while ()
+		*/
+		traverse_pval_item_template(item->u2.statements,depth+1);
+		break;
+			
+	case PV_BREAK:
+		/* fields: none
+		*/
+		break;
+			
+	case PV_RETURN:
+		/* fields: none
+		*/
+		break;
+			
+	case PV_CONTINUE:
+		/* fields: none
+		*/
+		break;
+			
+	case PV_IFTIME:
+		/* fields: item->u1.list        == there are 4 linked PV_WORDs here.
+
+				   item->u2.statements == a pval list of statements in the if ()
+				   item->u3.else_statements == a pval list of statements in the else
+											   (could be zero)
+		*/
+		traverse_pval_item_template(item->u2.statements,depth+1);
+		if ( item->u3.else_statements ) {
+			traverse_pval_item_template(item->u3.else_statements,depth+1);
+		}
+		break;
+			
+	case PV_RANDOM:
+		/* fields: item->u1.str        == the random number expression, as supplied by user
+
+				   item->u2.statements == a pval list of statements in the if ()
+				   item->u3.else_statements == a pval list of statements in the else
+											   (could be zero)
+		*/
+		traverse_pval_item_template(item->u2.statements,depth+1);
+		if ( item->u3.else_statements ) {
+			traverse_pval_item_template(item->u3.else_statements,depth+1);
+		}
+		break;
+			
+	case PV_IF:
+		/* fields: item->u1.str        == the if conditional, as supplied by user
+
+				   item->u2.statements == a pval list of statements in the if ()
+				   item->u3.else_statements == a pval list of statements in the else
+											   (could be zero)
+		*/
+		traverse_pval_item_template(item->u2.statements,depth+1);
+		if ( item->u3.else_statements ) {
+			traverse_pval_item_template(item->u3.else_statements,depth+1);
+		}
+		break;
+			
+	case PV_SWITCH:
+		/* fields: item->u1.str        == the switch expression
+
+				   item->u2.statements == a pval list of statements in the switch, 
+				   							(will be case statements, most likely!)
+		*/
+		traverse_pval_item_template(item->u2.statements,depth+1);
+		break;
+			
+	case PV_EXTENSION:
+		/* fields: item->u1.str        == the extension name, label, whatever it's called
+
+				   item->u2.statements == a pval list of statements in the extension
+				   item->u3.hints      == a char * hint argument
+				   item->u4.regexten   == an int boolean. non-zero says that regexten was specified
+		*/
+		traverse_pval_item_template(item->u2.statements,depth+1);
+		break;
+			
+	case PV_IGNOREPAT:
+		/* fields: item->u1.str        == the ignorepat data
+		*/
+		break;
+			
+	case PV_GLOBALS:
+		/* fields: item->u1.statements     == pval list of statements, usually vardecs
+		*/
+		traverse_pval_item_template(item->u1.statements,depth+1);
+		break;
+	}
+}
+
+void traverse_pval_template(pval *item, int depth) /* depth comes in handy for a pretty print (indentation),
+													  but you may not need it */
+{
+	pval *i;
+	
+	for (i=item; i; i=i->next) {
+		traverse_pval_item_template(i, depth);
+	}
+}
+
+
+/* SEMANTIC CHECKING FOR AEL:  ============================================================================= */
+
+/*   (not all that is syntactically legal is good! */
+
+
+static void check_macro_returns(pval *macro)
+{
+	pval *i;
+	if (!macro->u3.macro_statements)
+	{
+		pval *z = calloc(1, sizeof(struct pval));
+		ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s is empty! I will insert a return.\n",
+				macro->filename, macro->startline, macro->endline, macro->u1.str);
+
+		z->type = PV_RETURN;
+		z->startline = macro->startline;
+		z->endline = macro->endline;
+		z->startcol = macro->startcol;
+		z->endcol = macro->endcol;
+		z->filename = strdup(macro->filename);
+
+		macro->u3.macro_statements = z;
+		return;
+	}
+	for (i=macro->u3.macro_statements; i; i=i->next) {
+		/* if the last statement in the list is not return, then insert a return there */
+		if (i->next == NULL) {
+			if (i->type != PV_RETURN) {
+				pval *z = calloc(1, sizeof(struct pval));
+				ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s does not end with a return; I will insert one.\n",
+						macro->filename, macro->startline, macro->endline, macro->u1.str);
+
+				z->type = PV_RETURN;
+				z->startline = macro->startline;
+				z->endline = macro->endline;
+				z->startcol = macro->startcol;
+				z->endcol = macro->endcol;
+				z->filename = strdup(macro->filename);
+
+				i->next = z;
+				return;
+			}
+		}
+	}
+	return;
+}
+
+
+
+static int extension_matches(pval *here, const char *exten, const char *pattern)
+{
+	int err1;
+	regex_t preg;
+	
+	/* simple case, they match exactly, the pattern and exten name */
+	if (!strcmp(pattern,exten) == 0)
+		return 1;
+	
+	if (pattern[0] == '_') {
+		char reg1[2000];
+		const char *p;
+		char *r = reg1;
+		
+		if ( strlen(pattern)*5 >= 2000 ) /* safety valve */ {
+			ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n",
+					pattern);
+			return 0;
+		}
+		/* form a regular expression from the pattern, and then match it against exten */
+		*r++ = '^'; /* what if the extension is a pattern ?? */
+		*r++ = '_'; /* what if the extension is a pattern ?? */
+		*r++ = '?';
+		for (p=pattern+1; *p; p++) {
+			switch ( *p ) {
+			case 'X':
+				*r++ = '[';
+				*r++ = '0';
+				*r++ = '-';
+				*r++ = '9';
+				*r++ = 'X';
+				*r++ = ']';
+				break;
+				
+			case 'Z':
+				*r++ = '[';
+				*r++ = '1';
+				*r++ = '-';
+				*r++ = '9';
+				*r++ = 'Z';
+				*r++ = ']';
+				break;
+				
+			case 'N':
+				*r++ = '[';
+				*r++ = '2';
+				*r++ = '-';
+				*r++ = '9';
+				*r++ = 'N';
+				*r++ = ']';
+				break;
+				
+			case '[':
+				while ( *p && *p != ']' ) {
+					*r++ = *p++;
+				}
+				if ( *p != ']') {
+					ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The extension pattern '%s' is missing a closing bracket \n",
+							here->filename, here->startline, here->endline, pattern);
+				}
+				break;
+				
+			case '.':
+			case '!':
+				*r++ = '.';
+				*r++ = '*';
+				break;
+			case '*':
+				*r++ = '\\';
+				*r++ = '*';
+				break;
+			default:
+				*r++ = *p;
+				break;
+				
+			}
+		}
+		*r++ = '$'; /* what if the extension is a pattern ?? */
+		*r++ = *p++; /* put in the closing null */
+		err1 = regcomp(&preg, reg1, REG_NOSUB|REG_EXTENDED);
+		if ( err1 ) {
+			char errmess[500];
+			regerror(err1,&preg,errmess,sizeof(errmess));
+			regfree(&preg);
+			ast_log(LOG_WARNING, "Regcomp of %s failed, error code %d\n",
+					reg1, err1);
+			return 0;
+		}
+		err1 = regexec(&preg, exten, 0, 0, 0);
+		regfree(&preg);
+		
+		if ( err1 ) {
+			/* ast_log(LOG_NOTICE,"*****************************[%d]Extension %s did not match %s(%s)\n",
+			   err1,exten, pattern, reg1); */
+			return 0; /* no match */
+		} else {
+			/* ast_log(LOG_NOTICE,"*****************************Extension %s matched %s\n",
+			   exten, pattern); */
+			return 1;
+		}
+		
+		
+	} else {
+		if ( strcmp(exten,pattern) == 0 ) {
+			return 1;
+		} else
+			return 0;
+	}
+}
+
+
+static void check_expr2_input(pval *expr, char *str)
+{
+	int spaces = strspn(str,"\t \n");
+	if ( !strncmp(str+spaces,"$[",2) ) {
+		ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The expression '%s' is redundantly wrapped in '$[ ]'. \n",
+				expr->filename, expr->startline, expr->endline, str);
+		warns++;
+	}
+}
+
+static void check_includes(pval *includes)
+{
+	struct pval *p4;
+	for (p4=includes->u1.list; p4; p4=p4->next) {
+		/* for each context pointed to, find it, then find a context/label that matches the
+		   target here! */
+		char *incl_context = p4->u1.str;
+		/* find a matching context name */
+		struct pval *that_other_context = find_context(incl_context);
+		if (!that_other_context && strcmp(incl_context, "parkedcalls") != 0) {
+			ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The included context '%s' cannot be found.\n",
+					includes->filename, includes->startline, includes->endline, incl_context);
+			warns++;
+		}
+	}
+}
+
+
+static void check_timerange(pval *p)
+{
+	char *times;
+	char *e;
+	int s1, s2;
+	int e1, e2;
+
+	times = ast_strdupa(p->u1.str);
+
+	/* Star is all times */
+	if (ast_strlen_zero(times) || !strcmp(times, "*")) {
+		return;
+	}
+	/* Otherwise expect a range */
+	e = strchr(times, '-');
+	if (!e) {
+		ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) requires a '-' surrounded by two 24-hour times of day!\n",
+				p->filename, p->startline, p->endline, times);
+		warns++;
+		return;
+	}
+	*e = '\0';
+	e++;
+	while (*e && !isdigit(*e)) 
+		e++;
+	if (!*e) {
+		ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n",
+				p->filename, p->startline, p->endline, p->u1.str);
+		warns++;
+	}
+	if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
+		ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) isn't quite right!\n",
+				p->filename, p->startline, p->endline, times);
+		warns++;
+	}
+	if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
+		ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) isn't quite right!\n",
+				p->filename, p->startline, p->endline, times);
+		warns++;
+	}
+
+	s1 = s1 * 30 + s2/2;
+	if ((s1 < 0) || (s1 >= 24*30)) {
+		ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) is out of range!\n",
+				p->filename, p->startline, p->endline, times);
+		warns++;
+	}
+	e1 = e1 * 30 + e2/2;
+	if ((e1 < 0) || (e1 >= 24*30)) {
+		ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) is out of range!\n",
+				p->filename, p->startline, p->endline, e);
+		warns++;
+	}
+	return;
+}
+
+static char *days[] =
+{
+	"sun",
+	"mon",
+	"tue",
+	"wed",
+	"thu",
+	"fri",
+	"sat",
+};
+
+/*! \brief  get_dow: Get day of week */
+static void check_dow(pval *DOW)
+{
+	char *dow;
+	char *c;
+	/* The following line is coincidence, really! */
+	int s, e;
+	
+	dow = ast_strdupa(DOW->u1.str);
+
+	/* Check for all days */
+	if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
+		return;
+	/* Get start and ending days */
+	c = strchr(dow, '-');
+	if (c) {
+		*c = '\0';
+		c++;
+	} else
+		c = NULL;
+	/* Find the start */
+	s = 0;
+	while ((s < 7) && strcasecmp(dow, days[s])) s++;
+	if (s >= 7) {
+		ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n",
+				DOW->filename, DOW->startline, DOW->endline, dow);
+		warns++;
+	}
+	if (c) {
+		e = 0;
+		while ((e < 7) && strcasecmp(c, days[e])) e++;
+		if (e >= 7) {
+			ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n",
+					DOW->filename, DOW->startline, DOW->endline, c);
+			warns++;
+		}
+	} else
+		e = s;
+}
+
+static void check_day(pval *DAY)
+{
+	char *day;
+	char *c;
+	/* The following line is coincidence, really! */
+	int s, e;
+
+	day = ast_strdupa(DAY->u1.str);
+
+	/* Check for all days */
+	if (ast_strlen_zero(day) || !strcmp(day, "*")) {
+		return;
+	}
+	/* Get start and ending days */
+	c = strchr(day, '-');
+	if (c) {
+		*c = '\0';
+		c++;
+	}
+	/* Find the start */

[... 9513 lines stripped ...]


More information about the asterisk-commits mailing list