check_expr.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*** MODULEINFO
00020    <support_level>extended</support_level>
00021  ***/
00022 
00023 #include "asterisk.h"
00024 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 398755 $")
00025 
00026 #include "asterisk/ast_expr.h"
00027 
00028 #define AST_API_MODULE 1
00029 #include "asterisk/inline_api.h"
00030 
00031 #define AST_API_MODULE 1
00032 #include "asterisk/lock.h"
00033 
00034 #ifndef DEBUG_THREADS
00035 enum ast_lock_type {
00036            AST_MUTEX,
00037            AST_RDLOCK,
00038            AST_WRLOCK,
00039 };
00040 #endif
00041 #ifdef DEBUG_THREADLOCALS
00042 #define MALLOC_FAILURE_MSG \
00043    ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
00044 
00045 void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func);
00046 
00047 void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func)
00048 {
00049    void *p;
00050 
00051    if (!(p = calloc(num, len)))
00052       MALLOC_FAILURE_MSG;
00053 
00054    return p;
00055 }
00056 #endif
00057 
00058 #ifdef DEBUG_THREADS
00059 #if !defined(LOW_MEMORY)
00060 #ifdef HAVE_BKTR
00061 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00062               int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt);
00063 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00064               int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt)
00065 {
00066     /* not a lot to do in a standalone w/o threading! */
00067 }
00068 
00069 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt);
00070 void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
00071 {
00072     /* not a lot to do in a standalone w/o threading! */
00073 }
00074 
00075 int __ast_bt_get_addresses(struct ast_bt *bt);
00076 int __ast_bt_get_addresses(struct ast_bt *bt)
00077 {
00078    /* Suck it, you stupid utils directory! */
00079    return 0;
00080 }
00081 char **__ast_bt_get_symbols(void **addresses, size_t num_frames);
00082 char **__ast_bt_get_symbols(void **addresses, size_t num_frames)
00083 {
00084    char **foo = calloc(num_frames, sizeof(char *) + 1);
00085    if (foo) {
00086       int i;
00087       for (i = 0; i < num_frames; i++) {
00088          foo[i] = (char *) foo + sizeof(char *) * num_frames;
00089       }
00090    }
00091    return foo;
00092 }
00093 #else
00094 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00095               int line_num, const char *func, const char *lock_name, void *lock_addr);
00096 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
00097               int line_num, const char *func, const char *lock_name, void *lock_addr)
00098 {
00099     /* not a lot to do in a standalone w/o threading! */
00100 }
00101 
00102 void ast_remove_lock_info(void *lock_addr);
00103 void ast_remove_lock_info(void *lock_addr)
00104 {
00105     /* not a lot to do in a standalone w/o threading! */
00106 }
00107 #endif /* HAVE_BKTR */
00108 
00109 void ast_suspend_lock_info(void *lock_addr)
00110 {
00111 }
00112 void ast_restore_lock_info(void *lock_addr)
00113 {
00114 }
00115 void ast_mark_lock_acquired(void *);
00116 void ast_mark_lock_acquired(void *foo)
00117 {
00118     /* not a lot to do in a standalone w/o threading! */
00119 }
00120 #endif
00121 #endif /* DEBUG_THREADS */
00122 
00123 
00124 static int global_lineno = 1;
00125 static int global_expr_count=0;
00126 static int global_expr_max_size=0;
00127 static int global_expr_tot_size=0;
00128 static int global_warn_count=0;
00129 static int global_OK_count=0;
00130 
00131 struct varz
00132 {
00133    char varname[100]; /* a really ultra-simple, space-wasting linked list of var=val data */
00134    char varval[1000]; /* if any varname is bigger than 100 chars, or val greater than 1000, then **CRASH** */
00135    struct varz *next;
00136 };
00137 
00138 struct varz *global_varlist;
00139 
00140 /* Our own version of ast_log, since the expr parser uses it. */
00141 
00142 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf,5,6)));
00143 
00144 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
00145 {
00146    va_list vars;
00147    va_start(vars,fmt);
00148    
00149    printf("LOG: lev:%d file:%s  line:%d func: %s  ",
00150          level, file, line, function);
00151    vprintf(fmt, vars);
00152    fflush(stdout);
00153    va_end(vars);
00154 }
00155 //void ast_register_file_version(const char *file, const char *version);
00156 //void ast_unregister_file_version(const char *file);
00157 
00158 char *find_var(const char *varname);
00159 void set_var(const char *varname, const char *varval);
00160 unsigned int check_expr(char* buffer, char* error_report);
00161 int check_eval(char *buffer, char *error_report);
00162 void parse_file(const char *fname);
00163 
00164 void ast_register_file_version(const char *file, const char *version);  
00165 void ast_register_file_version(const char *file, const char *version) { }
00166 #if !defined(LOW_MEMORY)
00167 int ast_add_profile(const char *x, uint64_t scale) { return 0;} 
00168 #endif
00169 int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
00170 {
00171         int ret;
00172         ret = *p;
00173         *p += v;
00174         return ret;
00175 }
00176 
00177 void ast_unregister_file_version(const char *file);
00178 void ast_unregister_file_version(const char *file)
00179 {
00180 }
00181 
00182 char *find_var(const char *varname) /* the list should be pretty short, if there's any list at all */
00183 {
00184    struct varz *t;
00185    for (t= global_varlist; t; t = t->next) {
00186       if (!strcmp(t->varname, varname)) {
00187          return t->varval;
00188       }
00189    }
00190    return 0;
00191 }
00192 
00193 void set_var(const char *varname, const char *varval);
00194 
00195 void set_var(const char *varname, const char *varval)
00196 {
00197    struct varz *t = (struct varz*)calloc(1,sizeof(struct varz));
00198    if (!t)
00199       return;
00200    strcpy(t->varname, varname);
00201    strcpy(t->varval, varval);
00202    t->next = global_varlist;
00203    global_varlist = t;
00204 }
00205 
00206 unsigned int check_expr(char* buffer, char* error_report)
00207 {
00208    char* cp;
00209    unsigned int warn_found = 0;
00210 
00211    error_report[0] = 0;
00212    
00213    for (cp = buffer; *cp; ++cp)
00214    {
00215       switch (*cp)
00216       {
00217          case '"':
00218             /* skip to the other end */
00219             while (*(++cp) && *cp != '"') ;
00220 
00221             if (*cp == 0)
00222             {
00223                fprintf(stderr,
00224                   "Trouble? Unterminated double quote found at line %d\n",
00225                   global_lineno);
00226             }
00227             break;
00228             
00229          case '>':
00230          case '<':
00231          case '!':
00232             if (   (*(cp + 1) == '=')
00233                && ( ( (cp > buffer) && (*(cp - 1) != ' ') ) || (*(cp + 2) != ' ') ) )
00234             {
00235                char msg[200];
00236                snprintf(msg,
00237                   sizeof(msg),
00238                   "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",
00239                   global_lineno, *cp, *(cp + 1));
00240                strcat(error_report, msg);
00241                ++global_warn_count;
00242                ++warn_found;
00243             }
00244             break;
00245             
00246          case '|':
00247          case '&':
00248          case '=':
00249          case '+':
00250          case '-':
00251          case '*':
00252          case '/':
00253          case '%':
00254          case '?':
00255          case ':':
00256             if ( ( (cp > buffer) && (*(cp - 1) != ' ') ) || (*(cp + 1) != ' ') )
00257             {
00258                char msg[200];
00259                snprintf(msg,
00260                   sizeof(msg),
00261                   "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",
00262                   global_lineno, *cp );
00263                strcat(error_report, msg);
00264                ++global_warn_count;
00265                ++warn_found;
00266             }
00267             break;
00268       }
00269    }
00270 
00271    return warn_found;
00272 }
00273 
00274 int check_eval(char *buffer, char *error_report);
00275 
00276 struct ast_custom_function *ast_custom_function_find(const char *name);
00277 
00278 struct ast_custom_function *ast_custom_function_find(const char *name)
00279 {
00280    return 0;
00281 }
00282 
00283 int check_eval(char *buffer, char *error_report)
00284 {
00285    char *cp, *ep;
00286    char s[4096];
00287    char evalbuf[80000];
00288    int result;
00289 
00290    error_report[0] = 0;
00291    ep = evalbuf;
00292 
00293    for (cp=buffer;*cp;cp++) {
00294       if (*cp == '$' && *(cp+1) == '{') {
00295          int brack_lev = 1;
00296          char *xp= cp+2;
00297          
00298          while (*xp) {
00299             if (*xp == '{')
00300                brack_lev++;
00301             else if (*xp == '}')
00302                brack_lev--;
00303             
00304             if (brack_lev == 0)
00305                break;
00306             xp++;
00307          }
00308          if (*xp == '}') {
00309             char varname[200];
00310             char *val;
00311             
00312             strncpy(varname,cp+2, xp-cp-2);
00313             varname[xp-cp-2] = 0;
00314             cp = xp;
00315             val = find_var(varname);
00316             if (val) {
00317                char *z = val;
00318                while (*z)
00319                   *ep++ = *z++;
00320             }
00321             else {
00322                *ep++ = '5';  /* why not */
00323                *ep++ = '5';
00324                *ep++ = '5';
00325             }
00326          }
00327          else {
00328             printf("Unterminated variable reference at line %d\n", global_lineno);
00329             *ep++ = *cp;
00330          }
00331       }
00332       else if (*cp == '\\') {
00333          /* braindead simple elim of backslash */
00334          cp++;
00335          *ep++ = *cp;
00336       }
00337       else
00338          *ep++ = *cp;
00339    }
00340    *ep++ = 0;
00341 
00342    /* now, run the test */
00343    result = ast_expr(evalbuf, s, sizeof(s),NULL);
00344    if (result) {
00345       sprintf(error_report,"line %d, evaluation of $[ %s ] result: %s\n", global_lineno, evalbuf, s);
00346       return 1;
00347    } else {
00348       sprintf(error_report,"line %d, evaluation of $[ %s ] result: ****SYNTAX ERROR****\n", global_lineno, evalbuf);
00349       return 1;
00350    }
00351 }
00352 
00353 
00354 void parse_file(const char *fname);
00355 
00356 void parse_file(const char *fname)
00357 {
00358    FILE *f = fopen(fname,"r");
00359    FILE *l = fopen("expr2_log","w");
00360    int c1;
00361    char last_char= 0;
00362    char buffer[30000]; /* I sure hope no expr gets this big! */
00363    
00364    if (!f) {
00365       fprintf(stderr,"Couldn't open %s for reading... need an extensions.conf file to parse!\n",fname);
00366       exit(20);
00367    }
00368    if (!l) {
00369       fprintf(stderr,"Couldn't open 'expr2_log' file for writing... please fix and re-run!\n");
00370       exit(21);
00371    }
00372    
00373    global_lineno = 1;
00374    
00375    while ((c1 = fgetc(f)) != EOF) {
00376       if (c1 == '\n')
00377          global_lineno++;
00378       else if (c1 == '[') {
00379          if (last_char == '$') {
00380             /* bingo, an expr */
00381             int bracklev = 1;
00382             int bufcount = 0;
00383             int retval;
00384             char error_report[30000];
00385             
00386             while ((c1 = fgetc(f)) != EOF) {
00387                if (c1 == '[')
00388                   bracklev++;
00389                else if (c1 == ']')
00390                   bracklev--;
00391                if (c1 == '\n') {
00392                   fprintf(l, "ERROR-- A newline in an expression? Weird! ...at line %d\n", global_lineno);
00393                   fclose(f);
00394                   fclose(l);
00395                   printf("--- ERROR --- A newline in the middle of an expression at line %d!\n", global_lineno);
00396                }
00397                
00398                if (bracklev == 0)
00399                   break;
00400                buffer[bufcount++] = c1;
00401             }
00402             if (c1 == EOF) {
00403                fprintf(l, "ERROR-- End of File Reached in the middle of an Expr at line %d\n", global_lineno);
00404                fclose(f);
00405                fclose(l);
00406                printf("--- ERROR --- EOF reached in middle of an expression at line %d!\n", global_lineno);
00407                exit(22);
00408             }
00409             
00410             buffer[bufcount] = 0;
00411             /* update stats */
00412             global_expr_tot_size += bufcount;
00413             global_expr_count++;
00414             if (bufcount > global_expr_max_size)
00415                global_expr_max_size = bufcount;
00416             
00417             retval = check_expr(buffer, error_report); /* check_expr should bump the warning counter */
00418             if (retval != 0) {
00419                /* print error report */
00420                printf("Warning(s) at line %d, expression: $[%s]; see expr2_log file for details\n", 
00421                      global_lineno, buffer);
00422                fprintf(l, "%s", error_report);
00423             }
00424             else {
00425                printf("OK -- $[%s] at line %d\n", buffer, global_lineno);
00426                global_OK_count++;
00427             }
00428             error_report[0] = 0;
00429             retval = check_eval(buffer, error_report);
00430             fprintf(l, "%s", error_report);
00431          }
00432       }
00433       last_char = c1;
00434    }
00435    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",
00436          global_expr_count,
00437          global_OK_count,
00438          global_warn_count,
00439          global_expr_max_size,
00440          (global_expr_count) ? global_expr_tot_size/global_expr_count : 0);
00441    
00442    fclose(f);
00443    fclose(l);
00444 }
00445 
00446 
00447 int main(int argc,char **argv)
00448 {
00449    int argc1;
00450    char *eq;
00451    
00452    if (argc < 2) {
00453       printf("check_expr -- a program to look thru extensions.conf files for $[...] expressions,\n");
00454       printf("              and run them thru the parser, looking for problems\n");
00455       printf("Hey-- give me a path to an extensions.conf file!\n");
00456       printf(" You can also follow the file path with a series of variable decls,\n");
00457       printf("     of the form, varname=value, each separated from the next by spaces.\n");
00458       printf("     (this might allow you to avoid division by zero messages, check that math\n");
00459       printf("      is being done correctly, etc.)\n");
00460       printf(" Note that messages about operators not being surrounded by spaces is merely to alert\n");
00461       printf("  you to possible problems where you might be expecting those operators as part of a string.\n");
00462         printf("  (to include operators in a string, wrap with double quotes!)\n");
00463       
00464       exit(19);
00465    }
00466    global_varlist = 0;
00467    for (argc1=2;argc1 < argc; argc1++) {
00468       if ((eq = strchr(argv[argc1],'='))) {
00469          *eq = 0;
00470          set_var(argv[argc1],eq+1);
00471       }
00472    }
00473 
00474    /* parse command args for x=y and set varz */
00475    
00476    parse_file(argv[1]);
00477    return 0;
00478 }

Generated on Thu Apr 16 06:27:30 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6