5adaff1ebd6ededec714cf2dcc7907abc33a7344
[asterisk/asterisk.git] / res / ael / ael.flex
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2006, Digium, Inc.
5  *
6  * Steve Murphy <murf@parsetree.com>
7  *
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.
13  *
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.
17  */
18 /*! \file
19  *
20  * \brief Flex scanner description of tokens used in AEL2 .
21  *
22  */
23
24 /*
25  * Start with flex options:
26  *
27  * %x describes the contexts we have: paren, semic and argg, plus INITIAL
28  */
29 %x paren semic argg  comment
30
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.
34  */
35 %option prefix="ael_yy"
36 %option noyywrap
37
38 /* batch gives a bit more performance if we are using it in
39  * a non-interactive mode. We probably don't care much.
40  */
41 %option batch
42
43 /* outfile is the filename to be used instead of lex.yy.c */
44 %option outfile="ael_lex.c"
45
46 /*
47  * These are not supported in flex 2.5.4, but we need them
48  * at the moment:
49  * reentrant produces a thread-safe parser. Not 100% sure that
50  * we require it, though.
51  * bison-bridge passes an additional yylval argument to yylex().
52  * bison-locations is probably not needed.
53  */
54 %option reentrant
55 %option bison-bridge
56 %option bison-locations
57
58 %{
59 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
60
61 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <unistd.h>
64
65 #if defined(__Darwin__) || defined(__CYGWIN__)
66 #define GLOB_ABORTED GLOB_ABEND
67 #endif
68 # include <glob.h>
69
70 #include "asterisk/logger.h"
71 #include "asterisk/utils.h"
72 #include "ael/ael.tab.h"
73 #include "asterisk/ael_structs.h"
74
75 /*
76  * A stack to keep track of matching brackets ( [ { } ] )
77  */
78 static char pbcstack[400];      /* XXX missing size checks */
79 static int pbcpos = 0;
80 static void pbcpush(char x);
81 static int pbcpop(char x);
82
83 static int parencount = 0;
84
85 /*
86  * current line, column and filename, updated as we read the input.
87  */
88 static int my_lineno = 1;       /* current line in the source */
89 static int my_col = 1;          /* current column in the source */
90 char *my_file = 0;              /* used also in the bison code */
91 char *prev_word;                /* XXX document it */
92
93 #define MAX_INCLUDE_DEPTH 50
94
95 /*
96  * flex is not too smart, and generates global functions
97  * without prototypes so the compiler may complain.
98  * To avoid that, we declare the prototypes here,
99  * even though these functions are not used.
100  */
101 int ael_yyget_column  (yyscan_t yyscanner);
102 void ael_yyset_column (int  column_no , yyscan_t yyscanner);
103
104 int ael_yyparse (struct parse_io *);
105
106 /*
107  * A stack to process include files.
108  * As we switch into the new file we need to store the previous
109  * state to restore it later.
110  */
111 struct stackelement {
112         char *fname;
113         int lineno;
114         int colno;
115         glob_t globbuf;        /* the current globbuf */
116         int globbuf_pos;   /* where we are in the current globbuf */
117         YY_BUFFER_STATE bufstate;
118 };
119
120 static struct stackelement  include_stack[MAX_INCLUDE_DEPTH];
121 static int include_stack_index = 0;
122 static void setup_filestack(char *fnamebuf, int fnamebuf_siz, glob_t *globbuf, int globpos, yyscan_t xscan, int create);
123
124 /*
125  * if we use the @n feature of bison, we must supply the start/end
126  * location of tokens in the structure pointed by yylloc.
127  * Simple tokens are just assumed to be on the same line, so
128  * the line number is constant, and the column is incremented
129  * by the length of the token.
130  */
131 #ifdef FLEX_BETA        /* set for 2.5.33 */
132
133 /* compute the total number of lines and columns in the text
134  * passed as argument.
135  */
136 static void pbcwhere(const char *text, int *line, int *col )
137 {
138         int loc_line = *line;
139         int loc_col = *col;
140         char c;
141         while ( (c = *text++) ) {
142                 if ( c == '\t' ) {
143                         loc_col += 8 - (loc_col % 8);
144                 } else if ( c == '\n' ) {
145                         loc_line++;
146                         loc_col = 1;
147                 } else
148                         loc_col++;
149         }
150         *line = loc_line;
151         *col = loc_col;
152 }
153
154 #define STORE_POS do {                                                  \
155                 yylloc->first_line = yylloc->last_line = my_lineno;     \
156                 yylloc->first_column=my_col;                            \
157                 yylloc->last_column=my_col+yyleng-1;                    \
158                 my_col+=yyleng;                                         \
159         } while (0)
160
161 #define STORE_LOC do {                                  \
162                 yylloc->first_line = my_lineno;         \
163                 yylloc->first_column=my_col;            \
164                 pbcwhere(yytext, &my_lineno, &my_col);  \
165                 yylloc->last_line = my_lineno;          \
166                 yylloc->last_column = my_col - 1;       \
167         } while (0)
168 #else
169 #define STORE_POS
170 #define STORE_LOC
171 #endif
172 %}
173
174
175 NOPARENS        ([^()\[\]\{\}]|\\[()\[\]\{\}])*
176
177 NOARGG          ([^(),\{\}\[\]]|\\[,()\[\]\{\}])*
178
179 NOSEMIC         ([^;()\{\}\[\]]|\\[;()\[\]\{\}])*
180
181 %%
182
183 \{              { STORE_POS; return LC;}
184 \}              { STORE_POS; return RC;}
185 \(              { STORE_POS; return LP;}
186 \)              { STORE_POS; return RP;}
187 \;              { STORE_POS; return SEMI;}
188 \=              { STORE_POS; return EQ;}
189 \,              { STORE_POS; return COMMA;}
190 \:              { STORE_POS; return COLON;}
191 \&              { STORE_POS; return AMPER;}
192 \|              { STORE_POS; return BAR;}
193 \=\>            { STORE_POS; return EXTENMARK;}
194 \@              { STORE_POS; return AT;}
195 \/\/[^\n]*      {/*comment*/}
196 context         { STORE_POS; return KW_CONTEXT;}
197 abstract        { STORE_POS; return KW_ABSTRACT;}
198 macro           { STORE_POS; return KW_MACRO;};
199 globals         { STORE_POS; return KW_GLOBALS;}
200 local           { STORE_POS; return KW_LOCAL;}
201 ignorepat       { STORE_POS; return KW_IGNOREPAT;}
202 switch          { STORE_POS; return KW_SWITCH;}
203 if              { STORE_POS; return KW_IF;}
204 ifTime          { STORE_POS; return KW_IFTIME;}
205 random          { STORE_POS; return KW_RANDOM;}
206 regexten        { STORE_POS; return KW_REGEXTEN;}
207 hint            { STORE_POS; return KW_HINT;}
208 else            { STORE_POS; return KW_ELSE;}
209 goto            { STORE_POS; return KW_GOTO;}
210 jump            { STORE_POS; return KW_JUMP;}
211 return          { STORE_POS; return KW_RETURN;}
212 break           { STORE_POS; return KW_BREAK;}
213 continue        { STORE_POS; return KW_CONTINUE;}
214 for             { STORE_POS; return KW_FOR;}
215 while           { STORE_POS; return KW_WHILE;}
216 case            { STORE_POS; return KW_CASE;}
217 default         { STORE_POS; return KW_DEFAULT;}
218 pattern         { STORE_POS; return KW_PATTERN;}
219 catch           { STORE_POS; return KW_CATCH;}
220 switches        { STORE_POS; return KW_SWITCHES;}
221 eswitches       { STORE_POS; return KW_ESWITCHES;}
222 includes        { STORE_POS; return KW_INCLUDES;}
223 "/*"            { BEGIN(comment); my_col += 2; }
224
225 <comment>[^*\n]*        { my_col += yyleng; }
226 <comment>[^*\n]*\n      { ++my_lineno; my_col=1;}
227 <comment>"*"+[^*/\n]*   { my_col += yyleng; }
228 <comment>"*"+[^*/\n]*\n         { ++my_lineno; my_col=1;}
229 <comment>"*/"           { my_col += 2; BEGIN(INITIAL); }
230
231 \n              { my_lineno++; my_col = 1; }
232 [ ]+            { my_col += yyleng; }
233 [\t]+           { my_col += (yyleng*8)-(my_col%8); }
234
235 [-a-zA-Z0-9'"_/.\<\>\*\+!$#\[\]][-a-zA-Z0-9'"_/.!\*\+\<\>\{\}$#\[\]]*   {
236                 STORE_POS;
237                 yylval->str = strdup(yytext);
238                 prev_word = yylval->str;
239                 return word;
240         }
241
242
243
244         /*
245          * context used for arguments of if_head, random_head, switch_head,
246          * for (last statement), while (XXX why not iftime_head ?).
247          * End with the matching parentheses.
248          * A comma at the top level is valid here, unlike in argg where it
249          * is an argument separator so it must be returned as a token.
250          */
251 <paren>{NOPARENS}\)     {
252                 if ( pbcpop(')') ) {    /* error */
253                         STORE_LOC;
254                         ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression: %s !\n", my_file, my_lineno, my_col, yytext);
255                         BEGIN(0);
256                         yylval->str = strdup(yytext);
257                         prev_word = 0;
258                         return word;
259                 }
260                 parencount--;
261                 if ( parencount >= 0) {
262                         yymore();
263                 } else {
264                         STORE_LOC;
265                         yylval->str = strdup(yytext);
266                         yylval->str[yyleng-1] = '\0'; /* trim trailing ')' */
267                         unput(')');
268                         BEGIN(0);
269                         return word;
270                 }
271         }
272
273 <paren>{NOPARENS}[\(\[\{]       {
274                 char c = yytext[yyleng-1];
275                 if (c == '(')
276                         parencount++;
277                 pbcpush(c);
278                 yymore();
279         }
280
281 <paren>{NOPARENS}[\]\}] {
282                 char c = yytext[yyleng-1];
283                 if ( pbcpop(c))  { /* error */
284                         STORE_LOC;
285                         ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n",
286                                 my_file, my_lineno, my_col, c);
287                         BEGIN(0);
288                         yylval->str = strdup(yytext);
289                         return word;
290                 }
291                 yymore();
292         }
293
294
295         /*
296          * handlers for arguments to a macro or application calls.
297          * We enter this context when we find the initial '(' and
298          * stay here until we close all matching parentheses,
299          * and find the comma (argument separator) or the closing ')'
300          * of the (external) call, which happens when parencount == 0
301          * before the decrement.
302          */
303 <argg>{NOARGG}[\(\[\{]    {
304                 char c = yytext[yyleng-1];
305                 if (c == '(')
306                         parencount++;
307                 pbcpush(c);
308                 yymore();
309         }
310
311 <argg>{NOARGG}\)        {
312                 if ( pbcpop(')') ) { /* error */
313                         STORE_LOC;
314                         ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched ')' in expression!\n", my_file, my_lineno, my_col);
315                         BEGIN(0);
316                         yylval->str = strdup(yytext);
317                         return word;
318                 }
319
320                 parencount--;
321                 if( parencount >= 0){
322                         yymore();
323                 } else {
324                         STORE_LOC;
325                         BEGIN(0);
326                         if ( !strcmp(yytext, ")") )
327                                 return RP;
328                         yylval->str = strdup(yytext);
329                         yylval->str[yyleng-1] = '\0'; /* trim trailing ')' */
330                         unput(')');
331                         return word;
332                 }
333         }
334
335 <argg>{NOARGG}\,        {
336                 if( parencount != 0) { /* printf("Folding in a comma!\n"); */
337                         yymore();
338                 } else  {
339                         STORE_LOC;
340                         if( !strcmp(yytext,"," ) )
341                                 return COMMA;
342                         yylval->str = strdup(yytext);
343                         yylval->str[yyleng-1] = '\0';
344                         unput(',');
345                         return word;
346                 }
347         }
348
349 <argg>{NOARGG}[\]\}]    {
350                 char c = yytext[yyleng-1];
351                 if ( pbcpop(c) ) { /* error */
352                         STORE_LOC;
353                         ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n", my_file, my_lineno, my_col, c);
354                         BEGIN(0);
355                         yylval->str = strdup(yytext);
356                         return word;
357                 }
358                 yymore();
359         }
360
361         /*
362          * context used to find tokens in the right hand side of assignments,
363          * or in the first and second operand of a 'for'. As above, match
364          * commas and use ';' as a separator (hence return it as a separate token).
365          */
366 <semic>{NOSEMIC}[\(\[\{]        {
367                 char c = yytext[yyleng-1];
368                 yymore();
369                 pbcpush(c);
370         }
371
372 <semic>{NOSEMIC}[\)\]\}]        {
373                 char c = yytext[yyleng-1];
374                 if ( pbcpop(c) ) { /* error */
375                         STORE_LOC;
376                         ast_log(LOG_ERROR,"File=%s, line=%d, column=%d: Mismatched '%c' in expression!\n", my_file, my_lineno, my_col, c);
377                         BEGIN(0);
378                         yylval->str = strdup(yytext);
379                         return word;
380                 }
381                 yymore();
382         }
383
384 <semic>{NOSEMIC};       {
385                 STORE_LOC;
386                 yylval->str = strdup(yytext);
387                 yylval->str[yyleng-1] = '\0';
388                 unput(';');
389                 BEGIN(0);
390                 return word;
391         }
392
393 \#include[ \t]+\"[^\"]+\" {
394                 char fnamebuf[1024],*p1,*p2;
395                 int glob_ret;
396                 glob_t globbuf;        /* the current globbuf */
397                 int globbuf_pos = -1;   /* where we are in the current globbuf */
398                 globbuf.gl_offs = 0;    /* initialize it to silence gcc */
399                 
400                 p1 = strchr(yytext,'"');
401                 p2 = strrchr(yytext,'"');
402                 if ( include_stack_index >= MAX_INCLUDE_DEPTH ) {
403                         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);
404                 } else if ( (int)(p2-p1) > sizeof(fnamebuf) - 1 ) {
405                         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);
406                 } else {
407                         strncpy(fnamebuf, p1+1, p2-p1-1);
408                         fnamebuf[p2-p1-1] = 0;
409                 if (fnamebuf[0] != '/') {
410                    char fnamebuf2[1024];
411                    snprintf(fnamebuf2,sizeof(fnamebuf2), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, fnamebuf);
412                    ast_copy_string(fnamebuf,fnamebuf2,sizeof(fnamebuf));
413                 }
414 #ifdef SOLARIS
415                         glob_ret = glob(fnamebuf, GLOB_NOCHECK, NULL, &globbuf);
416 #else
417                         glob_ret = glob(fnamebuf, GLOB_NOMAGIC|GLOB_BRACE, NULL, &globbuf);
418 #endif
419                         if (glob_ret == GLOB_NOSPACE) {
420                                 ast_log(LOG_WARNING,
421                                         "Glob Expansion of pattern '%s' failed: Not enough memory\n", fnamebuf);
422                         } else if (glob_ret  == GLOB_ABORTED) {
423                                 ast_log(LOG_WARNING,
424                                         "Glob Expansion of pattern '%s' failed: Read error\n", fnamebuf);
425                         } else if (glob_ret  == GLOB_NOMATCH) {
426                                 ast_log(LOG_WARNING,
427                                         "Glob Expansion of pattern '%s' failed: No matches!\n", fnamebuf);
428                         } else {
429                           globbuf_pos = 0;
430                         }
431                 }
432                 if (globbuf_pos > -1) {
433                         setup_filestack(fnamebuf, sizeof(fnamebuf), &globbuf, 0, yyscanner, 1);
434                 }
435         }
436
437
438 <<EOF>>         {
439                 char fnamebuf[2048];
440                 if (include_stack_index > 0 && include_stack[include_stack_index-1].globbuf_pos < include_stack[include_stack_index-1].globbuf.gl_pathc-1) {
441                         free(my_file);
442                         my_file = 0;
443                         yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner );
444                         include_stack[include_stack_index-1].globbuf_pos++;
445                         setup_filestack(fnamebuf, sizeof(fnamebuf), &include_stack[include_stack_index-1].globbuf, include_stack[include_stack_index-1].globbuf_pos, yyscanner, 0);
446                         /* finish this */                       
447                         
448                 } else {
449                         if (include_stack[include_stack_index].fname) {
450                                 free(include_stack[include_stack_index].fname);
451                                 include_stack[include_stack_index].fname = 0;
452                         }
453                         if ( --include_stack_index < 0 ) {
454                                 yyterminate();
455                         } else {
456                                 if (my_file) {
457                                         free(my_file);
458                                         my_file = 0;
459                                 }
460                                 globfree(&include_stack[include_stack_index].globbuf);
461                                 include_stack[include_stack_index].globbuf_pos = -1;
462                                 
463                                 yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner );
464                                 yy_switch_to_buffer(include_stack[include_stack_index].bufstate, yyscanner );
465                                 my_lineno = include_stack[include_stack_index].lineno;
466                                 my_col    = include_stack[include_stack_index].colno;
467                                 my_file   = strdup(include_stack[include_stack_index].fname);
468                         }
469                 }
470         }
471
472 %%
473
474 static void pbcpush(char x)
475 {
476         pbcstack[pbcpos++] = x;
477 }
478
479 static int pbcpop(char x)
480 {
481         if (   ( x == ')' && pbcstack[pbcpos-1] == '(' )
482                 || ( x == ']' && pbcstack[pbcpos-1] == '[' )
483                 || ( x == '}' && pbcstack[pbcpos-1] == '{' )) {
484                 pbcpos--;
485                 return 0;
486         }
487         return 1; /* error */
488 }
489
490 static int c_prevword(void)
491 {
492         char *c = prev_word;
493         if (c == NULL)
494                 return 0;
495         while ( *c ) {
496                 switch (*c) {
497                 case '{':
498                 case '[':
499                 case '(':
500                         pbcpush(*c);
501                         break;
502                 case '}':
503                 case ']':
504                 case ')':
505                         if (pbcpop(*c))
506                                 return 1;
507                         break;
508                 }
509                 c++;
510         }
511         return 0;
512 }
513
514
515 /*
516  * The following three functions, reset_*, are used in the bison
517  * code to switch context. As a consequence, we need to
518  * declare them global and add a prototype so that the
519  * compiler does not complain.
520  *
521  * NOTE: yyg is declared because it is used in the BEGIN macros,
522  * though that should be hidden as the macro changes
523  * depending on the flex options that we use - in particular,
524  * %reentrant changes the way the macro is declared;
525  * without %reentrant, BEGIN uses yystart instead of yyg
526  */
527
528 void reset_parencount(yyscan_t yyscanner );
529 void reset_parencount(yyscan_t yyscanner )
530 {
531         struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
532         parencount = 0;
533         pbcpos = 0;
534         pbcpush('(');   /* push '(' so the last pcbpop (parencount= -1) will succeed */
535         c_prevword();
536         BEGIN(paren);
537 }
538
539 void reset_semicount(yyscan_t yyscanner );
540 void reset_semicount(yyscan_t yyscanner )
541 {
542         struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
543         pbcpos = 0;
544         BEGIN(semic);
545 }
546
547 void reset_argcount(yyscan_t yyscanner );
548 void reset_argcount(yyscan_t yyscanner )
549 {
550         struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
551         parencount = 0;
552         pbcpos = 0;
553         pbcpush('(');   /* push '(' so the last pcbpop (parencount= -1) will succeed */
554         c_prevword();
555         BEGIN(argg);
556 }
557
558 /* used elsewhere, but some local vars */
559 struct pval *ael2_parse(char *filename, int *errors)
560 {
561         struct pval *pval;
562         struct parse_io *io;
563         char *buffer;
564         struct stat stats;
565         FILE *fin;
566
567         /* extern int ael_yydebug; */
568
569         io = calloc(sizeof(struct parse_io),1);
570         /* reset the global counters */
571         prev_word = 0;
572         my_lineno = 1;
573         include_stack_index=0;
574         my_col = 0;
575         /* ael_yydebug = 1; */
576         ael_yylex_init(&io->scanner);
577         fin = fopen(filename,"r");
578         if ( !fin ) {
579                 ast_log(LOG_ERROR,"File %s could not be opened\n", filename);
580                 *errors = 1;
581                 return 0;
582         }
583         if (my_file)
584                 free(my_file);
585         my_file = strdup(filename);
586         stat(filename, &stats);
587         buffer = (char*)malloc(stats.st_size+2);
588         fread(buffer, 1, stats.st_size, fin);
589         buffer[stats.st_size]=0;
590         fclose(fin);
591
592         ael_yy_scan_string (buffer ,io->scanner);
593         ael_yyset_lineno(1 , io->scanner);
594
595         /* ael_yyset_in (fin , io->scanner);    OLD WAY */
596
597         ael_yyparse(io);
598
599
600         pval = io->pval;
601         *errors = io->syntax_error_count;
602
603         ael_yylex_destroy(io->scanner);
604         free(buffer);
605         free(io);
606
607         return pval;
608 }
609
610 static void setup_filestack(char *fnamebuf2, int fnamebuf_siz, glob_t *globbuf, int globpos, yyscan_t yyscanner, int create)
611 {
612         struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
613         int error, i;
614         FILE *in1;
615         char fnamebuf[2048];
616
617         if (globbuf && globbuf->gl_pathv && globbuf->gl_pathc > 0)
618 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
619                         strncpy(fnamebuf, globbuf->gl_pathv[globpos], fnamebuf_siz);
620 #else
621                         ast_copy_string(fnamebuf, globbuf->gl_pathv[globpos], fnamebuf_siz);
622 #endif
623         else {
624                 ast_log(LOG_ERROR,"Include file name not present!\n");
625                 return;
626         }
627         for (i=0; i<include_stack_index; i++) {
628                 if ( !strcmp(fnamebuf,include_stack[i].fname )) {
629                         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",
630                                 my_file, my_lineno, my_col, fnamebuf);
631                         break;
632                 }
633         }
634         error = 1;
635         if (i == include_stack_index)
636                 error = 0;      /* we can use this file */
637         if ( !error ) { /* valid file name */
638                 /* relative vs. absolute */
639                 if (fnamebuf[0] != '/')
640                         snprintf(fnamebuf2, fnamebuf_siz, "%s/%s", ast_config_AST_CONFIG_DIR, fnamebuf);
641                 else
642 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
643                         strncpy(fnamebuf2, fnamebuf, fnamebuf_siz);
644 #else
645                         ast_copy_string(fnamebuf2, fnamebuf, fnamebuf_siz);
646 #endif
647                 in1 = fopen( fnamebuf2, "r" );
648
649                 if ( ! in1 ) {
650                         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);
651                 } else {
652                         char *buffer;
653                         struct stat stats;
654                         stat(fnamebuf2, &stats);
655                         buffer = (char*)malloc(stats.st_size+1);
656                         fread(buffer, 1, stats.st_size, in1);
657                         buffer[stats.st_size] = 0;
658                         ast_log(LOG_NOTICE,"  --Read in included file %s, %d chars\n",fnamebuf2, (int)stats.st_size);
659                         fclose(in1);
660                         if (my_file)
661                                 free(my_file);
662                         my_file = strdup(fnamebuf2);
663                         include_stack[include_stack_index].fname = strdup(my_file);
664                         include_stack[include_stack_index].lineno = my_lineno;
665                         include_stack[include_stack_index].colno = my_col+yyleng;
666                         if (create)
667                                 include_stack[include_stack_index].globbuf = *globbuf;
668
669                         include_stack[include_stack_index].globbuf_pos = 0;
670
671                         include_stack[include_stack_index].bufstate = YY_CURRENT_BUFFER;
672                         if (create)
673                                 include_stack_index++;
674                         yy_switch_to_buffer(ael_yy_scan_string (buffer ,yyscanner),yyscanner);
675                         free(buffer);
676                         my_lineno = 1;
677                         my_col = 1;
678                         BEGIN(INITIAL);
679                 }
680         }
681 }