2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
24 #include <../include/asterisk/ast_expr.h>
26 static int global_lineno
= 1;
27 static int global_expr_count
=0;
28 static int global_expr_max_size
=0;
29 static int global_expr_tot_size
=0;
30 static int global_warn_count
=0;
31 static int global_OK_count
=0;
35 char varname
[100]; /* a really ultra-simple, space-wasting linked list of var=val data */
36 char varval
[1000]; /* if any varname is bigger than 100 chars, or val greater than 1000, then **CRASH** */
40 struct varz
*global_varlist
;
42 /* Our own version of ast_log, since the expr parser uses it. */
44 void ast_log(int level
, const char *file
, int line
, const char *function
, const char *fmt
, ...) __attribute__ ((format (printf
,5,6)));
46 void ast_log(int level
, const char *file
, int line
, const char *function
, const char *fmt
, ...)
51 printf("LOG: lev:%d file:%s line:%d func: %s ",
52 level
, file
, line
, function
);
57 void ast_register_file_version(const char *file
, const char *version
);
58 void ast_unregister_file_version(const char *file
);
60 char *find_var(const char *varname
);
61 void set_var(const char *varname
, const char *varval
);
62 unsigned int check_expr(char* buffer
, char* error_report
);
63 int check_eval(char *buffer
, char *error_report
);
64 void parse_file(const char *fname
);
66 void ast_register_file_version(const char *file
, const char *version
)
70 void ast_unregister_file_version(const char *file
)
74 char *find_var(const char *varname
) /* the list should be pretty short, if there's any list at all */
77 for (t
= global_varlist
; t
; t
= t
->next
) {
78 if (!strcmp(t
->varname
, varname
)) {
85 void set_var(const char *varname
, const char *varval
)
87 struct varz
*t
= (struct varz
*)calloc(1,sizeof(struct varz
));
88 strcpy(t
->varname
, varname
);
89 strcpy(t
->varval
, varval
);
90 t
->next
= global_varlist
;
94 unsigned int check_expr(char* buffer
, char* error_report
)
97 unsigned int warn_found
= 0;
101 for (cp
= buffer
; *cp
; ++cp
)
106 /* skip to the other end */
107 while (*(++cp
) && *cp
!= '"') ;
112 "Trouble? Unterminated double quote found at line %d\n",
120 if ( (*(cp
+ 1) == '=')
121 && ( ( (cp
> buffer
) && (*(cp
- 1) != ' ') ) || (*(cp
+ 2) != ' ') ) )
126 "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",
127 global_lineno
, *cp
, *(cp
+ 1));
128 strcat(error_report
, msg
);
144 if ( ( (cp
> buffer
) && (*(cp
- 1) != ' ') ) || (*(cp
+ 1) != ' ') )
149 "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",
150 global_lineno
, *cp
);
151 strcat(error_report
, msg
);
162 int check_eval(char *buffer
, char *error_report
)
172 for (cp
=buffer
;*cp
;cp
++) {
173 if (*cp
== '$' && *(cp
+1) == '{') {
191 strncpy(varname
,cp
+2, xp
-cp
-2);
192 varname
[xp
-cp
-2] = 0;
194 val
= find_var(varname
);
201 *ep
++ = '5'; /* why not */
207 printf("Unterminated variable reference at line %d\n", global_lineno
);
211 else if (*cp
== '\\') {
212 /* braindead simple elim of backslash */
221 /* now, run the test */
222 result
= ast_expr(evalbuf
, s
, sizeof(s
));
224 sprintf(error_report
,"line %d, evaluation of $[ %s ] result: %s\n", global_lineno
, evalbuf
, s
);
227 sprintf(error_report
,"line %d, evaluation of $[ %s ] result: ****SYNTAX ERROR****\n", global_lineno
, evalbuf
);
233 void parse_file(const char *fname
)
235 FILE *f
= fopen(fname
,"r");
236 FILE *l
= fopen("expr2_log","w");
239 char buffer
[30000]; /* I sure hope no expr gets this big! */
242 fprintf(stderr
,"Couldn't open %s for reading... need an extensions.conf file to parse!\n",fname
);
246 fprintf(stderr
,"Couldn't open 'expr2_log' file for writing... please fix and re-run!\n");
252 while ((c1
= fgetc(f
)) != EOF
) {
255 else if (c1
== '[') {
256 if (last_char
== '$') {
261 char error_report
[30000];
263 while ((c1
= fgetc(f
)) != EOF
) {
269 fprintf(l
, "ERROR-- A newline in an expression? Weird! ...at line %d\n", global_lineno
);
272 printf("--- ERROR --- A newline in the middle of an expression at line %d!\n", global_lineno
);
277 buffer
[bufcount
++] = c1
;
280 fprintf(l
, "ERROR-- End of File Reached in the middle of an Expr at line %d\n", global_lineno
);
283 printf("--- ERROR --- EOF reached in middle of an expression at line %d!\n", global_lineno
);
287 buffer
[bufcount
] = 0;
289 global_expr_tot_size
+= bufcount
;
291 if (bufcount
> global_expr_max_size
)
292 global_expr_max_size
= bufcount
;
294 retval
= check_expr(buffer
, error_report
); /* check_expr should bump the warning counter */
296 /* print error report */
297 printf("Warning(s) at line %d, expression: $[%s]; see expr2_log file for details\n",
298 global_lineno
, buffer
);
299 fprintf(l
, "%s", error_report
);
302 printf("OK -- $[%s] at line %d\n", buffer
, global_lineno
);
306 retval
= check_eval(buffer
, error_report
);
307 fprintf(l
, "%s", error_report
);
312 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",
316 global_expr_max_size
,
317 (global_expr_count
) ? global_expr_tot_size
/global_expr_count
: 0);
324 int main(int argc
,char **argv
)
330 printf("check_expr -- a program to look thru extensions.conf files for $[...] expressions,\n");
331 printf(" and run them thru the parser, looking for problems\n");
332 printf("Hey-- give me a path to an extensions.conf file!\n");
333 printf(" You can also follow the file path with a series of variable decls,\n");
334 printf(" of the form, varname=value, each separated from the next by spaces.\n");
335 printf(" (this might allow you to avoid division by zero messages, check that math\n");
336 printf(" is being done correctly, etc.)\n");
337 printf(" Note that messages about operators not being surrounded by spaces is merely to alert\n");
338 printf(" you to possible problems where you might be expecting those operators as part of a string.\n");
339 printf(" (to include operators in a string, wrap with double quotes!)\n");
344 for (argc1
=2;argc1
< argc
; argc1
++) {
345 if ((eq
= strchr(argv
[argc1
],'='))) {
347 set_var(argv
[argc1
],eq
+1);
351 /* parse command args for x=y and set varz */