mirror of
https://github.com/asterisk/asterisk.git
synced 2026-05-05 21:04:01 +00:00
merge new_loader_completion branch, including (at least):
- restructured build tree and makefiles to eliminate recursion problems - support for embedded modules - support for static builds - simpler cross-compilation support - simpler module/loader interface (no exported symbols) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@40722 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
405
main/ast_expr2.fl
Normal file
405
main/ast_expr2.fl
Normal file
@@ -0,0 +1,405 @@
|
||||
%{
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2006, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Dialplan Expression Lexical Scanner
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#ifndef STANDALONE
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
#include <ctype.h>
|
||||
#if !defined(SOLARIS) && !defined(__CYGWIN__)
|
||||
#include <err.h>
|
||||
#else
|
||||
#define quad_t int64_t
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <regex.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "asterisk/ast_expr.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/strings.h"
|
||||
|
||||
enum valtype {
|
||||
AST_EXPR_integer, AST_EXPR_numeric_string, AST_EXPR_string
|
||||
} ;
|
||||
|
||||
struct val {
|
||||
enum valtype type;
|
||||
union {
|
||||
char *s;
|
||||
quad_t i;
|
||||
} u;
|
||||
} ;
|
||||
|
||||
#include "ast_expr2.h" /* the o/p of the bison on ast_expr2.y */
|
||||
|
||||
#define SET_COLUMNS do { \
|
||||
yylloc_param->first_column = (int)(yyg->yytext_r - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); \
|
||||
yylloc_param->last_column += yyleng - 1; \
|
||||
yylloc_param->first_line = yylloc_param->last_line = 1; \
|
||||
} while (0)
|
||||
|
||||
#define SET_STRING do { \
|
||||
yylval_param->val = calloc(1, sizeof(struct val)); \
|
||||
yylval_param->val->type = AST_EXPR_string; \
|
||||
yylval_param->val->u.s = strdup(yytext); \
|
||||
} while (0)
|
||||
|
||||
#define SET_NUMERIC_STRING do { \
|
||||
yylval_param->val = calloc(1, sizeof(struct val)); \
|
||||
yylval_param->val->type = AST_EXPR_numeric_string; \
|
||||
yylval_param->val->u.s = strdup(yytext); \
|
||||
} while (0)
|
||||
|
||||
struct parse_io
|
||||
{
|
||||
char *string;
|
||||
struct val *val;
|
||||
yyscan_t scanner;
|
||||
};
|
||||
|
||||
void ast_yyset_column(int column_no, yyscan_t yyscanner);
|
||||
int ast_yyget_column(yyscan_t yyscanner);
|
||||
static int curlycount = 0;
|
||||
static char *expr2_token_subst(char *mess);
|
||||
%}
|
||||
|
||||
%option prefix="ast_yy"
|
||||
%option batch
|
||||
%option outfile="ast_expr2f.c"
|
||||
%option reentrant
|
||||
%option bison-bridge
|
||||
%option bison-locations
|
||||
%option noyywrap
|
||||
%x var trail
|
||||
|
||||
%%
|
||||
|
||||
\| { SET_COLUMNS; SET_STRING; return TOK_OR;}
|
||||
\& { SET_COLUMNS; SET_STRING; return TOK_AND;}
|
||||
\= { SET_COLUMNS; SET_STRING; return TOK_EQ;}
|
||||
\|\| { SET_COLUMNS; SET_STRING; return TOK_OR;}
|
||||
\&\& { SET_COLUMNS; SET_STRING; return TOK_AND;}
|
||||
\=\= { SET_COLUMNS; SET_STRING; return TOK_EQ;}
|
||||
\=~ { SET_COLUMNS; SET_STRING; return TOK_EQTILDE;}
|
||||
\> { SET_COLUMNS; SET_STRING; return TOK_GT;}
|
||||
\< { SET_COLUMNS; SET_STRING; return TOK_LT;}
|
||||
\>\= { SET_COLUMNS; SET_STRING; return TOK_GE;}
|
||||
\<\= { SET_COLUMNS; SET_STRING; return TOK_LE;}
|
||||
\!\= { SET_COLUMNS; SET_STRING; return TOK_NE;}
|
||||
\+ { SET_COLUMNS; SET_STRING; return TOK_PLUS;}
|
||||
\- { SET_COLUMNS; SET_STRING; return TOK_MINUS;}
|
||||
\* { SET_COLUMNS; SET_STRING; return TOK_MULT;}
|
||||
\/ { SET_COLUMNS; SET_STRING; return TOK_DIV;}
|
||||
\% { SET_COLUMNS; SET_STRING; return TOK_MOD;}
|
||||
\? { SET_COLUMNS; SET_STRING; return TOK_COND;}
|
||||
\! { SET_COLUMNS; SET_STRING; return TOK_COMPL;}
|
||||
\: { SET_COLUMNS; SET_STRING; return TOK_COLON;}
|
||||
\:\: { SET_COLUMNS; SET_STRING; return TOK_COLONCOLON;}
|
||||
\( { SET_COLUMNS; SET_STRING; return TOK_LP;}
|
||||
\) { SET_COLUMNS; SET_STRING; return TOK_RP;}
|
||||
\$\{ {
|
||||
/* gather the contents of ${} expressions, with trailing stuff,
|
||||
* into a single TOKEN.
|
||||
* They are much more complex now than they used to be
|
||||
*/
|
||||
curlycount = 0;
|
||||
BEGIN(var);
|
||||
yymore();
|
||||
}
|
||||
|
||||
[ \t\r] {}
|
||||
\"[^"]*\" {SET_COLUMNS; SET_STRING; return TOKEN;}
|
||||
|
||||
[\n] {/* what to do with eol */}
|
||||
[0-9]+ {
|
||||
SET_COLUMNS;
|
||||
/* the original behavior of the expression parser was
|
||||
* to bring in numbers as a numeric string
|
||||
*/
|
||||
SET_NUMERIC_STRING;
|
||||
return TOKEN;
|
||||
}
|
||||
|
||||
[a-zA-Z0-9,.';\\_^$#@]+ {
|
||||
SET_COLUMNS;
|
||||
SET_STRING;
|
||||
return TOKEN;
|
||||
}
|
||||
|
||||
|
||||
<var>[^{}]*\} {
|
||||
curlycount--;
|
||||
if (curlycount < 0) {
|
||||
BEGIN(trail);
|
||||
yymore();
|
||||
} else {
|
||||
yymore();
|
||||
}
|
||||
}
|
||||
|
||||
<var>[^{}]*\{ {
|
||||
curlycount++;
|
||||
yymore();
|
||||
}
|
||||
|
||||
|
||||
<trail>[^-\t\r \n$():?%/+=*<>!|&]* {
|
||||
BEGIN(0);
|
||||
SET_COLUMNS;
|
||||
SET_STRING;
|
||||
return TOKEN;
|
||||
}
|
||||
|
||||
<trail>[-\t\r \n$():?%/+=*<>!|&] {
|
||||
char c = yytext[yyleng-1];
|
||||
BEGIN(0);
|
||||
unput(c);
|
||||
SET_COLUMNS;
|
||||
SET_STRING;
|
||||
return TOKEN;
|
||||
}
|
||||
|
||||
<trail>\$\{ {
|
||||
curlycount = 0;
|
||||
BEGIN(var);
|
||||
yymore();
|
||||
}
|
||||
|
||||
<trail><<EOF>> {
|
||||
BEGIN(0);
|
||||
SET_COLUMNS;
|
||||
SET_STRING;
|
||||
return TOKEN;
|
||||
/*actually, if an expr is only a variable ref, this could happen a LOT */
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
/* I'm putting the interface routine to the whole parse here in the flexer input file
|
||||
mainly because of all the flexer initialization that has to be done. Shouldn't matter
|
||||
where it is, as long as it's somewhere. I didn't want to define a prototype for the
|
||||
ast_yy_scan_string in the .y file, because then, I'd have to define YY_BUFFER_STATE there...
|
||||
UGH! that would be inappropriate. */
|
||||
|
||||
int ast_yyparse(void *); /* need to/should define this prototype for the call to yyparse */
|
||||
int ast_yyerror(const char *, YYLTYPE *, struct parse_io *); /* likewise */
|
||||
|
||||
int ast_expr(char *expr, char *buf, int length)
|
||||
{
|
||||
struct parse_io io;
|
||||
int return_value = 0;
|
||||
|
||||
memset(&io, 0, sizeof(io));
|
||||
io.string = expr; /* to pass to the error routine */
|
||||
|
||||
ast_yylex_init(&io.scanner);
|
||||
|
||||
ast_yy_scan_string(expr, io.scanner);
|
||||
|
||||
ast_yyparse ((void *) &io);
|
||||
|
||||
ast_yylex_destroy(io.scanner);
|
||||
|
||||
if (!io.val) {
|
||||
if (length > 1) {
|
||||
strcpy(buf, "0");
|
||||
return_value = 1;
|
||||
}
|
||||
} else {
|
||||
if (io.val->type == AST_EXPR_integer) {
|
||||
int res_length;
|
||||
|
||||
res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i);
|
||||
return_value = (res_length <= length) ? res_length : length;
|
||||
} else {
|
||||
#ifdef STANDALONE
|
||||
strncpy(buf, io.val->u.s, length - 1);
|
||||
#else /* !STANDALONE */
|
||||
ast_copy_string(buf, io.val->u.s, length);
|
||||
#endif /* STANDALONE */
|
||||
return_value = strlen(buf);
|
||||
free(io.val->u.s);
|
||||
}
|
||||
free(io.val);
|
||||
}
|
||||
return return_value;
|
||||
}
|
||||
|
||||
|
||||
char extra_error_message[4095];
|
||||
int extra_error_message_supplied = 0;
|
||||
void ast_expr_register_extra_error_info(char *message);
|
||||
void ast_expr_clear_extra_error_info(void);
|
||||
|
||||
void ast_expr_register_extra_error_info(char *message)
|
||||
{
|
||||
extra_error_message_supplied=1;
|
||||
strcpy(extra_error_message, message);
|
||||
}
|
||||
|
||||
void ast_expr_clear_extra_error_info(void)
|
||||
{
|
||||
extra_error_message_supplied=0;
|
||||
extra_error_message[0] = 0;
|
||||
}
|
||||
|
||||
static char *expr2_token_equivs1[] =
|
||||
{
|
||||
"TOKEN",
|
||||
"TOK_COND",
|
||||
"TOK_COLONCOLON",
|
||||
"TOK_OR",
|
||||
"TOK_AND",
|
||||
"TOK_EQ",
|
||||
"TOK_GT",
|
||||
"TOK_LT",
|
||||
"TOK_GE",
|
||||
"TOK_LE",
|
||||
"TOK_NE",
|
||||
"TOK_PLUS",
|
||||
"TOK_MINUS",
|
||||
"TOK_MULT",
|
||||
"TOK_DIV",
|
||||
"TOK_MOD",
|
||||
"TOK_COMPL",
|
||||
"TOK_COLON",
|
||||
"TOK_EQTILDE",
|
||||
"TOK_RP",
|
||||
"TOK_LP"
|
||||
};
|
||||
|
||||
static char *expr2_token_equivs2[] =
|
||||
{
|
||||
"<token>",
|
||||
"?",
|
||||
"::",
|
||||
"|",
|
||||
"&",
|
||||
"=",
|
||||
">",
|
||||
"<",
|
||||
">=",
|
||||
"<=",
|
||||
"!=",
|
||||
"+",
|
||||
"-",
|
||||
"*",
|
||||
"/",
|
||||
"%",
|
||||
"!",
|
||||
":",
|
||||
"=~",
|
||||
")",
|
||||
"("
|
||||
};
|
||||
|
||||
|
||||
static char *expr2_token_subst(char *mess)
|
||||
{
|
||||
/* calc a length, malloc, fill, and return; yyerror had better free it! */
|
||||
int len=0,i;
|
||||
char *p;
|
||||
char *res, *s,*t;
|
||||
int expr2_token_equivs_entries = sizeof(expr2_token_equivs1)/sizeof(char*);
|
||||
|
||||
for (p=mess; *p; p++) {
|
||||
for (i=0; i<expr2_token_equivs_entries; i++) {
|
||||
if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 )
|
||||
{
|
||||
len+=strlen(expr2_token_equivs2[i])+2;
|
||||
p += strlen(expr2_token_equivs1[i])-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
len++;
|
||||
}
|
||||
res = (char*)malloc(len+1);
|
||||
res[0] = 0;
|
||||
s = res;
|
||||
for (p=mess; *p;) {
|
||||
int found = 0;
|
||||
for (i=0; i<expr2_token_equivs_entries; i++) {
|
||||
if ( strncmp(p,expr2_token_equivs1[i],strlen(expr2_token_equivs1[i])) == 0 ) {
|
||||
*s++ = '\'';
|
||||
for (t=expr2_token_equivs2[i]; *t;) {
|
||||
*s++ = *t++;
|
||||
}
|
||||
*s++ = '\'';
|
||||
p += strlen(expr2_token_equivs1[i]);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !found )
|
||||
*s++ = *p++;
|
||||
}
|
||||
*s++ = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_yyerror (const char *s, yyltype *loc, struct parse_io *parseio )
|
||||
{
|
||||
struct yyguts_t * yyg = (struct yyguts_t*)(parseio->scanner);
|
||||
char spacebuf[8000]; /* best safe than sorry */
|
||||
char spacebuf2[8000]; /* best safe than sorry */
|
||||
int i=0;
|
||||
char *s2 = expr2_token_subst((char *)s);
|
||||
spacebuf[0] = 0;
|
||||
|
||||
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,
|
||||
which is the same thing as... get this:
|
||||
yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]->yy_bs_column
|
||||
I was tempted to just use yy_buf_pos in the STATE, but..., well:
|
||||
a. the yy_buf_pos is the current position in the buffer, which
|
||||
may not relate to the entire string/buffer because of the
|
||||
buffering.
|
||||
b. but, analysis of the situation is that when you use the
|
||||
yy_scan_string func, it creates a single buffer the size of
|
||||
string, so the two would be the same...
|
||||
so, in the end, the yycolumn macro is available, shorter, therefore easier. */
|
||||
spacebuf2[i++]='^';
|
||||
spacebuf2[i]= 0;
|
||||
|
||||
#ifdef STANDALONE3
|
||||
/* easier to read in the standalone version */
|
||||
printf("ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",
|
||||
(extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
|
||||
#else
|
||||
ast_log(LOG_WARNING,"ast_yyerror(): %s syntax error: %s; Input:\n%s\n%s\n",
|
||||
(extra_error_message_supplied?extra_error_message:""), s2, parseio->string,spacebuf2);
|
||||
#endif
|
||||
#ifndef STANDALONE
|
||||
ast_log(LOG_WARNING,"If you have questions, please refer to doc/channelvariables.txt in the asterisk source.\n");
|
||||
#endif
|
||||
free(s2);
|
||||
return(0);
|
||||
}
|
||||
Reference in New Issue
Block a user