mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-11-03 20:38:59 +00:00 
			
		
		
		
	This fixes a number of broken links throughout the
tree, mostly caused by wiki.asterisk.org being replaced
with docs.asterisk.org, which should eliminate the
need for sporadic fixes as in f28047db36.
Resolves: #430
		
	
		
			
				
	
	
		
			476 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			476 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
%{
 | 
						|
/*
 | 
						|
 * 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 <sys/types.h>
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
#if defined(STANDALONE)
 | 
						|
#ifndef __USE_ISOC99
 | 
						|
#define __USE_ISOC99 1
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef __USE_ISOC99
 | 
						|
#define FP___PRINTF "%.18Lg"
 | 
						|
#define FP___FMOD   fmodl
 | 
						|
#define FP___STRTOD  strtold
 | 
						|
#define FP___TYPE    long double
 | 
						|
#else
 | 
						|
#define FP___PRINTF "%.16g"
 | 
						|
#define FP___FMOD   fmod
 | 
						|
#define FP___STRTOD  strtod
 | 
						|
#define FP___TYPE    double
 | 
						|
#endif
 | 
						|
 | 
						|
#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"
 | 
						|
#ifndef STANDALONE
 | 
						|
#include "asterisk/strings.h"
 | 
						|
#include "asterisk/channel.h"
 | 
						|
#endif
 | 
						|
 | 
						|
/* Conditionally redefine the macro from flex 2.5.35, in case someone uses flex <2.5.35 to regenerate this file. */
 | 
						|
#ifndef ECHO
 | 
						|
#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
 | 
						|
#endif
 | 
						|
 | 
						|
enum valtype {
 | 
						|
	AST_EXPR_number, AST_EXPR_numeric_string, AST_EXPR_string
 | 
						|
} ;
 | 
						|
 | 
						|
struct val {
 | 
						|
	enum valtype type;
 | 
						|
	union {
 | 
						|
		char *s;
 | 
						|
		FP___TYPE i; /* long double or just double if it's a bad day */
 | 
						|
	} 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;
 | 
						|
	struct ast_channel *chan;
 | 
						|
};
 | 
						|
 
 | 
						|
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(const char *mess);
 | 
						|
%}
 | 
						|
 | 
						|
%option prefix="ast_yy"
 | 
						|
%option batch
 | 
						|
%option 8bit
 | 
						|
%option outfile="ast_expr2f.c"
 | 
						|
%option reentrant
 | 
						|
%option bison-bridge
 | 
						|
%option bison-locations
 | 
						|
%option noyywrap
 | 
						|
%option noyyfree
 | 
						|
%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_TILDETILDE;}
 | 
						|
\>	{ 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_COMMA;}
 | 
						|
\-	{ 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]+(\.[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\.';\\_^#@]|[\x80-\xff]|($[^{]))+   {
 | 
						|
		SET_COLUMNS;
 | 
						|
		SET_STRING;
 | 
						|
		return TOKEN;
 | 
						|
	}
 | 
						|
 | 
						|
([a-zA-Z0-9\.';\\_^#@]|[\x80-\xff]|($[^{]))+\$\{	{
 | 
						|
		curlycount = 0;
 | 
						|
		BEGIN(var);
 | 
						|
		yymore();
 | 
						|
	}
 | 
						|
 | 
						|
<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$():?%/+=*<>!|&]*\$\{	{
 | 
						|
		curlycount = 0;
 | 
						|
		BEGIN(var);
 | 
						|
		yymore();
 | 
						|
	}
 | 
						|
	
 | 
						|
<trail>[-\t\r \n$():?%/+=*<>!|&]	{
 | 
						|
		char c = yytext[yyleng-1];
 | 
						|
		BEGIN(0);
 | 
						|
		unput(c);
 | 
						|
		SET_COLUMNS;
 | 
						|
		SET_STRING;
 | 
						|
		return TOKEN;
 | 
						|
	}
 | 
						|
	
 | 
						|
<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 */
 | 
						|
 | 
						|
void ast_yyfree(void *ptr, yyscan_t yyscanner)
 | 
						|
{
 | 
						|
    /* the normal generated yyfree func just frees its first arg;
 | 
						|
     this get complaints on some systems, as sometimes this
 | 
						|
     arg is a nil ptr! It's usually not fatal, but is irritating! */
 | 
						|
	free( (char *) ptr );
 | 
						|
}
 | 
						|
 | 
						|
int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
 | 
						|
{
 | 
						|
	struct parse_io io = { .string = expr, .chan = chan };
 | 
						|
	int return_value = 0;
 | 
						|
 | 
						|
	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_number) {
 | 
						|
			int res_length;
 | 
						|
 | 
						|
			res_length = snprintf(buf, length, FP___PRINTF, io.val->u.i);
 | 
						|
			return_value = (res_length <= length) ? res_length : length;
 | 
						|
		} else {
 | 
						|
			if (io.val->u.s)
 | 
						|
#if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE)
 | 
						|
				strncpy(buf, io.val->u.s, length - 1);
 | 
						|
#else /* !STANDALONE && !LOW_MEMORY */
 | 
						|
				ast_copy_string(buf, io.val->u.s, length);
 | 
						|
#endif /* STANDALONE || LOW_MEMORY */
 | 
						|
			else
 | 
						|
				buf[0] = 0;
 | 
						|
			return_value = strlen(buf);
 | 
						|
			free(io.val->u.s);
 | 
						|
		}
 | 
						|
		free(io.val);
 | 
						|
	}
 | 
						|
	return return_value;
 | 
						|
}
 | 
						|
 | 
						|
#ifndef STANDALONE
 | 
						|
int ast_str_expr(struct ast_str **str, ssize_t maxlen, struct ast_channel *chan, char *expr)
 | 
						|
{
 | 
						|
	struct parse_io io = { .string = expr, .chan = chan };
 | 
						|
 | 
						|
	ast_yylex_init(&io.scanner);
 | 
						|
	ast_yy_scan_string(expr, io.scanner);
 | 
						|
	ast_yyparse ((void *) &io);
 | 
						|
	ast_yylex_destroy(io.scanner);
 | 
						|
 | 
						|
	if (!io.val) {
 | 
						|
		ast_str_set(str, maxlen, "0");
 | 
						|
	} else {
 | 
						|
		if (io.val->type == AST_EXPR_number) {
 | 
						|
			ast_str_set(str, maxlen, FP___PRINTF, io.val->u.i);
 | 
						|
		} else if (io.val->u.s) {
 | 
						|
			ast_str_set(str, maxlen, "%s", io.val->u.s);
 | 
						|
			free(io.val->u.s);
 | 
						|
		}
 | 
						|
		free(io.val);
 | 
						|
	}
 | 
						|
	return ast_str_strlen(*str);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
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 const char * const 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_COMMA",
 | 
						|
	"TOK_RP",
 | 
						|
	"TOK_LP"
 | 
						|
};
 | 
						|
 | 
						|
static const char * const expr2_token_equivs2[] = 
 | 
						|
{
 | 
						|
	"<token>",
 | 
						|
	"?",
 | 
						|
	"::",
 | 
						|
	"|",
 | 
						|
	"&",
 | 
						|
	"=",
 | 
						|
	">",
 | 
						|
	"<",
 | 
						|
	">=",
 | 
						|
	"<=",
 | 
						|
	"!=",
 | 
						|
	"+",
 | 
						|
	"-",
 | 
						|
	"*",
 | 
						|
	"/",
 | 
						|
	"%",
 | 
						|
	"!",
 | 
						|
	":",
 | 
						|
	"=~",
 | 
						|
	",",
 | 
						|
	")",
 | 
						|
	"("
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
static char *expr2_token_subst(const char *mess)
 | 
						|
{
 | 
						|
	/* calc a length, malloc, fill, and return; yyerror had better free it! */
 | 
						|
	int len=0,i;
 | 
						|
	const char *p;
 | 
						|
	char *res, *s;
 | 
						|
	const char *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 */
 | 
						|
	int i=0;
 | 
						|
	char *s2 = expr2_token_subst(s);
 | 
						|
	spacebuf[0] = 0;
 | 
						|
 | 
						|
	for (i = 0; i < (int)(yytext - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); i++) {
 | 
						|
		spacebuf[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. */
 | 
						|
 | 
						|
	spacebuf[i++] = '^';
 | 
						|
	spacebuf[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, spacebuf);
 | 
						|
#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, spacebuf);
 | 
						|
#endif
 | 
						|
#ifndef STANDALONE
 | 
						|
	ast_log(LOG_WARNING,"If you have questions, please refer to https://docs.asterisk.org/Configuration/Dialplan/Variables/Channel-Variables/\n");
 | 
						|
#endif
 | 
						|
	free(s2);
 | 
						|
	return(0);
 | 
						|
}
 |