Let's also include aclocal.m4
[asterisk-bristuff.git] / main / ast_expr2.fl
blob67dd3aa6a9d4dba6fb161e0ccbcf2335df63f796
1 %{
2 /*
3  * Asterisk -- An open source telephony toolkit.
4  *
5  * Copyright (C) 1999 - 2006, Digium, Inc.
6  *
7  * Mark Spencer <markster@digium.com>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
20 /*! \file
21  *
22  * \brief Dialplan Expression Lexical Scanner
23  */
25 #include "asterisk.h"
27 #if !defined(STANDALONE_AEL)
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29 #endif
31 #include <sys/types.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <locale.h>
36 #include <ctype.h>
37 #if !defined(SOLARIS) && !defined(__CYGWIN__)
38 /* #include <err.h> */
39 #else
40 #define quad_t int64_t
41 #endif
42 #include <errno.h>
43 #include <regex.h>
44 #include <limits.h>
46 #include "asterisk/ast_expr.h"
47 #include "asterisk/logger.h"
48 #include "asterisk/strings.h"
50 enum valtype {
51         AST_EXPR_integer, AST_EXPR_numeric_string, AST_EXPR_string
52 } ;
54 struct val {
55         enum valtype type;
56         union {
57                 char *s;
58                 quad_t i;
59         } u;
60 } ;
62 #include "ast_expr2.h" /* the o/p of the bison on ast_expr2.y */
64 #define SET_COLUMNS     do {            \
65         yylloc_param->first_column = (int)(yyg->yytext_r - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); \
66         yylloc_param->last_column += yyleng - 1; \
67         yylloc_param->first_line = yylloc_param->last_line = 1; \
68         } while (0)
70 #define SET_STRING      do {            \
71         yylval_param->val = calloc(1, sizeof(struct val));      \
72         yylval_param->val->type = AST_EXPR_string;              \
73         yylval_param->val->u.s = strdup(yytext);                \
74         } while (0)
76 #define SET_NUMERIC_STRING      do {    \
77         yylval_param->val = calloc(1, sizeof(struct val));      \
78         yylval_param->val->type = AST_EXPR_numeric_string;      \
79         yylval_param->val->u.s = strdup(yytext);        \
80         } while (0)
82 struct parse_io
84         char *string;
85         struct val *val;
86         yyscan_t scanner;
89 void ast_yyset_column(int column_no, yyscan_t yyscanner);
90 int ast_yyget_column(yyscan_t yyscanner);
91 static int curlycount = 0;
92 static char *expr2_token_subst(const char *mess);
95 %option prefix="ast_yy"
96 %option batch
97 %option outfile="ast_expr2f.c"
98 %option reentrant
99 %option bison-bridge
100 %option bison-locations
101 %option noyywrap
102 %option noyyfree
103 %x var trail
107 \|      { SET_COLUMNS; SET_STRING; return TOK_OR;}
108 \&      { SET_COLUMNS; SET_STRING; return TOK_AND;}
109 \=      { SET_COLUMNS; SET_STRING; return TOK_EQ;}
110 \|\|    { SET_COLUMNS; SET_STRING; return TOK_OR;}
111 \&\&    { SET_COLUMNS; SET_STRING; return TOK_AND;}
112 \=\=    { SET_COLUMNS; SET_STRING; return TOK_EQ;}
113 \=~     { SET_COLUMNS; SET_STRING; return TOK_EQTILDE;}
114 \>      { SET_COLUMNS; SET_STRING; return TOK_GT;}
115 \<      { SET_COLUMNS; SET_STRING; return TOK_LT;}
116 \>\=    { SET_COLUMNS; SET_STRING; return TOK_GE;}
117 \<\=    { SET_COLUMNS; SET_STRING; return TOK_LE;}
118 \!\=    { SET_COLUMNS; SET_STRING; return TOK_NE;}
119 \+      { SET_COLUMNS; SET_STRING; return TOK_PLUS;}
120 \-      { SET_COLUMNS; SET_STRING; return TOK_MINUS;}
121 \*      { SET_COLUMNS; SET_STRING; return TOK_MULT;}
122 \/      { SET_COLUMNS; SET_STRING; return TOK_DIV;}
123 \%      { SET_COLUMNS; SET_STRING; return TOK_MOD;}
124 \?      { SET_COLUMNS; SET_STRING; return TOK_COND;}
125 \!      { SET_COLUMNS; SET_STRING; return TOK_COMPL;}
126 \:      { SET_COLUMNS; SET_STRING; return TOK_COLON;}
127 \:\:    { SET_COLUMNS; SET_STRING; return TOK_COLONCOLON;}
128 \(      { SET_COLUMNS; SET_STRING; return TOK_LP;}
129 \)      { SET_COLUMNS; SET_STRING; return TOK_RP;}
130 \$\{    {
131                 /* gather the contents of ${} expressions, with trailing stuff,
132                  * into a single TOKEN.
133                  * They are much more complex now than they used to be
134                  */
135                 curlycount = 0;
136                 BEGIN(var);
137                 yymore();
138         }
140 [ \t\r]         {}
141 \"[^"]*\"       {SET_COLUMNS; SET_STRING; return TOKEN;}
143 [\n]            {/* what to do with eol */}
144 [0-9]+          {
145                 SET_COLUMNS;
146                 /* the original behavior of the expression parser was
147                  * to bring in numbers as a numeric string
148                  */
149                 SET_NUMERIC_STRING;
150                 return TOKEN;
151         }
153 [a-zA-Z0-9,.';\\_^$#@]+ {
154                 SET_COLUMNS;
155                 SET_STRING;
156                 return TOKEN;
157         }
160 <var>[^{}]*\}   {
161                 curlycount--;
162                 if (curlycount < 0) {
163                         BEGIN(trail);
164                         yymore();
165                 } else {
166                         yymore();
167                 }
168         }
169         
170 <var>[^{}]*\{   {
171                 curlycount++;
172                 yymore();
173         }
174         
176 <trail>[^-\t\r \n$():?%/+=*<>!|&]*      {
177                 BEGIN(0);
178                 SET_COLUMNS;
179                 SET_STRING;
180                 return TOKEN;
181         }
182         
183 <trail>[-\t\r \n$():?%/+=*<>!|&]        {
184                 char c = yytext[yyleng-1];
185                 BEGIN(0);
186                 unput(c);
187                 SET_COLUMNS;
188                 SET_STRING;
189                 return TOKEN;
190         }
191         
192 <trail>\$\{     {
193                 curlycount = 0;
194                 BEGIN(var);
195                 yymore();
196         }
197         
198 <trail><<EOF>>  {
199                 BEGIN(0);
200                 SET_COLUMNS;
201                 SET_STRING;
202                 return TOKEN;
203                 /*actually, if an expr is only a variable ref, this could happen a LOT */
204         }
208 /* I'm putting the interface routine to the whole parse here in the flexer input file
209    mainly because of all the flexer initialization that has to be done. Shouldn't matter
210    where it is, as long as it's somewhere. I didn't want to define a prototype for the
211    ast_yy_scan_string in the .y file, because then, I'd have to define YY_BUFFER_STATE there...
212         UGH! that would be inappropriate. */
214 int ast_yyparse(void *); /* need to/should define this prototype for the call to yyparse */
215 int ast_yyerror(const char *, YYLTYPE *, struct parse_io *); /* likewise */
217 void ast_yyfree(void *ptr, yyscan_t yyscanner)
219       if (ptr) /* the normal generated yyfree func just frees its first arg;
220                     this get complaints on some systems, as sometimes this
221                     arg is a nil ptr! It's usually not fatal, but is irritating! */
222               free( (char *) ptr );
225 int ast_expr(char *expr, char *buf, int length)
227         struct parse_io io;
228         int return_value = 0;
229         
230         memset(&io, 0, sizeof(io));
231         io.string = expr;  /* to pass to the error routine */
232         
233         ast_yylex_init(&io.scanner);
234         
235         ast_yy_scan_string(expr, io.scanner);
236         
237         ast_yyparse ((void *) &io);
239         ast_yylex_destroy(io.scanner);
241         if (!io.val) {
242                 if (length > 1) {
243                         strcpy(buf, "0");
244                         return_value = 1;
245                 }
246         } else {
247                 if (io.val->type == AST_EXPR_integer) {
248                         int res_length;
250                         res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i);
251                         return_value = (res_length <= length) ? res_length : length;
252                 } else {
253 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
254                         strncpy(buf, io.val->u.s, length - 1);
255 #else /* !STANDALONE && !LOW_MEMORY */
256                         ast_copy_string(buf, io.val->u.s, length);
257 #endif /* STANDALONE || LOW_MEMORY */
258                         return_value = strlen(buf);
259                         free(io.val->u.s);
260                 }
261                 free(io.val);
262         }
263         return return_value;
267 char extra_error_message[4095];
268 int extra_error_message_supplied = 0;
269 void  ast_expr_register_extra_error_info(char *message);
270 void  ast_expr_clear_extra_error_info(void);
272 void  ast_expr_register_extra_error_info(char *message)
274        extra_error_message_supplied=1;
275        strcpy(extra_error_message, message);
278 void  ast_expr_clear_extra_error_info(void)
280        extra_error_message_supplied=0;
281        extra_error_message[0] = 0;
284 static char *expr2_token_equivs1[] = 
286         "TOKEN",
287         "TOK_COND",
288         "TOK_COLONCOLON",
289         "TOK_OR",
290         "TOK_AND",
291         "TOK_EQ",
292         "TOK_GT",
293         "TOK_LT",
294         "TOK_GE",
295         "TOK_LE",
296         "TOK_NE",
297         "TOK_PLUS",
298         "TOK_MINUS",
299         "TOK_MULT",
300         "TOK_DIV",
301         "TOK_MOD",
302         "TOK_COMPL",
303         "TOK_COLON",
304         "TOK_EQTILDE",
305         "TOK_RP",
306         "TOK_LP"
309 static char *expr2_token_equivs2[] = 
311         "<token>",
312         "?",
313         "::",
314         "|",
315         "&",
316         "=",
317         ">",
318         "<",
319         ">=",
320         "<=",
321         "!=",
322         "+",
323         "-",
324         "*",
325         "/",
326         "%",
327         "!",
328         ":",
329         "=~",
330         ")",
331         "("
335 static char *expr2_token_subst(const char *mess)
337         /* calc a length, malloc, fill, and return; yyerror had better free it! */
338         int len=0,i;
339         const char *p;
340         char *res, *s,*t;
341         int expr2_token_equivs_entries = sizeof(expr2_token_equivs1)/sizeof(char*);
343         for (p=mess; *p; p++) {
344                 for (i=0; i<expr2_token_equivs_entries; i++) {
345                         if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 )
346                         {
347                                 len+=strlen(expr2_token_equivs2[i])+2;
348                                 p += strlen(expr2_token_equivs1[i])-1;
349                                 break;
350                         }
351                 }
352                 len++;
353         }
354         res = (char*)malloc(len+1);
355         res[0] = 0;
356         s = res;
357         for (p=mess; *p;) {
358                 int found = 0;
359                 for (i=0; i<expr2_token_equivs_entries; i++) {
360                         if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 ) {
361                                 *s++ = '\'';
362                                 for (t=expr2_token_equivs2[i]; *t;) {
363                                         *s++ = *t++;
364                                 }
365                                 *s++ = '\'';
366                                 p += strlen(expr2_token_equivs1[i]);
367                                 found = 1;
368                                 break;
369                         }
370                 }
371                 if( !found )
372                         *s++ = *p++;
373         }
374         *s++ = 0;
375         return res;
378 int ast_yyerror (const char *s,  yyltype *loc, struct parse_io *parseio )
379 {       
380         struct yyguts_t * yyg = (struct yyguts_t*)(parseio->scanner);
381         char spacebuf[8000]; /* best safe than sorry */
382         char spacebuf2[8000]; /* best safe than sorry */
383         int i=0;
384         char *s2 = expr2_token_subst(s);
385         spacebuf[0] = 0;
386         
387         for(i=0;i< (int)(yytext - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf);i++) spacebuf2[i] = ' ';  /* uh... assuming yyg is defined, then I can use the yycolumn macro,
388                                                                                                                                                                                                 which is the same thing as... get this:
389                                                                                                         yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]->yy_bs_column
390                                                                                                         I was tempted to just use yy_buf_pos in the STATE, but..., well:
391                                                                                                                 a. the yy_buf_pos is the current position in the buffer, which
392                                                                                                                         may not relate to the entire string/buffer because of the
393                                                                                                                         buffering.
394                                                                                                                 b. but, analysis of the situation is that when you use the
395                                                                                                                         yy_scan_string func, it creates a single buffer the size of
396                                                                                                                         string, so the two would be the same... 
397                                                                                                         so, in the end, the yycolumn macro is available, shorter, therefore easier. */
398         spacebuf2[i++]='^';
399         spacebuf2[i]= 0;
401 #ifdef STANDALONE3
402         /* easier to read in the standalone version */
403         printf("ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",  
404                         (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
405 #else
406         ast_log(LOG_WARNING,"ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",  
407                         (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
408 #endif
409 #ifndef STANDALONE
410         ast_log(LOG_WARNING,"If you have questions, please refer to doc/channelvariables.txt in the asterisk source.\n");
411 #endif
412         free(s2);
413         return(0);