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:26:22 +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. */
2008-11-29 16:58:29 +00:00
void ast_log ( int level , const char * file , int line , const char * function , const char * fmt , ...) __attribute__ (( format ( printf , 5 , 6 )));
2005-06-21 20:16:51 +00:00
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:26:22 +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:26:22 +00:00
struct varz * t = ( struct varz * ) calloc ( 1 , sizeof ( struct varz ));
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:26:22 +00:00
unsigned int check_expr ( char * buffer , char * error_report )
2005-06-09 20:50:48 +00:00
{
2007-01-24 18:26:22 +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:26:22 +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:26:22 +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:26:22 +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:26:22 +00:00
break ;
2005-06-09 20:50:48 +00:00
2007-01-24 18:26:22 +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:26:22 +00:00
break ;
2005-06-09 20:50:48 +00:00
}
}
2007-01-24 18:26:22 +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:26:22 +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:26:22 +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:26:22 +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:26:22 +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:26:22 +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:26:22 +00:00
return 0;
2005-06-09 20:50:48 +00:00
}