2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2006, Digium, Inc.
6 * Steve Murphy <murf@parsetree.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 * \brief Flex scanner description of tokens used in AEL2 .
25 * Start with flex options:
27 * %x describes the contexts we have: paren, semic and argg, plus INITIAL
29 %x paren semic argg comment curlystate wordstate brackstate
31 /* prefix used for various globally-visible functions and variables.
32 * This renames also yywrap, but since we do not use it, we just
33 * add option noyywrap to remove it.
35 %option prefix="ael_yy"
38 /* I specify this option to suppress flex generating code with ECHO
39 in it. This generates compiler warnings in some systems; We've
40 seen the fwrite generate Unused variable warnings with 4.1.2 gcc.
41 Some systems have tweaked flex ECHO macro to keep the compiler
42 happy. To keep the warning message from getting output, I added
43 a default rule at the end of the patterns section */
46 /* yyfree normally just frees its arg. It can be null sometimes,
47 which some systems will complain about, so, we'll define our own version */
50 /* batch gives a bit more performance if we are using it in
51 * a non-interactive mode. We probably don't care much.
55 /* outfile is the filename to be used instead of lex.yy.c */
56 %option outfile="ael_lex.c"
59 * These are not supported in flex 2.5.4, but we need them
61 * reentrant produces a thread-safe parser. Not 100% sure that
62 * we require it, though.
63 * bison-bridge passes an additional yylval argument to yylex().
64 * bison-locations is probably not needed.
68 %option bison-locations
72 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
74 #include <sys/types.h>
79 #if !defined(GLOB_ABORTED)
80 #define GLOB_ABORTED GLOB_ABEND
83 #include "asterisk/logger.h"
84 #include "asterisk/utils.h"
85 #include "asterisk/lock.h"
86 #include "asterisk/hashtab.h"
87 #include "ael/ael.tab.h"
88 #include "asterisk/ael_structs.h"
91 * A stack to keep track of matching brackets ( [ { } ] )
93 static char pbcstack[400]; /* XXX missing size checks */
94 static int pbcpos = 0;
95 static void pbcpush(char x);
96 static int pbcpop(char x);
97 static int parencount = 0;
100 * A similar stack to keep track of matching brackets ( [ { } ] ) in word tokens surrounded by ${ ... }
102 static char pbcstack2[400]; /* XXX missing size checks */
103 static int pbcpos2 = 0;
104 static void pbcpush2(char x);
105 static int pbcpop2(char x);
106 static int parencount2 = 0;
109 * A similar stack to keep track of matching brackets ( [ { } ] ) in word tokens surrounded by $[ ... ]
111 static char pbcstack3[400]; /* XXX missing size checks */
112 static int pbcpos3 = 0;
113 static void pbcpush3(char x);
114 static int pbcpop3(char x);
115 static int parencount3 = 0;
119 * current line, column and filename, updated as we read the input.
121 static int my_lineno = 1; /* current line in the source */
122 static int my_col = 1; /* current column in the source */
123 char *my_file = 0; /* used also in the bison code */
124 char *prev_word; /* XXX document it */
126 #define MAX_INCLUDE_DEPTH 50
129 * flex is not too smart, and generates global functions
130 * without prototypes so the compiler may complain.
131 * To avoid that, we declare the prototypes here,
132 * even though these functions are not used.
134 int ael_yyget_column (yyscan_t yyscanner);
135 void ael_yyset_column (int column_no , yyscan_t yyscanner);
137 int ael_yyparse (struct parse_io *);
140 * A stack to process include files.
141 * As we switch into the new file we need to store the previous
142 * state to restore it later.
144 struct stackelement {
148 glob_t globbuf; /* the current globbuf */
149 int globbuf_pos; /* where we are in the current globbuf */
150 YY_BUFFER_STATE bufstate;
153 static struct stackelement include_stack[MAX_INCLUDE_DEPTH];
154 static int include_stack_index = 0;
155 static void setup_filestack(char *fnamebuf, int fnamebuf_siz, glob_t *globbuf, int globpos, yyscan_t xscan, int create);
158 * if we use the @n feature of bison, we must supply the start/end
159 * location of tokens in the structure pointed by yylloc.
160 * Simple tokens are just assumed to be on the same line, so
161 * the line number is constant, and the column is incremented
162 * by the length of the token.
164 #ifdef FLEX_BETA /* set for 2.5.33 */
166 /* compute the total number of lines and columns in the text
167 * passed as argument.
169 static void pbcwhere(const char *text, int *line, int *col )
171 int loc_line = *line;
174 while ( (c = *text++) ) {
176 loc_col += 8 - (loc_col % 8);
177 } else if ( c == '\n' ) {
187 #define STORE_POS do { \
188 yylloc->first_line = yylloc->last_line = my_lineno; \
189 yylloc->first_column=my_col; \
190 yylloc->last_column=my_col+yyleng-1; \
194 #define STORE_LOC do { \
195 yylloc->first_line = my_lineno; \
196 yylloc->first_column=my_col; \
197 pbcwhere(yytext, &my_lineno, &my_col); \
198 yylloc->last_line = my_lineno; \
199 yylloc->last_column = my_col - 1; \
207 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)
209 NOPARENS ([^()\[\]\{\}]|\\[()\[\]\{\}])*
211 NOARGG ([^(),\{\}\[\]]|\\[,()\[\]\{\}])*
213 NOSEMIC ([^;()\{\}\[\]]|\\[;()\[\]\{\}])*
219 \{ { STORE_POS; return LC;}
220 \} { STORE_POS; return RC;}
221 \( { STORE_POS; return LP;}
222 \) { STORE_POS; return RP;}
223 \; { STORE_POS; return SEMI;}
224 \= { STORE_POS; return EQ;}
225 \, { STORE_POS; return COMMA;}
226 \: { STORE_POS; return COLON;}
227 \& { STORE_POS; return AMPER;}
228 \| { STORE_POS; return BAR;}
229 \=\> { STORE_POS; return EXTENMARK;}
230 \@ { STORE_POS; return AT;}
231 \/\/[^\n]* {/*comment*/}
232 context { STORE_POS; return KW_CONTEXT;}
233 abstract { STORE_POS; return KW_ABSTRACT;}
234 extend { STORE_POS; return KW_EXTEND;}
235 macro { STORE_POS; return KW_MACRO;};
236 globals { STORE_POS; return KW_GLOBALS;}
237 local { STORE_POS; return KW_LOCAL;}
238 ignorepat { STORE_POS; return KW_IGNOREPAT;}
239 switch { STORE_POS; return KW_SWITCH;}
240 if { STORE_POS; return KW_IF;}
241 ifTime { STORE_POS; return KW_IFTIME;}
242 random { STORE_POS; return KW_RANDOM;}
243 regexten { STORE_POS; return KW_REGEXTEN;}
244 hint { STORE_POS; return KW_HINT;}
245 else { STORE_POS; return KW_ELSE;}
246 goto { STORE_POS; return KW_GOTO;}
247 jump { STORE_POS; return KW_JUMP;}
248 return { STORE_POS; return KW_RETURN;}
249 break { STORE_POS; return KW_BREAK;}
250 continue { STORE_POS; return KW_CONTINUE;}
251 for { STORE_POS; return KW_FOR;}
252 while { STORE_POS; return KW_WHILE;}
253 case { STORE_POS; return KW_CASE;}
254 default { STORE_POS; return KW_DEFAULT;}
255 pattern { STORE_POS; return KW_PATTERN;}
256 catch { STORE_POS; return KW_CATCH;}
257 switches { STORE_POS; return KW_SWITCHES;}
258 eswitches { STORE_POS; return KW_ESWITCHES;}
259 includes { STORE_POS; return KW_INCLUDES;}
260 "/*" { BEGIN(comment); my_col += 2; }
262 <comment>[^*\n]* { my_col += yyleng; }
263 <comment>[^*\n]*\n { ++my_lineno; my_col=1;}
264 <comment>"*"+[^*/\n]* { my_col += yyleng; }
265 <comment>"*"+[^*/\n]*\n { ++my_lineno; my_col=1;}
266 <comment>"*/" { my_col += 2; BEGIN(INITIAL); } /* the nice thing about comments is that you know exactly what ends them */
268 \n { my_lineno++; my_col = 1; }
269 [ ]+ { my_col += yyleng; }
270 [\t]+ { my_col += (yyleng*8)-(my_col%8); }
272 ({KEYWORD}?[-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]]|{HIBIT}|(\\.)|(\$\{)|(\$\[)) {
273 /* boy did I open a can of worms when I changed the lexical token "word".
274 all the above keywords can be used as a beginning to a "word".-
275 before, a "word" would match a longer sequence than the above
276 keywords, and all would be well. But now "word" is a single char
277 and feeds into a statemachine sort of sequence from there on. So...
278 I added the {KEYWORD}? to the beginning of the word match sequence */
280 if (!strcmp(yytext,"${")) {
283 pbcpush2('{'); /* push '{' so the last pcbpop (parencount2 = -1) will succeed */
286 } else if (!strcmp(yytext,"$[")) {
289 pbcpush3('['); /* push '[' so the last pcbpop (parencount3 = -1) will succeed */
298 <wordstate>[-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]] { yymore(); /* Keep going */ }
299 <wordstate>{HIBIT} { yymore(); /* Keep going */ }
300 <wordstate>(\\.) { yymore(); /* Keep Going */ }
301 <wordstate>(\$\{) { /* the beginning of a ${} construct. prepare and pop into curlystate */
304 pbcpush2('{'); /* push '{' so the last pcbpop (parencount2 = -1) will succeed */
308 <wordstate>(\$\[) { /* the beginning of a $[] construct. prepare and pop into brackstate */
311 pbcpush3('['); /* push '[' so the last pcbpop (parencount3 = -1) will succeed */
315 <wordstate>([^a-zA-Z0-9\x80-\xff\x2d'"_/.\<\>\*\+!$#\[\]]) {
316 /* a non-word constituent char, like a space, tab, curly, paren, etc */
317 char c = yytext[yyleng-1];
319 yylval->str = malloc(yyleng);
320 strncpy(yylval->str, yytext, yyleng);
321 yylval->str[yyleng-1] = 0;
322 unput(c); /* put this ending char back in the stream */
328 <curlystate>{NOPARENS}\} {
329 if ( pbcpop2('}') ) { /* error */
331 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext);
333 yylval->str = malloc(yyleng+1);
334 strncpy(yylval->str, yytext, yyleng);
335 yylval->str[yyleng] = 0;
339 if ( parencount2 >= 0) {
342 BEGIN(wordstate); /* Finished with the current ${} construct. Return to word gathering state */
347 <curlystate>{NOPARENS}[\(\[\{] {
348 char c = yytext[yyleng-1];
355 <curlystate>{NOPARENS}[\]\)] {
356 char c = yytext[yyleng-1];
357 if ( pbcpop2(c)) { /* error */
359 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n",
360 my_file, my_lineno, my_col, c);
362 yylval->str = malloc(yyleng+1);
363 strncpy(yylval->str, yytext, yyleng);
364 yylval->str[yyleng] = 0;
371 <brackstate>{NOPARENS}\] {
372 if ( pbcpop3(']') ) { /* error */
374 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext);
376 yylval->str = malloc(yyleng+1);
377 strncpy(yylval->str, yytext, yyleng);
378 yylval->str[yyleng] = 0;
382 if ( parencount3 >= 0) {
385 BEGIN(wordstate); /* Finished with the current ${} construct. Return to word gathering state */
390 <brackstate>{NOPARENS}[\(\[\{] {
391 char c = yytext[yyleng-1];
398 <brackstate>{NOPARENS}[\}\)] {
399 char c = yytext[yyleng-1];
400 if ( pbcpop3(c)) { /* error */
402 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n",
403 my_file, my_lineno, my_col, c);
405 yylval->str = malloc(yyleng+1);
406 strncpy(yylval->str, yytext, yyleng);
407 yylval->str[yyleng] = 0;
415 * context used for arguments of if_head, random_head, switch_head,
416 * for (last statement), while (XXX why not iftime_head ?).
417 * End with the matching parentheses.
418 * A comma at the top level is valid here, unlike in argg where it
419 * is an argument separator so it must be returned as a token.
421 <paren>{NOPARENS}\) {
422 if ( pbcpop(')') ) { /* error */
424 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext);
426 yylval->str = malloc(yyleng+1);
427 strncpy(yylval->str, yytext, yyleng);
428 yylval->str[yyleng] = 0;
433 if ( parencount >= 0) {
437 yylval->str = malloc(yyleng);
438 strncpy(yylval->str, yytext, yyleng);
439 yylval->str[yyleng-1] = 0;
446 <paren>{NOPARENS}[\(\[\{] {
447 char c = yytext[yyleng-1];
454 <paren>{NOPARENS}[\]\}] {
455 char c = yytext[yyleng-1];
456 if ( pbcpop(c)) { /* error */
458 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n",
459 my_file, my_lineno, my_col, c);
461 yylval->str = malloc(yyleng+1);
462 strncpy(yylval->str, yytext, yyleng);
463 yylval->str[yyleng] = 0;
471 * handlers for arguments to a macro or application calls.
472 * We enter this context when we find the initial '(' and
473 * stay here until we close all matching parentheses,
474 * and find the comma (argument separator) or the closing ')'
475 * of the (external) call, which happens when parencount == 0
476 * before the decrement.
478 <argg>{NOARGG}[\(\[\{] {
479 char c = yytext[yyleng-1];
487 if ( pbcpop(')') ) { /* error */
489 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression!\n", my_file, my_lineno, my_col);
491 yylval->str = malloc(yyleng+1);
492 strncpy(yylval->str, yytext, yyleng);
493 yylval->str[yyleng] = 0;
498 if( parencount >= 0){
503 if ( !strcmp(yytext, ")") )
505 yylval->str = malloc(yyleng);
506 strncpy(yylval->str, yytext, yyleng);
507 yylval->str[yyleng-1] = '\0'; /* trim trailing ')' */
514 if( parencount != 0) { /* ast_log(LOG_NOTICE,"Folding in a comma!\n"); */
518 if( !strcmp(yytext,"," ) )
520 yylval->str = malloc(yyleng);
521 strncpy(yylval->str, yytext, yyleng);
522 yylval->str[yyleng-1] = '\0'; /* trim trailing ',' */
528 <argg>{NOARGG}[\]\}] {
529 char c = yytext[yyleng-1];
530 if ( pbcpop(c) ) { /* error */
532 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n", my_file, my_lineno, my_col, c);
534 yylval->str = malloc(yyleng+1);
535 strncpy(yylval->str, yytext, yyleng);
536 yylval->str[yyleng] = '\0';
543 * context used to find tokens in the right hand side of assignments,
544 * or in the first and second operand of a 'for'. As above, match
545 * commas and use ';' as a separator (hence return it as a separate token).
547 <semic>{NOSEMIC}[\(\[\{] {
548 char c = yytext[yyleng-1];
553 <semic>{NOSEMIC}[\)\]\}] {
554 char c = yytext[yyleng-1];
555 if ( pbcpop(c) ) { /* error */
557 ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n", my_file, my_lineno, my_col, c);
559 yylval->str = malloc(yyleng+1);
560 strncpy(yylval->str, yytext, yyleng);
561 yylval->str[yyleng] = '\0';
569 yylval->str = malloc(yyleng);
570 strncpy(yylval->str, yytext, yyleng);
571 yylval->str[yyleng-1] = '\0'; /* trim trailing ';' */
577 \#include[ \t]+\"[^\"]+\" {
578 char fnamebuf[1024],*p1,*p2;
580 glob_t globbuf; /* the current globbuf */
581 int globbuf_pos = -1; /* where we are in the current globbuf */
582 globbuf.gl_offs = 0; /* initialize it to silence gcc */
584 p1 = strchr(yytext,'"');
585 p2 = strrchr(yytext,'"');
586 if ( include_stack_index >= MAX_INCLUDE_DEPTH ) {
587 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);
588 } else if ( (int)(p2-p1) > sizeof(fnamebuf) - 1 ) {
589 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);
591 strncpy(fnamebuf, p1+1, p2-p1-1);
592 fnamebuf[p2-p1-1] = 0;
593 if (fnamebuf[0] != '/') {
594 char fnamebuf2[1024];
595 snprintf(fnamebuf2,sizeof(fnamebuf2), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, fnamebuf);
596 ast_copy_string(fnamebuf,fnamebuf2,sizeof(fnamebuf));
599 glob_ret = glob(fnamebuf, GLOB_NOCHECK, NULL, &globbuf);
601 glob_ret = glob(fnamebuf, GLOB_NOMAGIC|GLOB_BRACE, NULL, &globbuf);
603 if (glob_ret == GLOB_NOSPACE) {
605 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fnamebuf);
606 } else if (glob_ret == GLOB_ABORTED) {
608 "Glob Expansion of pattern '%s' failed: Read error\n", fnamebuf);
609 } else if (glob_ret == GLOB_NOMATCH) {
611 "Glob Expansion of pattern '%s' failed: No matches!\n", fnamebuf);
616 if (globbuf_pos > -1) {
617 setup_filestack(fnamebuf, sizeof(fnamebuf), &globbuf, 0, yyscanner, 1);
624 if (include_stack_index > 0 && include_stack[include_stack_index-1].globbuf_pos < include_stack[include_stack_index-1].globbuf.gl_pathc-1) {
625 yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner );
626 include_stack[include_stack_index-1].globbuf_pos++;
627 setup_filestack(fnamebuf, sizeof(fnamebuf), &include_stack[include_stack_index-1].globbuf, include_stack[include_stack_index-1].globbuf_pos, yyscanner, 0);
631 if (include_stack[include_stack_index].fname) {
632 free(include_stack[include_stack_index].fname);
633 include_stack[include_stack_index].fname = 0;
639 if ( --include_stack_index < 0 ) {
642 globfree(&include_stack[include_stack_index].globbuf);
643 include_stack[include_stack_index].globbuf_pos = -1;
645 yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner );
646 yy_switch_to_buffer(include_stack[include_stack_index].bufstate, yyscanner );
647 my_lineno = include_stack[include_stack_index].lineno;
648 my_col = include_stack[include_stack_index].colno;
649 my_file = strdup(include_stack[include_stack_index].fname);
654 <*>.|\n { /* default rule */ ast_log(LOG_ERROR,"Unhandled char(s): %s\n", yytext); }
658 static void pbcpush(char x)
660 pbcstack[pbcpos++] = x;
663 void ael_yyfree(void *ptr, yyscan_t yyscanner)
669 static int pbcpop(char x)
671 if ( ( x == ')' && pbcstack[pbcpos-1] == '(' )
672 || ( x == ']' && pbcstack[pbcpos-1] == '[' )
673 || ( x == '}' && pbcstack[pbcpos-1] == '{' )) {
677 return 1; /* error */
680 static void pbcpush2(char x)
682 pbcstack2[pbcpos2++] = x;
685 static int pbcpop2(char x)
687 if ( ( x == ')' && pbcstack2[pbcpos2-1] == '(' )
688 || ( x == ']' && pbcstack2[pbcpos2-1] == '[' )
689 || ( x == '}' && pbcstack2[pbcpos2-1] == '{' )) {
693 return 1; /* error */
696 static void pbcpush3(char x)
698 pbcstack3[pbcpos3++] = x;
701 static int pbcpop3(char x)
703 if ( ( x == ')' && pbcstack3[pbcpos3-1] == '(' )
704 || ( x == ']' && pbcstack3[pbcpos3-1] == '[' )
705 || ( x == '}' && pbcstack3[pbcpos3-1] == '{' )) {
709 return 1; /* error */
712 static int c_prevword(void)
738 * The following three functions, reset_*, are used in the bison
739 * code to switch context. As a consequence, we need to
740 * declare them global and add a prototype so that the
741 * compiler does not complain.
743 * NOTE: yyg is declared because it is used in the BEGIN macros,
744 * though that should be hidden as the macro changes
745 * depending on the flex options that we use - in particular,
746 * %reentrant changes the way the macro is declared;
747 * without %reentrant, BEGIN uses yystart instead of yyg
750 void reset_parencount(yyscan_t yyscanner );
751 void reset_parencount(yyscan_t yyscanner )
753 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
756 pbcpush('('); /* push '(' so the last pcbpop (parencount= -1) will succeed */
761 void reset_semicount(yyscan_t yyscanner );
762 void reset_semicount(yyscan_t yyscanner )
764 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
769 void reset_argcount(yyscan_t yyscanner );
770 void reset_argcount(yyscan_t yyscanner )
772 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
775 pbcpush('('); /* push '(' so the last pcbpop (parencount= -1) will succeed */
780 /* used elsewhere, but some local vars */
781 struct pval *ael2_parse(char *filename, int *errors)
789 /* extern int ael_yydebug; */
791 io = calloc(sizeof(struct parse_io),1);
792 /* reset the global counters */
795 include_stack_index=0;
797 /* ael_yydebug = 1; */
798 ael_yylex_init(&io->scanner);
799 fin = fopen(filename,"r");
801 ast_log(LOG_ERROR,"File %s could not be opened\n", filename);
807 my_file = strdup(filename);
808 if (stat(filename, &stats)) {
809 ast_log(LOG_WARNING, "failed to populate stats from file '%s'\n", filename);
811 buffer = (char*)malloc(stats.st_size+2);
812 if (fread(buffer, 1, stats.st_size, fin) != stats.st_size) {
813 ast_log(LOG_ERROR, "fread() failed: %s\n", strerror(errno));
815 buffer[stats.st_size]=0;
818 ael_yy_scan_string (buffer ,io->scanner);
819 ael_yyset_lineno(1 , io->scanner);
821 /* ael_yyset_in (fin , io->scanner); OLD WAY */
827 *errors = io->syntax_error_count;
829 ael_yylex_destroy(io->scanner);
836 static void setup_filestack(char *fnamebuf2, int fnamebuf_siz, glob_t *globbuf, int globpos, yyscan_t yyscanner, int create)
838 struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
843 if (globbuf && globbuf->gl_pathv && globbuf->gl_pathc > 0)
844 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
845 strncpy(fnamebuf, globbuf->gl_pathv[globpos], fnamebuf_siz);
847 ast_copy_string(fnamebuf, globbuf->gl_pathv[globpos], fnamebuf_siz);
850 ast_log(LOG_ERROR,"Include file name not present!\n");
853 for (i=0; i<include_stack_index; i++) {
854 if ( !strcmp(fnamebuf,include_stack[i].fname )) {
855 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",
856 my_file, my_lineno, my_col, fnamebuf);
861 if (i == include_stack_index)
862 error = 0; /* we can use this file */
863 if ( !error ) { /* valid file name */
864 /* relative vs. absolute */
865 if (fnamebuf[0] != '/')
866 snprintf(fnamebuf2, fnamebuf_siz, "%s/%s", ast_config_AST_CONFIG_DIR, fnamebuf);
868 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
869 strncpy(fnamebuf2, fnamebuf, fnamebuf_siz);
871 ast_copy_string(fnamebuf2, fnamebuf, fnamebuf_siz);
873 in1 = fopen( fnamebuf2, "r" );
876 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);
880 if (stat(fnamebuf2, &stats)) {
881 ast_log(LOG_WARNING, "Failed to populate stats from file '%s'\n", fnamebuf2);
883 buffer = (char*)malloc(stats.st_size+1);
884 if (fread(buffer, 1, stats.st_size, in1) != stats.st_size) {
885 ast_log(LOG_ERROR, "fread() failed: %s\n", strerror(errno));
887 buffer[stats.st_size] = 0;
888 ast_debug(1, " --Read in included file %s, %d chars\n",fnamebuf2, (int)stats.st_size);
890 if (include_stack[include_stack_index].fname) {
891 free(include_stack[include_stack_index].fname);
892 include_stack[include_stack_index].fname = 0;
894 include_stack[include_stack_index].fname = strdup(S_OR(my_file, "<none>"));
895 include_stack[include_stack_index].lineno = my_lineno;
896 include_stack[include_stack_index].colno = my_col+yyleng;
899 my_file = strdup(fnamebuf2);
901 include_stack[include_stack_index].globbuf = *globbuf;
903 include_stack[include_stack_index].globbuf_pos = 0;
905 include_stack[include_stack_index].bufstate = YY_CURRENT_BUFFER;
907 include_stack_index++;
908 yy_switch_to_buffer(ael_yy_scan_string (buffer ,yyscanner),yyscanner);