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