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