2005-09-14 20:46:50 +00:00
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, 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.
*/
2005-06-09 20:50:48 +00:00
#include <stdio.h>
#include <stddef.h>
2005-06-21 20:16:51 +00:00
#include <stdarg.h>
2005-06-09 20:50:48 +00:00
#include <string.h>
#include <stdlib.h>
2005-08-29 22:03:37 +00:00
#include <../include/asterisk/ast_expr.h>
2005-06-09 20:50:48 +00:00
2005-06-21 20:16:51 +00:00
int global_lineno = 1 ;
int global_expr_count = 0 ;
int global_expr_max_size = 0 ;
int global_expr_tot_size = 0 ;
int global_warn_count = 0 ;
int global_OK_count = 0 ;
struct varz
{
char varname [ 100 ]; /* a really ultra-simple, space-wasting linked list of var=val data */
char varval [ 1000 ]; /* if any varname is bigger than 100 chars, or val greater than 1000, then **CRASH** */
struct varz * next ;
};
struct varz * global_varlist ;
/* Our own version of ast_log, since the expr parser uses it. */
void ast_log ( int level , const char * file , int line , const char * function , const char * fmt , ...) __attribute__ (( format ( printf , 5 , 6 )));
void ast_log ( int level , const char * file , int line , const char * function , const char * fmt , ...)
{
va_list vars ;
va_start ( vars , fmt );
printf ( "LOG: lev:%d file:%s line:%d func: %s " ,
level , file , line , function );
vprintf ( fmt , vars );
fflush ( stdout );
va_end ( vars );
}
char * find_var ( const char * varname ) /* the list should be pretty short, if there's any list at all */
{
struct varz * t ;
for ( t = global_varlist ; t ; t = t -> next ) {
if ( ! strcmp ( t -> varname , varname )) {
return t -> varval ;
}
}
return 0 ;
}
void set_var ( const char * varname , const char * varval )
{
struct varz * t = calloc ( 1 , sizeof ( struct varz ));
strcpy ( t -> varname , varname );
strcpy ( t -> varval , varval );
t -> next = global_varlist ;
global_varlist = t ;
}
2005-06-09 20:50:48 +00:00
int check_expr ( char * buffer , char * error_report )
{
char * cp ;
int oplen = 0 ;
int warn_found = 0 ;
error_report [ 0 ] = 0 ;
2005-06-21 20:16:51 +00:00
for ( cp = buffer ; * cp ; cp ++ ) {
2005-06-09 20:50:48 +00:00
2005-06-21 20:16:51 +00:00
if ( * cp == '|'
2005-06-09 20:50:48 +00:00
|| * cp == '&'
|| * cp == '='
|| * cp == '>'
|| * cp == '<'
|| * cp == '+'
|| * cp == '-'
|| * cp == '*'
|| * cp == '/'
|| * cp == '%'
|| * cp == '?'
|| * cp == ':'
/* || *cp == '('
|| *cp == ')' These are pretty hard to track, as they are in funcalls, etc. */
2005-06-21 20:16:51 +00:00
|| * cp == '"' ) {
if ( * cp == '"' ) {
2005-06-09 20:50:48 +00:00
/* skip to the other end */
cp ++ ;
2005-06-21 20:16:51 +00:00
while ( * cp && * cp != '"' )
2005-06-09 20:50:48 +00:00
cp ++ ;
2005-06-21 20:16:51 +00:00
if ( * cp == 0 ) {
2005-06-09 20:50:48 +00:00
fprintf ( stderr , "Trouble? Unterminated double quote found at line %d \n " ,
2005-06-21 20:16:51 +00:00
global_lineno );
2005-06-09 20:50:48 +00:00
}
}
2005-06-21 20:16:51 +00:00
else {
if (( * cp == '>' ||* cp == '<' ||* cp == '!' ) && ( * ( cp + 1 ) == '=' )) {
2005-06-09 20:50:48 +00:00
oplen = 2 ;
}
2005-06-21 20:16:51 +00:00
else {
2005-06-09 20:50:48 +00:00
oplen = 1 ;
}
2005-06-21 20:16:51 +00:00
if (( cp > buffer && * ( cp - 1 ) != ' ' ) || * ( cp + oplen ) != ' ' ) {
2005-06-09 20:50:48 +00:00
char tbuf [ 1000 ];
2005-06-21 20:16:51 +00:00
if ( oplen == 1 )
2005-06-09 20:50:48 +00:00
sprintf ( tbuf , "WARNING: line %d, '%c' operator not separated by spaces. This may lead to confusion. You may wish to use double quotes to quote the grouping it is in. Please check! \n " ,
2005-06-21 20:16:51 +00:00
global_lineno , * cp );
2005-06-09 20:50:48 +00:00
else
sprintf ( tbuf , "WARNING: line %d, '%c%c' operator not separated by spaces. This may lead to confusion. You may wish to use double quotes to quote the grouping it is in. Please check! \n " ,
2005-06-21 20:16:51 +00:00
global_lineno , * cp , * ( cp + 1 ));
2005-06-09 20:50:48 +00:00
strcat ( error_report , tbuf );
2005-06-21 20:16:51 +00:00
global_warn_count ++ ;
2005-06-09 20:50:48 +00:00
warn_found ++ ;
}
}
}
}
return warn_found ;
}
2005-06-21 20:16:51 +00:00
int check_eval ( char * buffer , char * error_report )
{
2005-08-29 22:03:37 +00:00
char * cp , * ep , * xp ;
char s [ 4096 ];
2005-06-21 20:16:51 +00:00
char evalbuf [ 80000 ];
int oplen = 0 ;
int warn_found = 0 ;
2005-08-29 22:03:37 +00:00
int result ;
2005-06-21 20:16:51 +00:00
error_report [ 0 ] = 0 ;
ep = evalbuf ;
for ( cp = buffer ; * cp ; cp ++ ) {
if ( * cp == '$' && * ( cp + 1 ) == '{' ) {
int brack_lev = 1 ;
char * xp = cp + 2 ;
while ( * xp ) {
if ( * xp == '{' )
brack_lev ++ ;
else if ( * xp == '}' )
brack_lev -- ;
if ( brack_lev == 0 )
break ;
xp ++ ;
}
if ( * xp == '}' ) {
char varname [ 200 ];
char * val ;
strncpy ( varname , cp + 2 , xp - cp - 2 );
varname [ xp - cp - 2 ] = 0 ;
cp = xp ;
val = find_var ( varname );
if ( val ) {
char * z = val ;
while ( * z )
* ep ++ = * z ++ ;
}
else {
* ep ++ = '5' ; /* why not */
* ep ++ = '5' ;
* ep ++ = '5' ;
}
}
else {
printf ( "Unterminated variable reference at line %d \n " , global_lineno );
* ep ++ = * cp ;
}
}
else if ( * cp == '\\' ) {
/* braindead simple elim of backslash */
cp ++ ;
* ep ++ = * cp ;
}
else
* ep ++ = * cp ;
}
* ep ++ = 0 ;
/* now, run the test */
2005-08-29 22:03:37 +00:00
result = ast_expr ( evalbuf , s , sizeof ( s ));
if ( result ) {
2005-06-21 20:16:51 +00:00
sprintf ( error_report , "line %d, evaluation of $[ %s ] result: %s \n " , global_lineno , evalbuf , s );
return 1 ;
2005-08-29 22:03:37 +00:00
} else {
2005-06-21 20:16:51 +00:00
sprintf ( error_report , "line %d, evaluation of $[ %s ] result: ****SYNTAX ERROR**** \n " , global_lineno , evalbuf );
return 1 ;
}
}
2005-06-09 20:50:48 +00:00
2005-06-21 20:16:51 +00:00
void parse_file ( const char * fname )
2005-06-09 20:50:48 +00:00
{
FILE * f = fopen ( fname , "r" );
FILE * l = fopen ( "expr2_log" , "w" );
int c1 ;
char last_char = 0 ;
char buffer [ 30000 ]; /* I sure hope no expr gets this big! */
2005-06-21 20:16:51 +00:00
if ( ! f ) {
2005-06-09 20:50:48 +00:00
fprintf ( stderr , "Couldn't open %s for reading... need an extensions.conf file to parse! \n " );
exit ( 20 );
}
2005-06-21 20:16:51 +00:00
if ( ! l ) {
2005-06-09 20:50:48 +00:00
fprintf ( stderr , "Couldn't open 'expr2_log' file for writing... please fix and re-run! \n " );
exit ( 21 );
}
2005-06-21 20:16:51 +00:00
global_lineno = 1 ;
2005-06-09 20:50:48 +00:00
2005-06-21 20:16:51 +00:00
while (( c1 = fgetc ( f )) != EOF ) {
if ( c1 == '\n' )
global_lineno ++ ;
else if ( c1 == '[' ) {
if ( last_char == '$' ) {
2005-06-09 20:50:48 +00:00
/* bingo, an expr */
int bracklev = 1 ;
int bufcount = 0 ;
int retval ;
char error_report [ 30000 ];
2005-06-21 20:16:51 +00:00
while (( c1 = fgetc ( f )) != EOF ) {
if ( c1 == '[' )
2005-06-09 20:50:48 +00:00
bracklev ++ ;
2005-06-21 20:16:51 +00:00
else if ( c1 == ']' )
2005-06-09 20:50:48 +00:00
bracklev -- ;
2005-06-21 20:16:51 +00:00
if ( c1 == '\n' ) {
fprintf ( l , "ERROR-- A newline in an expression? Weird! ...at line %d \n " , global_lineno );
2005-06-09 20:50:48 +00:00
fclose ( f );
fclose ( l );
2005-06-21 20:16:51 +00:00
printf ( "--- ERROR --- A newline in the middle of an expression at line %d! \n " , global_lineno );
2005-06-09 20:50:48 +00:00
}
2005-06-21 20:16:51 +00:00
if ( bracklev == 0 )
2005-06-09 20:50:48 +00:00
break ;
buffer [ bufcount ++ ] = c1 ;
}
2005-06-21 20:16:51 +00:00
if ( c1 == EOF ) {
fprintf ( l , "ERROR-- End of File Reached in the middle of an Expr at line %d \n " , global_lineno );
2005-06-09 20:50:48 +00:00
fclose ( f );
fclose ( l );
2005-06-21 20:16:51 +00:00
printf ( "--- ERROR --- EOF reached in middle of an expression at line %d! \n " , global_lineno );
2005-06-09 20:50:48 +00:00
exit ( 22 );
}
buffer [ bufcount ] = 0 ;
/* update stats */
2005-06-21 20:16:51 +00:00
global_expr_tot_size += bufcount ;
global_expr_count ++ ;
if ( bufcount > global_expr_max_size )
global_expr_max_size = bufcount ;
2005-06-09 20:50:48 +00:00
retval = check_expr ( buffer , error_report ); /* check_expr should bump the warning counter */
2005-06-21 20:16:51 +00:00
if ( retval != 0 ) {
2005-06-09 20:50:48 +00:00
/* print error report */
printf ( "Warning(s) at line %d, expression: $[%s]; see expr2_log file for details \n " ,
2005-06-21 20:16:51 +00:00
global_lineno , buffer );
2005-06-09 20:50:48 +00:00
fprintf ( l , "%s" , error_report );
}
2005-06-21 20:16:51 +00:00
else {
printf ( "OK -- $[%s] at line %d \n " , buffer , global_lineno );
global_OK_count ++ ;
2005-06-09 20:50:48 +00:00
}
2005-06-21 20:16:51 +00:00
error_report [ 0 ] = 0 ;
retval = check_eval ( buffer , error_report );
fprintf ( l , "%s" , error_report );
2005-06-09 20:50:48 +00:00
}
}
last_char = c1 ;
}
printf ( "Summary: \n Expressions detected: %d \n Expressions OK: %d \n Total # Warnings: %d \n Longest Expr: %d chars \n Ave expr len: %d chars \n " ,
2005-06-21 20:16:51 +00:00
global_expr_count ,
global_OK_count ,
global_warn_count ,
global_expr_max_size ,
( global_expr_count ) ? global_expr_tot_size / global_expr_count : 0 );
2005-06-09 20:50:48 +00:00
fclose ( f );
fclose ( l );
}
main ( int argc , char ** argv )
{
2005-06-21 20:16:51 +00:00
int argc1 ;
char * eq ;
if ( argc < 2 ) {
2005-06-09 20:50:48 +00:00
printf ( "Hey-- give me a path to an extensions.conf file! \n " );
exit ( 19 );
}
2005-06-21 20:16:51 +00:00
global_varlist = 0 ;
for ( argc1 = 2 ; argc1 < argc ; argc1 ++ ) {
if (( eq = strchr ( argv [ argc1 ], '=' ))) {
* eq = 0 ;
set_var ( argv [ argc1 ], eq + 1 );
}
}
/* parse command args for x=y and set varz */
2005-06-09 20:50:48 +00:00
parse_file ( argv [ 1 ]);
}