Index: utils/Makefile =================================================================== RCS file: /usr/cvsroot/asterisk/utils/Makefile,v retrieving revision 1.11 diff -u -r1.11 Makefile --- utils/Makefile 9 Jun 2005 21:12:03 -0000 1.11 +++ utils/Makefile 18 Jun 2005 07:19:19 -0000 @@ -34,6 +34,9 @@ stereorize: stereorize.o frame.o $(CC) $(CFLAGS) -o stereorize stereorize.o frame.o -lm +check_expr : check_expr.c ../ast_expr.a + $(CC) $(CFLAGS) -o check_expr check_expr.c ../ast_expr.a + smsq: smsq.o $(CC) $(CFLAGS) -o smsq ${SOL} smsq.o -lpopt Index: utils/check_expr.c =================================================================== RCS file: /usr/cvsroot/asterisk/utils/check_expr.c,v retrieving revision 1.1 diff -u -r1.1 check_expr.c --- utils/check_expr.c 9 Jun 2005 20:50:48 -0000 1.1 +++ utils/check_expr.c 18 Jun 2005 07:19:19 -0000 @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -10,6 +11,51 @@ int warn_count = 0; int OK_count = 0; +struct varz +{ + char varname[100]; /* a really ultra-simple, space-wasting linked list of var=val data */ + char varval[1000]; + struct varz *next; +}; + +struct varz *varlist; + +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(char *varname) /* the list should be pretty short, if there's any list at all */ +{ + struct varz *t; + for( t= varlist; t; t = t->next ) + { + if( !strcmp(t->varname, varname) ) + { + return t->varval; + } + } + return 0; +} + +void set_var(char *varname, char *varval) +{ + struct varz *t = calloc(1,sizeof(struct varz)); + strcpy(t->varname, varname); + strcpy(t->varval, varval); + t->next = varlist; + varlist = t; +} + int check_expr(char *buffer, char *error_report) { char *cp; @@ -80,6 +126,88 @@ return warn_found; } +int check_eval(char *buffer, char *error_report) +{ + char *cp, *ep, *xp, *s; + char evalbuf[80000]; + extern char *ast_expr(char *); + int oplen = 0; + int warn_found = 0; + + 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", lineno); + *ep++ = *cp; + } + } + else if( *cp == '\\' ) + { + /* braindead simple elim of backslash */ + cp++; + *ep++ = *cp; + } + else + *ep++ = *cp; + } + *ep++ = 0; + + /* now, run the test */ + s = ast_expr(evalbuf); + if( s ) + { + sprintf(error_report,"evaluation of $[ %s ] result: %s\n", evalbuf, s); + return 1; + } + else + { + sprintf(error_report,"evaluation of $[ %s ] result: ****SYNTAX ERROR****\n", evalbuf); + return 1; + } +} + void parse_file(char *fname) { @@ -163,6 +291,9 @@ printf("OK -- $[%s] at line %d\n", buffer, lineno); OK_count++; } + error_report[0] = 0; + retval = check_eval(buffer, error_report); + fprintf(l, "%s", error_report); } } last_char = c1; @@ -181,11 +312,25 @@ main(int argc,char **argv) { + int argc1; + char *eq; + if( argc < 2 ) { printf("Hey-- give me a path to an extensions.conf file!\n"); exit(19); } + 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 */ parse_file(argv[1]); } Index: doc/README.variables =================================================================== RCS file: /usr/cvsroot/asterisk/doc/README.variables,v retrieving revision 1.46 diff -u -r1.46 README.variables --- doc/README.variables 16 May 2005 00:43:16 -0000 1.46 +++ doc/README.variables 18 Jun 2005 07:19:20 -0000 @@ -498,6 +520,74 @@ ** match anywhere in the string. The only diff with the ':' is that ** match doesn't have to be anchored to the beginning of the string. + +-------------------------------------------------------- +Debugging Hints for $[ ] expressions +-------------------------------------------------------- + +** THE FOLLOWING UTILITIES ARE PROVIDED ONLY FOR SYSTEMS THAT +** HAVE FLEX-2.5.31 OR GREATER, AND USE THE UPGRADED LEXER!!! +** +** There are two utilities you can build to help debug the $[ ] in +** your extensions.conf file. +** +** The first, and most simplistic, is to issue the command: +** +** make testexpr2 +** +** in the top level asterisk source directory. This will build +** a small executable, that is able to take the first command line +** argument, and run it thru the expression parser. No variable +** substitutions will be performed. It might be safest to wrap +** the expression in single quotes... +** +** testexpr2 '2*2+2/2' +** +** is an example. +** +** And, in the utils directory, you can say: +** +** make check_expr +** +** and a small program will be built, that will check the file +** mentioned in the first command line argument, for any expressions +** that might be have problems when you move to flex-2.5.31. +** It was originally designed to help spot possible incompatibilities +** when moving from the pre-2.5.31 world to the upgraded version of +** the lexer. +** +** But one more capability has been added to check_expr, that might +** make it more generally useful. It now does a simple minded evaluation of +** all variables, and then passes the $[] exprs to the parser. If there are +** any parse errors, they will be reported in the log file. You can use +** check_expr to do a quick sanity check of the expressions in your +** extensions.conf file, to see if they pass a crude syntax check. +** +** The "simple-minded" variable substitution replaces ${varname} variable +** references with '555'. You can override the 555 for variable values, +** by entering in var=val arguments after the filename on the command line. +** So... +** +** check_expr /etc/asterisk/extensions.conf CALLERIDNUM=3075551212 DIALSTATUS=TORTURE EXTEN=121 +** +** will substitute any ${CALLERIDNUM} variable references with 3075551212, any ${DIALSTATUS} +** variable references with 'TORTURE', and any ${EXTEN} references with '121'. +** If there is any fancy stuff going on in the reference, like ${EXTEN:2}, then the +** override will not work. Everything in the ${...} has to match. So, to substitute +** #{EXTEN:2} references, you'd best say: +** +** check_expr /etc/asterisk/extensions.conf CALLERIDNUM=3075551212 DIALSTATUS=TORTURE EXTEN:2=121 +** +** on stdout, you will see something like: +** +** OK -- $[ "${DIALSTATUS}" = "TORTURE" | "${DIALSTATUS}" = "DONTCALL" ] at line 416 +** +** In the expr2_log file that is generated, you will see: +** +** evaluation of $[ "TORTURE" = "TORTURE" | "TORTURE" = "DONTCALL" ] result: 1 +** +** check_expr is a very simplistic algorithm, and it is far from being guaranteed +** to work in all cases, but it is hoped that it will be useful. --------------------------------------------------------- Asterisk standard channel variables