3 * Asterisk -- An open source telephony toolkit.
5 * Copyright (C) 1999 - 2006, Digium, Inc.
7 * Mark Spencer <markster@digium.com>
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.
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.
22 * \brief Dialplan Expression Lexical Scanner
25 #include <sys/types.h>
28 #if !defined(STANDALONE)
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32 #define __USE_ISOC99 1
37 #define FP___PRINTF "%.18Lg"
38 #define FP___FMOD fmodl
39 #define FP___STRTOD strtold
40 #define FP___TYPE long double
42 #define FP___PRINTF "%.16g"
43 #define FP___FMOD fmod
44 #define FP___STRTOD strtod
45 #define FP___TYPE double
52 #if !defined(SOLARIS) && !defined(__CYGWIN__)
53 /* #include <err.h> */
55 #define quad_t int64_t
61 #include "asterisk/ast_expr.h"
62 #include "asterisk/logger.h"
64 #include "asterisk/strings.h"
65 #include "asterisk/channel.h"
68 /*!\note The latest Flex uses fwrite without checking its return value, which
69 * is a warning on some compilers. Therefore, we use this workaround, to trick
70 * the compiler into suppressing this warning. */
71 #define fwrite(a,b,c,d) do { int __res = fwrite(a,b,c,d); (__res); } while (0)
74 AST_EXPR_number, AST_EXPR_numeric_string, AST_EXPR_string
81 FP___TYPE i; /* long double or just double if it's a bad day */
85 #include "ast_expr2.h" /* the o/p of the bison on ast_expr2.y */
87 #define SET_COLUMNS do { \
88 yylloc_param->first_column = (int)(yyg->yytext_r - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); \
89 yylloc_param->last_column += yyleng - 1; \
90 yylloc_param->first_line = yylloc_param->last_line = 1; \
93 #define SET_STRING do { \
94 yylval_param->val = calloc(1, sizeof(struct val)); \
95 yylval_param->val->type = AST_EXPR_string; \
96 yylval_param->val->u.s = strdup(yytext); \
99 #define SET_NUMERIC_STRING do { \
100 yylval_param->val = calloc(1, sizeof(struct val)); \
101 yylval_param->val->type = AST_EXPR_numeric_string; \
102 yylval_param->val->u.s = strdup(yytext); \
110 struct ast_channel *chan;
113 void ast_yyset_column(int column_no, yyscan_t yyscanner);
114 int ast_yyget_column(yyscan_t yyscanner);
115 static int curlycount = 0;
116 static char *expr2_token_subst(const char *mess);
119 %option prefix="ast_yy"
122 %option outfile="ast_expr2f.c"
125 %option bison-locations
132 \| { SET_COLUMNS; SET_STRING; return TOK_OR;}
133 \& { SET_COLUMNS; SET_STRING; return TOK_AND;}
134 \= { SET_COLUMNS; SET_STRING; return TOK_EQ;}
135 \|\| { SET_COLUMNS; SET_STRING; return TOK_OR;}
136 \&\& { SET_COLUMNS; SET_STRING; return TOK_AND;}
137 \=\= { SET_COLUMNS; SET_STRING; return TOK_EQ;}
138 \=~ { SET_COLUMNS; SET_STRING; return TOK_EQTILDE;}
139 \~~ { SET_COLUMNS; SET_STRING; return TOK_TILDETILDE;}
140 \> { SET_COLUMNS; SET_STRING; return TOK_GT;}
141 \< { SET_COLUMNS; SET_STRING; return TOK_LT;}
142 \>\= { SET_COLUMNS; SET_STRING; return TOK_GE;}
143 \<\= { SET_COLUMNS; SET_STRING; return TOK_LE;}
144 \!\= { SET_COLUMNS; SET_STRING; return TOK_NE;}
145 \+ { SET_COLUMNS; SET_STRING; return TOK_PLUS;}
146 \, { SET_COLUMNS; SET_STRING; return TOK_COMMA;}
147 \- { SET_COLUMNS; SET_STRING; return TOK_MINUS;}
148 \* { SET_COLUMNS; SET_STRING; return TOK_MULT;}
149 \/ { SET_COLUMNS; SET_STRING; return TOK_DIV;}
150 \% { SET_COLUMNS; SET_STRING; return TOK_MOD;}
151 \? { SET_COLUMNS; SET_STRING; return TOK_COND;}
152 \! { SET_COLUMNS; SET_STRING; return TOK_COMPL;}
153 \: { SET_COLUMNS; SET_STRING; return TOK_COLON;}
154 \:\: { SET_COLUMNS; SET_STRING; return TOK_COLONCOLON;}
155 \( { SET_COLUMNS; SET_STRING; return TOK_LP;}
156 \) { SET_COLUMNS; SET_STRING; return TOK_RP;}
158 /* gather the contents of ${} expressions, with trailing stuff,
159 * into a single TOKEN.
160 * They are much more complex now than they used to be
168 \"[^"]*\" {SET_COLUMNS; SET_STRING; return TOKEN;}
170 [\n] {/* what to do with eol */}
173 /* the original behavior of the expression parser was
174 * to bring in numbers as a numeric string
180 ([a-zA-Z0-9\.';\\_^#@]|[\x80-\xff]|($[^{]))+ {
186 ([a-zA-Z0-9\.';\\_^#@]|[\x80-\xff]|($[^{]))+\$\{ {
194 if (curlycount < 0) {
208 <trail>[^-\t\r \n$():?%/+=*<>!|&]* {
215 <trail>[^-\t\r \n$():?%/+=*<>!|&]*\$\{ {
221 <trail>[-\t\r \n$():?%/+=*<>!|&] {
222 char c = yytext[yyleng-1];
235 /*actually, if an expr is only a variable ref, this could happen a LOT */
240 /* I'm putting the interface routine to the whole parse here in the flexer input file
241 mainly because of all the flexer initialization that has to be done. Shouldn't matter
242 where it is, as long as it's somewhere. I didn't want to define a prototype for the
243 ast_yy_scan_string in the .y file, because then, I'd have to define YY_BUFFER_STATE there...
244 UGH! that would be inappropriate. */
246 int ast_yyparse(void *); /* need to/should define this prototype for the call to yyparse */
247 int ast_yyerror(const char *, YYLTYPE *, struct parse_io *); /* likewise */
249 void ast_yyfree(void *ptr, yyscan_t yyscanner)
251 /* the normal generated yyfree func just frees its first arg;
252 this get complaints on some systems, as sometimes this
253 arg is a nil ptr! It's usually not fatal, but is irritating! */
254 free( (char *) ptr );
257 int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
259 struct parse_io io = { .string = expr, .chan = chan };
260 int return_value = 0;
262 ast_yylex_init(&io.scanner);
264 ast_yy_scan_string(expr, io.scanner);
266 ast_yyparse ((void *) &io);
268 ast_yylex_destroy(io.scanner);
276 if (io.val->type == AST_EXPR_number) {
279 res_length = snprintf(buf, length, FP___PRINTF, io.val->u.i);
280 return_value = (res_length <= length) ? res_length : length;
283 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE)
284 strncpy(buf, io.val->u.s, length - 1);
285 #else /* !STANDALONE && !LOW_MEMORY */
286 ast_copy_string(buf, io.val->u.s, length);
287 #endif /* STANDALONE || LOW_MEMORY */
290 return_value = strlen(buf);
299 int ast_str_expr(struct ast_str **str, ssize_t maxlen, struct ast_channel *chan, char *expr)
301 struct parse_io io = { .string = expr, .chan = chan };
303 ast_yylex_init(&io.scanner);
304 ast_yy_scan_string(expr, io.scanner);
305 ast_yyparse ((void *) &io);
306 ast_yylex_destroy(io.scanner);
309 ast_str_set(str, maxlen, "0");
311 if (io.val->type == AST_EXPR_number) {
313 ast_str_set(str, maxlen, FP___PRINTF, io.val->u.i);
314 } else if (io.val->u.s) {
315 ast_str_set(str, maxlen, "%s", io.val->u.s);
320 return ast_str_strlen(*str);
325 char extra_error_message[4095];
326 int extra_error_message_supplied = 0;
327 void ast_expr_register_extra_error_info(char *message);
328 void ast_expr_clear_extra_error_info(void);
330 void ast_expr_register_extra_error_info(char *message)
332 extra_error_message_supplied=1;
333 strcpy(extra_error_message, message);
336 void ast_expr_clear_extra_error_info(void)
338 extra_error_message_supplied=0;
339 extra_error_message[0] = 0;
342 static const char * const expr2_token_equivs1[] =
368 static const char * const expr2_token_equivs2[] =
395 static char *expr2_token_subst(const char *mess)
397 /* calc a length, malloc, fill, and return; yyerror had better free it! */
402 int expr2_token_equivs_entries = sizeof(expr2_token_equivs1)/sizeof(char*);
404 for (p=mess; *p; p++) {
405 for (i=0; i<expr2_token_equivs_entries; i++) {
406 if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 )
408 len+=strlen(expr2_token_equivs2[i])+2;
409 p += strlen(expr2_token_equivs1[i])-1;
415 res = (char*)malloc(len+1);
420 for (i=0; i<expr2_token_equivs_entries; i++) {
421 if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 ) {
423 for (t=expr2_token_equivs2[i]; *t;) {
427 p += strlen(expr2_token_equivs1[i]);
439 int ast_yyerror (const char *s, yyltype *loc, struct parse_io *parseio )
441 struct yyguts_t * yyg = (struct yyguts_t*)(parseio->scanner);
442 char spacebuf[8000]; /* best safe than sorry */
443 char spacebuf2[8000]; /* best safe than sorry */
445 char *s2 = expr2_token_subst(s);
448 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,
449 which is the same thing as... get this:
450 yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]->yy_bs_column
451 I was tempted to just use yy_buf_pos in the STATE, but..., well:
452 a. the yy_buf_pos is the current position in the buffer, which
453 may not relate to the entire string/buffer because of the
455 b. but, analysis of the situation is that when you use the
456 yy_scan_string func, it creates a single buffer the size of
457 string, so the two would be the same...
458 so, in the end, the yycolumn macro is available, shorter, therefore easier. */
463 /* easier to read in the standalone version */
464 printf("ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",
465 (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
467 ast_log(LOG_WARNING,"ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",
468 (extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
471 ast_log(LOG_WARNING,"If you have questions, please refer to doc/tex/channelvariables.tex.\n");