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
2007-01-24 18:39:49 +00:00
static int global_lineno = 1 ;
static int global_expr_count = 0 ;
static int global_expr_max_size = 0 ;
static int global_expr_tot_size = 0 ;
static int global_warn_count = 0 ;
static int global_OK_count = 0 ;
2005-06-21 20:16:51 +00:00
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 ) ;
}
2007-01-24 18:39:49 +00:00
void ast_register_file_version ( const char * file , const char * version ) ;
void ast_unregister_file_version ( const char * file ) ;
char * find_var ( const char * varname ) ;
void set_var ( const char * varname , const char * varval ) ;
unsigned int check_expr ( char * buffer , char * error_report ) ;
int check_eval ( char * buffer , char * error_report ) ;
void parse_file ( const char * fname ) ;
void ast_register_file_version ( const char * file , const char * version )
{
}
void ast_unregister_file_version ( const char * file )
{
}
2005-06-21 20:16:51 +00:00
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 )
{
2007-01-24 18:39:49 +00:00
struct varz * t = ( struct varz * ) calloc ( 1 , sizeof ( struct varz ) ) ;
2006-11-06 18:05:11 +00:00
if ( ! t )
return ;
2005-06-21 20:16:51 +00:00
strcpy ( t - > varname , varname ) ;
strcpy ( t - > varval , varval ) ;
t - > next = global_varlist ;
global_varlist = t ;
}
2005-06-09 20:50:48 +00:00
2007-01-24 18:39:49 +00:00
unsigned int check_expr ( char * buffer , char * error_report )
2005-06-09 20:50:48 +00:00
{
2007-01-24 18:39:49 +00:00
char * cp ;
unsigned int warn_found = 0 ;
2005-06-09 20:50:48 +00:00
error_report [ 0 ] = 0 ;
2007-01-24 18:39:49 +00:00
for ( cp = buffer ; * cp ; + + cp )
{
switch ( * cp )
{
case ' " ' :
2005-06-09 20:50:48 +00:00
/* skip to the other end */
2007-01-24 18:39:49 +00:00
while ( * ( + + cp ) & & * cp ! = ' " ' ) ;
if ( * cp = = 0 )
{
fprintf ( stderr ,
" Trouble? Unterminated double quote found at line %d \n " ,
global_lineno ) ;
2005-06-09 20:50:48 +00:00
}
2007-01-24 18:39:49 +00:00
break ;
case ' > ' :
case ' < ' :
case ' ! ' :
if ( ( * ( cp + 1 ) = = ' = ' )
& & ( ( ( cp > buffer ) & & ( * ( cp - 1 ) ! = ' ' ) ) | | ( * ( cp + 2 ) ! = ' ' ) ) )
{
char msg [ 200 ] ;
snprintf ( msg ,
sizeof ( msg ) ,
" 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 " ,
global_lineno , * cp , * ( cp + 1 ) ) ;
strcat ( error_report , msg ) ;
+ + global_warn_count ;
+ + warn_found ;
2005-06-09 20:50:48 +00:00
}
2007-01-24 18:39:49 +00:00
break ;
2005-06-09 20:50:48 +00:00
2007-01-24 18:39:49 +00:00
case ' | ' :
case ' & ' :
case ' = ' :
case ' + ' :
case ' - ' :
case ' * ' :
case ' / ' :
case ' % ' :
case ' ? ' :
case ' : ' :
if ( ( ( cp > buffer ) & & ( * ( cp - 1 ) ! = ' ' ) ) | | ( * ( cp + 1 ) ! = ' ' ) )
{
char msg [ 200 ] ;
snprintf ( msg ,
sizeof ( msg ) ,
" 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 " ,
global_lineno , * cp ) ;
strcat ( error_report , msg ) ;
+ + global_warn_count ;
+ + warn_found ;
2005-06-09 20:50:48 +00:00
}
2007-01-24 18:39:49 +00:00
break ;
2005-06-09 20:50:48 +00:00
}
}
2007-01-24 18:39:49 +00:00
2005-06-09 20:50:48 +00:00
return warn_found ;
}
2005-06-21 20:16:51 +00:00
int check_eval ( char * buffer , char * error_report )
{
2007-01-24 18:39:49 +00:00
char * cp , * ep ;
2005-08-29 22:03:37 +00:00
char s [ 4096 ] ;
2005-06-21 20:16:51 +00:00
char evalbuf [ 80000 ] ;
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 ) {
2007-01-24 18:39:49 +00:00
fprintf ( stderr , " Couldn't open %s for reading... need an extensions.conf file to parse! \n " , fname ) ;
2005-06-09 20:50:48 +00:00
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 ) ;
}
2007-01-24 18:39:49 +00:00
int main ( int argc , char * * argv )
2005-06-09 20:50:48 +00:00
{
2005-06-21 20:16:51 +00:00
int argc1 ;
char * eq ;
if ( argc < 2 ) {
2007-01-24 18:39:49 +00:00
printf ( " check_expr -- a program to look thru extensions.conf files for $[...] expressions, \n " ) ;
printf ( " and run them thru the parser, looking for problems \n " ) ;
2005-06-09 20:50:48 +00:00
printf ( " Hey-- give me a path to an extensions.conf file! \n " ) ;
2007-01-24 18:39:49 +00:00
printf ( " You can also follow the file path with a series of variable decls, \n " ) ;
printf ( " of the form, varname=value, each separated from the next by spaces. \n " ) ;
printf ( " (this might allow you to avoid division by zero messages, check that math \n " ) ;
printf ( " is being done correctly, etc.) \n " ) ;
printf ( " Note that messages about operators not being surrounded by spaces is merely to alert \n " ) ;
printf ( " you to possible problems where you might be expecting those operators as part of a string. \n " ) ;
printf ( " (to include operators in a string, wrap with double quotes!) \n " ) ;
2005-06-09 20:50:48 +00:00
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 ] ) ;
2007-01-24 18:39:49 +00:00
return 0 ;
2005-06-09 20:50:48 +00:00
}