[Asterisk-cvs] asterisk ast_expr2.fl, NONE, 1.1 ast_expr2.y, NONE, 1.1 vercomp.sh, NONE, 1.1 Makefile, 1.154, 1.155

kpfleming at lists.digium.com kpfleming at lists.digium.com
Sun May 15 20:30:15 CDT 2005


Update of /usr/cvsroot/asterisk
In directory mongoose.digium.com:/tmp/cvs-serv19505

Modified Files:
	Makefile 
Added Files:
	ast_expr2.fl ast_expr2.y vercomp.sh 
Log Message:
add upgraded expression parser (bug #2058)


--- NEW FILE: ast_expr2.fl ---
%{
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <regex.h>
#include <limits.h>
#include <asterisk/ast_expr.h>
#include <asterisk/logger.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 yylloc_param->first_column = (int)(yyg->yytext_r - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf);yylloc_param->last_column = yylloc_param->last_column + yyleng - 1; yylloc_param->first_line = yylloc_param->last_line = 1
#define SET_STRING yylval_param->val = (struct val *)calloc(sizeof(struct val),1); yylval_param->val->type = AST_EXPR_string; yylval_param->val->u.s = strdup(yytext);

struct parse_io
{
	char *string;
	struct val *val;
	yyscan_t scanner;
};
 

%}

%option prefix="ast_yy"
%option batch
%option outfile="ast_expr2f.c"
%option reentrant
%option bison-bridge
%option bison-locations
%option noyywrap

%%

\|	{ 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_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_COLON;}
\(	{ SET_COLUMNS; SET_STRING; return TOK_LP;}
\)	{ SET_COLUMNS; SET_STRING; return TOK_RP;}

[ 	\r]		{}
\"[^"]*\"   {SET_COLUMNS; SET_STRING; return TOKEN;}

[\n]	{/* what to do with eol */}
[0-9]+		{   SET_COLUMNS; 
				yylval_param->val = (struct val *)calloc(sizeof(struct val),1);
				yylval_param->val->type = AST_EXPR_integer; 
				yylval_param->val->u.i = atoi(yytext); 
				return TOKEN;}
[a-zA-Z0-9,.?';{}\\_^%$#@!]+	{SET_COLUMNS; SET_STRING; return TOKEN;}

%%

/* 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 */
char *ast_expr(char *arg); /* and this prototype for the following func */
int		ast_yyerror(const char *,YYLTYPE *, struct parse_io *); /* likewise */

char *ast_expr (char *arg)
{
	struct parse_io *io;
	char *pirouni;
	
	io = (struct parse_io *)calloc(sizeof(struct parse_io),1);
	io->string = arg;  /* to pass to the error routine */
	
	ast_yylex_init(&io->scanner);
	
	ast_yy_scan_string(arg,io->scanner);
	
	ast_yyparse ((void *)io);

	ast_yylex_destroy(io->scanner);
	

	if (io->val==NULL) {
		pirouni=strdup("0");
		return(pirouni);
	} else {
		if (io->val->type == AST_EXPR_integer) {
			pirouni=malloc(256);
			sprintf (pirouni,"%lld", (long long)io->val->u.i);
		}
		else {
			pirouni=strdup(io->val->u.s);
		}
		free(io->val);
	}
	free(io);
	return(pirouni);
}

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;
	spacebuf[0] = 0;
	
#ifdef WHEN_LOC_MEANS_SOMETHING
	if( loc->first_column > 7990 ) /* if things get out of whack, why crash? */
		loc->first_column = 7990;
	if( loc->last_column > 7990 )
		loc->last_column = 7990;
	for(i=0;i<loc->first_column;i++) spacebuf[i] = ' ';
	for(   ;i<loc->last_column;i++) spacebuf[i] = '^';
	spacebuf[i] = 0;
#endif
	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 STANDALONE
	/* easier to read in the standalone version */
	printf("ast_yyerror(): syntax error: %s; Input:\n%s\n%s\n",  
			s, parseio->string,spacebuf2);
#else
	ast_log(LOG_WARNING,"ast_yyerror(): syntax error: %s; Input:\n%s\n%s\n",  
			s, parseio->string,spacebuf2);
	ast_log(LOG_WARNING,"If you have questions, please refer to doc/README.variables2 in the asterisk source.\n");
#endif
	return(0);
}

--- NEW FILE: ast_expr2.y ---
%{
/* Written by Pace Willisson (pace at blitz.com) 
 * and placed in the public domain.
 *
 * Largely rewritten by J.T. Conklin (jtc at wimsey.com)
 *
 * And then overhauled twice by Steve Murphy (murf at e-tools.com)
 * to add double-quoted strings, allow mult. spaces, improve
 * error messages, and then to fold in a flex scanner for the 
 * yylex operation.
 *
 * $FreeBSD: src/bin/expr/expr.y,v 1.16 2000/07/22 10:59:36 se Exp $
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <regex.h>
#include <limits.h>
#include <asterisk/ast_expr.h>
#include <asterisk/logger.h>

#ifdef LONG_LONG_MIN
#define QUAD_MIN LONG_LONG_MIN
#endif
#ifdef LONG_LONG_MAX
#define QUAD_MAX LONG_LONG_MAX
#endif

#  if ! defined(QUAD_MIN)
#   define QUAD_MIN     (-0x7fffffffffffffffL-1)
#  endif
#  if ! defined(QUAD_MAX)
#   define QUAD_MAX     (0x7fffffffffffffffL)
#  endif

#define YYPARSE_PARAM parseio
#define YYLEX_PARAM ((struct parse_io *)parseio)->scanner
#define YYERROR_VERBOSE 1

/* #define ast_log fprintf
#define LOG_WARNING stderr */
  
enum valtype {
	AST_EXPR_integer, AST_EXPR_numeric_string, AST_EXPR_string
} ;

struct val {
	enum valtype type;
	union {
		char *s;
		quad_t i;
	} u;
} ;

typedef void *yyscan_t;

struct parse_io
{
	char *string;
	struct val *val;
	yyscan_t scanner;
};
 
static int		chk_div __P((quad_t, quad_t));
static int		chk_minus __P((quad_t, quad_t, quad_t));
static int		chk_plus __P((quad_t, quad_t, quad_t));
static int		chk_times __P((quad_t, quad_t, quad_t));
static void		free_value __P((struct val *));
static int		is_zero_or_null __P((struct val *));
static int		isstring __P((struct val *));
static struct val	*make_integer __P((quad_t));
static struct val	*make_str __P((const char *));
static struct val	*op_and __P((struct val *, struct val *));
static struct val	*op_colon __P((struct val *, struct val *));
static struct val	*op_eqtilde __P((struct val *, struct val *));
static struct val	*op_div __P((struct val *, struct val *));
static struct val	*op_eq __P((struct val *, struct val *));
static struct val	*op_ge __P((struct val *, struct val *));
static struct val	*op_gt __P((struct val *, struct val *));
static struct val	*op_le __P((struct val *, struct val *));
static struct val	*op_lt __P((struct val *, struct val *));
static struct val	*op_minus __P((struct val *, struct val *));
static struct val	*op_negate __P((struct val *));
static struct val	*op_compl __P((struct val *));
static struct val	*op_ne __P((struct val *, struct val *));
static struct val	*op_or __P((struct val *, struct val *));
static struct val	*op_plus __P((struct val *, struct val *));
static struct val	*op_rem __P((struct val *, struct val *));
static struct val	*op_times __P((struct val *, struct val *));
static quad_t		to_integer __P((struct val *));
static void		to_string __P((struct val *));

/* uh, if I want to predeclare yylex with a YYLTYPE, I have to predeclare the yyltype... sigh */
typedef struct yyltype
{
  int first_line;
  int first_column;

  int last_line;
  int last_column;
} yyltype;

# define YYLTYPE yyltype
# define YYLTYPE_IS_TRIVIAL 1

/* we will get warning about no prototype for yylex! But we can't
   define it here, we have no definition yet for YYSTYPE. */

int		ast_yyerror(const char *,YYLTYPE *, struct parse_io *);
 
/* I wanted to add args to the yyerror routine, so I could print out
   some useful info about the error. Not as easy as it looks, but it
   is possible. */
#define ast_yyerror(x) ast_yyerror(x,&yyloc,parseio)

%}
 
%pure-parser
%locations
/* %debug  for when you are having big problems */

/* %name-prefix="ast_yy" */

%union
{
	struct val *val;
}

/* IN_ANOTHER_LIFE
%{
static int		ast_yylex __P((YYSTYPE *, YYLTYPE *, yyscan_t));
%}
*/

%left <val> TOK_OR
%left <val> TOK_AND
%left <val> TOK_EQ TOK_GT TOK_LT TOK_GE TOK_LE TOK_NE
%left <val> TOK_PLUS TOK_MINUS
%left <val> TOK_MULT TOK_DIV TOK_MOD
%left <val> TOK_COMPL TOK_EQTILDE
%left UMINUS
%left <val> TOK_COLON
%left <val> TOK_RP TOK_LP

%token <val> TOKEN
%type <val> start expr

%%

start: expr { ((struct parse_io *)parseio)->val = (struct val *)calloc(sizeof(struct val),1);
              ((struct parse_io *)parseio)->val->type = $$->type;
              ((struct parse_io *)parseio)->val->u.s = $$->u.s; }
	;

expr:	TOKEN   { $$= $1;}
	| TOK_LP expr TOK_RP { $$ = $2; 
	                       @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						   @$.first_line=0; @$.last_line=0;}
	| expr TOK_OR expr { $$ = op_or ($1, $3);
                         @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						 @$.first_line=0; @$.last_line=0;}
	| expr TOK_AND expr { $$ = op_and ($1, $3); 
	                      @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
                          @$.first_line=0; @$.last_line=0;}
	| expr TOK_EQ expr { $$ = op_eq ($1, $3); 
	                     @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						 @$.first_line=0; @$.last_line=0;}
	| expr TOK_GT expr { $$ = op_gt ($1, $3);
                         @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						 @$.first_line=0; @$.last_line=0;}
	| expr TOK_LT expr { $$ = op_lt ($1, $3); 
	                     @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						 @$.first_line=0; @$.last_line=0;}
	| expr TOK_GE expr  { $$ = op_ge ($1, $3); 
	                      @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						  @$.first_line=0; @$.last_line=0;}
	| expr TOK_LE expr  { $$ = op_le ($1, $3); 
	                      @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						  @$.first_line=0; @$.last_line=0;}
	| expr TOK_NE expr  { $$ = op_ne ($1, $3); 
	                      @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						  @$.first_line=0; @$.last_line=0;}
	| expr TOK_PLUS expr { $$ = op_plus ($1, $3); 
	                       @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						   @$.first_line=0; @$.last_line=0;}
	| expr TOK_MINUS expr { $$ = op_minus ($1, $3); 
	                        @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
							@$.first_line=0; @$.last_line=0;}
	| TOK_MINUS expr %prec UMINUS { $$ = op_negate ($2); 
	                        @$.first_column = @1.first_column; @$.last_column = @2.last_column; 
							@$.first_line=0; @$.last_line=0;}
	| TOK_COMPL expr %prec UMINUS { $$ = op_compl ($2); 
	                        @$.first_column = @1.first_column; @$.last_column = @2.last_column; 
							@$.first_line=0; @$.last_line=0;}
	| expr TOK_MULT expr { $$ = op_times ($1, $3); 
	                       @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						   @$.first_line=0; @$.last_line=0;}
	| expr TOK_DIV expr { $$ = op_div ($1, $3); 
	                      @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						  @$.first_line=0; @$.last_line=0;}
	| expr TOK_MOD expr { $$ = op_rem ($1, $3); 
	                      @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
						  @$.first_line=0; @$.last_line=0;}
	| expr TOK_COLON expr { $$ = op_colon ($1, $3); 
	                        @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
							@$.first_line=0; @$.last_line=0;}
	| expr TOK_EQTILDE expr { $$ = op_eqtilde ($1, $3); 
	                        @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
							@$.first_line=0; @$.last_line=0;}
	;

%%

static struct val *
make_integer (quad_t i)
{
	struct val *vp;

	vp = (struct val *) malloc (sizeof (*vp));
	if (vp == NULL) {
		ast_log(LOG_WARNING, "malloc() failed\n");
		return(NULL);
	}

	vp->type = AST_EXPR_integer;
	vp->u.i  = i;
	return vp; 
}

static struct val *
make_str (const char *s)
{
	struct val *vp;
	size_t i;
	int isint;

	vp = (struct val *) malloc (sizeof (*vp));
	if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
		ast_log(LOG_WARNING,"malloc() failed\n");
		return(NULL);
	}

	for(i = 1, isint = isdigit(s[0]) || s[0] == '-';
	    isint && i < strlen(s);
	    i++)
	{
		if(!isdigit(s[i]))
			 isint = 0;
	}

	if (isint)
		vp->type = AST_EXPR_numeric_string;
	else	
		vp->type = AST_EXPR_string;

	return vp;
}


static void
free_value (struct val *vp)
{	
	if (vp==NULL) {
		return;
	}
	if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string)
		free (vp->u.s);	
}


static quad_t
to_integer (struct val *vp)
{
	quad_t i;

	if (vp == NULL) {
		ast_log(LOG_WARNING,"vp==NULL in to_integer()\n");
		return(0);
	}

	if (vp->type == AST_EXPR_integer)
		return 1;

	if (vp->type == AST_EXPR_string)
		return 0;

	/* vp->type == AST_EXPR_numeric_string, make it numeric */
	errno = 0;
	i  = strtoq(vp->u.s, (char**)NULL, 10);
	if (errno != 0) {
		free(vp->u.s);
		ast_log(LOG_WARNING,"overflow\n");
		return(0);
	}
	free (vp->u.s);
	vp->u.i = i;
	vp->type = AST_EXPR_integer;
	return 1;
}

static void
strip_quotes(struct val *vp)
{
	if (vp->type != AST_EXPR_string && vp->type != AST_EXPR_numeric_string)
		return;
	
	if( vp->u.s[0] == '"' && vp->u.s[strlen(vp->u.s)-1] == '"' )
	{
		char *f, *t;
		f = vp->u.s;
		t = vp->u.s;
		
		while( *f )
		{
			if( *f  && *f != '"' )
				*t++ = *f++;
			else
				f++;
		}
		*t = *f;
	}
}

static void
to_string (struct val *vp)
{
	char *tmp;

	if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string)
		return;

	tmp = malloc ((size_t)25);
	if (tmp == NULL) {
		ast_log(LOG_WARNING,"malloc() failed\n");
		return;
	}

	sprintf (tmp, "%lld", (long long)vp->u.i);
	vp->type = AST_EXPR_string;
	vp->u.s  = tmp;
}


static int
isstring (struct val *vp)
{
	/* only TRUE if this string is not a valid integer */
	return (vp->type == AST_EXPR_string);
}


static int
is_zero_or_null (struct val *vp)
{
	if (vp->type == AST_EXPR_integer) {
		return (vp->u.i == 0);
	} else {
		return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
	}
	/* NOTREACHED */
}

#ifdef STANDALONE

void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
{
	printf("LOG: lev:%d file:%s  line:%d func: %s  fmt:%s\n",
		   level, file, line, function, fmt);
	fflush(stdout);
}

int main(int argc,char **argv) {
	char *s;

	s=ast_expr(argv[1]);

	printf("=====%s======\n",s);
}

#endif

#undef ast_yyerror
#define ast_yyerror(x) ast_yyerror(x, YYLTYPE *yylloc, struct parse_io *parseio)

/* I put the ast_yyerror func in the flex input file,
   because it refers to the buffer state. Best to
   let it access the BUFFER stuff there and not trying
   define all the structs, macros etc. in this file! */


static struct val *
op_or (struct val *a, struct val *b)
{
	if (is_zero_or_null (a)) {
		free_value (a);
		return (b);
	} else {
		free_value (b);
		return (a);
	}
}
		
static struct val *
op_and (struct val *a, struct val *b)
{
	if (is_zero_or_null (a) || is_zero_or_null (b)) {
		free_value (a);
		free_value (b);
		return (make_integer ((quad_t)0));
	} else {
		free_value (b);
		return (a);
	}
}

static struct val *
op_eq (struct val *a, struct val *b)
{
	struct val *r; 

	if (isstring (a) || isstring (b)) {
		to_string (a);
		to_string (b);	
		r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) == 0));
	} else {
		(void)to_integer(a);
		(void)to_integer(b);
		r = make_integer ((quad_t)(a->u.i == b->u.i));
	}

	free_value (a);
	free_value (b);
	return r;
}

static struct val *
op_gt (struct val *a, struct val *b)
{
	struct val *r;

	if (isstring (a) || isstring (b)) {
		to_string (a);
		to_string (b);
		r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) > 0));
	} else {
		(void)to_integer(a);
		(void)to_integer(b);
		r = make_integer ((quad_t)(a->u.i > b->u.i));
	}

	free_value (a);
	free_value (b);
	return r;
}

static struct val *
op_lt (struct val *a, struct val *b)
{
	struct val *r;

	if (isstring (a) || isstring (b)) {
		to_string (a);
		to_string (b);
		r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) < 0));
	} else {
		(void)to_integer(a);
		(void)to_integer(b);
		r = make_integer ((quad_t)(a->u.i < b->u.i));
	}

	free_value (a);
	free_value (b);
	return r;
}

static struct val *
op_ge (struct val *a, struct val *b)
{
	struct val *r;

	if (isstring (a) || isstring (b)) {
		to_string (a);
		to_string (b);
		r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) >= 0));
	} else {
		(void)to_integer(a);
		(void)to_integer(b);
		r = make_integer ((quad_t)(a->u.i >= b->u.i));
	}

	free_value (a);
	free_value (b);
	return r;
}

static struct val *
op_le (struct val *a, struct val *b)
{
	struct val *r;

	if (isstring (a) || isstring (b)) {
		to_string (a);
		to_string (b);
		r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) <= 0));
	} else {
		(void)to_integer(a);
		(void)to_integer(b);
		r = make_integer ((quad_t)(a->u.i <= b->u.i));
	}

	free_value (a);
	free_value (b);
	return r;
}

static struct val *
op_ne (struct val *a, struct val *b)
{
	struct val *r;

	if (isstring (a) || isstring (b)) {
		to_string (a);
		to_string (b);
		r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) != 0));
	} else {
		(void)to_integer(a);
		(void)to_integer(b);
		r = make_integer ((quad_t)(a->u.i != b->u.i));
	}

	free_value (a);
	free_value (b);
	return r;
}

static int
chk_plus (quad_t a, quad_t b, quad_t r)
{
	/* sum of two positive numbers must be positive */
	if (a > 0 && b > 0 && r <= 0)
		return 1;
	/* sum of two negative numbers must be negative */
	if (a < 0 && b < 0 && r >= 0)
		return 1;
	/* all other cases are OK */
	return 0;
}

static struct val *
op_plus (struct val *a, struct val *b)
{
	struct val *r;

	if (!to_integer (a)) {
		ast_log(LOG_WARNING,"non-numeric argument\n");
		if (!to_integer (b)) {
			free_value(a);
			free_value(b);
			return make_integer(0);
		} else {
			free_value(a);
			return (b);
		}
	} else if (!to_integer(b)) {
		free_value(b);
		return (a);
	}

	r = make_integer (/*(quad_t)*/(a->u.i + b->u.i));
	if (chk_plus (a->u.i, b->u.i, r->u.i)) {
		ast_log(LOG_WARNING,"overflow\n");
	}
	free_value (a);
	free_value (b);
	return r;
}

static int
chk_minus (quad_t a, quad_t b, quad_t r)
{
	/* special case subtraction of QUAD_MIN */
	if (b == QUAD_MIN) {
		if (a >= 0)
			return 1;
		else
			return 0;
	}
	/* this is allowed for b != QUAD_MIN */
	return chk_plus (a, -b, r);
}

static struct val *
op_minus (struct val *a, struct val *b)
{
	struct val *r;

	if (!to_integer (a)) {
		ast_log(LOG_WARNING, "non-numeric argument\n");
		if (!to_integer (b)) {
			free_value(a);
			free_value(b);
			return make_integer(0);
		} else {
			r = make_integer(0 - b->u.i);
			free_value(a);
			free_value(b);
			return (r);
		}
	} else if (!to_integer(b)) {
		ast_log(LOG_WARNING, "non-numeric argument\n");
		free_value(b);
		return (a);
	}

	r = make_integer (/*(quad_t)*/(a->u.i - b->u.i));
	if (chk_minus (a->u.i, b->u.i, r->u.i)) {
		ast_log(LOG_WARNING, "overflow\n");
	}
	free_value (a);
	free_value (b);
	return r;
}

static struct val *
op_negate (struct val *a)
{
	struct val *r;

	if (!to_integer (a) ) {
		free_value(a);
		ast_log(LOG_WARNING, "non-numeric argument\n");
		return make_integer(0);
	}

	r = make_integer (/*(quad_t)*/(- a->u.i));
	if (chk_minus (0, a->u.i, r->u.i)) {
		ast_log(LOG_WARNING, "overflow\n");
	}
	free_value (a);
	return r;
}

static struct val *
op_compl (struct val *a)
{
	int v1 = 1;
	struct val *r;
	
	if( !a )
	{
		v1 = 0;
	}
	else
	{
		switch( a->type )
		{
		case AST_EXPR_integer:
			if( a->u.i == 0 )
				v1 = 0;
			break;
			
		case AST_EXPR_string:
			if( a->u.s == 0 )
				v1 = 0;
			else
			{
				if( a->u.s[0] == 0 )
					v1 = 0;
				else if (strlen(a->u.s) == 1 && a->u.s[0] == '0' )
					v1 = 0;
			}
			break;
			
		case AST_EXPR_numeric_string:
			if( a->u.s == 0 )
				v1 = 0;
			else
			{
				if( a->u.s[0] == 0 )
					v1 = 0;
				else if (strlen(a->u.s) == 1 && a->u.s[0] == '0' )
					v1 = 0;
			}
			break;
		}
	}
	
	r = make_integer (!v1);
	free_value (a);
	return r;
}

static int
chk_times (quad_t a, quad_t b, quad_t r)
{
	/* special case: first operand is 0, no overflow possible */
	if (a == 0)
		return 0;
	/* cerify that result of division matches second operand */
	if (r / a != b)
		return 1;
	return 0;
}

static struct val *
op_times (struct val *a, struct val *b)
{
	struct val *r;

	if (!to_integer (a) || !to_integer (b)) {
		free_value(a);
		free_value(b);
		ast_log(LOG_WARNING, "non-numeric argument\n");
		return(make_integer(0));
	}

	r = make_integer (/*(quad_t)*/(a->u.i * b->u.i));
	if (chk_times (a->u.i, b->u.i, r->u.i)) {
		ast_log(LOG_WARNING, "overflow\n");
	}
	free_value (a);
	free_value (b);
	return (r);
}

static int
chk_div (quad_t a, quad_t b)
{
	/* div by zero has been taken care of before */
	/* only QUAD_MIN / -1 causes overflow */
	if (a == QUAD_MIN && b == -1)
		return 1;
	/* everything else is OK */
	return 0;
}

static struct val *
op_div (struct val *a, struct val *b)
{
	struct val *r;

	if (!to_integer (a)) {
		free_value(a);
		free_value(b);
		ast_log(LOG_WARNING, "non-numeric argument\n");
		return make_integer(0);
	} else if (!to_integer (b)) {
		free_value(a);
		free_value(b);
		ast_log(LOG_WARNING, "non-numeric argument\n");
		return make_integer(INT_MAX);
	}

	if (b->u.i == 0) {
		ast_log(LOG_WARNING, "division by zero\n");		
		free_value(a);
		free_value(b);
		return make_integer(INT_MAX);
	}

	r = make_integer (/*(quad_t)*/(a->u.i / b->u.i));
	if (chk_div (a->u.i, b->u.i)) {
		ast_log(LOG_WARNING, "overflow\n");
	}
	free_value (a);
	free_value (b);
	return r;
}
	
static struct val *
op_rem (struct val *a, struct val *b)
{
	struct val *r;

	if (!to_integer (a) || !to_integer (b)) {
		ast_log(LOG_WARNING, "non-numeric argument\n");
		free_value(a);
		free_value(b);
		return make_integer(0);
	}

	if (b->u.i == 0) {
		ast_log(LOG_WARNING, "div by zero\n");
		free_value(a);
		return(b);
	}

	r = make_integer (/*(quad_t)*/(a->u.i % b->u.i));
	/* chk_rem necessary ??? */
	free_value (a);
	free_value (b);
	return r;
}
	

static struct val *
op_colon (struct val *a, struct val *b)
{
	regex_t rp;
	regmatch_t rm[2];
	char errbuf[256];
	int eval;
	struct val *v;

	/* coerce to both arguments to strings */
	to_string(a);
	to_string(b);
	/* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
	strip_quotes(a);
	strip_quotes(b);
	/* compile regular expression */
	if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
		regerror (eval, &rp, errbuf, sizeof(errbuf));
		ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
		free_value(a);
		free_value(b);
		return make_str("");		
	}

	/* compare string against pattern */
	/* remember that patterns are anchored to the beginning of the line */
	if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
		if (rm[1].rm_so >= 0) {
			*(a->u.s + rm[1].rm_eo) = '\0';
			v = make_str (a->u.s + rm[1].rm_so);

		} else {
			v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
		}
	} else {
		if (rp.re_nsub == 0) {
			v = make_integer ((quad_t)0);
		} else {
			v = make_str ("");
		}
	}

	/* free arguments and pattern buffer */
	free_value (a);
	free_value (b);
	regfree (&rp);

	return v;
}
	

static struct val *
op_eqtilde (struct val *a, struct val *b)
{
	regex_t rp;
	regmatch_t rm[2];
	char errbuf[256];
	int eval;
	struct val *v;

	/* coerce to both arguments to strings */
	to_string(a);
	to_string(b);
	/* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
	strip_quotes(a);
	strip_quotes(b);
	/* compile regular expression */
	if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
		regerror (eval, &rp, errbuf, sizeof(errbuf));
		ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
		free_value(a);
		free_value(b);
		return make_str("");		
	}

	/* compare string against pattern */
	/* remember that patterns are anchored to the beginning of the line */
	if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 ) {
		if (rm[1].rm_so >= 0) {
			*(a->u.s + rm[1].rm_eo) = '\0';
			v = make_str (a->u.s + rm[1].rm_so);

		} else {
			v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
		}
	} else {
		if (rp.re_nsub == 0) {
			v = make_integer ((quad_t)0);
		} else {
			v = make_str ("");
		}
	}

	/* free arguments and pattern buffer */
	free_value (a);
	free_value (b);
	regfree (&rp);

	return v;
}

--- NEW FILE: vercomp.sh ---
#! /bin/bash

### flex just outputs a single line:

## flex version 2.5.4


### but bison is a bit more wordy

## bison (GNU Bison) 1.875c
## Written by Robert Corbett and Richard Stallman.
## 
## Copyright (C) 2003 Free Software Foundation, Inc.
## This is free software; see the source for copying conditions.  There is NO
## warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

### based on this, the version number of the program:
###   a. in the first line of output
###   b. is the last "word" of that line

program=$1
comparefunc=$2
argver=$3

progver1=`$program --version | head -1`

[[ $progver1 =~ '([^ ]+$)'  ]]

progver=$BASH_REMATCH

progver2=$progver
numprogverlist=0

while [[ $progver2 =~ '^([^.]+)\.(.*)' ]]; do
	progver2=${BASH_REMATCH[2]}
	progverlist[$numprogverlist]=${BASH_REMATCH[1]}
	progverlist[$(( ${numprogverlist}+1 ))]=${BASH_REMATCH[2]}

##	echo ${BASH_REMATCH[0]}
##	echo ${BASH_REMATCH[1]}
##	echo ${BASH_REMATCH[2]}
  	(( numprogverlist=$(( $numprogverlist+1 )) ))

done
	(( numprogverlist=$(( $numprogverlist+1 )) ))
  	
##	echo number of elements = $numprogverlist
##	echo element 0 = ${progverlist[0]}
##	echo element 1 = ${progverlist[1]}
##	echo element 2 = ${progverlist[2]}

argver2=$argver
numargverlist=0

while [[ $argver2 =~ '^([^.]+)\.(.*)' ]]; do
	argver2=${BASH_REMATCH[2]}
	argverlist[$numargverlist]=${BASH_REMATCH[1]}
	argverlist[$(( ${numargverlist}+1 ))]=${BASH_REMATCH[2]}

##	echo ${BASH_REMATCH[0]}
##	echo ${BASH_REMATCH[1]}
##	echo ${BASH_REMATCH[2]}
  	(( numargverlist=$(( $numargverlist+1 )) ))

done
	(( numargverlist=$(( $numargverlist+1 )) ))
  	
##	echo number of argver elements = $numargverlist
##	echo element 0 = ${argverlist[0]}
##	echo element 1 = ${argverlist[1]}
##	echo element 2 = ${argverlist[2]}

if (( $numprogverlist < $numargverlist )); then
	for (( i=$numprogverlist ; $i < $numargverlist ; i=$i + 1 )) ; do
##		echo setting progverlist "[" $i "]" to 0
		(( progverlist[$i]='0' ))
		(( numprogverlist=${numprogverlist}+1 ))
	done
elif (( $numargverlist < $numprogverlist )); then
	for (( i=$numargverlist ; $i < $numprogverlist ; i=$i + 1 )) ; do
##		echo setting argverlist "[" $i "]" to 0
		(( argverlist[$i]='0' ))
		(( numargverlist=${numargverlist}+1 ))
	done
fi

## echo numarg=$numargverlist   numprog=$numprogverlist
## echo arg0: ${argverlist[0]}
## echo arg1: ${argverlist[1]}
## echo arg2: ${argverlist[2]}
## echo prog0: ${progverlist[0]}
## echo prog1: ${progverlist[1]}
## echo prog2: ${progverlist[2]}

## the main comparison loop 

for (( i=0 ; $i < $numargverlist ; i=$i + 1 )) ; do
##	echo i= $i

	if [[ ${progverlist[$i]} =~ '^[0-9]+$' &&  ${argverlist[$i]} =~ '^[0-9]+$' ]] ; then  ## nothing but numbers
		if (( ${progverlist[$i]} != ${argverlist[$i]} )); then
			if [[ ${progverlist[$i]}  -lt ${argverlist[$i]} ]]; then
				if [[ $comparefunc == "=" ]]; then
					echo "false"
					exit 0;
				elif [[ $comparefunc == "<" || $comparefunc == "<=" ]]; then
					echo "true"
					exit 0;
				elif [[ $comparefunc == ">" || $comparefunc == ">=" ]]; then
					echo "false"
					exit 0;
				fi
			elif [[ ${progverlist[$i]} -gt ${argverlist[$i]} ]]; then
				if [[ $comparefunc == "=" ]]; then
					echo "false"
					exit 0;
				elif [[ $comparefunc == "<" || $comparefunc == "<=" ]]; then
					echo "false"
					exit 0;
				elif [[ $comparefunc == ">" || $comparefunc == ">=" ]]; then
					echo "true"
					exit 0;
				fi
			fi
		fi
	else  ## something besides just numbers
		if [[ ${progverlist[$i]} != ${argverlist[$i]} ]]; then
			if [[ ${progverlist[$i]} < ${argverlist[$i]} ]]; then
				if [[ $comparefunc == "=" ]]; then
					echo "false"
					exit 0;
				elif [[ $comparefunc == "<" || $comparefunc == "<=" ]]; then
					echo "true"
					exit 0;
				elif [[ $comparefunc == ">" || $comparefunc == ">=" ]]; then
					echo "false"
					exit 0;
				fi
			elif [[ ${progverlist[$i]} > ${argverlist[$i]} ]]; then
				if [[ $comparefunc == "=" ]]; then
					echo "false"
					exit 0;
				elif [[ $comparefunc == "<" || $comparefunc == "<=" ]]; then
					echo "false"
					exit 0;
				elif [[ $comparefunc == ">" || $comparefunc == ">=" ]]; then
					echo "true"
					exit 0;
				fi
			fi
		fi
	fi
done

if [[ $comparefunc == "=" ]]; then
	echo "true"
elif [[ $comparefunc == "<=" || $comparefunc == ">=" ]]; then
	echo "true"
else
	echo "false"
fi

exit 0;

Index: Makefile
===================================================================
RCS file: /usr/cvsroot/asterisk/Makefile,v
retrieving revision 1.154
retrieving revision 1.155
diff -u -d -r1.154 -r1.155
--- Makefile	5 May 2005 05:39:33 -0000	1.154
+++ Makefile	16 May 2005 00:35:38 -0000	1.155
@@ -258,10 +258,21 @@
 LIBS+=-lpthread -ldl -lnsl -lsocket -lresolv -L$(CROSS_COMPILE_TARGET)/usr/local/ssl/lib
 endif
 LIBS+=-lssl
+
+FLEXVER_GT_2_5_31=$(shell ./vercomp.sh flex \>= 2.5.31)
+BISONVER=$(shell bison --version | grep \^bison | egrep -o '[0-9]+\.[-0-9.]+[a-z]?' )
+BISONVERGE_85=$(shell ./vercomp.sh bison \>= 1.85 )
+
+ifeq (${FLEXVER_GT_2_5_31},true)
+FLEXOBJS=ast_expr2.o ast_expr2f.o
+else
+FLEXOBJS=ast_expr.o
+endif
+
 OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \
 	translate.o file.o say.o pbx.o cli.o md5.o term.o \
 	ulaw.o alaw.o callerid.o fskmodem.o image.o app.o \
-	cdr.o tdd.o acl.o rtp.o manager.o asterisk.o ast_expr.o \
+	cdr.o tdd.o acl.o rtp.o manager.o asterisk.o ${FLEXOBJS}  \
 	dsp.o chanvars.o indications.o autoservice.o db.o privacy.o \
 	astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
 	utils.o config_old.o plc.o jitterbuf.o dnsmgr.o
@@ -333,14 +344,46 @@
 .version: _version
 
 .y.c:
-	bison $< --name-prefix=ast_yy -o $@
+	@if (($(BISONVERGE_85) = false)); then \
+		echo ================================================================================= ;\
+		echo NOTE: you may have trouble if you do not have bison-1.85 or higher installed! ;\
+		echo NOTE: you can pick up a copy at: http://ftp.gnu.org/ or its mirrors ;\
+		echo NOTE: You Have: $(BISONVER) ;\
+		echo ================================================================================; \
+	else \
+		echo EXCELLENT-- You have Bison version $(BISONVER), this should work just fine...;\
+	fi
+	bison -v -d --name-prefix=ast_yy $< -o $@
 
 ast_expr.o: ast_expr.c
+	@echo NOTE:
+	@echo NOTE:
+	@echo NOTE: Using older version of ast_expr. To use the newer version,
+	@echo NOTE: Upgrade to flex 2.5.31 or higher, which can be found at http://
+	@echo NOTE:  http://sourceforge.net/project/showfiles.php?group_id=72099
+	@echo NOTE:
+	@echo NOTE:
+	$(CC) -c $(CPPFLAGS) $(CFLAGS) ast_expr.c
+
+ast_expr2.o: ast_expr2.c
+
+ast_expr2f.o: ast_expr2f.c
+ast_expr2f.c: ast_expr2.fl
+	flex ast_expr2.fl
 
 cli.o: cli.c build.h
 
 asterisk.o: asterisk.c build.h
 
+testexpr2 :
+	flex ast_expr2.fl
+	bison -v -d --name-prefix=ast_yy -o ast_expr2.c ast_expr2.y
+	gcc -g -c -DSTANDALONE ast_expr2f.c
+	gcc -g -c -DSTANDALONE ast_expr2.c
+	gcc -g -o testexpr2 ast_expr2f.o ast_expr2.o
+	rm ast_expr2.c ast_expr2.o ast_expr2f.o ast_expr2f.c
+
+
 manpage: asterisk.8.gz
 
 asterisk.8.gz: asterisk.sgml




More information about the svn-commits mailing list