simplify autoconfig include mechanism (make tholo happy he can use lint again :-)
[asterisk/asterisk.git] / ast_expr2.fl
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  */
19
20 /*! \file
21  *
22  * \brief Dialplan Expression Lexical Scanner
23  */
24
25 #include "asterisk.h"
26
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
28
29 #include <sys/types.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <locale.h>
34 #include <ctype.h>
35 #if !defined(SOLARIS) && !defined(__CYGWIN__)
36 #include <err.h>
37 #else
38 #define quad_t int64_t
39 #endif
40 #include <errno.h>
41 #include <regex.h>
42 #include <limits.h>
43
44 #include "asterisk/ast_expr.h"
45 #include "asterisk/logger.h"
46 #include "asterisk/strings.h"
47
48 enum valtype {
49         AST_EXPR_integer, AST_EXPR_numeric_string, AST_EXPR_string
50 } ;
51
52 struct val {
53         enum valtype type;
54         union {
55                 char *s;
56                 quad_t i;
57         } u;
58 } ;
59
60 #include "ast_expr2.h" /* the o/p of the bison on ast_expr2.y */
61
62 #define SET_COLUMNS     do {            \
63         yylloc_param->first_column = (int)(yyg->yytext_r - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); \
64         yylloc_param->last_column += yyleng - 1; \
65         yylloc_param->first_line = yylloc_param->last_line = 1; \
66         } while (0)
67
68 #define SET_STRING      do {            \
69         yylval_param->val = calloc(1, sizeof(struct val));      \
70         yylval_param->val->type = AST_EXPR_string;              \
71         yylval_param->val->u.s = strdup(yytext);                \
72         } while (0)
73
74 #define SET_NUMERIC_STRING      do {    \
75         yylval_param->val = calloc(1, sizeof(struct val));      \
76         yylval_param->val->type = AST_EXPR_numeric_string;      \
77         yylval_param->val->u.s = strdup(yytext);        \
78         } while (0)
79
80 struct parse_io
81 {
82         char *string;
83         struct val *val;
84         yyscan_t scanner;
85 };
86  
87 void ast_yyset_column(int column_no, yyscan_t yyscanner);
88 int ast_yyget_column(yyscan_t yyscanner);
89 static int curlycount = 0;
90 static char *expr2_token_subst(char *mess);
91 %}
92
93 %option prefix="ast_yy"
94 %option batch
95 %option outfile="ast_expr2f.c"
96 %option reentrant
97 %option bison-bridge
98 %option bison-locations
99 %option noyywrap
100 %x var trail
101
102 %%
103
104 \|      { SET_COLUMNS; SET_STRING; return TOK_OR;}
105 \&      { SET_COLUMNS; SET_STRING; return TOK_AND;}
106 \=      { SET_COLUMNS; SET_STRING; return TOK_EQ;}
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_EQTILDE;}
111 \>      { SET_COLUMNS; SET_STRING; return TOK_GT;}
112 \<      { SET_COLUMNS; SET_STRING; return TOK_LT;}
113 \>\=    { SET_COLUMNS; SET_STRING; return TOK_GE;}
114 \<\=    { SET_COLUMNS; SET_STRING; return TOK_LE;}
115 \!\=    { SET_COLUMNS; SET_STRING; return TOK_NE;}
116 \+      { SET_COLUMNS; SET_STRING; return TOK_PLUS;}
117 \-      { SET_COLUMNS; SET_STRING; return TOK_MINUS;}
118 \*      { SET_COLUMNS; SET_STRING; return TOK_MULT;}
119 \/      { SET_COLUMNS; SET_STRING; return TOK_DIV;}
120 \%      { SET_COLUMNS; SET_STRING; return TOK_MOD;}
121 \?      { SET_COLUMNS; SET_STRING; return TOK_COND;}
122 \!      { SET_COLUMNS; SET_STRING; return TOK_COMPL;}
123 \:      { SET_COLUMNS; SET_STRING; return TOK_COLON;}
124 \:\:    { SET_COLUMNS; SET_STRING; return TOK_COLONCOLON;}
125 \(      { SET_COLUMNS; SET_STRING; return TOK_LP;}
126 \)      { SET_COLUMNS; SET_STRING; return TOK_RP;}
127 \$\{    {
128                 /* gather the contents of ${} expressions, with trailing stuff,
129                  * into a single TOKEN.
130                  * They are much more complex now than they used to be
131                  */
132                 curlycount = 0;
133                 BEGIN(var);
134                 yymore();
135         }
136
137 [ \t\r]         {}
138 \"[^"]*\"       {SET_COLUMNS; SET_STRING; return TOKEN;}
139
140 [\n]            {/* what to do with eol */}
141 [0-9]+          {
142                 SET_COLUMNS;
143                 /* the original behavior of the expression parser was
144                  * to bring in numbers as a numeric string
145                  */
146                 SET_NUMERIC_STRING;
147                 return TOKEN;
148         }
149
150 [a-zA-Z0-9,.';\\_^$#@]+ {
151                 SET_COLUMNS;
152                 SET_STRING;
153                 return TOKEN;
154         }
155
156
157 <var>[^{}]*\}   {
158                 curlycount--;
159                 if (curlycount < 0) {
160                         BEGIN(trail);
161                         yymore();
162                 } else {
163                         yymore();
164                 }
165         }
166         
167 <var>[^{}]*\{   {
168                 curlycount++;
169                 yymore();
170         }
171         
172
173 <trail>[^-\t\r \n$():?%/+=*<>!|&]*      {
174                 BEGIN(0);
175                 SET_COLUMNS;
176                 SET_STRING;
177                 return TOKEN;
178         }
179         
180 <trail>[-\t\r \n$():?%/+=*<>!|&]        {
181                 char c = yytext[yyleng-1];
182                 BEGIN(0);
183                 unput(c);
184                 SET_COLUMNS;
185                 SET_STRING;
186                 return TOKEN;
187         }
188         
189 <trail>\$\{     {
190                 curlycount = 0;
191                 BEGIN(var);
192                 yymore();
193         }
194         
195 <trail><<EOF>>  {
196                 BEGIN(0);
197                 SET_COLUMNS;
198                 SET_STRING;
199                 return TOKEN;
200                 /*actually, if an expr is only a variable ref, this could happen a LOT */
201         }
202
203 %%
204
205 /* I'm putting the interface routine to the whole parse here in the flexer input file
206    mainly because of all the flexer initialization that has to be done. Shouldn't matter
207    where it is, as long as it's somewhere. I didn't want to define a prototype for the
208    ast_yy_scan_string in the .y file, because then, I'd have to define YY_BUFFER_STATE there...
209         UGH! that would be inappropriate. */
210
211 int ast_yyparse(void *); /* need to/should define this prototype for the call to yyparse */
212 int ast_yyerror(const char *, YYLTYPE *, struct parse_io *); /* likewise */
213
214 int ast_expr(char *expr, char *buf, int length)
215 {
216         struct parse_io io;
217         int return_value = 0;
218         
219         memset(&io, 0, sizeof(io));
220         io.string = expr;  /* to pass to the error routine */
221         
222         ast_yylex_init(&io.scanner);
223         
224         ast_yy_scan_string(expr, io.scanner);
225         
226         ast_yyparse ((void *) &io);
227
228         ast_yylex_destroy(io.scanner);
229
230         if (!io.val) {
231                 if (length > 1) {
232                         strcpy(buf, "0");
233                         return_value = 1;
234                 }
235         } else {
236                 if (io.val->type == AST_EXPR_integer) {
237                         int res_length;
238
239                         res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i);
240                         return_value = (res_length <= length) ? res_length : length;
241                 } else {
242 #ifdef STANDALONE
243                         strncpy(buf, io.val->u.s, length - 1);
244 #else /* !STANDALONE */
245                         ast_copy_string(buf, io.val->u.s, length);
246 #endif /* STANDALONE */
247                         return_value = strlen(buf);
248                         free(io.val->u.s);
249                 }
250                 free(io.val);
251         }
252         return return_value;
253 }
254
255
256 char extra_error_message[4095];
257 int extra_error_message_supplied = 0;
258 void  ast_expr_register_extra_error_info(char *message);
259 void  ast_expr_clear_extra_error_info(void);
260
261 void  ast_expr_register_extra_error_info(char *message)
262 {
263        extra_error_message_supplied=1;
264        strcpy(extra_error_message, message);
265 }
266
267 void  ast_expr_clear_extra_error_info(void)
268 {
269        extra_error_message_supplied=0;
270        extra_error_message[0] = 0;
271 }
272
273 static char *expr2_token_equivs1[] = 
274 {
275         "TOKEN",
276         "TOK_COND",
277         "TOK_COLONCOLON",
278         "TOK_OR",
279         "TOK_AND",
280         "TOK_EQ",
281         "TOK_GT",
282         "TOK_LT",
283         "TOK_GE",
284         "TOK_LE",
285         "TOK_NE",
286         "TOK_PLUS",
287         "TOK_MINUS",
288         "TOK_MULT",
289         "TOK_DIV",
290         "TOK_MOD",
291         "TOK_COMPL",
292         "TOK_COLON",
293         "TOK_EQTILDE",
294         "TOK_RP",
295         "TOK_LP"
296 };
297
298 static char *expr2_token_equivs2[] = 
299 {
300         "<token>",
301         "?",
302         "::",
303         "|",
304         "&",
305         "=",
306         ">",
307         "<",
308         ">=",
309         "<=",
310         "!=",
311         "+",
312         "-",
313         "*",
314         "/",
315         "%",
316         "!",
317         ":",
318         "=~",
319         ")",
320         "("
321 };
322
323
324 static char *expr2_token_subst(char *mess)
325 {
326         /* calc a length, malloc, fill, and return; yyerror had better free it! */
327         int len=0,i;
328         char *p;
329         char *res, *s,*t;
330         int expr2_token_equivs_entries = sizeof(expr2_token_equivs1)/sizeof(char*);
331
332         for (p=mess; *p; p++) {
333                 for (i=0; i<expr2_token_equivs_entries; i++) {
334                         if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 )
335                         {
336                                 len+=strlen(expr2_token_equivs2[i])+2;
337                                 p += strlen(expr2_token_equivs1[i])-1;
338                                 break;
339                         }
340                 }
341                 len++;
342         }
343         res = (char*)malloc(len+1);
344         res[0] = 0;
345         s = res;
346         for (p=mess; *p;) {
347                 int found = 0;
348                 for (i=0; i<expr2_token_equivs_entries; i++) {
349                         if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 ) {
350                                 *s++ = '\'';
351                                 for (t=expr2_token_equivs2[i]; *t;) {
352                                         *s++ = *t++;
353                                 }
354                                 *s++ = '\'';
355                                 p += strlen(expr2_token_equivs1[i]);
356                                 found = 1;
357                                 break;
358                         }
359                 }
360                 if( !found )
361                         *s++ = *p++;
362         }
363         *s++ = 0;
364         return res;
365 }
366
367 int ast_yyerror (const char *s,  yyltype *loc, struct parse_io *parseio )
368 {       
369         struct yyguts_t * yyg = (struct yyguts_t*)(parseio->scanner);
370         char spacebuf[8000]; /* best safe than sorry */
371         char spacebuf2[8000]; /* best safe than sorry */
372         int i=0;
373         char *s2 = expr2_token_subst((char *)s);
374         spacebuf[0] = 0;
375         
376         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,
377                                                                                                                                                                                                 which is the same thing as... get this:
378                                                                                                         yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]->yy_bs_column
379                                                                                                         I was tempted to just use yy_buf_pos in the STATE, but..., well:
380                                                                                                                 a. the yy_buf_pos is the current position in the buffer, which
381                                                                                                                         may not relate to the entire string/buffer because of the
382                                                                                                                         buffering.
383                                                                                                                 b. but, analysis of the situation is that when you use the
384                                                                                                                         yy_scan_string func, it creates a single buffer the size of
385                                                                                                                         string, so the two would be the same... 
386                                                                                                         so, in the end, the yycolumn macro is available, shorter, therefore easier. */
387         spacebuf2[i++]='^';
388         spacebuf2[i]= 0;
389
390 #ifdef STANDALONE3
391         /* easier to read in the standalone version */
392         printf("ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",  
393                         (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
394 #else
395         ast_log(LOG_WARNING,"ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",  
396                         (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
397 #endif
398 #ifndef STANDALONE
399         ast_log(LOG_WARNING,"If you have questions, please refer to doc/channelvariables.txt in the asterisk source.\n");
400 #endif
401         free(s2);
402         return(0);
403 }