mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-25 14:06:27 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			922 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			922 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| /*
 | |
|  * Asterisk -- An open source telephony toolkit.
 | |
|  *
 | |
|  * Copyright (C) 2006, Digium, Inc.
 | |
|  *
 | |
|  * Steve Murphy <murf@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 Flex scanner description of tokens used in AEL2 .
 | |
|  *
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Start with flex options:
 | |
|  *
 | |
|  * %x describes the contexts we have: paren, semic and argg, plus INITIAL
 | |
|  */
 | |
| %x paren semic argg  comment curlystate wordstate brackstate
 | |
| 
 | |
| /* prefix used for various globally-visible functions and variables.
 | |
|  * This renames also yywrap, but since we do not use it, we just
 | |
|  * add option noyywrap to remove it.
 | |
|  */
 | |
| %option prefix="ael_yy"
 | |
| %option noyywrap 8bit
 | |
| 
 | |
| /* I specify this option to suppress flex generating code with ECHO
 | |
|   in it. This generates compiler warnings in some systems; We've
 | |
|   seen the fwrite generate Unused variable warnings with 4.1.2 gcc.
 | |
|   Some systems have tweaked flex ECHO macro to keep the compiler
 | |
|   happy.  To keep the warning message from getting output, I added
 | |
|   a default rule at the end of the patterns section */
 | |
| %option nodefault
 | |
| 
 | |
| /* yyfree normally just frees its arg. It can be null sometimes,
 | |
|    which some systems will complain about, so, we'll define our own version */
 | |
| %option noyyfree
 | |
| 
 | |
| /* batch gives a bit more performance if we are using it in
 | |
|  * a non-interactive mode. We probably don't care much.
 | |
|  */
 | |
| %option batch
 | |
| 
 | |
| /* outfile is the filename to be used instead of lex.yy.c */
 | |
| %option outfile="ael_lex.c"
 | |
| 
 | |
| /*
 | |
|  * These are not supported in flex 2.5.4, but we need them
 | |
|  * at the moment:
 | |
|  * reentrant produces a thread-safe parser. Not 100% sure that
 | |
|  * we require it, though.
 | |
|  * bison-bridge passes an additional yylval argument to yylex().
 | |
|  * bison-locations is probably not needed.
 | |
|  */
 | |
| %option reentrant
 | |
| %option bison-bridge
 | |
| %option bison-locations
 | |
| 
 | |
| %{
 | |
| #define ASTMM_LIBC ASTMM_REDIRECT
 | |
| #include "asterisk.h"
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <unistd.h>
 | |
| #include <glob.h>
 | |
| 
 | |
| #if !defined(GLOB_ABORTED)
 | |
| #define GLOB_ABORTED GLOB_ABEND
 | |
| #endif
 | |
| #if !defined(GLOB_BRACE)
 | |
| #define GLOB_BRACE 0
 | |
| #endif
 | |
| #if !defined(GLOB_NOMAGIC)
 | |
| #define GLOB_NOMAGIC 0
 | |
| #endif
 | |
| 
 | |
| #include "asterisk/logger.h"
 | |
| #include "asterisk/utils.h"
 | |
| #include "asterisk/lock.h"
 | |
| #include "asterisk/hashtab.h"
 | |
| #include "ael/ael.tab.h"
 | |
| #include "asterisk/ael_structs.h"
 | |
| 
 | |
| /*
 | |
|  * A stack to keep track of matching brackets ( [ { } ] )
 | |
|  */
 | |
| static char pbcstack[400];	/* XXX missing size checks */
 | |
| static int pbcpos = 0;
 | |
| static void pbcpush(char x);
 | |
| static int pbcpop(char x);
 | |
| static int parencount = 0;
 | |
| 
 | |
| /*
 | |
|  * A similar stack to keep track of matching brackets ( [ { } ] ) in word tokens surrounded by ${ ... }
 | |
|  */
 | |
| static char pbcstack2[400];	/* XXX missing size checks */
 | |
| static int pbcpos2 = 0;
 | |
| static void pbcpush2(char x);
 | |
| static int pbcpop2(char x);
 | |
| static int parencount2 = 0;
 | |
| 
 | |
| /*
 | |
|  * A similar stack to keep track of matching brackets ( [ { } ] ) in word tokens surrounded by $[ ... ]
 | |
|  */
 | |
| static char pbcstack3[400];	/* XXX missing size checks */
 | |
| static int pbcpos3 = 0;
 | |
| static void pbcpush3(char x);
 | |
| static int pbcpop3(char x);
 | |
| static int parencount3 = 0;
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * current line, column and filename, updated as we read the input.
 | |
|  */
 | |
| static int my_lineno = 1;	/* current line in the source */
 | |
| static int my_col = 1;		/* current column in the source */
 | |
| char *my_file = 0;		/* used also in the bison code */
 | |
| char *prev_word;		/* XXX document it */
 | |
| 
 | |
| #define MAX_INCLUDE_DEPTH 50
 | |
| 
 | |
| /*
 | |
|  * flex is not too smart, and generates global functions
 | |
|  * without prototypes so the compiler may complain.
 | |
|  * To avoid that, we declare the prototypes here,
 | |
|  * even though these functions are not used.
 | |
|  */
 | |
| int ael_yyget_column  (yyscan_t yyscanner);
 | |
| void ael_yyset_column (int  column_no , yyscan_t yyscanner);
 | |
| 
 | |
| int ael_yyparse (struct parse_io *);
 | |
| 
 | |
| /*
 | |
|  * A stack to process include files.
 | |
|  * As we switch into the new file we need to store the previous
 | |
|  * state to restore it later.
 | |
|  */
 | |
| struct stackelement {
 | |
| 	char *fname;
 | |
| 	int lineno;
 | |
| 	int colno;
 | |
| 	glob_t globbuf;        /* the current globbuf */
 | |
| 	int globbuf_pos;   /* where we are in the current globbuf */
 | |
| 	YY_BUFFER_STATE bufstate;
 | |
| };
 | |
| 
 | |
| static struct stackelement  include_stack[MAX_INCLUDE_DEPTH];
 | |
| static int include_stack_index = 0;
 | |
| static void setup_filestack(char *fnamebuf, int fnamebuf_siz, glob_t *globbuf, int globpos, yyscan_t xscan, int create);
 | |
| 
 | |
| /*
 | |
|  * if we use the @n feature of bison, we must supply the start/end
 | |
|  * location of tokens in the structure pointed by yylloc.
 | |
|  * Simple tokens are just assumed to be on the same line, so
 | |
|  * the line number is constant, and the column is incremented
 | |
|  * by the length of the token.
 | |
|  */
 | |
| #ifdef FLEX_BETA	/* set for 2.5.33 */
 | |
| 
 | |
| /* compute the total number of lines and columns in the text
 | |
|  * passed as argument.
 | |
|  */
 | |
| static void pbcwhere(const char *text, int *line, int *col )
 | |
| {
 | |
| 	int loc_line = *line;
 | |
| 	int loc_col = *col;
 | |
| 	char c;
 | |
| 	while ( (c = *text++) ) {
 | |
| 		if ( c == '\t' ) {
 | |
| 			loc_col += 8 - (loc_col % 8);
 | |
| 		} else if ( c == '\n' ) {
 | |
| 			loc_line++;
 | |
| 			loc_col = 1;
 | |
| 		} else
 | |
| 			loc_col++;
 | |
| 	}
 | |
| 	*line = loc_line;
 | |
| 	*col = loc_col;
 | |
| }
 | |
| 
 | |
| #define	STORE_POS do {							\
 | |
| 		yylloc->first_line = yylloc->last_line = my_lineno;	\
 | |
| 		yylloc->first_column=my_col;				\
 | |
| 		yylloc->last_column=my_col+yyleng-1;			\
 | |
| 		my_col+=yyleng;						\
 | |
| 	} while (0)
 | |
| 
 | |
| #define	STORE_LOC do {					\
 | |
| 		yylloc->first_line = my_lineno;		\
 | |
| 		yylloc->first_column=my_col;		\
 | |
| 		pbcwhere(yytext, &my_lineno, &my_col);	\
 | |
| 		yylloc->last_line = my_lineno;		\
 | |
| 		yylloc->last_column = my_col - 1;	\
 | |
| 	} while (0)
 | |
| #else
 | |
| #define	STORE_POS
 | |
| #define	STORE_LOC
 | |
| #endif
 | |
| %}
 | |
| 
 | |
| KEYWORD     (context|abstract|extend|macro|globals|local|ignorepat|switch|if|ifTime|random|regexten|hint|else|goto|jump|return|break|continue|for|while|case|default|pattern|catch|switches|eswitches|includes)
 | |
| 
 | |
| NOPARENS	([^()\[\]\{\}]|\\[()\[\]\{\}])*
 | |
| 
 | |
| NOARGG		([^(),\{\}\[\]]|\\[,()\[\]\{\}])*
 | |
| 
 | |
| NOSEMIC		([^;()\{\}\[\]]|\\[;()\[\]\{\}])*
 | |
| 
 | |
| HIBIT		[\x80-\xff]
 | |
| 
 | |
| %%
 | |
| 
 | |
| \{		{ STORE_POS; return LC;}
 | |
| \}		{ STORE_POS; return RC;}
 | |
| \(		{ STORE_POS; return LP;}
 | |
| \)		{ STORE_POS; return RP;}
 | |
| \;		{ STORE_POS; return SEMI;}
 | |
| \=		{ STORE_POS; return EQ;}
 | |
| \,		{ STORE_POS; return COMMA;}
 | |
| \:		{ STORE_POS; return COLON;}
 | |
| \&		{ STORE_POS; return AMPER;}
 | |
| \|		{ STORE_POS; return BAR;}
 | |
| \=\>		{ STORE_POS; return EXTENMARK;}
 | |
| \@		{ STORE_POS; return AT;}
 | |
| \/\/[^\n]*	{/*comment*/}
 | |
| context		{ STORE_POS; return KW_CONTEXT;}
 | |
| abstract	{ STORE_POS; return KW_ABSTRACT;}
 | |
| extend		{ STORE_POS; return KW_EXTEND;}
 | |
| macro		{ STORE_POS; return KW_MACRO;};
 | |
| globals		{ STORE_POS; return KW_GLOBALS;}
 | |
| local		{ STORE_POS; return KW_LOCAL;}
 | |
| ignorepat	{ STORE_POS; return KW_IGNOREPAT;}
 | |
| switch		{ STORE_POS; return KW_SWITCH;}
 | |
| if		{ STORE_POS; return KW_IF;}
 | |
| ifTime		{ STORE_POS; return KW_IFTIME;}
 | |
| random		{ STORE_POS; return KW_RANDOM;}
 | |
| regexten	{ STORE_POS; return KW_REGEXTEN;}
 | |
| hint		{ STORE_POS; return KW_HINT;}
 | |
| else		{ STORE_POS; return KW_ELSE;}
 | |
| goto		{ STORE_POS; return KW_GOTO;}
 | |
| jump		{ STORE_POS; return KW_JUMP;}
 | |
| return		{ STORE_POS; return KW_RETURN;}
 | |
| break		{ STORE_POS; return KW_BREAK;}
 | |
| continue	{ STORE_POS; return KW_CONTINUE;}
 | |
| for		{ STORE_POS; return KW_FOR;}
 | |
| while		{ STORE_POS; return KW_WHILE;}
 | |
| case		{ STORE_POS; return KW_CASE;}
 | |
| default		{ STORE_POS; return KW_DEFAULT;}
 | |
| pattern		{ STORE_POS; return KW_PATTERN;}
 | |
| catch		{ STORE_POS; return KW_CATCH;}
 | |
| switches	{ STORE_POS; return KW_SWITCHES;}
 | |
| eswitches	{ STORE_POS; return KW_ESWITCHES;}
 | |
| includes	{ STORE_POS; return KW_INCLUDES;}
 | |
| "/*"            { BEGIN(comment); my_col += 2; }
 | |
| 
 | |
| <comment>[^*\n]*	{ my_col += yyleng; }
 | |
| <comment>[^*\n]*\n	{ ++my_lineno; my_col=1;}
 | |
| <comment>"*"+[^*/\n]*	{ my_col += yyleng; }
 | |
| <comment>"*"+[^*/\n]*\n 	{ ++my_lineno; my_col=1;}
 | |
| <comment>"*/"		{ my_col += 2; BEGIN(INITIAL); } /* the nice thing about comments is that you know exactly what ends them */
 | |
| 
 | |
| \n		{ my_lineno++; my_col = 1; }
 | |
| [ ]+		{ my_col += yyleng; }
 | |
| [\t]+		{ my_col += (yyleng*8)-(my_col%8); }
 | |
| 
 | |
| ({KEYWORD}?[-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]]|{HIBIT}|(\\.)|(\$\{)|(\$\[)) {
 | |
|       /* boy did I open a can of worms when I changed the lexical token "word".
 | |
|   	  	 all the above keywords can be used as a beginning to a "word".-
 | |
| 		 before, a "word" would match a longer sequence than the above
 | |
| 	     keywords, and all would be well. But now "word" is a single char
 | |
| 	     and feeds into a statemachine sort of sequence from there on. So...
 | |
| 		 I added the {KEYWORD}? to the beginning of the word match sequence */
 | |
| 
 | |
| 		if (!strcmp(yytext,"${")) {
 | |
| 		   	parencount2 = 0;
 | |
| 			pbcpos2 = 0;
 | |
| 			pbcpush2('{');	/* push '{' so the last pcbpop (parencount2 = -1) will succeed */
 | |
| 			BEGIN(curlystate);
 | |
| 			yymore();
 | |
| 		} else if (!strcmp(yytext,"$[")) {
 | |
| 		   	parencount3 = 0;
 | |
| 			pbcpos3 = 0;
 | |
| 			pbcpush3('[');	/* push '[' so the last pcbpop (parencount3 = -1) will succeed */
 | |
| 			BEGIN(brackstate);
 | |
| 			yymore();
 | |
| 		} else {
 | |
| 		    BEGIN(wordstate);
 | |
| 			yymore();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| <wordstate>[-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]] { yymore(); /* Keep going */ }
 | |
| <wordstate>{HIBIT} { yymore(); /* Keep going */ }
 | |
| <wordstate>(\\.)  { yymore(); /* Keep Going */ }
 | |
| <wordstate>(\$\{)  { /* the beginning of a ${} construct. prepare and pop into curlystate */
 | |
| 	   	parencount2 = 0;
 | |
| 		pbcpos2 = 0;
 | |
| 		pbcpush2('{');	/* push '{' so the last pcbpop (parencount2 = -1) will succeed */
 | |
| 		BEGIN(curlystate);
 | |
| 		yymore();
 | |
| 	}
 | |
| <wordstate>(\$\[)  { /* the beginning of a $[] construct. prepare and pop into brackstate */
 | |
| 	   	parencount3 = 0;
 | |
| 		pbcpos3 = 0;
 | |
| 		pbcpush3('[');	/* push '[' so the last pcbpop (parencount3 = -1) will succeed */
 | |
| 		BEGIN(brackstate);
 | |
| 		yymore();
 | |
| 	}
 | |
| <wordstate>([^a-zA-Z0-9\x80-\xff\x2d'"_/.\<\>\*\+!$#\[\]]) {
 | |
| 		/* a non-word constituent char, like a space, tab, curly, paren, etc */
 | |
| 		char c = yytext[yyleng-1];
 | |
| 		STORE_POS;
 | |
| 		yylval->str = malloc(yyleng);
 | |
| 		strncpy(yylval->str, yytext, yyleng);
 | |
| 		yylval->str[yyleng-1] = 0;
 | |
| 		unput(c);  /* put this ending char back in the stream */
 | |
| 		BEGIN(0);
 | |
| 		return word;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| <curlystate>{NOPARENS}\}	{
 | |
| 		if ( pbcpop2('}') ) {	/* error */
 | |
| 			STORE_LOC;
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext);
 | |
| 			BEGIN(0);
 | |
| 			yylval->str = malloc(yyleng+1);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng] = 0;
 | |
| 			return word;
 | |
| 		}
 | |
| 		parencount2--;
 | |
| 		if ( parencount2 >= 0) {
 | |
| 			yymore();
 | |
| 		} else {
 | |
| 			BEGIN(wordstate); /* Finished with the current ${} construct. Return to word gathering state */
 | |
| 			yymore();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| <curlystate>{NOPARENS}[\(\[\{]	{
 | |
| 		char c = yytext[yyleng-1];
 | |
| 		if (c == '{')
 | |
| 			parencount2++;
 | |
| 		pbcpush2(c);
 | |
| 		yymore();
 | |
| 	}
 | |
| 
 | |
| <curlystate>{NOPARENS}[\]\)]	{
 | |
| 		char c = yytext[yyleng-1];
 | |
| 		if ( pbcpop2(c))  { /* error */
 | |
| 			STORE_LOC;
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n",
 | |
| 				my_file, my_lineno, my_col, c);
 | |
| 			BEGIN(0);
 | |
| 			yylval->str = malloc(yyleng+1);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng] = 0;
 | |
| 			return word;
 | |
| 		}
 | |
| 		yymore();
 | |
| 	}
 | |
| 
 | |
| 
 | |
| <brackstate>{NOPARENS}\]	{
 | |
| 		if ( pbcpop3(']') ) {	/* error */
 | |
| 			STORE_LOC;
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext);
 | |
| 			BEGIN(0);
 | |
| 			yylval->str = malloc(yyleng+1);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng] = 0;
 | |
| 			return word;
 | |
| 		}
 | |
| 		parencount3--;
 | |
| 		if ( parencount3 >= 0) {
 | |
| 			yymore();
 | |
| 		} else {
 | |
| 			BEGIN(wordstate); /* Finished with the current ${} construct. Return to word gathering state */
 | |
| 			yymore();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| <brackstate>{NOPARENS}[\(\[\{]	{
 | |
| 		char c = yytext[yyleng-1];
 | |
| 		if (c == '[')
 | |
| 			parencount3++;
 | |
| 		pbcpush3(c);
 | |
| 		yymore();
 | |
| 	}
 | |
| 
 | |
| <brackstate>{NOPARENS}[\}\)]	{
 | |
| 		char c = yytext[yyleng-1];
 | |
| 		if ( pbcpop3(c))  { /* error */
 | |
| 			STORE_LOC;
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n",
 | |
| 				my_file, my_lineno, my_col, c);
 | |
| 			BEGIN(0);
 | |
| 			yylval->str = malloc(yyleng+1);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng] = 0;
 | |
| 			return word;
 | |
| 		}
 | |
| 		yymore();
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/*
 | |
| 	 * context used for arguments of if_head, random_head, switch_head,
 | |
| 	 * for (last statement), while (XXX why not iftime_head ?).
 | |
| 	 * End with the matching parentheses.
 | |
| 	 * A comma at the top level is valid here, unlike in argg where it
 | |
| 	 * is an argument separator so it must be returned as a token.
 | |
| 	 */
 | |
| <paren>{NOPARENS}\)	{
 | |
| 		if ( pbcpop(')') ) {	/* error */
 | |
| 			STORE_LOC;
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext);
 | |
| 			BEGIN(0);
 | |
| 			yylval->str = malloc(yyleng+1);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng] = 0;
 | |
| 			prev_word = 0;
 | |
| 			return word;
 | |
| 		}
 | |
| 		parencount--;
 | |
| 		if ( parencount >= 0) {
 | |
| 			yymore();
 | |
| 		} else {
 | |
| 			STORE_LOC;
 | |
| 			yylval->str = malloc(yyleng);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng-1] = 0;
 | |
| 			unput(')');
 | |
| 			BEGIN(0);
 | |
| 			return word;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| <paren>{NOPARENS}[\(\[\{]	{
 | |
| 		char c = yytext[yyleng-1];
 | |
| 		if (c == '(')
 | |
| 			parencount++;
 | |
| 		pbcpush(c);
 | |
| 		yymore();
 | |
| 	}
 | |
| 
 | |
| <paren>{NOPARENS}[\]\}]	{
 | |
| 		char c = yytext[yyleng-1];
 | |
| 		if ( pbcpop(c))  { /* error */
 | |
| 			STORE_LOC;
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n",
 | |
| 				my_file, my_lineno, my_col, c);
 | |
| 			BEGIN(0);
 | |
| 			yylval->str = malloc(yyleng+1);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng] = 0;
 | |
| 			return word;
 | |
| 		}
 | |
| 		yymore();
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/*
 | |
| 	 * handlers for arguments to a macro or application calls.
 | |
| 	 * We enter this context when we find the initial '(' and
 | |
| 	 * stay here until we close all matching parentheses,
 | |
| 	 * and find the comma (argument separator) or the closing ')'
 | |
| 	 * of the (external) call, which happens when parencount == 0
 | |
| 	 * before the decrement.
 | |
| 	 */
 | |
| <argg>{NOARGG}[\(\[\{]	  {
 | |
| 		char c = yytext[yyleng-1];
 | |
| 		if (c == '(')
 | |
| 			parencount++;
 | |
| 		pbcpush(c);
 | |
| 		yymore();
 | |
| 	}
 | |
| 
 | |
| <argg>{NOARGG}\)	{
 | |
| 		if ( pbcpop(')') ) { /* error */
 | |
| 			STORE_LOC;
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression!\n", my_file, my_lineno, my_col);
 | |
| 			BEGIN(0);
 | |
| 			yylval->str = malloc(yyleng+1);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng] = 0;
 | |
| 			return word;
 | |
| 		}
 | |
| 
 | |
| 		parencount--;
 | |
| 		if( parencount >= 0){
 | |
| 			yymore();
 | |
| 		} else {
 | |
| 			STORE_LOC;
 | |
| 			BEGIN(0);
 | |
| 			if ( !strcmp(yytext, ")") )
 | |
| 				return RP;
 | |
| 			yylval->str = malloc(yyleng);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng-1] = '\0'; /* trim trailing ')' */
 | |
| 			unput(')');
 | |
| 			return word;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| <argg>{NOARGG}\,	{
 | |
| 		if( parencount != 0) { /* ast_log(LOG_NOTICE,"Folding in a comma!\n"); */
 | |
| 			yymore();
 | |
| 		} else  {
 | |
| 			STORE_LOC;
 | |
| 			if( !strcmp(yytext,"," ) )
 | |
| 				return COMMA;
 | |
| 			yylval->str = malloc(yyleng);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng-1] = '\0'; /* trim trailing ',' */
 | |
| 			unput(',');
 | |
| 			return word;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| <argg>{NOARGG}[\]\}]	{
 | |
| 		char c = yytext[yyleng-1];
 | |
| 		if ( pbcpop(c) ) { /* error */
 | |
| 			STORE_LOC;
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n", my_file, my_lineno, my_col, c);
 | |
| 			BEGIN(0);
 | |
| 			yylval->str = malloc(yyleng+1);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng] = '\0';
 | |
| 			return word;
 | |
| 		}
 | |
| 		yymore();
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * context used to find tokens in the right hand side of assignments,
 | |
| 	 * or in the first and second operand of a 'for'. As above, match
 | |
| 	 * commas and use ';' as a separator (hence return it as a separate token).
 | |
| 	 */
 | |
| <semic>{NOSEMIC}[\(\[\{]	{
 | |
| 		char c = yytext[yyleng-1];
 | |
| 		yymore();
 | |
| 		pbcpush(c);
 | |
| 	}
 | |
| 
 | |
| <semic>{NOSEMIC}[\)\]\}]	{
 | |
| 		char c = yytext[yyleng-1];
 | |
| 		if ( pbcpop(c) ) { /* error */
 | |
| 			STORE_LOC;
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n", my_file, my_lineno, my_col, c);
 | |
| 			BEGIN(0);
 | |
| 			yylval->str = malloc(yyleng+1);
 | |
| 			strncpy(yylval->str, yytext, yyleng);
 | |
| 			yylval->str[yyleng] = '\0';
 | |
| 			return word;
 | |
| 		}
 | |
| 		yymore();
 | |
| 	}
 | |
| 
 | |
| <semic>{NOSEMIC};	{
 | |
| 		STORE_LOC;
 | |
| 		yylval->str = malloc(yyleng);
 | |
| 		strncpy(yylval->str, yytext, yyleng);
 | |
| 		yylval->str[yyleng-1] = '\0'; /* trim trailing ';' */
 | |
| 		unput(';');
 | |
| 		BEGIN(0);
 | |
| 		return word;
 | |
| 	}
 | |
| 
 | |
| \#include[ \t]+\"[^\"]+\" {
 | |
| 		char fnamebuf[1024],*p1,*p2;
 | |
| 		int glob_ret;
 | |
| 		glob_t globbuf;        /* the current globbuf */
 | |
| 		int globbuf_pos = -1;   /* where we are in the current globbuf */
 | |
| 		globbuf.gl_offs = 0;	/* initialize it to silence gcc */
 | |
| 
 | |
| 		p1 = strchr(yytext,'"');
 | |
| 		p2 = strrchr(yytext,'"');
 | |
| 		if ( include_stack_index >= MAX_INCLUDE_DEPTH ) {
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Includes nested too deeply! Wow!!! How did you do that?\n", my_file, my_lineno, my_col);
 | |
| 		} else if ( (int)(p2-p1) > sizeof(fnamebuf) - 1 ) {
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Filename is incredibly way too long (%d chars!). Inclusion ignored!\n", my_file, my_lineno, my_col, yyleng - 10);
 | |
| 		} else {
 | |
| 			strncpy(fnamebuf, p1+1, p2-p1-1);
 | |
| 			fnamebuf[p2-p1-1] = 0;
 | |
| 		if (fnamebuf[0] != '/') {
 | |
| 		   char fnamebuf2[1024];
 | |
| 		   snprintf(fnamebuf2,sizeof(fnamebuf2), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, fnamebuf);
 | |
| 		   ast_copy_string(fnamebuf,fnamebuf2,sizeof(fnamebuf));
 | |
| 		}
 | |
| #ifdef SOLARIS
 | |
| 			glob_ret = glob(fnamebuf, GLOB_NOCHECK, NULL, &globbuf);
 | |
| #else
 | |
| 			glob_ret = glob(fnamebuf, GLOB_NOMAGIC|GLOB_BRACE, NULL, &globbuf);
 | |
| #endif
 | |
| 			if (glob_ret == GLOB_NOSPACE) {
 | |
| 				ast_log(LOG_WARNING,
 | |
| 					"Glob Expansion of pattern '%s' failed: Not enough memory\n", fnamebuf);
 | |
| 			} else if (glob_ret  == GLOB_ABORTED) {
 | |
| 				ast_log(LOG_WARNING,
 | |
| 					"Glob Expansion of pattern '%s' failed: Read error\n", fnamebuf);
 | |
| 			} else if (glob_ret  == GLOB_NOMATCH) {
 | |
| 				ast_log(LOG_WARNING,
 | |
| 					"Glob Expansion of pattern '%s' failed: No matches!\n", fnamebuf);
 | |
| 			} else {
 | |
| 			  globbuf_pos = 0;
 | |
| 			}
 | |
| 		}
 | |
| 		if (globbuf_pos > -1) {
 | |
| 			setup_filestack(fnamebuf, sizeof(fnamebuf), &globbuf, 0, yyscanner, 1);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 
 | |
| <<EOF>>		{
 | |
| 		char fnamebuf[2048];
 | |
| 		if (include_stack_index > 0 && include_stack[include_stack_index-1].globbuf_pos < include_stack[include_stack_index-1].globbuf.gl_pathc-1) {
 | |
| 			yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner );
 | |
| 			include_stack[include_stack_index-1].globbuf_pos++;
 | |
| 			setup_filestack(fnamebuf, sizeof(fnamebuf), &include_stack[include_stack_index-1].globbuf, include_stack[include_stack_index-1].globbuf_pos, yyscanner, 0);
 | |
| 			/* finish this */
 | |
| 
 | |
| 		} else {
 | |
| 			if (include_stack[include_stack_index].fname) {
 | |
| 				free(include_stack[include_stack_index].fname);
 | |
| 				include_stack[include_stack_index].fname = 0;
 | |
| 			}
 | |
| 			if (my_file) {
 | |
| 				free(my_file);
 | |
| 				my_file = 0;
 | |
| 			}
 | |
| 			if ( --include_stack_index < 0 ) {
 | |
| 				yyterminate();
 | |
| 			} else {
 | |
| 				globfree(&include_stack[include_stack_index].globbuf);
 | |
| 				include_stack[include_stack_index].globbuf_pos = -1;
 | |
| 
 | |
| 				yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner );
 | |
| 				yy_switch_to_buffer(include_stack[include_stack_index].bufstate, yyscanner );
 | |
| 				my_lineno = include_stack[include_stack_index].lineno;
 | |
| 				my_col    = include_stack[include_stack_index].colno;
 | |
| 				my_file   = strdup(include_stack[include_stack_index].fname);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| <*>.|\n		{ /* default rule */ ast_log(LOG_ERROR,"Unhandled char(s): %s\n", yytext); }
 | |
| 
 | |
| %%
 | |
| 
 | |
| static void pbcpush(char x)
 | |
| {
 | |
| 	pbcstack[pbcpos++] = x;
 | |
| }
 | |
| 
 | |
| void ael_yyfree(void *ptr, yyscan_t yyscanner)
 | |
| {
 | |
| 	if (ptr)
 | |
| 		free( (char*) ptr );
 | |
| }
 | |
| 
 | |
| static int pbcpop(char x)
 | |
| {
 | |
| 	if (   ( x == ')' && pbcstack[pbcpos-1] == '(' )
 | |
| 		|| ( x == ']' && pbcstack[pbcpos-1] == '[' )
 | |
| 		|| ( x == '}' && pbcstack[pbcpos-1] == '{' )) {
 | |
| 		pbcpos--;
 | |
| 		return 0;
 | |
| 	}
 | |
| 	return 1; /* error */
 | |
| }
 | |
| 
 | |
| static void pbcpush2(char x)
 | |
| {
 | |
| 	pbcstack2[pbcpos2++] = x;
 | |
| }
 | |
| 
 | |
| static int pbcpop2(char x)
 | |
| {
 | |
| 	if (   ( x == ')' && pbcstack2[pbcpos2-1] == '(' )
 | |
| 		|| ( x == ']' && pbcstack2[pbcpos2-1] == '[' )
 | |
| 		|| ( x == '}' && pbcstack2[pbcpos2-1] == '{' )) {
 | |
| 		pbcpos2--;
 | |
| 		return 0;
 | |
| 	}
 | |
| 	return 1; /* error */
 | |
| }
 | |
| 
 | |
| static void pbcpush3(char x)
 | |
| {
 | |
| 	pbcstack3[pbcpos3++] = x;
 | |
| }
 | |
| 
 | |
| static int pbcpop3(char x)
 | |
| {
 | |
| 	if (   ( x == ')' && pbcstack3[pbcpos3-1] == '(' )
 | |
| 		|| ( x == ']' && pbcstack3[pbcpos3-1] == '[' )
 | |
| 		|| ( x == '}' && pbcstack3[pbcpos3-1] == '{' )) {
 | |
| 		pbcpos3--;
 | |
| 		return 0;
 | |
| 	}
 | |
| 	return 1; /* error */
 | |
| }
 | |
| 
 | |
| static int c_prevword(void)
 | |
| {
 | |
| 	char *c = prev_word;
 | |
| 	if (c == NULL)
 | |
| 		return 0;
 | |
| 	while ( *c ) {
 | |
| 		switch (*c) {
 | |
| 		case '{':
 | |
| 		case '[':
 | |
| 		case '(':
 | |
| 			pbcpush(*c);
 | |
| 			break;
 | |
| 		case '}':
 | |
| 		case ']':
 | |
| 		case ')':
 | |
| 			if (pbcpop(*c))
 | |
| 				return 1;
 | |
| 			break;
 | |
| 		}
 | |
| 		c++;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * The following three functions, reset_*, are used in the bison
 | |
|  * code to switch context. As a consequence, we need to
 | |
|  * declare them global and add a prototype so that the
 | |
|  * compiler does not complain.
 | |
|  *
 | |
|  * NOTE: yyg is declared because it is used in the BEGIN macros,
 | |
|  * though that should be hidden as the macro changes
 | |
|  * depending on the flex options that we use - in particular,
 | |
|  * %reentrant changes the way the macro is declared;
 | |
|  * without %reentrant, BEGIN uses yystart instead of yyg
 | |
|  */
 | |
| 
 | |
| void reset_parencount(yyscan_t yyscanner );
 | |
| void reset_parencount(yyscan_t yyscanner )
 | |
| {
 | |
| 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 | |
| 	parencount = 0;
 | |
| 	pbcpos = 0;
 | |
| 	pbcpush('(');	/* push '(' so the last pcbpop (parencount= -1) will succeed */
 | |
| 	c_prevword();
 | |
| 	BEGIN(paren);
 | |
| }
 | |
| 
 | |
| void reset_semicount(yyscan_t yyscanner );
 | |
| void reset_semicount(yyscan_t yyscanner )
 | |
| {
 | |
| 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 | |
| 	pbcpos = 0;
 | |
| 	BEGIN(semic);
 | |
| }
 | |
| 
 | |
| void reset_argcount(yyscan_t yyscanner );
 | |
| void reset_argcount(yyscan_t yyscanner )
 | |
| {
 | |
| 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 | |
| 	parencount = 0;
 | |
| 	pbcpos = 0;
 | |
| 	pbcpush('(');	/* push '(' so the last pcbpop (parencount= -1) will succeed */
 | |
| 	c_prevword();
 | |
| 	BEGIN(argg);
 | |
| }
 | |
| 
 | |
| /* used elsewhere, but some local vars */
 | |
| struct pval *ael2_parse(char *filename, int *errors)
 | |
| {
 | |
| 	struct pval *pvalue;
 | |
| 	struct parse_io *io;
 | |
| 	char *buffer;
 | |
| 	struct stat stats;
 | |
| 	FILE *fin;
 | |
| 
 | |
| 	/* extern int ael_yydebug; */
 | |
| 
 | |
| 	io = calloc(sizeof(struct parse_io),1);
 | |
| 	/* reset the global counters */
 | |
| 	prev_word = 0;
 | |
| 	my_lineno = 1;
 | |
| 	include_stack_index=0;
 | |
| 	my_col = 0;
 | |
| 	/* ael_yydebug = 1; */
 | |
| 	ael_yylex_init(&io->scanner);
 | |
| 	fin = fopen(filename,"r");
 | |
| 	if ( !fin ) {
 | |
| 		ast_log(LOG_ERROR,"File %s could not be opened\n", filename);
 | |
| 		*errors = 1;
 | |
| 		return 0;
 | |
| 	}
 | |
| 	if (my_file)
 | |
| 		free(my_file);
 | |
| 	my_file = strdup(filename);
 | |
| 	if (stat(filename, &stats)) {
 | |
| 		ast_log(LOG_WARNING, "failed to populate stats from file '%s'\n", filename);
 | |
| 	}
 | |
| 	buffer = (char*)malloc(stats.st_size+2);
 | |
| 	if (fread(buffer, 1, stats.st_size, fin) != stats.st_size) {
 | |
| 		ast_log(LOG_ERROR, "fread() failed: %s\n", strerror(errno));
 | |
| 	}
 | |
| 	buffer[stats.st_size]=0;
 | |
| 	fclose(fin);
 | |
| 
 | |
| 	ael_yy_scan_string (buffer ,io->scanner);
 | |
| 	ael_yyset_lineno(1 , io->scanner);
 | |
| 
 | |
| 	/* ael_yyset_in (fin , io->scanner);	OLD WAY */
 | |
| 
 | |
| 	ael_yyparse(io);
 | |
| 
 | |
| 
 | |
| 	pvalue = io->pval;
 | |
| 	*errors = io->syntax_error_count;
 | |
| 
 | |
| 	ael_yylex_destroy(io->scanner);
 | |
| 	free(buffer);
 | |
| 	free(io);
 | |
| 
 | |
| 	return pvalue;
 | |
| }
 | |
| 
 | |
| static void setup_filestack(char *fnamebuf2, int fnamebuf_siz, glob_t *globbuf, int globpos, yyscan_t yyscanner, int create)
 | |
| {
 | |
| 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 | |
| 	int error, i;
 | |
| 	FILE *in1;
 | |
| 	char fnamebuf[2048];
 | |
| 
 | |
| 	if (globbuf && globbuf->gl_pathv && globbuf->gl_pathc > 0)
 | |
| #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
 | |
| 			strncpy(fnamebuf, globbuf->gl_pathv[globpos], fnamebuf_siz);
 | |
| #else
 | |
| 			ast_copy_string(fnamebuf, globbuf->gl_pathv[globpos], fnamebuf_siz);
 | |
| #endif
 | |
| 	else {
 | |
| 		ast_log(LOG_ERROR,"Include file name not present!\n");
 | |
| 		return;
 | |
| 	}
 | |
| 	for (i=0; i<include_stack_index; i++) {
 | |
| 		if ( !strcmp(fnamebuf,include_stack[i].fname )) {
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Nice Try!!! But %s has already been included (perhaps by another file), and would cause an infinite loop of file inclusions!!! Include directive ignored\n",
 | |
| 				my_file, my_lineno, my_col, fnamebuf);
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 	error = 1;
 | |
| 	if (i == include_stack_index)
 | |
| 		error = 0;	/* we can use this file */
 | |
| 	if ( !error ) {	/* valid file name */
 | |
| 		/* relative vs. absolute */
 | |
| 		if (fnamebuf[0] != '/')
 | |
| 			snprintf(fnamebuf2, fnamebuf_siz, "%s/%s", ast_config_AST_CONFIG_DIR, fnamebuf);
 | |
| 		else
 | |
| #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
 | |
| 			strncpy(fnamebuf2, fnamebuf, fnamebuf_siz);
 | |
| #else
 | |
| 			ast_copy_string(fnamebuf2, fnamebuf, fnamebuf_siz);
 | |
| #endif
 | |
| 		in1 = fopen( fnamebuf2, "r" );
 | |
| 
 | |
| 		if ( ! in1 ) {
 | |
| 			ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Couldn't find the include file: %s; ignoring the Include directive!\n", my_file, my_lineno, my_col, fnamebuf2);
 | |
| 		} else {
 | |
| 			char *buffer;
 | |
| 			struct stat stats;
 | |
| 			if (stat(fnamebuf2, &stats)) {
 | |
| 				ast_log(LOG_WARNING, "Failed to populate stats from file '%s'\n", fnamebuf2);
 | |
| 			}
 | |
| 			buffer = (char*)malloc(stats.st_size+1);
 | |
| 			if (fread(buffer, 1, stats.st_size, in1) != stats.st_size) {
 | |
| 				ast_log(LOG_ERROR, "fread() failed: %s\n", strerror(errno));
 | |
| 			}
 | |
| 			buffer[stats.st_size] = 0;
 | |
| 			ast_debug(1, "  --Read in included file %s, %d chars\n",fnamebuf2, (int)stats.st_size);
 | |
| 			fclose(in1);
 | |
| 			if (include_stack[include_stack_index].fname) {
 | |
| 			   	free(include_stack[include_stack_index].fname);
 | |
| 				include_stack[include_stack_index].fname = 0;
 | |
| 			}
 | |
| 			include_stack[include_stack_index].fname = strdup(S_OR(my_file, "<none>"));
 | |
| 			include_stack[include_stack_index].lineno = my_lineno;
 | |
| 			include_stack[include_stack_index].colno = my_col+yyleng;
 | |
| 			if (my_file)
 | |
| 				free(my_file);
 | |
| 			my_file = strdup(fnamebuf2);
 | |
| 			if (create)
 | |
| 				include_stack[include_stack_index].globbuf = *globbuf;
 | |
| 
 | |
| 			include_stack[include_stack_index].globbuf_pos = 0;
 | |
| 
 | |
| 			include_stack[include_stack_index].bufstate = YY_CURRENT_BUFFER;
 | |
| 			if (create)
 | |
| 				include_stack_index++;
 | |
| 			yy_switch_to_buffer(ael_yy_scan_string (buffer ,yyscanner),yyscanner);
 | |
| 			free(buffer);
 | |
| 			my_lineno = 1;
 | |
| 			my_col = 1;
 | |
| 			BEGIN(INITIAL);
 | |
| 		}
 | |
| 	}
 | |
| }
 |