Asterisk - The Open Source Telephony Project GIT-master-a358458
check_expr.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2005, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
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.
13 *
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.
17 */
18
19/*** MODULEINFO
20 <support_level>extended</support_level>
21 ***/
22
23#define ASTMM_LIBC ASTMM_IGNORE
24#include "asterisk.h"
25
26#include "asterisk/ast_expr.h"
27
28#define AST_API_MODULE 1
29#include "asterisk/inline_api.h"
30
31#define AST_API_MODULE 1
32#include "asterisk/lock.h"
33
34#ifndef DEBUG_THREADS
39};
40#endif
41#ifdef DEBUG_THREADLOCALS
42#define MALLOC_FAILURE_MSG \
43 ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
44
45void * attribute_malloc __ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func);
46
47void * attribute_malloc __ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func)
48{
49 void *p;
50
51 if (!(p = calloc(num, len)))
53
54 return p;
55}
56#endif
57
58#ifdef DEBUG_THREADS
59void ast_store_lock_info(enum ast_lock_type type, const char *filename,
60 int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt);
61void ast_store_lock_info(enum ast_lock_type type, const char *filename,
62 int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
63{
64 /* not a lot to do in a standalone w/o threading! */
65}
66
67void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt);
68void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
69{
70 /* not a lot to do in a standalone w/o threading! */
71}
72
73#ifdef HAVE_BKTR
74int __ast_bt_get_addresses(struct ast_bt *bt);
75int __ast_bt_get_addresses(struct ast_bt *bt)
76{
77 /* Suck it, you stupid utils directory! */
78 return 0;
79}
80struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames);
81struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames)
82{
83 return NULL;
84}
85#endif /* HAVE_BKTR */
86
87void ast_suspend_lock_info(void *lock_addr)
88{
89}
90void ast_restore_lock_info(void *lock_addr)
91{
92}
93void ast_mark_lock_acquired(void *);
94void ast_mark_lock_acquired(void *foo)
95{
96 /* not a lot to do in a standalone w/o threading! */
97}
98#endif /* DEBUG_THREADS */
99
100
101static int global_lineno = 1;
102static int global_expr_count=0;
105static int global_warn_count=0;
106static int global_OK_count=0;
107
108struct varz
109{
110 char varname[100]; /* a really ultra-simple, space-wasting linked list of var=val data */
111 char varval[1000]; /* if any varname is bigger than 100 chars, or val greater than 1000, then **CRASH** */
112 struct varz *next;
113};
114
116
117/* Our own version of ast_log, since the expr parser uses it. */
118
119void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf,5,6)));
120
121void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
122{
123 va_list vars;
124 va_start(vars,fmt);
125
126 printf("LOG: lev:%d file:%s line:%d func: %s ",
127 level, file, line, function);
128 vprintf(fmt, vars);
129 fflush(stdout);
130 va_end(vars);
131}
132
133char *find_var(const char *varname);
134void set_var(const char *varname, const char *varval);
135unsigned int check_expr(char* buffer, char* error_report);
136int check_eval(char *buffer, char *error_report);
137void parse_file(const char *fname);
138
139int ast_add_profile(const char *x, uint64_t scale) { return 0;}
140
141char *find_var(const char *varname) /* the list should be pretty short, if there's any list at all */
142{
143 struct varz *t;
144 for (t= global_varlist; t; t = t->next) {
145 if (!strcmp(t->varname, varname)) {
146 return t->varval;
147 }
148 }
149 return 0;
150}
151
152void set_var(const char *varname, const char *varval);
153
154void set_var(const char *varname, const char *varval)
155{
156 struct varz *t = (struct varz*)calloc(1,sizeof(struct varz));
157 if (!t)
158 return;
159 strcpy(t->varname, varname);
160 strcpy(t->varval, varval);
161 t->next = global_varlist;
162 global_varlist = t;
163}
164
165unsigned int check_expr(char* buffer, char* error_report)
166{
167 char* cp;
168 unsigned int warn_found = 0;
169
170 error_report[0] = 0;
171
172 for (cp = buffer; *cp; ++cp)
173 {
174 switch (*cp)
175 {
176 case '"':
177 /* skip to the other end */
178 while (*(++cp) && *cp != '"') ;
179
180 if (*cp == 0)
181 {
182 fprintf(stderr,
183 "Trouble? Unterminated double quote found at line %d\n",
185 }
186 break;
187
188 case '>':
189 case '<':
190 case '!':
191 if ( (*(cp + 1) == '=')
192 && ( ( (cp > buffer) && (*(cp - 1) != ' ') ) || (*(cp + 2) != ' ') ) )
193 {
194 char msg[200];
195 snprintf(msg,
196 sizeof(msg),
197 "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",
198 global_lineno, *cp, *(cp + 1));
199 strcat(error_report, msg);
201 ++warn_found;
202 }
203 break;
204
205 case '|':
206 case '&':
207 case '=':
208 case '+':
209 case '-':
210 case '*':
211 case '/':
212 case '%':
213 case '?':
214 case ':':
215 if ( ( (cp > buffer) && (*(cp - 1) != ' ') ) || (*(cp + 1) != ' ') )
216 {
217 char msg[200];
218 snprintf(msg,
219 sizeof(msg),
220 "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",
221 global_lineno, *cp );
222 strcat(error_report, msg);
224 ++warn_found;
225 }
226 break;
227 }
228 }
229
230 return warn_found;
231}
232
233int check_eval(char *buffer, char *error_report);
234
236
238{
239 return 0;
240}
241
242int check_eval(char *buffer, char *error_report)
243{
244 char *cp, *ep;
245 char s[4096];
246 char evalbuf[80000];
247 int result;
248
249 error_report[0] = 0;
250 ep = evalbuf;
251
252 for (cp=buffer;*cp;cp++) {
253 if (*cp == '$' && *(cp+1) == '{') {
254 int brack_lev = 1;
255 char *xp= cp+2;
256
257 while (*xp) {
258 if (*xp == '{')
259 brack_lev++;
260 else if (*xp == '}')
261 brack_lev--;
262
263 if (brack_lev == 0)
264 break;
265 xp++;
266 }
267 if (*xp == '}') {
268 char varname[200];
269 char *val;
270
271 strncpy(varname,cp+2, xp-cp-2);
272 varname[xp-cp-2] = 0;
273 cp = xp;
274 val = find_var(varname);
275 if (val) {
276 char *z = val;
277 while (*z)
278 *ep++ = *z++;
279 }
280 else {
281 *ep++ = '5'; /* why not */
282 *ep++ = '5';
283 *ep++ = '5';
284 }
285 }
286 else {
287 printf("Unterminated variable reference at line %d\n", global_lineno);
288 *ep++ = *cp;
289 }
290 }
291 else if (*cp == '\\') {
292 /* braindead simple elim of backslash */
293 cp++;
294 *ep++ = *cp;
295 }
296 else
297 *ep++ = *cp;
298 }
299 *ep++ = 0;
300
301 /* now, run the test */
302 result = ast_expr(evalbuf, s, sizeof(s),NULL);
303 if (result) {
304 sprintf(error_report,"line %d, evaluation of $[ %s ] result: %s\n", global_lineno, evalbuf, s);
305 return 1;
306 } else {
307 sprintf(error_report,"line %d, evaluation of $[ %s ] result: ****SYNTAX ERROR****\n", global_lineno, evalbuf);
308 return 1;
309 }
310}
311
312
313void parse_file(const char *fname);
314
315void parse_file(const char *fname)
316{
317 FILE *f = fopen(fname,"r");
318 FILE *l = fopen("expr2_log","w");
319 int c1;
320 char last_char= 0;
321 char buffer[30000]; /* I sure hope no expr gets this big! */
322
323 if (!f) {
324 fprintf(stderr,"Couldn't open %s for reading... need an extensions.conf file to parse!\n",fname);
325 exit(20);
326 }
327 if (!l) {
328 fprintf(stderr,"Couldn't open 'expr2_log' file for writing... please fix and re-run!\n");
329 exit(21);
330 }
331
332 global_lineno = 1;
333
334 while ((c1 = fgetc(f)) != EOF) {
335 if (c1 == '\n')
337 else if (c1 == '[') {
338 if (last_char == '$') {
339 /* bingo, an expr */
340 int bracklev = 1;
341 int bufcount = 0;
342 int retval;
343 char error_report[30000];
344
345 while ((c1 = fgetc(f)) != EOF) {
346 if (c1 == '[')
347 bracklev++;
348 else if (c1 == ']')
349 bracklev--;
350 if (c1 == '\n') {
351 fprintf(l, "ERROR-- A newline in an expression? Weird! ...at line %d\n", global_lineno);
352 fclose(f);
353 fclose(l);
354 printf("--- ERROR --- A newline in the middle of an expression at line %d!\n", global_lineno);
355 }
356
357 if (bracklev == 0)
358 break;
359 buffer[bufcount++] = c1;
360 }
361 if (c1 == EOF) {
362 fprintf(l, "ERROR-- End of File Reached in the middle of an Expr at line %d\n", global_lineno);
363 fclose(f);
364 fclose(l);
365 printf("--- ERROR --- EOF reached in middle of an expression at line %d!\n", global_lineno);
366 exit(22);
367 }
368
369 buffer[bufcount] = 0;
370 /* update stats */
371 global_expr_tot_size += bufcount;
373 if (bufcount > global_expr_max_size)
374 global_expr_max_size = bufcount;
375
376 retval = check_expr(buffer, error_report); /* check_expr should bump the warning counter */
377 if (retval != 0) {
378 /* print error report */
379 printf("Warning(s) at line %d, expression: $[%s]; see expr2_log file for details\n",
380 global_lineno, buffer);
381 fprintf(l, "%s", error_report);
382 }
383 else {
384 printf("OK -- $[%s] at line %d\n", buffer, global_lineno);
386 }
387 error_report[0] = 0;
388 retval = check_eval(buffer, error_report);
389 fprintf(l, "%s", error_report);
390 }
391 }
392 last_char = c1;
393 }
394 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",
400
401 fclose(f);
402 fclose(l);
403}
404
405
406int main(int argc,char **argv)
407{
408 int argc1;
409 char *eq;
410
411 if (argc < 2) {
412 printf("check_expr -- a program to look thru extensions.conf files for $[...] expressions,\n");
413 printf(" and run them thru the parser, looking for problems\n");
414 printf("Hey-- give me a path to an extensions.conf file!\n");
415 printf(" You can also follow the file path with a series of variable decls,\n");
416 printf(" of the form, varname=value, each separated from the next by spaces.\n");
417 printf(" (this might allow you to avoid division by zero messages, check that math\n");
418 printf(" is being done correctly, etc.)\n");
419 printf(" Note that messages about operators not being surrounded by spaces is merely to alert\n");
420 printf(" you to possible problems where you might be expecting those operators as part of a string.\n");
421 printf(" (to include operators in a string, wrap with double quotes!)\n");
422
423 exit(19);
424 }
425 global_varlist = 0;
426 for (argc1=2;argc1 < argc; argc1++) {
427 if ((eq = strchr(argv[argc1],'='))) {
428 *eq = 0;
429 set_var(argv[argc1],eq+1);
430 }
431 }
432
433 /* parse command args for x=y and set varz */
434
435 parse_file(argv[1]);
436 return 0;
437}
int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
Evaluate the given expression.
Definition: ast_expr2f.c:2391
Asterisk main include file. File version handling, generic pbx functions.
#define MALLOC_FAILURE_MSG
Definition: astmm.c:70
#define calloc(a, b)
Definition: astmm.h:155
void * __ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) attribute_malloc
Definition: astmm.c:1603
struct ast_vector_string * __ast_bt_get_symbols(void **addresses, size_t num_frames)
Definition: backtrace.c:281
int __ast_bt_get_addresses(struct ast_bt *bt)
Definition: backtrace.c:92
static PGresult * result
Definition: cel_pgsql.c:84
static const char type[]
Definition: chan_ooh323.c:109
static int global_lineno
Definition: check_expr.c:101
int main(int argc, char **argv)
Definition: check_expr.c:406
char * find_var(const char *varname)
Definition: check_expr.c:141
void set_var(const char *varname, const char *varval)
Definition: check_expr.c:154
struct ast_custom_function * ast_custom_function_find(const char *name)
Definition: check_expr.c:237
unsigned int check_expr(char *buffer, char *error_report)
Definition: check_expr.c:165
int ast_add_profile(const char *x, uint64_t scale)
support for event profiling
Definition: check_expr.c:139
struct varz * global_varlist
Definition: check_expr.c:115
int check_eval(char *buffer, char *error_report)
Definition: check_expr.c:242
ast_lock_type
Definition: check_expr.c:35
@ AST_RDLOCK
Definition: check_expr.c:37
@ AST_WRLOCK
Definition: check_expr.c:38
@ AST_MUTEX
Definition: check_expr.c:36
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: check_expr.c:121
void parse_file(const char *fname)
Definition: check_expr.c:315
static int global_expr_tot_size
Definition: check_expr.c:104
static int global_warn_count
Definition: check_expr.c:105
static int global_expr_count
Definition: check_expr.c:102
static int global_expr_max_size
Definition: check_expr.c:103
static int global_OK_count
Definition: check_expr.c:106
#define attribute_malloc
Definition: compiler.h:59
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static ENTRY retval
Definition: hsearch.c:50
Inlinable API function macro.
Asterisk locking-related definitions:
#define NULL
Definition: resample.c:96
A structure to hold backtrace information. This structure provides an easy means to store backtrace i...
Definition: backtrace.h:50
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
String vector definitions.
Definition: vector.h:55
Definition: ast_expr2.c:325
char varval[1000]
Definition: check_expr.c:111
struct varz * next
Definition: check_expr.c:112
char varname[100]
Definition: check_expr.c:110