Skip to content
Snippets Groups Projects
ast_expr2f.c 69.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	for ( i = 0; i < _yybytes_len; ++i )
    		buf[i] = yybytes[i];
    
    	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
    
    
    	b = ast_yy_scan_buffer(buf,n ,yyscanner);
    	if ( ! b )
    		YY_FATAL_ERROR( "bad buffer in ast_yy_scan_bytes()" );
    
    	/* It's okay to grow etc. this buffer, and we should throw it
    	 * away when we're done.
    	 */
    	b->yy_is_our_buffer = 1;
    
    	return b;
    }
    
    #ifndef YY_EXIT_FAILURE
    #define YY_EXIT_FAILURE 2
    #endif
    
    static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
    {
        	(void) fprintf( stderr, "%s\n", msg );
    	exit( YY_EXIT_FAILURE );
    }
    
    /* Redefine yyless() so it works in section 3 code. */
    
    #undef yyless
    #define yyless(n) \
    	do \
    		{ \
    		/* Undo effects of setting up yytext. */ \
            int yyless_macro_arg = (n); \
            YY_LESS_LINENO(yyless_macro_arg);\
    		yytext[yyleng] = yyg->yy_hold_char; \
    		yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
    		yyg->yy_hold_char = *yyg->yy_c_buf_p; \
    		*yyg->yy_c_buf_p = '\0'; \
    		yyleng = yyless_macro_arg; \
    		} \
    	while ( 0 )
    
    /* Accessor  methods (get/set functions) to struct members. */
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /** Get the user-defined data for this scanner.
     * @param yyscanner The scanner object.
    
     */
    YY_EXTRA_TYPE ast_yyget_extra  (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        return yyextra;
    }
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /** Get the current line number.
     * @param yyscanner The scanner object.
    
     */
    int ast_yyget_lineno  (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        
            if (! YY_CURRENT_BUFFER)
                return 0;
        
        return yylineno;
    }
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /** Get the current column number.
     * @param yyscanner The scanner object.
    
     */
    int ast_yyget_column  (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        
            if (! YY_CURRENT_BUFFER)
                return 0;
        
        return yycolumn;
    }
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /** Get the input stream.
     * @param yyscanner The scanner object.
    
     */
    FILE *ast_yyget_in  (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        return yyin;
    }
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /** Get the output stream.
     * @param yyscanner The scanner object.
    
     */
    FILE *ast_yyget_out  (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        return yyout;
    }
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /** Get the length of the current token.
     * @param yyscanner The scanner object.
    
     */
    int ast_yyget_leng  (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        return yyleng;
    }
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /** Get the current token.
     * @param yyscanner The scanner object.
    
     */
    
    char *ast_yyget_text  (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        return yytext;
    }
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /** Set the user-defined data. This data is never touched by the scanner.
     * @param user_defined The data to be associated with this scanner.
     * @param yyscanner The scanner object.
    
     */
    void ast_yyset_extra (YY_EXTRA_TYPE  user_defined , yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        yyextra = user_defined ;
    }
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /** Set the current line number.
     * @param line_number
     * @param yyscanner The scanner object.
    
     */
    void ast_yyset_lineno (int  line_number , yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
    
            /* lineno is only valid if an input buffer exists. */
            if (! YY_CURRENT_BUFFER )
               yy_fatal_error( "ast_yyset_lineno called with no buffer" , yyscanner); 
        
        yylineno = line_number;
    }
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /** Set the current column.
    
     * \param column_no line_number
     * \param yyscanner The scanner object.
    
     */
    void ast_yyset_column (int  column_no , yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
    
            /* column is only valid if an input buffer exists. */
            if (! YY_CURRENT_BUFFER )
               yy_fatal_error( "ast_yyset_column called with no buffer" , yyscanner); 
        
        yycolumn = column_no;
    }
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /** Set the input stream. This does not discard the current
    
     * input buffer.
    
    Steve Murphy's avatar
    Steve Murphy committed
     * @param in_str A readable stream.
     * @param yyscanner The scanner object.
     * @see ast_yy_switch_to_buffer
    
     */
    void ast_yyset_in (FILE *  in_str , yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        yyin = in_str ;
    }
    
    void ast_yyset_out (FILE *  out_str , yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        yyout = out_str ;
    }
    
    int ast_yyget_debug  (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        return yy_flex_debug;
    }
    
    void ast_yyset_debug (int  bdebug , yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        yy_flex_debug = bdebug ;
    }
    
    /* Accessor methods for yylval and yylloc */
    
    YYSTYPE * ast_yyget_lval  (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        return yylval;
    }
    
    void ast_yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        yylval = yylval_param;
    }
    
    YYLTYPE *ast_yyget_lloc  (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        return yylloc;
    }
        
    void ast_yyset_lloc (YYLTYPE *  yylloc_param , yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        yylloc = yylloc_param;
    }
        
    
    /* User-visible API */
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* ast_yylex_init is special because it creates the scanner itself, so it is
     * the ONLY reentrant function that doesn't take the scanner as the last argument.
     * That's why we explicitly handle the declaration, instead of using our macros.
    
     */
    
    int ast_yylex_init(yyscan_t* ptr_yy_globals)
    
    {
        if (ptr_yy_globals == NULL){
            errno = EINVAL;
            return 1;
        }
    
        *ptr_yy_globals = (yyscan_t) ast_yyalloc ( sizeof( struct yyguts_t ), NULL );
    
        if (*ptr_yy_globals == NULL){
            errno = ENOMEM;
            return 1;
        }
    
        /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
        memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
    
        return yy_init_globals ( *ptr_yy_globals );
    }
    
    
    /* ast_yylex_init_extra has the same functionality as ast_yylex_init, but follows the
     * convention of taking the scanner as the last argument. Note however, that
     * this is a *pointer* to a scanner, as it will be allocated by this call (and
     * is the reason, too, why this function also must handle its own declaration).
     * The user defined value in the first argument will be available to ast_yyalloc in
     * the yyextra field.
     */
    
    int ast_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
    
    {
        struct yyguts_t dummy_yyguts;
    
        ast_yyset_extra (yy_user_defined, &dummy_yyguts);
    
        if (ptr_yy_globals == NULL){
            errno = EINVAL;
            return 1;
        }
    	
        *ptr_yy_globals = (yyscan_t) ast_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
    	
        if (*ptr_yy_globals == NULL){
            errno = ENOMEM;
            return 1;
        }
        
        /* By setting to 0xAA, we expose bugs in
        yy_init_globals. Leave at 0x00 for releases. */
        memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
        
        ast_yyset_extra (yy_user_defined, *ptr_yy_globals);
        
        return yy_init_globals ( *ptr_yy_globals );
    }
    
    
    static int yy_init_globals (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
        /* Initialization is the same as for the non-reentrant scanner.
    
         * This function is called from ast_yylex_destroy(), so don't allocate here.
         */
    
    
        yyg->yy_buffer_stack = 0;
        yyg->yy_buffer_stack_top = 0;
        yyg->yy_buffer_stack_max = 0;
        yyg->yy_c_buf_p = (char *) 0;
    
        yyg->yy_init = 0;
    
        yyg->yy_start_stack_ptr = 0;
        yyg->yy_start_stack_depth = 0;
    
        yyg->yy_start_stack =  NULL;
    
    
    /* Defined in main.c */
    #ifdef YY_STDINIT
        yyin = stdin;
        yyout = stdout;
    #else
        yyin = (FILE *) 0;
        yyout = (FILE *) 0;
    #endif
    
        /* For future reference: Set errno on error, since we are called by
         * ast_yylex_init()
         */
        return 0;
    }
    
    
    /* ast_yylex_destroy is for both reentrant and non-reentrant scanners. */
    
    int ast_yylex_destroy  (yyscan_t yyscanner)
    {
        struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
    
        /* Pop the buffer stack, destroying each element. */
    	while(YY_CURRENT_BUFFER){
    		ast_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
    		YY_CURRENT_BUFFER_LVALUE = NULL;
    		ast_yypop_buffer_state(yyscanner);
    	}
    
    	/* Destroy the stack itself. */
    	ast_yyfree(yyg->yy_buffer_stack ,yyscanner);
    	yyg->yy_buffer_stack = NULL;
    
        /* Destroy the start condition stack. */
            ast_yyfree(yyg->yy_start_stack ,yyscanner );
            yyg->yy_start_stack = NULL;
    
    
        /* Reset the globals. This is important in a non-reentrant scanner so the next time
         * ast_yylex() is called, initialization will occur. */
        yy_init_globals( yyscanner);
    
    
        /* Destroy the main struct (reentrant only). */
        ast_yyfree ( yyscanner , yyscanner );
    
        yyscanner = NULL;
    
        return 0;
    }
    
    /*
     * Internal utility routines.
     */
    
    #ifndef yytext_ptr
    static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
    {
    	register int i;
    	for ( i = 0; i < n; ++i )
    		s1[i] = s2[i];
    }
    #endif
    
    #ifdef YY_NEED_STRLEN
    static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
    {
    	register int n;
    	for ( n = 0; s[n]; ++n )
    		;
    
    	return n;
    }
    #endif
    
    void *ast_yyalloc (yy_size_t  size , yyscan_t yyscanner)
    {
    	return (void *) malloc( size );
    }
    
    void *ast_yyrealloc  (void * ptr, yy_size_t  size , yyscan_t yyscanner)
    {
    	/* The cast to (char *) in the following accommodates both
    	 * implementations that use char* generic pointers, and those
    	 * that use void* generic pointers.  It works with the latter
    	 * because both ANSI C and C++ allow castless assignment from
    	 * any pointer type to void*, and deal with argument conversions
    	 * as though doing an assignment.
    	 */
    	return (void *) realloc( (char *) ptr, size );
    }
    
    #define YYTABLES_NAME "yytables"
    
    
    #line 238 "ast_expr2.fl"
    
    
    
    
    /* 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 ast_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);
    
    			return_value = 1;
    
    		if (io.val->type == AST_EXPR_number) {
    
    			res_length = snprintf(buf, length, FP___PRINTF, io.val->u.i);
    
    			return_value = (res_length <= length) ? res_length : length;
    
    #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 */
    
    			return_value = strlen(buf);
    
    	return return_value;
    
    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",
    
    static const char * const expr2_token_equivs2[] = 
    
    static char *expr2_token_subst(const char *mess)
    
    {
    	/* calc a length, malloc, fill, and return; yyerror had better free it! */
    	int len=0,i;
    
    	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);
    
    
    	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
    		ast_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);
    
    	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);
    
    	ast_log(LOG_WARNING,"If you have questions, please refer to https://wiki.asterisk.org/wiki/display/AST/Channel+Variables\n");