00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "asterisk.h"
00026
00027 #if !defined(STANDALONE_AEL)
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211528 $")
00029 #endif
00030
00031 #include <sys/types.h>
00032 #include <stdlib.h>
00033 #include <unistd.h>
00034 #include <stdio.h>
00035 #include <string.h>
00036 #include <ctype.h>
00037 #include <errno.h>
00038 #include <regex.h>
00039 #include <sys/stat.h>
00040
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/config.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/cli.h"
00046 #include "asterisk/app.h"
00047 #include "asterisk/callerid.h"
00048 #include "asterisk/ael_structs.h"
00049 #ifdef AAL_ARGCHECK
00050 #include "asterisk/argdesc.h"
00051 #include <dirent.h>
00052 #endif
00053
00054 static char expr_output[2096];
00055
00056
00057
00058 #define DEBUG_READ (1 << 0)
00059 #define DEBUG_TOKENS (1 << 1)
00060 #define DEBUG_MACROS (1 << 2)
00061 #define DEBUG_CONTEXTS (1 << 3)
00062
00063 #define AST_MAX_FILENAME_LEN 256
00064
00065 static char *config = "extensions.ael";
00066 static char *registrar = "pbx_ael";
00067 static int pbx_load_module(void);
00068
00069 static int errs, warns;
00070 static int notes;
00071
00072 #ifndef AAL_ARGCHECK
00073
00074
00075
00076
00077
00078
00079 struct argapp
00080 {
00081 struct argapp *next;
00082 };
00083
00084 #endif
00085
00086 #ifdef AAL_ARGCHECK
00087 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app);
00088 int option_matches( struct argdesc *should, pval *is, struct argapp *app);
00089 int ael_is_funcname(char *name);
00090 #endif
00091
00092 int check_app_args(pval *appcall, pval *arglist, struct argapp *app);
00093 void check_pval(pval *item, struct argapp *apps, int in_globals);
00094 void check_pval_item(pval *item, struct argapp *apps, int in_globals);
00095 void check_switch_expr(pval *item, struct argapp *apps);
00096 void ast_expr_register_extra_error_info(char *errmsg);
00097 void ast_expr_clear_extra_error_info(void);
00098 int ast_expr(char *expr, char *buf, int length);
00099 struct pval *find_macro(char *name);
00100 struct pval *find_context(char *name);
00101 struct pval *find_context(char *name);
00102 struct pval *find_macro(char *name);
00103 struct ael_priority *new_prio(void);
00104 struct ael_extension *new_exten(void);
00105 void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten);
00106 void destroy_extensions(struct ael_extension *exten);
00107 static void linkexten(struct ael_extension *exten, struct ael_extension *add);
00108 static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *context );
00109 void set_priorities(struct ael_extension *exten);
00110 void add_extensions(struct ael_extension *exten);
00111 void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root);
00112 void destroy_pval(pval *item);
00113 void destroy_pval_item(pval *item);
00114 int is_float(char *arg );
00115 int is_int(char *arg );
00116 int is_empty(char *arg);
00117 static pval *current_db=0;
00118 static pval *current_context=0;
00119 static pval *current_extension=0;
00120
00121 static const char *match_context;
00122 static const char *match_exten;
00123 static const char *match_label;
00124 static int in_abstract_context;
00125 static int count_labels;
00126 static int label_count;
00127 static int return_on_context_match;
00128 static pval *last_matched_label;
00129 struct pval *match_pval(pval *item);
00130 static void check_timerange(pval *p);
00131 static void check_dow(pval *DOW);
00132 static void check_day(pval *DAY);
00133 static void check_month(pval *MON);
00134 static void check_expr2_input(pval *expr, char *str);
00135 static int extension_matches(pval *here, const char *exten, const char *pattern);
00136 static void check_goto(pval *item);
00137 static void find_pval_goto_item(pval *item, int lev);
00138 static void find_pval_gotos(pval *item, int lev);
00139
00140 static struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont);
00141 static struct pval *find_first_label_in_current_context(char *label, pval *curr_cont);
00142 static void print_pval_list(FILE *fin, pval *item, int depth);
00143
00144 static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext);
00145 static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label);
00146 static pval *get_goto_target(pval *item);
00147 static int label_inside_case(pval *label);
00148 static void attach_exten(struct ael_extension **list, struct ael_extension *newmem);
00149 static void fix_gotos_in_extensions(struct ael_extension *exten);
00150 static pval *get_extension_or_contxt(pval *p);
00151 static pval *get_contxt(pval *p);
00152 static void remove_spaces_before_equals(char *str);
00153 static void substitute_commas(char *str);
00154
00155
00156 static void substitute_commas(char *str)
00157 {
00158 char *p = str;
00159
00160 while (p && *p)
00161 {
00162 if (*p == ',' && ((p != str && *(p-1) != '\\')
00163 || p == str))
00164 *p = '|';
00165 if (*p == '\\' && *(p+1) == ',') {
00166 char *q = p;
00167 while (*q) {
00168 *q = *(q+1);
00169 q++;
00170 }
00171 }
00172 p++;
00173 }
00174 }
00175
00176
00177
00178
00179 static void print_pval(FILE *fin, pval *item, int depth)
00180 {
00181 int i;
00182 pval *lp;
00183
00184 for (i=0; i<depth; i++) {
00185 fprintf(fin, "\t");
00186 }
00187
00188 switch ( item->type ) {
00189 case PV_WORD:
00190 fprintf(fin,"%s;\n", item->u1.str);
00191 break;
00192
00193 case PV_MACRO:
00194 fprintf(fin,"macro %s(", item->u1.str);
00195 for (lp=item->u2.arglist; lp; lp=lp->next) {
00196 if (lp != item->u2.arglist )
00197 fprintf(fin,", ");
00198 fprintf(fin,"%s", lp->u1.str);
00199 }
00200 fprintf(fin,") {\n");
00201 print_pval_list(fin,item->u3.macro_statements,depth+1);
00202 for (i=0; i<depth; i++) {
00203 fprintf(fin,"\t");
00204 }
00205 fprintf(fin,"};\n\n");
00206 break;
00207
00208 case PV_CONTEXT:
00209 if ( item->u3.abstract )
00210 fprintf(fin,"abstract context %s {\n", item->u1.str);
00211 else
00212 fprintf(fin,"context %s {\n", item->u1.str);
00213 print_pval_list(fin,item->u2.statements,depth+1);
00214 for (i=0; i<depth; i++) {
00215 fprintf(fin,"\t");
00216 }
00217 fprintf(fin,"};\n\n");
00218 break;
00219
00220 case PV_MACRO_CALL:
00221 fprintf(fin,"&%s(", item->u1.str);
00222 for (lp=item->u2.arglist; lp; lp=lp->next) {
00223 if ( lp != item->u2.arglist )
00224 fprintf(fin,", ");
00225 fprintf(fin,"%s", lp->u1.str);
00226 }
00227 fprintf(fin,");\n");
00228 break;
00229
00230 case PV_APPLICATION_CALL:
00231 fprintf(fin,"%s(", item->u1.str);
00232 for (lp=item->u2.arglist; lp; lp=lp->next) {
00233 if ( lp != item->u2.arglist )
00234 fprintf(fin,",");
00235 fprintf(fin,"%s", lp->u1.str);
00236 }
00237 fprintf(fin,");\n");
00238 break;
00239
00240 case PV_CASE:
00241 fprintf(fin,"case %s:\n", item->u1.str);
00242 print_pval_list(fin,item->u2.statements, depth+1);
00243 break;
00244
00245 case PV_PATTERN:
00246 fprintf(fin,"pattern %s:\n", item->u1.str);
00247 print_pval_list(fin,item->u2.statements, depth+1);
00248 break;
00249
00250 case PV_DEFAULT:
00251 fprintf(fin,"default:\n");
00252 print_pval_list(fin,item->u2.statements, depth+1);
00253 break;
00254
00255 case PV_CATCH:
00256 fprintf(fin,"catch %s {\n", item->u1.str);
00257 print_pval_list(fin,item->u2.statements, depth+1);
00258 for (i=0; i<depth; i++) {
00259 fprintf(fin,"\t");
00260 }
00261 fprintf(fin,"};\n");
00262 break;
00263
00264 case PV_SWITCHES:
00265 fprintf(fin,"switches {\n");
00266 print_pval_list(fin,item->u1.list,depth+1);
00267 for (i=0; i<depth; i++) {
00268 fprintf(fin,"\t");
00269 }
00270 fprintf(fin,"};\n");
00271 break;
00272
00273 case PV_ESWITCHES:
00274 fprintf(fin,"eswitches {\n");
00275 print_pval_list(fin,item->u1.list,depth+1);
00276 for (i=0; i<depth; i++) {
00277 fprintf(fin,"\t");
00278 }
00279 fprintf(fin,"};\n");
00280 break;
00281
00282 case PV_INCLUDES:
00283 fprintf(fin,"includes {\n");
00284 for (lp=item->u1.list; lp; lp=lp->next) {
00285 for (i=0; i<depth+1; i++) {
00286 fprintf(fin,"\t");
00287 }
00288 fprintf(fin,"%s", lp->u1.str);
00289 if ( lp->u2.arglist )
00290 fprintf(fin,"|%s|%s|%s|%s",
00291 lp->u2.arglist->u1.str,
00292 lp->u2.arglist->next->u1.str,
00293 lp->u2.arglist->next->next->u1.str,
00294 lp->u2.arglist->next->next->next->u1.str
00295 );
00296 fprintf(fin,";\n");
00297 }
00298
00299 print_pval_list(fin,item->u1.list,depth+1);
00300 for (i=0; i<depth; i++) {
00301 fprintf(fin,"\t");
00302 }
00303 fprintf(fin,"};\n");
00304 break;
00305
00306 case PV_STATEMENTBLOCK:
00307 fprintf(fin,"{\n");
00308 print_pval_list(fin,item->u1.list, depth+1);
00309 for (i=0; i<depth; i++) {
00310 fprintf(fin,"\t");
00311 }
00312 fprintf(fin,"};\n");
00313 break;
00314
00315 case PV_VARDEC:
00316 fprintf(fin,"%s=%s;\n", item->u1.str, item->u2.val);
00317 break;
00318
00319 case PV_GOTO:
00320 fprintf(fin,"goto %s", item->u1.list->u1.str);
00321 if ( item->u1.list->next )
00322 fprintf(fin,"|%s", item->u1.list->next->u1.str);
00323 if ( item->u1.list->next && item->u1.list->next->next )
00324 fprintf(fin,"|%s", item->u1.list->next->next->u1.str);
00325 fprintf(fin,"\n");
00326 break;
00327
00328 case PV_LABEL:
00329 fprintf(fin,"%s:\n", item->u1.str);
00330 break;
00331
00332 case PV_FOR:
00333 fprintf(fin,"for (%s; %s; %s)\n", item->u1.for_init, item->u2.for_test, item->u3.for_inc);
00334 print_pval_list(fin,item->u4.for_statements,depth+1);
00335 break;
00336
00337 case PV_WHILE:
00338 fprintf(fin,"while (%s)\n", item->u1.str);
00339 print_pval_list(fin,item->u2.statements,depth+1);
00340 break;
00341
00342 case PV_BREAK:
00343 fprintf(fin,"break;\n");
00344 break;
00345
00346 case PV_RETURN:
00347 fprintf(fin,"return;\n");
00348 break;
00349
00350 case PV_CONTINUE:
00351 fprintf(fin,"continue;\n");
00352 break;
00353
00354 case PV_RANDOM:
00355 case PV_IFTIME:
00356 case PV_IF:
00357 if ( item->type == PV_IFTIME ) {
00358
00359 fprintf(fin,"ifTime ( %s|%s|%s|%s )\n",
00360 item->u1.list->u1.str,
00361 item->u1.list->next->u1.str,
00362 item->u1.list->next->next->u1.str,
00363 item->u1.list->next->next->next->u1.str
00364 );
00365 } else if ( item->type == PV_RANDOM ) {
00366 fprintf(fin,"random ( %s )\n", item->u1.str );
00367 } else
00368 fprintf(fin,"if ( %s )\n", item->u1.str);
00369 if ( item->u2.statements && item->u2.statements->next ) {
00370 for (i=0; i<depth; i++) {
00371 fprintf(fin,"\t");
00372 }
00373 fprintf(fin,"{\n");
00374 print_pval_list(fin,item->u2.statements,depth+1);
00375 for (i=0; i<depth; i++) {
00376 fprintf(fin,"\t");
00377 }
00378 if ( item->u3.else_statements )
00379 fprintf(fin,"}\n");
00380 else
00381 fprintf(fin,"};\n");
00382 } else if (item->u2.statements ) {
00383 print_pval_list(fin,item->u2.statements,depth+1);
00384 } else {
00385 if (item->u3.else_statements )
00386 fprintf(fin, " {} ");
00387 else
00388 fprintf(fin, " {}; ");
00389 }
00390 if ( item->u3.else_statements ) {
00391 for (i=0; i<depth; i++) {
00392 fprintf(fin,"\t");
00393 }
00394 fprintf(fin,"else\n");
00395 print_pval_list(fin,item->u3.else_statements, depth);
00396 }
00397 break;
00398
00399 case PV_SWITCH:
00400 fprintf(fin,"switch( %s ) {\n", item->u1.str);
00401 print_pval_list(fin,item->u2.statements,depth+1);
00402 for (i=0; i<depth; i++) {
00403 fprintf(fin,"\t");
00404 }
00405 fprintf(fin,"}\n");
00406 break;
00407
00408 case PV_EXTENSION:
00409 if ( item->u4.regexten )
00410 fprintf(fin, "regexten ");
00411 if ( item->u3.hints )
00412 fprintf(fin,"hints(%s) ", item->u3.hints);
00413
00414 fprintf(fin,"%s => \n", item->u1.str);
00415 print_pval_list(fin,item->u2.statements,depth+1);
00416 break;
00417
00418 case PV_IGNOREPAT:
00419 fprintf(fin,"ignorepat => %s\n", item->u1.str);
00420 break;
00421
00422 case PV_GLOBALS:
00423 fprintf(fin,"globals {\n");
00424 print_pval_list(fin,item->u1.statements,depth+1);
00425 for (i=0; i<depth; i++) {
00426 fprintf(fin,"\t");
00427 }
00428 fprintf(fin,"}\n");
00429 break;
00430 }
00431 }
00432
00433 static void print_pval_list(FILE *fin, pval *item, int depth)
00434 {
00435 pval *i;
00436
00437 for (i=item; i; i=i->next) {
00438 print_pval(fin, i, depth);
00439 }
00440 }
00441
00442 #if 0
00443 static void ael2_print(char *fname, pval *tree)
00444 {
00445 FILE *fin = fopen(fname,"w");
00446 if ( !fin ) {
00447 ast_log(LOG_ERROR, "Couldn't open %s for writing.\n", fname);
00448 return;
00449 }
00450 print_pval_list(fin, tree, 0);
00451 fclose(fin);
00452 }
00453 #endif
00454
00455
00456
00457
00458 void traverse_pval_template(pval *item, int depth);
00459 void traverse_pval_item_template(pval *item, int depth);
00460
00461
00462 void traverse_pval_item_template(pval *item, int depth)
00463
00464 {
00465 pval *lp;
00466
00467 switch ( item->type ) {
00468 case PV_WORD:
00469
00470 break;
00471
00472 case PV_MACRO:
00473
00474
00475
00476
00477
00478
00479
00480 for (lp=item->u2.arglist; lp; lp=lp->next) {
00481
00482 }
00483 traverse_pval_item_template(item->u3.macro_statements,depth+1);
00484 break;
00485
00486 case PV_CONTEXT:
00487
00488
00489
00490
00491 traverse_pval_item_template(item->u2.statements,depth+1);
00492 break;
00493
00494 case PV_MACRO_CALL:
00495
00496
00497
00498
00499
00500 for (lp=item->u2.arglist; lp; lp=lp->next) {
00501 }
00502 break;
00503
00504 case PV_APPLICATION_CALL:
00505
00506
00507
00508
00509
00510 for (lp=item->u2.arglist; lp; lp=lp->next) {
00511 }
00512 break;
00513
00514 case PV_CASE:
00515
00516
00517
00518 traverse_pval_item_template(item->u2.statements,depth+1);
00519 break;
00520
00521 case PV_PATTERN:
00522
00523
00524
00525 traverse_pval_item_template(item->u2.statements,depth+1);
00526 break;
00527
00528 case PV_DEFAULT:
00529
00530
00531
00532 traverse_pval_item_template(item->u2.statements,depth+1);
00533 break;
00534
00535 case PV_CATCH:
00536
00537
00538
00539 traverse_pval_item_template(item->u2.statements,depth+1);
00540 break;
00541
00542 case PV_SWITCHES:
00543
00544
00545 traverse_pval_item_template(item->u1.list,depth+1);
00546 break;
00547
00548 case PV_ESWITCHES:
00549
00550
00551 traverse_pval_item_template(item->u1.list,depth+1);
00552 break;
00553
00554 case PV_INCLUDES:
00555
00556
00557
00558 traverse_pval_item_template(item->u1.list,depth+1);
00559 traverse_pval_item_template(item->u2.arglist,depth+1);
00560 break;
00561
00562 case PV_STATEMENTBLOCK:
00563
00564
00565 traverse_pval_item_template(item->u1.list,depth+1);
00566 break;
00567
00568 case PV_VARDEC:
00569
00570
00571
00572 break;
00573
00574 case PV_GOTO:
00575
00576
00577
00578
00579 if ( item->u1.list->next )
00580 ;
00581 if ( item->u1.list->next && item->u1.list->next->next )
00582 ;
00583
00584 break;
00585
00586 case PV_LABEL:
00587
00588
00589 break;
00590
00591 case PV_FOR:
00592
00593
00594
00595
00596
00597
00598 traverse_pval_item_template(item->u4.for_statements,depth+1);
00599 break;
00600
00601 case PV_WHILE:
00602
00603
00604
00605
00606 traverse_pval_item_template(item->u2.statements,depth+1);
00607 break;
00608
00609 case PV_BREAK:
00610
00611
00612 break;
00613
00614 case PV_RETURN:
00615
00616
00617 break;
00618
00619 case PV_CONTINUE:
00620
00621
00622 break;
00623
00624 case PV_IFTIME:
00625
00626
00627
00628
00629
00630
00631 traverse_pval_item_template(item->u2.statements,depth+1);
00632 if ( item->u3.else_statements ) {
00633 traverse_pval_item_template(item->u3.else_statements,depth+1);
00634 }
00635 break;
00636
00637 case PV_RANDOM:
00638
00639
00640
00641
00642
00643
00644 traverse_pval_item_template(item->u2.statements,depth+1);
00645 if ( item->u3.else_statements ) {
00646 traverse_pval_item_template(item->u3.else_statements,depth+1);
00647 }
00648 break;
00649
00650 case PV_IF:
00651
00652
00653
00654
00655
00656
00657 traverse_pval_item_template(item->u2.statements,depth+1);
00658 if ( item->u3.else_statements ) {
00659 traverse_pval_item_template(item->u3.else_statements,depth+1);
00660 }
00661 break;
00662
00663 case PV_SWITCH:
00664
00665
00666
00667
00668
00669 traverse_pval_item_template(item->u2.statements,depth+1);
00670 break;
00671
00672 case PV_EXTENSION:
00673
00674
00675
00676
00677
00678
00679 traverse_pval_item_template(item->u2.statements,depth+1);
00680 break;
00681
00682 case PV_IGNOREPAT:
00683
00684
00685 break;
00686
00687 case PV_GLOBALS:
00688
00689
00690 traverse_pval_item_template(item->u1.statements,depth+1);
00691 break;
00692 }
00693 }
00694
00695 void traverse_pval_template(pval *item, int depth)
00696
00697 {
00698 pval *i;
00699
00700 for (i=item; i; i=i->next) {
00701 traverse_pval_item_template(i, depth);
00702 }
00703 }
00704
00705
00706
00707
00708
00709
00710
00711
00712 static int extension_matches(pval *here, const char *exten, const char *pattern)
00713 {
00714 int err1;
00715 regex_t preg;
00716
00717
00718 if( strcmp(pattern,exten) == 0 )
00719 return 1;
00720
00721 if ( pattern[0] == '_' ) {
00722 char reg1[2000];
00723 const char *p;
00724 char *r = reg1;
00725
00726 if ( strlen(pattern)*5 >= 2000 ) {
00727 ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n",
00728 pattern);
00729 return 0;
00730 }
00731
00732 *r++ = '^';
00733 *r++ = '_';
00734 *r++ = '?';
00735 for (p=pattern+1; *p; p++) {
00736 switch ( *p ) {
00737 case 'X':
00738 *r++ = '[';
00739 *r++ = '0';
00740 *r++ = '-';
00741 *r++ = '9';
00742 *r++ = 'X';
00743 *r++ = ']';
00744 break;
00745
00746 case 'Z':
00747 *r++ = '[';
00748 *r++ = '1';
00749 *r++ = '-';
00750 *r++ = '9';
00751 *r++ = 'Z';
00752 *r++ = ']';
00753 break;
00754
00755 case 'N':
00756 *r++ = '[';
00757 *r++ = '2';
00758 *r++ = '-';
00759 *r++ = '9';
00760 *r++ = 'N';
00761 *r++ = ']';
00762 break;
00763
00764 case '[':
00765 while ( *p && *p != ']' ) {
00766 *r++ = *p++;
00767 }
00768 *r++ = ']';
00769 if ( *p != ']') {
00770 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The extension pattern '%s' is missing a closing bracket \n",
00771 here->filename, here->startline, here->endline, pattern);
00772 }
00773 break;
00774
00775 case '.':
00776 case '!':
00777 *r++ = '.';
00778 *r++ = '*';
00779 break;
00780 case '*':
00781 *r++ = '\\';
00782 *r++ = '*';
00783 break;
00784 default:
00785 *r++ = *p;
00786 break;
00787
00788 }
00789 }
00790 *r++ = '$';
00791 *r++ = *p++;
00792 err1 = regcomp(&preg, reg1, REG_NOSUB|REG_EXTENDED);
00793 if ( err1 ) {
00794 char errmess[500];
00795 regerror(err1,&preg,errmess,sizeof(errmess));
00796 regfree(&preg);
00797 ast_log(LOG_WARNING, "Regcomp of %s failed, error code %d\n",
00798 reg1, err1);
00799 return 0;
00800 }
00801 err1 = regexec(&preg, exten, 0, 0, 0);
00802 regfree(&preg);
00803
00804 if ( err1 ) {
00805
00806
00807 return 0;
00808 } else {
00809
00810
00811 return 1;
00812 }
00813
00814
00815 } else {
00816 if ( strcmp(exten,pattern) == 0 ) {
00817 return 1;
00818 } else
00819 return 0;
00820 }
00821 }
00822
00823
00824 static void check_expr2_input(pval *expr, char *str)
00825 {
00826 int spaces = strspn(str,"\t \n");
00827 if ( !strncmp(str+spaces,"$[",2) ) {
00828 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The expression '%s' is redundantly wrapped in '$[ ]'. \n",
00829 expr->filename, expr->startline, expr->endline, str);
00830 warns++;
00831 }
00832 }
00833
00834 static void check_includes(pval *includes)
00835 {
00836 struct pval *p4;
00837 for (p4=includes->u1.list; p4; p4=p4->next) {
00838
00839
00840 char *incl_context = p4->u1.str;
00841
00842 struct pval *that_other_context = find_context(incl_context);
00843 if (!that_other_context && strcmp(incl_context, "parkedcalls") != 0) {
00844 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The included context '%s' cannot be found.\n\
00845 (You may ignore this warning if '%s' exists in extensions.conf, or is created by another module. I cannot check for those.)\n",
00846 includes->filename, includes->startline, includes->endline, incl_context, incl_context);
00847 warns++;
00848 }
00849 }
00850 }
00851
00852
00853 static void check_timerange(pval *p)
00854 {
00855 char *times;
00856 char *e;
00857 int s1, s2;
00858 int e1, e2;
00859
00860 times = ast_strdupa(p->u1.str);
00861
00862
00863 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
00864 return;
00865 }
00866
00867 e = strchr(times, '-');
00868 if (!e) {
00869 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) requires a '-' surrounded by two 24-hour times of day!\n",
00870 p->filename, p->startline, p->endline, times);
00871 warns++;
00872 return;
00873 }
00874 *e = '\0';
00875 e++;
00876 while (*e && !isdigit(*e))
00877 e++;
00878 if (!*e) {
00879 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n",
00880 p->filename, p->startline, p->endline, p->u1.str);
00881 warns++;
00882 }
00883 if (sscanf(times, "%2d:%2d", &s1, &s2) != 2) {
00884 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) isn't quite right!\n",
00885 p->filename, p->startline, p->endline, times);
00886 warns++;
00887 }
00888 if (sscanf(e, "%2d:%2d", &e1, &e2) != 2) {
00889 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) isn't quite right!\n",
00890 p->filename, p->startline, p->endline, times);
00891 warns++;
00892 }
00893
00894 s1 = s1 * 30 + s2/2;
00895 if ((s1 < 0) || (s1 >= 24*30)) {
00896 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) is out of range!\n",
00897 p->filename, p->startline, p->endline, times);
00898 warns++;
00899 }
00900 e1 = e1 * 30 + e2/2;
00901 if ((e1 < 0) || (e1 >= 24*30)) {
00902 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) is out of range!\n",
00903 p->filename, p->startline, p->endline, e);
00904 warns++;
00905 }
00906 return;
00907 }
00908
00909 static char *days[] =
00910 {
00911 "sun",
00912 "mon",
00913 "tue",
00914 "wed",
00915 "thu",
00916 "fri",
00917 "sat",
00918 };
00919
00920
00921 static void check_dow(pval *DOW)
00922 {
00923 char *dow;
00924 char *c;
00925
00926 int s, e;
00927
00928 dow = ast_strdupa(DOW->u1.str);
00929
00930
00931 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
00932 return;
00933
00934 c = strchr(dow, '-');
00935 if (c) {
00936 *c = '\0';
00937 c++;
00938 } else
00939 c = NULL;
00940
00941 s = 0;
00942 while ((s < 7) && strcasecmp(dow, days[s])) s++;
00943 if (s >= 7) {
00944 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n",
00945 DOW->filename, DOW->startline, DOW->endline, dow);
00946 warns++;
00947 }
00948 if (c) {
00949 e = 0;
00950 while ((e < 7) && strcasecmp(c, days[e])) e++;
00951 if (e >= 7) {
00952 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n",
00953 DOW->filename, DOW->startline, DOW->endline, c);
00954 warns++;
00955 }
00956 } else
00957 e = s;
00958 }
00959
00960 static void check_day(pval *DAY)
00961 {
00962 char *day;
00963 char *c;
00964
00965 int s, e;
00966
00967 day = ast_strdupa(DAY->u1.str);
00968
00969
00970 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
00971 return;
00972 }
00973
00974 c = strchr(day, '-');
00975 if (c) {
00976 *c = '\0';
00977 c++;
00978 }
00979
00980 if (sscanf(day, "%2d", &s) != 1) {
00981 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number!\n",
00982 DAY->filename, DAY->startline, DAY->endline, day);
00983 warns++;
00984 }
00985 else if ((s < 1) || (s > 31)) {
00986 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number in the range [1-31]!\n",
00987 DAY->filename, DAY->startline, DAY->endline, day);
00988 warns++;
00989 }
00990 s--;
00991 if (c) {
00992 if (sscanf(c, "%2d", &e) != 1) {
00993 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number!\n",
00994 DAY->filename, DAY->startline, DAY->endline, c);
00995 warns++;
00996 }
00997 else if ((e < 1) || (e > 31)) {
00998 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number in the range [1-31]!\n",
00999 DAY->filename, DAY->startline, DAY->endline, day);
01000 warns++;
01001 }
01002 e--;
01003 } else
01004 e = s;
01005 }
01006
01007 static char *months[] =
01008 {
01009 "jan",
01010 "feb",
01011 "mar",
01012 "apr",
01013 "may",
01014 "jun",
01015 "jul",
01016 "aug",
01017 "sep",
01018 "oct",
01019 "nov",
01020 "dec",
01021 };
01022
01023 static void check_month(pval *MON)
01024 {
01025 char *mon;
01026 char *c;
01027
01028 int s, e;
01029
01030 mon = ast_strdupa(MON->u1.str);
01031
01032
01033 if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
01034 return ;
01035
01036 c = strchr(mon, '-');
01037 if (c) {
01038 *c = '\0';
01039 c++;
01040 }
01041
01042 s = 0;
01043 while ((s < 12) && strcasecmp(mon, months[s])) s++;
01044 if (s >= 12) {
01045 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
01046 MON->filename, MON->startline, MON->endline, mon);
01047 warns++;
01048 }
01049 if (c) {
01050 e = 0;
01051 while ((e < 12) && strcasecmp(mon, months[e])) e++;
01052 if (e >= 12) {
01053 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
01054 MON->filename, MON->startline, MON->endline, c);
01055 warns++;
01056 }
01057 } else
01058 e = s;
01059 }
01060
01061 static int check_break(pval *item)
01062 {
01063 pval *p = item;
01064
01065 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) {
01066
01067
01068 if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN
01069 || p->type == PV_WHILE || p->type == PV_FOR ) {
01070 return 1;
01071 }
01072 p = p->dad;
01073 }
01074 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'break' not in switch, for, or while statement!\n",
01075 item->filename, item->startline, item->endline);
01076 errs++;
01077
01078 return 0;
01079 }
01080
01081 static int check_continue(pval *item)
01082 {
01083 pval *p = item;
01084
01085 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) {
01086
01087
01088 if( p->type == PV_WHILE || p->type == PV_FOR ) {
01089 return 1;
01090 }
01091 p = p->dad;
01092 }
01093 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'continue' not in 'for' or 'while' statement!\n",
01094 item->filename, item->startline, item->endline);
01095 errs++;
01096
01097 return 0;
01098 }
01099
01100
01101
01102
01103 static void check_label(pval *item)
01104 {
01105
01106
01107
01108 struct pval *curr;
01109 struct pval *x;
01110
01111
01112 if( !current_extension )
01113 curr = current_context;
01114 else
01115 curr = current_extension;
01116
01117 x = find_first_label_in_current_context((char *)item->u1.str, curr);
01118
01119 if( x && x != item )
01120 {
01121 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Duplicate label %s! Previously defined at file %s, line %d.\n",
01122 item->filename, item->startline, item->endline, item->u1.str, x->filename, x->startline);
01123 errs++;
01124 }
01125
01126 }
01127
01128 static pval *get_goto_target(pval *item)
01129 {
01130
01131 pval *curr_ext = get_extension_or_contxt(item);
01132 pval *curr_cont;
01133
01134 if (item->u1.list && !item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) {
01135 struct pval *x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), curr_ext);
01136 return x;
01137 }
01138
01139 curr_cont = get_contxt(item);
01140
01141
01142 if (item->u1.list->next && !item->u1.list->next->next) {
01143 if (!strstr((item->u1.list)->u1.str,"${")
01144 && !strstr(item->u1.list->next->u1.str,"${") ) {
01145 struct pval *x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, curr_cont);
01146 return x;
01147 }
01148 }
01149
01150
01151 if (item->u1.list->next && item->u1.list->next->next) {
01152
01153 pval *first = item->u1.list;
01154 pval *second = item->u1.list->next;
01155 pval *third = item->u1.list->next->next;
01156
01157 if (!strstr((item->u1.list)->u1.str,"${")
01158 && !strstr(item->u1.list->next->u1.str,"${")
01159 && !strstr(item->u1.list->next->next->u1.str,"${")) {
01160 struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
01161 if (!x) {
01162
01163 struct pval *p3;
01164 struct pval *that_context = find_context(item->u1.list->u1.str);
01165
01166
01167
01168 if (that_context) {
01169 for (p3=that_context->u2.statements; p3; p3=p3->next) {
01170 if (p3->type == PV_INCLUDES) {
01171 struct pval *p4;
01172 for (p4=p3->u1.list; p4; p4=p4->next) {
01173
01174
01175 char *incl_context = p4->u1.str;
01176
01177 struct pval *that_other_context = find_context(incl_context);
01178 if (that_other_context) {
01179 struct pval *x3;
01180 x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
01181 if (x3) {
01182 return x3;
01183 }
01184 }
01185 }
01186 }
01187 }
01188 }
01189 }
01190 return x;
01191 }
01192 }
01193 return 0;
01194 }
01195
01196 static void check_goto(pval *item)
01197 {
01198
01199 if ( !(item->u1.list)->next && !(item->u1.list)->u1.str ) {
01200 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: empty label reference found!\n",
01201 item->filename, item->startline, item->endline);
01202 errs++;
01203 }
01204
01205
01206
01207 if (item->u1.list && !item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) {
01208 struct pval *z = get_extension_or_contxt(item);
01209 struct pval *x = 0;
01210 if (z)
01211 x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), z);
01212
01213
01214 if (!x) {
01215 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s exists in the current extension!\n",
01216 item->filename, item->startline, item->endline, item->u1.list->u1.str);
01217 errs++;
01218 }
01219 else
01220 return;
01221 }
01222
01223
01224 if (item->u1.list->next && !item->u1.list->next->next) {
01225
01226
01227
01228 if (!strstr((item->u1.list)->u1.str,"${")
01229 && !strstr(item->u1.list->next->u1.str,"${") ) {
01230 struct pval *z = get_contxt(item);
01231 struct pval *x = 0;
01232
01233 if (z)
01234 x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, z);
01235
01236 if (!x) {
01237 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s|%s exists in the current context, or any of its inclusions!\n",
01238 item->filename, item->startline, item->endline, item->u1.list->u1.str, item->u1.list->next->u1.str );
01239 errs++;
01240 }
01241 else
01242 return;
01243 }
01244 }
01245
01246
01247 if (item->u1.list->next && item->u1.list->next->next) {
01248
01249 pval *first = item->u1.list;
01250 pval *second = item->u1.list->next;
01251 pval *third = item->u1.list->next->next;
01252
01253
01254
01255 if (!strstr((item->u1.list)->u1.str,"${")
01256 && !strstr(item->u1.list->next->u1.str,"${")
01257 && !strstr(item->u1.list->next->next->u1.str,"${")) {
01258 struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
01259 if (!x) {
01260 struct pval *p3;
01261 struct pval *found = 0;
01262 struct pval *that_context = find_context(item->u1.list->u1.str);
01263
01264
01265
01266 if (that_context) {
01267 for (p3=that_context->u2.statements; p3; p3=p3->next) {
01268 if (p3->type == PV_INCLUDES) {
01269 struct pval *p4;
01270 for (p4=p3->u1.list; p4; p4=p4->next) {
01271
01272
01273 char *incl_context = p4->u1.str;
01274
01275 struct pval *that_other_context = find_context(incl_context);
01276 if (that_other_context) {
01277 struct pval *x3;
01278 x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
01279 if (x3) {
01280 found = x3;
01281 break;
01282 }
01283 }
01284 }
01285 }
01286 }
01287 if (!found) {
01288 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s|%s exists in the context %s or its inclusions!\n",
01289 item->filename, item->startline, item->endline, item->u1.list->next->u1.str, item->u1.list->next->next->u1.str, item->u1.list->u1.str );
01290 errs++;
01291 }
01292 } else {
01293
01294 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: no context %s could be found that matches the goto target!\n",
01295 item->filename, item->startline, item->endline, item->u1.list->u1.str);
01296 warns++;
01297 }
01298 }
01299 }
01300 }
01301 }
01302
01303
01304 static void find_pval_goto_item(pval *item, int lev)
01305 {
01306 struct pval *p4;
01307
01308 if (lev>100) {
01309 ast_log(LOG_ERROR,"find_pval_goto in infinite loop! item_type: %d\n\n", item->type);
01310 return;
01311 }
01312
01313 switch ( item->type ) {
01314 case PV_MACRO:
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324 find_pval_gotos(item->u3.macro_statements,lev+1);
01325
01326 break;
01327
01328 case PV_CONTEXT:
01329
01330
01331
01332
01333 break;
01334
01335 case PV_CASE:
01336
01337
01338
01339
01340 find_pval_gotos(item->u2.statements,lev+1);
01341 break;
01342
01343 case PV_PATTERN:
01344
01345
01346
01347
01348 find_pval_gotos(item->u2.statements,lev+1);
01349 break;
01350
01351 case PV_DEFAULT:
01352
01353
01354
01355
01356 find_pval_gotos(item->u2.statements,lev+1);
01357 break;
01358
01359 case PV_CATCH:
01360
01361
01362
01363
01364 find_pval_gotos(item->u2.statements,lev+1);
01365 break;
01366
01367 case PV_STATEMENTBLOCK:
01368
01369
01370
01371 find_pval_gotos(item->u1.list,lev+1);
01372 break;
01373
01374 case PV_GOTO:
01375
01376
01377
01378 check_goto(item);
01379 break;
01380
01381 case PV_INCLUDES:
01382
01383
01384 for (p4=item->u1.list; p4; p4=p4->next) {
01385
01386
01387 char *incl_context = p4->u1.str;
01388
01389 struct pval *that_context = find_context(incl_context);
01390 if (that_context && that_context->u2.statements) {
01391
01392 find_pval_gotos(that_context->u2.statements,lev+1);
01393 }
01394 }
01395 break;
01396
01397 case PV_FOR:
01398
01399
01400
01401
01402
01403
01404
01405 find_pval_gotos(item->u4.for_statements,lev+1);
01406 break;
01407
01408 case PV_WHILE:
01409
01410
01411
01412
01413
01414 find_pval_gotos(item->u2.statements,lev+1);
01415 break;
01416
01417 case PV_RANDOM:
01418
01419
01420
01421
01422
01423
01424
01425 case PV_IFTIME:
01426
01427
01428
01429
01430
01431
01432 case PV_IF:
01433
01434
01435
01436
01437
01438
01439
01440 find_pval_gotos(item->u2.statements,lev+1);
01441
01442 if (item->u3.else_statements) {
01443
01444 find_pval_gotos(item->u3.else_statements,lev+1);
01445 }
01446 break;
01447
01448 case PV_SWITCH:
01449
01450
01451
01452
01453
01454
01455 find_pval_gotos(item->u3.else_statements,lev+1);
01456 break;
01457
01458 case PV_EXTENSION:
01459
01460
01461
01462
01463
01464
01465
01466
01467 find_pval_gotos(item->u2.statements,lev+1);
01468 break;
01469
01470 default:
01471 break;
01472 }
01473 }
01474
01475 static void find_pval_gotos(pval *item,int lev)
01476 {
01477 pval *i;
01478
01479 for (i=item; i; i=i->next) {
01480
01481 find_pval_goto_item(i, lev);
01482 }
01483 }
01484
01485
01486
01487
01488 static struct pval *match_pval_item(pval *item)
01489 {
01490 pval *x;
01491
01492 switch ( item->type ) {
01493 case PV_MACRO:
01494
01495
01496
01497
01498
01499
01500
01501
01502 if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
01503
01504
01505
01506 if (return_on_context_match && !strcmp(item->u1.str, match_context)) {
01507
01508 return item;
01509 }
01510
01511
01512 if (!return_on_context_match) {
01513
01514 if ((x=match_pval(item->u3.macro_statements))) {
01515
01516 return x;
01517 }
01518 }
01519 } else {
01520
01521 }
01522
01523 break;
01524
01525 case PV_CONTEXT:
01526
01527
01528
01529
01530
01531 if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
01532 if (return_on_context_match && !strcmp(item->u1.str, match_context)) {
01533
01534
01535 return item;
01536 }
01537
01538 if (!return_on_context_match ) {
01539
01540 if ((x=match_pval(item->u2.statements))) {
01541
01542 return x;
01543 }
01544 }
01545 } else {
01546
01547 }
01548 break;
01549
01550 case PV_CASE:
01551
01552
01553
01554
01555 if ((x=match_pval(item->u2.statements))) {
01556
01557 return x;
01558 }
01559 break;
01560
01561 case PV_PATTERN:
01562
01563
01564
01565
01566 if ((x=match_pval(item->u2.statements))) {
01567
01568 return x;
01569 }
01570 break;
01571
01572 case PV_DEFAULT:
01573
01574
01575
01576
01577 if ((x=match_pval(item->u2.statements))) {
01578
01579 return x;
01580 }
01581 break;
01582
01583 case PV_CATCH:
01584
01585
01586
01587
01588 if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) {
01589
01590 if (strcmp(match_label,"1") == 0) {
01591 if (item->u2.statements) {
01592 struct pval *p5 = item->u2.statements;
01593 while (p5 && p5->type == PV_LABEL)
01594 p5 = p5->next;
01595 if (p5)
01596 return p5;
01597 else
01598 return 0;
01599 }
01600 else
01601 return 0;
01602 }
01603
01604 if ((x=match_pval(item->u2.statements))) {
01605
01606 return x;
01607 }
01608 } else {
01609
01610 }
01611 break;
01612
01613 case PV_STATEMENTBLOCK:
01614
01615
01616
01617 if ((x=match_pval(item->u1.list))) {
01618
01619 return x;
01620 }
01621 break;
01622
01623 case PV_LABEL:
01624
01625
01626
01627
01628
01629 if (count_labels) {
01630 if (!strcmp(match_label, item->u1.str)) {
01631 label_count++;
01632 last_matched_label = item;
01633 }
01634
01635 } else {
01636 if (!strcmp(match_label, item->u1.str)) {
01637
01638 return item;
01639 }
01640 }
01641 break;
01642
01643 case PV_FOR:
01644
01645
01646
01647
01648
01649
01650
01651 if ((x=match_pval(item->u4.for_statements))) {
01652
01653 return x;
01654 }
01655 break;
01656
01657 case PV_WHILE:
01658
01659
01660
01661
01662
01663 if ((x=match_pval(item->u2.statements))) {
01664
01665 return x;
01666 }
01667 break;
01668
01669 case PV_RANDOM:
01670
01671
01672
01673
01674
01675
01676
01677 case PV_IFTIME:
01678
01679
01680
01681
01682
01683
01684 case PV_IF:
01685
01686
01687
01688
01689
01690
01691
01692 if ((x=match_pval(item->u2.statements))) {
01693 return x;
01694 }
01695 if (item->u3.else_statements) {
01696 if ((x=match_pval(item->u3.else_statements))) {
01697
01698 return x;
01699 }
01700 }
01701 break;
01702
01703 case PV_SWITCH:
01704
01705
01706
01707
01708
01709
01710 if ((x=match_pval(item->u2.statements))) {
01711
01712 return x;
01713 }
01714 break;
01715
01716 case PV_EXTENSION:
01717
01718
01719
01720
01721
01722
01723
01724 if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) {
01725
01726 if (strcmp(match_label,"1") == 0) {
01727 if (item->u2.statements) {
01728 struct pval *p5 = item->u2.statements;
01729 while (p5 && p5->type == PV_LABEL)
01730 p5 = p5->next;
01731 if (p5)
01732 return p5;
01733 else
01734 return 0;
01735 }
01736 else
01737 return 0;
01738 }
01739
01740 if ((x=match_pval(item->u2.statements))) {
01741
01742 return x;
01743 }
01744 } else {
01745
01746 }
01747 break;
01748 default:
01749
01750 break;
01751 }
01752 return 0;
01753 }
01754
01755 struct pval *match_pval(pval *item)
01756 {
01757 pval *i;
01758
01759 for (i=item; i; i=i->next) {
01760 pval *x;
01761
01762
01763 if ((x = match_pval_item(i))) {
01764
01765 return x;
01766 }
01767 }
01768 return 0;
01769 }
01770
01771 #if 0
01772 int count_labels_in_current_context(char *label)
01773 {
01774 label_count = 0;
01775 count_labels = 1;
01776 return_on_context_match = 0;
01777 match_pval(current_context->u2.statements);
01778
01779 return label_count;
01780 }
01781 #endif
01782
01783 struct pval *find_first_label_in_current_context(char *label, pval *curr_cont)
01784 {
01785
01786 struct pval *ret;
01787 struct pval *p3;
01788 struct pval *startpt = ((curr_cont->type==PV_MACRO)?curr_cont->u3.macro_statements: curr_cont->u2.statements);
01789
01790 count_labels = 0;
01791 return_on_context_match = 0;
01792 match_context = "*";
01793 match_exten = "*";
01794 match_label = label;
01795
01796 ret = match_pval(curr_cont);
01797 if (ret)
01798 return ret;
01799
01800
01801
01802 for (p3=startpt; p3; p3=p3->next) {
01803 if (p3->type == PV_INCLUDES) {
01804 struct pval *p4;
01805 for (p4=p3->u1.list; p4; p4=p4->next) {
01806
01807
01808 char *incl_context = p4->u1.str;
01809
01810 struct pval *that_context = find_context(incl_context);
01811 if (that_context) {
01812 struct pval *x3;
01813 x3 = find_first_label_in_current_context(label, that_context);
01814 if (x3) {
01815 return x3;
01816 }
01817 }
01818 }
01819 }
01820 }
01821 return 0;
01822 }
01823
01824 struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont)
01825 {
01826
01827 struct pval *ret;
01828 struct pval *p3;
01829 struct pval *startpt;
01830
01831 count_labels = 0;
01832 return_on_context_match = 0;
01833 match_context = "*";
01834 match_exten = exten;
01835 match_label = label;
01836 if (curr_cont->type == PV_MACRO)
01837 startpt = curr_cont->u3.macro_statements;
01838 else
01839 startpt = curr_cont->u2.statements;
01840
01841 ret = match_pval(startpt);
01842 if (ret)
01843 return ret;
01844
01845
01846
01847 for (p3=startpt; p3; p3=p3->next) {
01848 if (p3->type == PV_INCLUDES) {
01849 struct pval *p4;
01850 for (p4=p3->u1.list; p4; p4=p4->next) {
01851
01852
01853 char *incl_context = p4->u1.str;
01854
01855 struct pval *that_context = find_context(incl_context);
01856 if (that_context) {
01857 struct pval *x3;
01858 x3 = find_label_in_current_context(exten, label, that_context);
01859 if (x3) {
01860 return x3;
01861 }
01862 }
01863 }
01864 }
01865 }
01866 return 0;
01867 }
01868
01869 static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext)
01870 {
01871
01872 count_labels = 0;
01873 return_on_context_match = 0;
01874 match_context = "*";
01875 match_exten = "*";
01876 match_label = label;
01877 return match_pval(curr_ext);
01878 }
01879
01880 static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label)
01881 {
01882
01883 count_labels = 0;
01884 return_on_context_match = 0;
01885
01886 match_context = context;
01887 match_exten = exten;
01888 match_label = label;
01889
01890 return match_pval(current_db);
01891 }
01892
01893
01894 struct pval *find_macro(char *name)
01895 {
01896 return_on_context_match = 1;
01897 count_labels = 0;
01898 match_context = name;
01899 match_exten = "*";
01900 match_label = "*";
01901 return match_pval(current_db);
01902 }
01903
01904 struct pval *find_context(char *name)
01905 {
01906 return_on_context_match = 1;
01907 count_labels = 0;
01908 match_context = name;
01909 match_exten = "*";
01910 match_label = "*";
01911 return match_pval(current_db);
01912 }
01913
01914 int is_float(char *arg )
01915 {
01916 char *s;
01917 for (s=arg; *s; s++) {
01918 if (*s != '.' && (*s < '0' || *s > '9'))
01919 return 0;
01920 }
01921 return 1;
01922 }
01923 int is_int(char *arg )
01924 {
01925 char *s;
01926 for (s=arg; *s; s++) {
01927 if (*s < '0' || *s > '9')
01928 return 0;
01929 }
01930 return 1;
01931 }
01932 int is_empty(char *arg)
01933 {
01934 if (!arg)
01935 return 1;
01936 if (*arg == 0)
01937 return 1;
01938 while (*arg) {
01939 if (*arg != ' ' && *arg != '\t')
01940 return 0;
01941 arg++;
01942 }
01943 return 1;
01944 }
01945
01946 #ifdef AAL_ARGCHECK
01947 int option_matches_j( struct argdesc *should, pval *is, struct argapp *app)
01948 {
01949 struct argchoice *ac;
01950 char *opcop,*q,*p;
01951
01952 switch (should->dtype) {
01953 case ARGD_OPTIONSET:
01954 if ( strstr(is->u1.str,"${") )
01955 return 0;
01956
01957 opcop = ast_strdupa(is->u1.str);
01958
01959 for (q=opcop;*q;q++) {
01960 if ( *q == '(' ) {
01961 p = q+1;
01962 while (*p && *p != ')' )
01963 *p++ = '+';
01964 q = p+1;
01965 }
01966 }
01967
01968 for (ac=app->opts; ac; ac=ac->next) {
01969 if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0)
01970 return 0;
01971 }
01972 for (ac=app->opts; ac; ac=ac->next) {
01973 if (strlen(ac->name)==1 || strchr(ac->name,'(')) {
01974 char *p = strchr(opcop,ac->name[0]);
01975
01976 if (p && *p == 'j') {
01977 ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The j option in the %s application call is not appropriate for AEL!\n",
01978 is->filename, is->startline, is->endline, app->name);
01979 errs++;
01980 }
01981
01982 if (p) {
01983 *p = '+';
01984 if (ac->name[1] == '(') {
01985 if (*(p+1) != '(') {
01986 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The %c option in the %s application call should have an (argument), but doesn't!\n",
01987 is->filename, is->startline, is->endline, ac->name[0], app->name);
01988 warns++;
01989 }
01990 }
01991 }
01992 }
01993 }
01994 for (q=opcop; *q; q++) {
01995 if ( *q != '+' && *q != '(' && *q != ')') {
01996 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The %c option in the %s application call is not available as an option!\n",
01997 is->filename, is->startline, is->endline, *q, app->name);
01998 warns++;
01999 }
02000 }
02001 return 1;
02002 break;
02003 default:
02004 return 0;
02005 }
02006
02007 }
02008
02009 int option_matches( struct argdesc *should, pval *is, struct argapp *app)
02010 {
02011 struct argchoice *ac;
02012 char *opcop;
02013
02014 switch (should->dtype) {
02015 case ARGD_STRING:
02016 if (is_empty(is->u1.str) && should->type == ARGD_REQUIRED)
02017 return 0;
02018 if (is->u1.str && strlen(is->u1.str) > 0)
02019 return 1;
02020 break;
02021
02022 case ARGD_INT:
02023 if (is_int(is->u1.str))
02024 return 1;
02025 else
02026 return 0;
02027 break;
02028
02029 case ARGD_FLOAT:
02030 if (is_float(is->u1.str))
02031 return 1;
02032 else
02033 return 0;
02034 break;
02035
02036 case ARGD_ENUM:
02037 if( !is->u1.str || strlen(is->u1.str) == 0 )
02038 return 1;
02039 for (ac=should->choices; ac; ac=ac->next) {
02040 if (strcmp(ac->name,is->u1.str) == 0)
02041 return 1;
02042 }
02043 return 0;
02044 break;
02045
02046 case ARGD_OPTIONSET:
02047 opcop = ast_strdupa(is->u1.str);
02048
02049 for (ac=app->opts; ac; ac=ac->next) {
02050 if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0)
02051 return 1;
02052 }
02053 for (ac=app->opts; ac; ac=ac->next) {
02054 if (strlen(ac->name)==1 || strchr(ac->name,'(')) {
02055 char *p = strchr(opcop,ac->name[0]);
02056
02057 if (p) {
02058 *p = '+';
02059 if (ac->name[1] == '(') {
02060 if (*(p+1) == '(') {
02061 char *q = p+1;
02062 while (*q && *q != ')') {
02063 *q++ = '+';
02064 }
02065 *q = '+';
02066 }
02067 }
02068 }
02069 }
02070 }
02071 return 1;
02072 break;
02073 case ARGD_VARARG:
02074 return 1;
02075 break;
02076 }
02077 return 1;
02078 }
02079 #endif
02080
02081 int check_app_args(pval* appcall, pval *arglist, struct argapp *app)
02082 {
02083 #ifdef AAL_ARGCHECK
02084 struct argdesc *ad = app->args;
02085 pval *pa;
02086 int z;
02087
02088 for (pa = arglist; pa; pa=pa->next) {
02089 if (!ad) {
02090 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
02091 arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
02092 warns++;
02093 return 1;
02094 } else {
02095
02096 do {
02097 if ( ad->dtype == ARGD_VARARG )
02098 break;
02099
02100 z= option_matches( ad, pa, app);
02101 if (!z) {
02102 if ( !arglist )
02103 arglist=appcall;
02104
02105 if (ad->type == ARGD_REQUIRED) {
02106 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02107 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02108 warns++;
02109 return 1;
02110 }
02111 } else if (z && ad->dtype == ARGD_OPTIONSET) {
02112 option_matches_j( ad, pa, app);
02113 }
02114 ad = ad->next;
02115 } while (ad && !z);
02116 }
02117 }
02118
02119 for ( ; ad; ad=ad->next) {
02120 if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
02121 if ( !arglist )
02122 arglist=appcall;
02123 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02124 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02125 warns++;
02126 return 1;
02127 }
02128 }
02129 return 0;
02130 #else
02131 return 0;
02132 #endif
02133 }
02134
02135 void check_switch_expr(pval *item, struct argapp *apps)
02136 {
02137 #ifdef AAL_ARGCHECK
02138
02139 char *buff1, *p;
02140 struct argapp *a,*a2;
02141 struct appsetvar *v,*v2;
02142 struct argchoice *c;
02143 pval *t;
02144
02145 p = item->u1.str;
02146 while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) )
02147 p++;
02148
02149 buff1 = ast_strdupa(p);
02150
02151 while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t'))
02152 buff1[strlen(buff1)-1] = 0;
02153
02154 v = 0;
02155 for (a=apps; a; a=a->next) {
02156 for (v=a->setvars;v;v=v->next) {
02157 if (strcmp(v->name,buff1) == 0) {
02158 break;
02159 }
02160 }
02161 if ( v )
02162 break;
02163 }
02164 if (v && v->vals) {
02165
02166 int def= 0;
02167 int pat = 0;
02168 int f1 = 0;
02169
02170
02171 for (t=item->u2.statements; t; t=t->next) {
02172 if (t->type == PV_DEFAULT) {
02173 def =1;
02174 break;
02175 }
02176 if (t->type == PV_PATTERN) {
02177 pat++;
02178 }
02179 }
02180 if (def || pat)
02181 return;
02182 for (c=v->vals; c; c=c->next) {
02183 f1 = 0;
02184 for (t=item->u2.statements; t; t=t->next) {
02185 if (t->type == PV_CASE || t->type == PV_PATTERN) {
02186 if (!strcmp(t->u1.str,c->name)) {
02187 f1 = 1;
02188 break;
02189 }
02190 }
02191 }
02192 if (!f1) {
02193 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n",
02194 item->filename, item->startline, item->endline, item->u1.str, c->name);
02195 warns++;
02196 }
02197 }
02198
02199 f1 = 0;
02200 t = current_extension->u2.statements;
02201 if ( t && t->type == PV_STATEMENTBLOCK )
02202 t = t->u1.statements;
02203 for (; t && t != item; t=t->next) {
02204 if (t->type == PV_APPLICATION_CALL) {
02205
02206 for (a2=apps; a2; a2=a2->next) {
02207 if (strcasecmp(a2->name, t->u1.str)==0) {
02208 for (v2=a2->setvars; v2; v2=v2->next) {
02209 if (strcmp(v2->name, buff1) == 0) {
02210
02211 f1 = 1;
02212 break;
02213 }
02214 }
02215 }
02216 if (f1)
02217 break;
02218 }
02219 }
02220 if (f1)
02221 break;
02222 }
02223
02224
02225 if (!f1) {
02226 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: Couldn't find an application call in this extension that sets the expression (%s) value!\n",
02227 item->filename, item->startline, item->endline, item->u1.str);
02228 warns++;
02229 }
02230 }
02231 #else
02232 pval *t,*tl=0,*p2;
02233 int def= 0;
02234
02235
02236 for (t=item->u2.statements; t; t=t->next) {
02237 if (t->type == PV_DEFAULT) {
02238 def =1;
02239 break;
02240 }
02241 tl = t;
02242 }
02243 if (def)
02244 return;
02245
02246 p2 = tl->next = calloc(1, sizeof(struct pval));
02247
02248 p2->type = PV_DEFAULT;
02249 p2->startline = tl->startline;
02250 p2->endline = tl->endline;
02251 p2->startcol = tl->startcol;
02252 p2->endcol = tl->endcol;
02253 p2->filename = strdup(tl->filename);
02254 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n",
02255 p2->filename, p2->startline, p2->endline);
02256 warns++;
02257
02258 #endif
02259 }
02260
02261 static void check_context_names(void)
02262 {
02263 pval *i,*j;
02264 for (i=current_db; i; i=i->next) {
02265 if (i->type == PV_CONTEXT || i->type == PV_MACRO) {
02266 for (j=i->next; j; j=j->next) {
02267 if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) {
02268 if ( !strcmp(i->u1.str, j->u1.str) && !(i->u3.abstract&2) && !(j->u3.abstract&2) )
02269 {
02270 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: The context name (%s) is also declared in file %s, line %d-%d! (and neither is marked 'extend')\n",
02271 i->filename, i->startline, i->endline, i->u1.str, j->filename, j->startline, j->endline);
02272 errs++;
02273 }
02274 }
02275 }
02276 }
02277 }
02278 }
02279
02280 static void check_abstract_reference(pval *abstract_context)
02281 {
02282 pval *i,*j;
02283
02284
02285
02286
02287 for (i=current_db; i; i=i->next) {
02288 if (i->type == PV_CONTEXT) {
02289 for (j=i->u2. statements; j; j=j->next) {
02290 if ( j->type == PV_INCLUDES ) {
02291 struct pval *p4;
02292 for (p4=j->u1.list; p4; p4=p4->next) {
02293
02294
02295 if ( !strcmp(p4->u1.str, abstract_context->u1.str) )
02296 return;
02297 }
02298 }
02299 }
02300 }
02301 }
02302 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: Couldn't find a reference to this abstract context (%s) in any other context!\n",
02303 abstract_context->filename, abstract_context->startline, abstract_context->endline, abstract_context->u1.str);
02304 warns++;
02305 }
02306
02307
02308 void check_pval_item(pval *item, struct argapp *apps, int in_globals)
02309 {
02310 pval *lp;
02311 #ifdef AAL_ARGCHECK
02312 struct argapp *app, *found;
02313 #endif
02314 struct pval *macro_def;
02315 struct pval *app_def;
02316
02317 char errmsg[4096];
02318 char *strp;
02319
02320 switch (item->type) {
02321 case PV_WORD:
02322
02323
02324 break;
02325
02326 case PV_MACRO:
02327
02328
02329
02330
02331
02332
02333
02334 in_abstract_context = 0;
02335 current_context = item;
02336 current_extension = 0;
02337 for (lp=item->u2.arglist; lp; lp=lp->next) {
02338
02339 }
02340 check_pval(item->u3.macro_statements, apps,in_globals);
02341 break;
02342
02343 case PV_CONTEXT:
02344
02345
02346
02347
02348 current_context = item;
02349 current_extension = 0;
02350 if ( item->u3.abstract ) {
02351 in_abstract_context = 1;
02352 check_abstract_reference(item);
02353 } else
02354 in_abstract_context = 0;
02355 check_pval(item->u2.statements, apps,in_globals);
02356 break;
02357
02358 case PV_MACRO_CALL:
02359
02360
02361
02362
02363
02364 macro_def = find_macro(item->u1.str);
02365 if (!macro_def) {
02366
02367 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s ! Hopefully it is present in extensions.conf! \n",
02368 item->filename, item->startline, item->endline, item->u1.str);
02369 warns++;
02370 } else if (macro_def->type != PV_MACRO) {
02371 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n",
02372 item->filename, item->startline, item->endline, item->u1.str);
02373 errs++;
02374 } else {
02375
02376 int hereargs = 0;
02377 int thereargs = 0;
02378
02379 for (lp=item->u2.arglist; lp; lp=lp->next) {
02380 hereargs++;
02381 }
02382 for (lp=macro_def->u2.arglist; lp; lp=lp->next) {
02383 thereargs++;
02384 }
02385 if (hereargs != thereargs ) {
02386 ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The macro call to %s has %d arguments, but the macro definition has %d arguments\n",
02387 item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs);
02388 errs++;
02389 }
02390 }
02391 break;
02392
02393 case PV_APPLICATION_CALL:
02394
02395
02396
02397
02398
02399
02400 app_def = find_context(item->u1.str);
02401 if (app_def && app_def->type == PV_MACRO) {
02402 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n",
02403 item->filename, item->startline, item->endline, item->u1.str);
02404 errs++;
02405 }
02406 if (strcasecmp(item->u1.str,"GotoIf") == 0
02407 || strcasecmp(item->u1.str,"GotoIfTime") == 0
02408 || strcasecmp(item->u1.str,"while") == 0
02409 || strcasecmp(item->u1.str,"endwhile") == 0
02410 || strcasecmp(item->u1.str,"random") == 0
02411 || strcasecmp(item->u1.str,"execIf") == 0 ) {
02412 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s needs to be re-written using AEL if, while, goto, etc. keywords instead!\n",
02413 item->filename, item->startline, item->endline, item->u1.str);
02414 warns++;
02415 }
02416 #ifdef AAL_ARGCHECK
02417 found = 0;
02418 for (app=apps; app; app=app->next) {
02419 if (strcasecmp(app->name, item->u1.str) == 0) {
02420 found =app;
02421 break;
02422 }
02423 }
02424 if (!found) {
02425 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n",
02426 item->filename, item->startline, item->endline, item->u1.str);
02427 warns++;
02428 } else
02429 check_app_args(item, item->u2.arglist, app);
02430 #endif
02431 break;
02432
02433 case PV_CASE:
02434
02435
02436
02437
02438
02439 check_pval(item->u2.statements, apps,in_globals);
02440 break;
02441
02442 case PV_PATTERN:
02443
02444
02445
02446
02447
02448
02449 check_pval(item->u2.statements, apps,in_globals);
02450 break;
02451
02452 case PV_DEFAULT:
02453
02454
02455
02456
02457 check_pval(item->u2.statements, apps,in_globals);
02458 break;
02459
02460 case PV_CATCH:
02461
02462
02463
02464 check_pval(item->u2.statements, apps,in_globals);
02465 break;
02466
02467 case PV_SWITCHES:
02468
02469
02470 check_pval(item->u1.list, apps,in_globals);
02471 break;
02472
02473 case PV_ESWITCHES:
02474
02475
02476 check_pval(item->u1.list, apps,in_globals);
02477 break;
02478
02479 case PV_INCLUDES:
02480
02481
02482 check_pval(item->u1.list, apps,in_globals);
02483 check_includes(item);
02484 for (lp=item->u1.list; lp; lp=lp->next){
02485 char *incl_context = lp->u1.str;
02486 struct pval *that_context = find_context(incl_context);
02487
02488 if ( lp->u2.arglist ) {
02489 check_timerange(lp->u2.arglist);
02490 check_dow(lp->u2.arglist->next);
02491 check_day(lp->u2.arglist->next->next);
02492 check_month(lp->u2.arglist->next->next->next);
02493 }
02494
02495 if (that_context) {
02496 find_pval_gotos(that_context->u2.statements,0);
02497
02498 }
02499 }
02500 break;
02501
02502 case PV_STATEMENTBLOCK:
02503
02504
02505 check_pval(item->u1.list, apps,in_globals);
02506 break;
02507
02508 case PV_VARDEC:
02509
02510
02511
02512
02513 if( !in_globals ) {
02514 snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", config, item->startline, item->startcol, item->endcol, item->u2.val);
02515 ast_expr_register_extra_error_info(errmsg);
02516 ast_expr(item->u2.val, expr_output, sizeof(expr_output));
02517 ast_expr_clear_extra_error_info();
02518 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
02519 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02520 item->filename, item->startline, item->endline, item->u2.val);
02521 warns++;
02522 }
02523 check_expr2_input(item,item->u2.val);
02524 }
02525 break;
02526
02527 case PV_GOTO:
02528
02529
02530
02531
02532 if ( in_abstract_context )
02533 break;
02534
02535 check_goto(item);
02536 break;
02537
02538 case PV_LABEL:
02539
02540
02541 if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) {
02542 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n",
02543 item->filename, item->startline, item->endline, item->u1.str);
02544 warns++;
02545 }
02546
02547 check_label(item);
02548 break;
02549
02550 case PV_FOR:
02551
02552
02553
02554
02555
02556
02557 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, for test expr '%s':", config, item->startline, item->startcol, item->endcol, item->u2.for_test);
02558 ast_expr_register_extra_error_info(errmsg);
02559
02560 strp = strchr(item->u1.for_init, '=');
02561 if (strp) {
02562 ast_expr(strp+1, expr_output, sizeof(expr_output));
02563 }
02564 ast_expr(item->u2.for_test, expr_output, sizeof(expr_output));
02565 strp = strchr(item->u3.for_inc, '=');
02566 if (strp) {
02567 ast_expr(strp+1, expr_output, sizeof(expr_output));
02568 }
02569 if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) {
02570 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02571 item->filename, item->startline, item->endline, item->u2.for_test);
02572 warns++;
02573 }
02574 if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) {
02575 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02576 item->filename, item->startline, item->endline, item->u3.for_inc);
02577 warns++;
02578 }
02579 check_expr2_input(item,item->u2.for_test);
02580 check_expr2_input(item,item->u3.for_inc);
02581
02582 ast_expr_clear_extra_error_info();
02583 check_pval(item->u4.for_statements, apps,in_globals);
02584 break;
02585
02586 case PV_WHILE:
02587
02588
02589
02590
02591 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, while expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02592 ast_expr_register_extra_error_info(errmsg);
02593 ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02594 ast_expr_clear_extra_error_info();
02595 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02596 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02597 item->filename, item->startline, item->endline, item->u1.str);
02598 warns++;
02599 }
02600 check_expr2_input(item,item->u1.str);
02601 check_pval(item->u2.statements, apps,in_globals);
02602 break;
02603
02604 case PV_BREAK:
02605
02606
02607 check_break(item);
02608 break;
02609
02610 case PV_RETURN:
02611
02612
02613 break;
02614
02615 case PV_CONTINUE:
02616
02617
02618 check_continue(item);
02619 break;
02620
02621 case PV_RANDOM:
02622
02623
02624
02625
02626
02627
02628 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, random expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02629 ast_expr_register_extra_error_info(errmsg);
02630 ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02631 ast_expr_clear_extra_error_info();
02632 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02633 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n",
02634 item->filename, item->startline, item->endline, item->u1.str);
02635 warns++;
02636 }
02637 check_expr2_input(item,item->u1.str);
02638 check_pval(item->u2.statements, apps,in_globals);
02639 if (item->u3.else_statements) {
02640 check_pval(item->u3.else_statements, apps,in_globals);
02641 }
02642 break;
02643
02644 case PV_IFTIME:
02645
02646
02647
02648
02649
02650
02651 if ( item->u2.arglist ) {
02652 check_timerange(item->u1.list);
02653 check_dow(item->u1.list->next);
02654 check_day(item->u1.list->next->next);
02655 check_month(item->u1.list->next->next->next);
02656 }
02657
02658 check_pval(item->u2.statements, apps,in_globals);
02659 if (item->u3.else_statements) {
02660 check_pval(item->u3.else_statements, apps,in_globals);
02661 }
02662 break;
02663
02664 case PV_IF:
02665
02666
02667
02668
02669
02670
02671 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, if expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02672 ast_expr_register_extra_error_info(errmsg);
02673 ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02674 ast_expr_clear_extra_error_info();
02675 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02676 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n",
02677 item->filename, item->startline, item->endline, item->u1.str);
02678 warns++;
02679 }
02680 check_expr2_input(item,item->u1.str);
02681 check_pval(item->u2.statements, apps,in_globals);
02682 if (item->u3.else_statements) {
02683 check_pval(item->u3.else_statements, apps,in_globals);
02684 }
02685 break;
02686
02687 case PV_SWITCH:
02688
02689
02690
02691
02692
02693
02694
02695 check_switch_expr(item, apps);
02696 check_pval(item->u2.statements, apps,in_globals);
02697 break;
02698
02699 case PV_EXTENSION:
02700
02701
02702
02703
02704
02705
02706 current_extension = item ;
02707
02708 check_pval(item->u2.statements, apps,in_globals);
02709 break;
02710
02711 case PV_IGNOREPAT:
02712
02713
02714 break;
02715
02716 case PV_GLOBALS:
02717
02718
02719 in_abstract_context = 0;
02720 check_pval(item->u1.statements, apps, 1);
02721 break;
02722 default:
02723 break;
02724 }
02725 }
02726
02727 void check_pval(pval *item, struct argapp *apps, int in_globals)
02728 {
02729 pval *i;
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739
02740
02741
02742 for (i=item; i; i=i->next) {
02743 check_pval_item(i,apps,in_globals);
02744 }
02745 }
02746
02747 static void ael2_semantic_check(pval *item, int *arg_errs, int *arg_warns, int *arg_notes)
02748 {
02749
02750 #ifdef AAL_ARGCHECK
02751 int argapp_errs =0;
02752 char *rfilename, *rdirname, *xappsfilename;
02753 DIR *dir = NULL;
02754 struct dirent *de;
02755 #endif
02756 struct argapp *apps=0, *xapps=0, *app;
02757
02758 if (!item)
02759 return;
02760 #ifdef AAL_ARGCHECK
02761 rfilename = alloca(10 + strlen(ast_config_AST_VAR_DIR));
02762 sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR);
02763
02764 apps = argdesc_parse(rfilename, &argapp_errs);
02765
02766 if (argapp_errs == 0) {
02767 ast_log(LOG_NOTICE, "AEL load process: parsed default apps desc file '%s'.\n", rfilename);
02768 } else {
02769 ast_log(LOG_ERROR, "AEL load process: %d errors found parsing apps file '%s'.\n", argapp_errs, rfilename);
02770 }
02771
02772
02773 rdirname = alloca(16 + strlen(ast_config_AST_VAR_DIR));
02774 sprintf(rdirname, "%s/applist.d", ast_config_AST_VAR_DIR);
02775 dir = opendir(rdirname);
02776 if (!dir) {
02777 ast_log(LOG_WARNING, "Unable to open ael2 extra apps dir. %s is not a valid directory\n", rdirname);
02778 } else {
02779
02780 argapp_errs = 0;
02781
02782 xappsfilename = alloca(AST_MAX_FILENAME_LEN + strlen(rdirname));
02783 while ((de = readdir(dir))) {
02784 xappsfilename[0] = 0;
02785 if ((strlen(de->d_name) > 4) && !strcasecmp(de->d_name + strlen(de->d_name) - 5, ".apps")) {
02786 sprintf(xappsfilename, "%s/%s", rdirname, de->d_name);
02787 xapps = argdesc_parse(xappsfilename, &argapp_errs);
02788
02789 if(xapps != NULL) {
02790 if (argapp_errs == 0) {
02791 ast_log(LOG_NOTICE, "AEL load process: parsed extra apps desc file '%s'.\n", xappsfilename);
02792 } else {
02793 ast_log(LOG_ERROR, "AEL load process: %d errors found parsing extra apps file '%s'.\n", argapp_errs, xappsfilename);
02794 }
02795 app=xapps;
02796 while (app->next != NULL) {
02797 app=app->next;
02798 }
02799 app->next = apps;
02800 apps = xapps;
02801 } else {
02802 ast_log(LOG_WARNING, "AEL load process: no apps desc found into file '%s'.\n", xappsfilename);
02803 }
02804 }
02805 }
02806 }
02807 #endif
02808 current_db = item;
02809 errs = warns = notes = 0;
02810
02811 check_context_names();
02812 check_pval(item, apps, 0);
02813
02814 #ifdef AAL_ARGCHECK
02815 argdesc_destroy(apps);
02816 #endif
02817 current_db = 0;
02818
02819 *arg_errs = errs;
02820 *arg_warns = warns;
02821 *arg_notes = notes;
02822 }
02823
02824
02825
02826
02827
02828 static int control_statement_count = 0;
02829
02830 struct ael_priority *new_prio(void)
02831 {
02832 struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
02833 return x;
02834 }
02835
02836 struct ael_extension *new_exten(void)
02837 {
02838 struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
02839 return x;
02840 }
02841
02842 void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
02843 {
02844 char *p1, *p2;
02845
02846 if (!exten->plist) {
02847 exten->plist = prio;
02848 exten->plist_last = prio;
02849 } else {
02850 exten->plist_last->next = prio;
02851 exten->plist_last = prio;
02852 }
02853 if( !prio->exten )
02854 prio->exten = exten;
02855
02856
02857
02858
02859
02860 if (prio->appargs && ((mother_exten && mother_exten->has_switch) || exten->has_switch) ) {
02861 while ((p1 = strstr(prio->appargs, "${EXTEN}"))) {
02862 p2 = malloc(strlen(prio->appargs)+5);
02863 *p1 = 0;
02864 strcpy(p2, prio->appargs);
02865 strcat(p2, "${~~EXTEN~~}");
02866 if (*(p1+8))
02867 strcat(p2, p1+8);
02868 free(prio->appargs);
02869 prio->appargs = p2;
02870 }
02871 while ((p1 = strstr(prio->appargs, "${EXTEN:"))) {
02872 p2 = malloc(strlen(prio->appargs)+5);
02873 *p1 = 0;
02874 strcpy(p2, prio->appargs);
02875 strcat(p2, "${~~EXTEN~~:");
02876 if (*(p1+8))
02877 strcat(p2, p1+8);
02878 free(prio->appargs);
02879 prio->appargs = p2;
02880 }
02881 }
02882 }
02883
02884 void destroy_extensions(struct ael_extension *exten)
02885 {
02886 struct ael_extension *ne, *nen;
02887 for (ne=exten; ne; ne=nen) {
02888 struct ael_priority *pe, *pen;
02889
02890 if (ne->name)
02891 free(ne->name);
02892
02893
02894
02895
02896
02897 if (ne->hints)
02898 free(ne->hints);
02899
02900 for (pe=ne->plist; pe; pe=pen) {
02901 pen = pe->next;
02902 if (pe->app)
02903 free(pe->app);
02904 pe->app = 0;
02905 if (pe->appargs)
02906 free(pe->appargs);
02907 pe->appargs = 0;
02908 pe->origin = 0;
02909 pe->goto_true = 0;
02910 pe->goto_false = 0;
02911 free(pe);
02912 }
02913 nen = ne->next_exten;
02914 ne->next_exten = 0;
02915 ne->plist =0;
02916 ne->plist_last = 0;
02917 ne->next_exten = 0;
02918 ne->loop_break = 0;
02919 ne->loop_continue = 0;
02920 free(ne);
02921 }
02922 }
02923
02924 static int label_inside_case(pval *label)
02925 {
02926 pval *p = label;
02927
02928 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) {
02929 if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN ) {
02930 return 1;
02931 }
02932
02933 p = p->dad;
02934 }
02935 return 0;
02936 }
02937
02938 static void linkexten(struct ael_extension *exten, struct ael_extension *add)
02939 {
02940 add->next_exten = exten->next_exten;
02941 exten->next_exten = add;
02942 }
02943
02944 static void remove_spaces_before_equals(char *str)
02945 {
02946 char *p;
02947 while( str && *str && *str != '=' )
02948 {
02949 if( *str == ' ' || *str == '\n' || *str == '\r' || *str == '\t' )
02950 {
02951 p = str;
02952 while( *p )
02953 {
02954 *p = *(p+1);
02955 p++;
02956 }
02957 }
02958 else
02959 str++;
02960 }
02961 }
02962
02963 static void gen_match_to_pattern(char *pattern, char *result)
02964 {
02965
02966 char *p=pattern, *t=result;
02967 while (*p) {
02968 if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
02969 *t++ = '9';
02970 else if (*p == '[') {
02971 char *z = p+1;
02972 while (*z != ']')
02973 z++;
02974 if (*(z+1)== ']')
02975 z++;
02976 *t++=*(p+1);
02977 p = z;
02978 } else {
02979 *t++ = *p;
02980 }
02981 p++;
02982 }
02983 *t++ = 0;
02984 }
02985
02986
02987
02988 int find_switch_item(pval *item);
02989 int contains_switch(pval *item);
02990
02991
02992 int find_switch_item(pval *item)
02993 {
02994 switch ( item->type ) {
02995 case PV_WORD:
02996
02997 break;
02998
02999 case PV_MACRO:
03000
03001
03002
03003
03004
03005
03006
03007
03008 if (contains_switch(item->u3.macro_statements))
03009 return 1;
03010 break;
03011
03012 case PV_CONTEXT:
03013
03014
03015
03016
03017
03018 if (contains_switch(item->u2.statements))
03019 return 1;
03020 break;
03021
03022 case PV_MACRO_CALL:
03023
03024
03025
03026
03027
03028 break;
03029
03030 case PV_APPLICATION_CALL:
03031
03032
03033
03034
03035
03036 break;
03037
03038 case PV_CASE:
03039
03040
03041
03042
03043 if (contains_switch(item->u2.statements))
03044 return 1;
03045 break;
03046
03047 case PV_PATTERN:
03048
03049
03050
03051
03052 if (contains_switch(item->u2.statements))
03053 return 1;
03054 break;
03055
03056 case PV_DEFAULT:
03057
03058
03059
03060
03061 if (contains_switch(item->u2.statements))
03062 return 1;
03063 break;
03064
03065 case PV_CATCH:
03066
03067
03068
03069
03070 if (contains_switch(item->u2.statements))
03071 return 1;
03072 break;
03073
03074 case PV_SWITCHES:
03075
03076
03077 break;
03078
03079 case PV_ESWITCHES:
03080
03081
03082 break;
03083
03084 case PV_INCLUDES:
03085
03086
03087
03088 break;
03089
03090 case PV_STATEMENTBLOCK:
03091
03092
03093 if (contains_switch(item->u1.list) )
03094 return 1;
03095 break;
03096
03097 case PV_VARDEC:
03098
03099
03100
03101 break;
03102
03103 case PV_GOTO:
03104
03105
03106
03107 break;
03108
03109 case PV_LABEL:
03110
03111
03112 break;
03113
03114 case PV_FOR:
03115
03116
03117
03118
03119
03120
03121 if (contains_switch(item->u4.for_statements))
03122 return 1;
03123 break;
03124
03125 case PV_WHILE:
03126
03127
03128
03129
03130 if (contains_switch(item->u2.statements))
03131 return 1;
03132 break;
03133
03134 case PV_BREAK:
03135
03136
03137 break;
03138
03139 case PV_RETURN:
03140
03141
03142 break;
03143
03144 case PV_CONTINUE:
03145
03146
03147 break;
03148
03149 case PV_IFTIME:
03150
03151
03152
03153
03154
03155
03156 if (contains_switch(item->u2.statements))
03157 return 1;
03158 if ( item->u3.else_statements ) {
03159 if (contains_switch(item->u3.else_statements))
03160 return 1;
03161 }
03162 break;
03163
03164 case PV_RANDOM:
03165
03166
03167
03168
03169
03170
03171 if (contains_switch(item->u2.statements))
03172 return 1;
03173 if ( item->u3.else_statements ) {
03174 if (contains_switch(item->u3.else_statements))
03175 return 1;
03176 }
03177 break;
03178
03179 case PV_IF:
03180
03181
03182
03183
03184
03185
03186 if (contains_switch(item->u2.statements))
03187 return 1;
03188 if ( item->u3.else_statements ) {
03189 if (contains_switch(item->u3.else_statements))
03190 return 1;
03191 }
03192 break;
03193
03194 case PV_SWITCH:
03195
03196
03197
03198
03199
03200 return 1;
03201 break;
03202
03203 case PV_EXTENSION:
03204
03205
03206
03207
03208
03209
03210 if (contains_switch(item->u2.statements))
03211 return 1;
03212 break;
03213
03214 case PV_IGNOREPAT:
03215
03216
03217 break;
03218
03219 case PV_GLOBALS:
03220
03221
03222 break;
03223 }
03224 return 0;
03225 }
03226
03227 int contains_switch(pval *item)
03228 {
03229 pval *i;
03230
03231 for (i=item; i; i=i->next) {
03232 if (find_switch_item(i))
03233 return 1;
03234 }
03235 return 0;
03236 }
03237
03238
03239 static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *this_context )
03240 {
03241 pval *p,*p2,*p3;
03242 struct ael_priority *pr;
03243 struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end;
03244 struct ael_priority *while_test, *while_loop, *while_end;
03245 struct ael_priority *switch_set, *switch_test, *switch_end, *fall_thru, *switch_empty;
03246 struct ael_priority *if_test, *if_end, *if_skip, *if_false;
03247 #ifdef OLD_RAND_ACTION
03248 struct ael_priority *rand_test, *rand_end, *rand_skip;
03249 #endif
03250 char buf1[2000];
03251 char buf2[2000];
03252 char *strp, *strp2;
03253 char new_label[2000];
03254 int default_exists;
03255 int local_control_statement_count;
03256 struct ael_priority *loop_break_save;
03257 struct ael_priority *loop_continue_save;
03258 struct ael_extension *switch_case,*switch_null;
03259
03260 if ((mother_exten && !mother_exten->checked_switch) || (exten && !exten->checked_switch)) {
03261 if (contains_switch(statement)) {
03262 if (mother_exten) {
03263 if (!mother_exten->has_switch) {
03264 switch_set = new_prio();
03265 switch_set->type = AEL_APPCALL;
03266 switch_set->app = strdup("Set");
03267 switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
03268 linkprio(exten, switch_set, mother_exten);
03269 mother_exten->has_switch = 1;
03270 mother_exten->checked_switch = 1;
03271 if (exten) {
03272 exten->has_switch = 1;
03273 exten->checked_switch = 1;
03274 }
03275 }
03276 } else if (exten) {
03277 if (!exten->has_switch) {
03278 switch_set = new_prio();
03279 switch_set->type = AEL_APPCALL;
03280 switch_set->app = strdup("Set");
03281 switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
03282 linkprio(exten, switch_set, mother_exten);
03283 exten->has_switch = 1;
03284 exten->checked_switch = 1;
03285 if (mother_exten) {
03286 mother_exten->has_switch = 1;
03287 mother_exten->checked_switch = 1;
03288 }
03289 }
03290 }
03291 } else {
03292 if (mother_exten) {
03293 mother_exten->checked_switch = 1;
03294 }
03295 if (exten) {
03296 exten->checked_switch = 1;
03297 }
03298 }
03299 }
03300 for (p=statement; p; p=p->next) {
03301 switch (p->type) {
03302 case PV_VARDEC:
03303 pr = new_prio();
03304 pr->type = AEL_APPCALL;
03305 snprintf(buf1,sizeof(buf1),"%s=$[%s]", p->u1.str, p->u2.val);
03306 pr->app = strdup("Set");
03307 remove_spaces_before_equals(buf1);
03308 pr->appargs = strdup(buf1);
03309 pr->origin = p;
03310 linkprio(exten, pr, mother_exten);
03311 break;
03312
03313 case PV_GOTO:
03314 pr = new_prio();
03315 pr->type = AEL_APPCALL;
03316 p->u2.goto_target = get_goto_target(p);
03317 if( p->u2.goto_target ) {
03318 p->u3.goto_target_in_case = label_inside_case(p->u2.goto_target);
03319 }
03320
03321 if (!p->u1.list->next) {
03322 pr->app = strdup("Goto");
03323 if (!mother_exten)
03324 pr->appargs = strdup(p->u1.list->u1.str);
03325 else {
03326 snprintf(buf1,sizeof(buf1),"%s|%s", mother_exten->name, p->u1.list->u1.str);
03327 pr->appargs = strdup(buf1);
03328 }
03329
03330 } else if (p->u1.list->next && !p->u1.list->next->next) {
03331 snprintf(buf1,sizeof(buf1),"%s|%s", p->u1.list->u1.str, p->u1.list->next->u1.str);
03332 pr->app = strdup("Goto");
03333 pr->appargs = strdup(buf1);
03334 } else if (p->u1.list->next && p->u1.list->next->next) {
03335 snprintf(buf1,sizeof(buf1),"%s|%s|%s", p->u1.list->u1.str,
03336 p->u1.list->next->u1.str,
03337 p->u1.list->next->next->u1.str);
03338 pr->app = strdup("Goto");
03339 pr->appargs = strdup(buf1);
03340 }
03341 pr->origin = p;
03342 linkprio(exten, pr, mother_exten);
03343 break;
03344
03345 case PV_LABEL:
03346 pr = new_prio();
03347 pr->type = AEL_LABEL;
03348 pr->origin = p;
03349 p->u3.compiled_label = exten;
03350 linkprio(exten, pr, mother_exten);
03351 break;
03352
03353 case PV_FOR:
03354 control_statement_count++;
03355 loop_break_save = exten->loop_break;
03356 loop_continue_save = exten->loop_continue;
03357 snprintf(new_label,sizeof(new_label),"for-%s-%d", label, control_statement_count);
03358 for_init = new_prio();
03359 for_inc = new_prio();
03360 for_test = new_prio();
03361 for_loop = new_prio();
03362 for_end = new_prio();
03363 for_init->type = AEL_APPCALL;
03364 for_inc->type = AEL_APPCALL;
03365 for_test->type = AEL_FOR_CONTROL;
03366 for_test->goto_false = for_end;
03367 for_loop->type = AEL_CONTROL1;
03368 for_end->type = AEL_APPCALL;
03369 for_init->app = strdup("Set");
03370
03371 strcpy(buf2,p->u1.for_init);
03372 remove_spaces_before_equals(buf2);
03373 strp = strchr(buf2, '=');
03374 if (strp) {
03375 strp2 = strchr(p->u1.for_init, '=');
03376 *(strp+1) = 0;
03377 strcat(buf2,"$[");
03378 strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03379 strcat(buf2,"]");
03380 for_init->appargs = strdup(buf2);
03381
03382 } else {
03383 strp2 = p->u1.for_init;
03384 while (*strp2 && isspace(*strp2))
03385 strp2++;
03386 if (*strp2 == '&') {
03387 char *strp3 = strp2+1;
03388 while (*strp3 && isspace(*strp3))
03389 strp3++;
03390 strcpy(buf2, strp3);
03391 strp3 = strchr(buf2,'(');
03392 if (strp3) {
03393 *strp3 = '|';
03394 }
03395 while ((strp3=strchr(buf2,','))) {
03396 *strp3 = '|';
03397 }
03398 strp3 = strrchr(buf2, ')');
03399 if (strp3)
03400 *strp3 = 0;
03401
03402 for_init->appargs = strdup(buf2);
03403 if (for_init->app)
03404 free(for_init->app);
03405 for_init->app = strdup("Macro");
03406 } else {
03407 char *strp3;
03408 strcpy(buf2, strp2);
03409 strp3 = strchr(buf2,'(');
03410 if (strp3) {
03411 *strp3 = 0;
03412 if (for_init->app)
03413 free(for_init->app);
03414 for_init->app = strdup(buf2);
03415 for_init->appargs = strdup(strp3+1);
03416 strp3 = strrchr(for_init->appargs, ')');
03417 if (strp3)
03418 *strp3 = 0;
03419 }
03420 }
03421 }
03422
03423 strcpy(buf2,p->u3.for_inc);
03424 remove_spaces_before_equals(buf2);
03425 strp = strchr(buf2, '=');
03426 if (strp) {
03427 strp2 = strchr(p->u3.for_inc, '=');
03428 *(strp+1) = 0;
03429 strcat(buf2,"$[");
03430 strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03431 strcat(buf2,"]");
03432 for_inc->appargs = strdup(buf2);
03433 for_inc->app = strdup("Set");
03434 } else {
03435 strp2 = p->u3.for_inc;
03436 while (*strp2 && isspace(*strp2))
03437 strp2++;
03438 if (*strp2 == '&') {
03439 char *strp3 = strp2+1;
03440 while (*strp3 && isspace(*strp3))
03441 strp3++;
03442 strcpy(buf2, strp3);
03443 strp3 = strchr(buf2,'(');
03444 if (strp3) {
03445 *strp3 = '|';
03446 }
03447 while ((strp3=strchr(buf2,','))) {
03448 *strp3 = '|';
03449 }
03450 strp3 = strrchr(buf2, ')');
03451 if (strp3)
03452 *strp3 = 0;
03453
03454 for_inc->appargs = strdup(buf2);
03455
03456 for_inc->app = strdup("Macro");
03457 } else {
03458 char *strp3;
03459 strcpy(buf2, strp2);
03460 strp3 = strchr(buf2,'(');
03461 if (strp3) {
03462 *strp3 = 0;
03463 for_inc->app = strdup(buf2);
03464 for_inc->appargs = strdup(strp3+1);
03465 strp3 = strrchr(for_inc->appargs, ')');
03466 if (strp3)
03467 *strp3 = 0;
03468 }
03469 }
03470 }
03471 snprintf(buf1,sizeof(buf1),"$[%s]",p->u2.for_test);
03472 for_test->app = 0;
03473 for_test->appargs = strdup(buf1);
03474 for_loop->goto_true = for_test;
03475 snprintf(buf1,sizeof(buf1),"Finish for-%s-%d", label, control_statement_count);
03476 for_end->app = strdup("NoOp");
03477 for_end->appargs = strdup(buf1);
03478
03479 linkprio(exten, for_init, mother_exten);
03480 linkprio(exten, for_test, mother_exten);
03481
03482
03483 exten->loop_break = for_end;
03484 exten->loop_continue = for_inc;
03485
03486 gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context);
03487
03488 linkprio(exten, for_inc, mother_exten);
03489 linkprio(exten, for_loop, mother_exten);
03490 linkprio(exten, for_end, mother_exten);
03491
03492
03493 exten->loop_break = loop_break_save;
03494 exten->loop_continue = loop_continue_save;
03495 for_loop->origin = p;
03496 break;
03497
03498 case PV_WHILE:
03499 control_statement_count++;
03500 loop_break_save = exten->loop_break;
03501 loop_continue_save = exten->loop_continue;
03502 snprintf(new_label,sizeof(new_label),"while-%s-%d", label, control_statement_count);
03503 while_test = new_prio();
03504 while_loop = new_prio();
03505 while_end = new_prio();
03506 while_test->type = AEL_FOR_CONTROL;
03507 while_test->goto_false = while_end;
03508 while_loop->type = AEL_CONTROL1;
03509 while_end->type = AEL_APPCALL;
03510 snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str);
03511 while_test->app = 0;
03512 while_test->appargs = strdup(buf1);
03513 while_loop->goto_true = while_test;
03514 snprintf(buf1,sizeof(buf1),"Finish while-%s-%d", label, control_statement_count);
03515 while_end->app = strdup("NoOp");
03516 while_end->appargs = strdup(buf1);
03517
03518 linkprio(exten, while_test, mother_exten);
03519
03520
03521 exten->loop_break = while_end;
03522 exten->loop_continue = while_test;
03523
03524 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
03525
03526 linkprio(exten, while_loop, mother_exten);
03527 linkprio(exten, while_end, mother_exten);
03528
03529
03530 exten->loop_break = loop_break_save;
03531 exten->loop_continue = loop_continue_save;
03532 while_loop->origin = p;
03533 break;
03534
03535 case PV_SWITCH:
03536 control_statement_count++;
03537 local_control_statement_count = control_statement_count;
03538 loop_break_save = exten->loop_break;
03539 loop_continue_save = exten->loop_continue;
03540 snprintf(new_label,sizeof(new_label),"sw-%s-%d", label, control_statement_count);
03541 switch_test = new_prio();
03542 switch_end = new_prio();
03543 switch_test->type = AEL_APPCALL;
03544 switch_end->type = AEL_APPCALL;
03545 strncpy(buf2,p->u1.str,sizeof(buf2));
03546 buf2[sizeof(buf2)-1] = 0;
03547 substitute_commas(buf2);
03548 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",control_statement_count, buf2);
03549 switch_test->app = strdup("Goto");
03550 switch_test->appargs = strdup(buf1);
03551 snprintf(buf1,sizeof(buf1),"Finish switch-%s-%d", label, control_statement_count);
03552 switch_end->app = strdup("NoOp");
03553 switch_end->appargs = strdup(buf1);
03554 switch_end->origin = p;
03555 switch_end->exten = exten;
03556
03557 linkprio(exten, switch_test, mother_exten);
03558 linkprio(exten, switch_end, mother_exten);
03559
03560 exten->loop_break = switch_end;
03561 exten->loop_continue = 0;
03562 default_exists = 0;
03563
03564 for (p2=p->u2.statements; p2; p2=p2->next) {
03565
03566 if (p2->type == PV_CASE) {
03567
03568 switch_case = new_exten();
03569 if (mother_exten && mother_exten->checked_switch) {
03570 switch_case->has_switch = mother_exten->has_switch;
03571 switch_case->checked_switch = mother_exten->checked_switch;
03572 }
03573 if (exten && exten->checked_switch) {
03574 switch_case->has_switch = exten->has_switch;
03575 switch_case->checked_switch = exten->checked_switch;
03576 }
03577 switch_case->context = this_context;
03578 switch_case->is_switch = 1;
03579
03580 switch_case->loop_break = exten->loop_break;
03581 switch_case->loop_continue = exten->loop_continue;
03582
03583 linkexten(exten,switch_case);
03584 strncpy(buf2,p2->u1.str,sizeof(buf2));
03585 buf2[sizeof(buf2)-1] = 0;
03586 substitute_commas(buf2);
03587 snprintf(buf1,sizeof(buf1),"sw-%d-%s", local_control_statement_count, buf2);
03588 switch_case->name = strdup(buf1);
03589 snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count);
03590
03591 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context);
03592
03593
03594 for (p3=p2->u2.statements; p3; p3=p3->next) {
03595 if (!p3->next)
03596 break;
03597 }
03598
03599 if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN) ) {
03600
03601 if (p2->next && p2->next->type == PV_CASE) {
03602 fall_thru = new_prio();
03603 fall_thru->type = AEL_APPCALL;
03604 fall_thru->app = strdup("Goto");
03605 strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03606 buf2[sizeof(buf2)-1] = 0;
03607 substitute_commas(buf2);
03608 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03609 fall_thru->appargs = strdup(buf1);
03610 linkprio(switch_case, fall_thru, mother_exten);
03611 } else if (p2->next && p2->next->type == PV_PATTERN) {
03612 fall_thru = new_prio();
03613 fall_thru->type = AEL_APPCALL;
03614 fall_thru->app = strdup("Goto");
03615 gen_match_to_pattern(p2->next->u1.str, buf2);
03616 substitute_commas(buf2);
03617 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10", local_control_statement_count, buf2);
03618 fall_thru->appargs = strdup(buf1);
03619 linkprio(switch_case, fall_thru, mother_exten);
03620 } else if (p2->next && p2->next->type == PV_DEFAULT) {
03621 fall_thru = new_prio();
03622 fall_thru->type = AEL_APPCALL;
03623 fall_thru->app = strdup("Goto");
03624 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03625 fall_thru->appargs = strdup(buf1);
03626 linkprio(switch_case, fall_thru, mother_exten);
03627 } else if (!p2->next) {
03628 fall_thru = new_prio();
03629 fall_thru->type = AEL_CONTROL1;
03630 fall_thru->goto_true = switch_end;
03631 fall_thru->app = strdup("Goto");
03632 linkprio(switch_case, fall_thru, mother_exten);
03633 }
03634 }
03635 if (switch_case->return_needed) {
03636 char buf[2000];
03637 struct ael_priority *np2 = new_prio();
03638 np2->type = AEL_APPCALL;
03639 np2->app = strdup("NoOp");
03640 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03641 np2->appargs = strdup(buf);
03642 linkprio(switch_case, np2, mother_exten);
03643 switch_case-> return_target = np2;
03644 }
03645 } else if (p2->type == PV_PATTERN) {
03646
03647 switch_case = new_exten();
03648 if (mother_exten && mother_exten->checked_switch) {
03649 switch_case->has_switch = mother_exten->has_switch;
03650 switch_case->checked_switch = mother_exten->checked_switch;
03651 }
03652 if (exten && exten->checked_switch) {
03653 switch_case->has_switch = exten->has_switch;
03654 switch_case->checked_switch = exten->checked_switch;
03655 }
03656 switch_case->context = this_context;
03657 switch_case->is_switch = 1;
03658
03659 switch_case->loop_break = exten->loop_break;
03660 switch_case->loop_continue = exten->loop_continue;
03661
03662 linkexten(exten,switch_case);
03663 strncpy(buf2,p2->u1.str,sizeof(buf2));
03664 buf2[sizeof(buf2)-1] = 0;
03665 substitute_commas(buf2);
03666 snprintf(buf1,sizeof(buf1),"_sw-%d-%s", local_control_statement_count, buf2);
03667 switch_case->name = strdup(buf1);
03668 snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count);
03669
03670 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context);
03671
03672 for (p3=p2->u2.statements; p3; p3=p3->next) {
03673 if (!p3->next)
03674 break;
03675 }
03676
03677 if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03678
03679 if (p2->next && p2->next->type == PV_CASE) {
03680 fall_thru = new_prio();
03681 fall_thru->type = AEL_APPCALL;
03682 fall_thru->app = strdup("Goto");
03683 strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03684 buf2[sizeof(buf2)-1] = 0;
03685 substitute_commas(buf2);
03686 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03687 fall_thru->appargs = strdup(buf1);
03688 linkprio(switch_case, fall_thru, mother_exten);
03689 } else if (p2->next && p2->next->type == PV_PATTERN) {
03690 fall_thru = new_prio();
03691 fall_thru->type = AEL_APPCALL;
03692 fall_thru->app = strdup("Goto");
03693 gen_match_to_pattern(p2->next->u1.str, buf2);
03694 substitute_commas(buf2);
03695 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03696 fall_thru->appargs = strdup(buf1);
03697 linkprio(switch_case, fall_thru, mother_exten);
03698 } else if (p2->next && p2->next->type == PV_DEFAULT) {
03699 fall_thru = new_prio();
03700 fall_thru->type = AEL_APPCALL;
03701 fall_thru->app = strdup("Goto");
03702 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03703 fall_thru->appargs = strdup(buf1);
03704 linkprio(switch_case, fall_thru, mother_exten);
03705 } else if (!p2->next) {
03706 fall_thru = new_prio();
03707 fall_thru->type = AEL_CONTROL1;
03708 fall_thru->goto_true = switch_end;
03709 fall_thru->app = strdup("Goto");
03710 linkprio(switch_case, fall_thru, mother_exten);
03711 }
03712 }
03713 if (switch_case->return_needed) {
03714 char buf[2000];
03715 struct ael_priority *np2 = new_prio();
03716 np2->type = AEL_APPCALL;
03717 np2->app = strdup("NoOp");
03718 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03719 np2->appargs = strdup(buf);
03720 linkprio(switch_case, np2, mother_exten);
03721 switch_case-> return_target = np2;
03722 }
03723 } else if (p2->type == PV_DEFAULT) {
03724
03725 switch_case = new_exten();
03726 if (mother_exten && mother_exten->checked_switch) {
03727 switch_case->has_switch = mother_exten->has_switch;
03728 switch_case->checked_switch = mother_exten->checked_switch;
03729 }
03730 if (exten && exten->checked_switch) {
03731 switch_case->has_switch = exten->has_switch;
03732 switch_case->checked_switch = exten->checked_switch;
03733 }
03734 switch_case->context = this_context;
03735 switch_case->is_switch = 1;
03736
03737
03738
03739
03740
03741 default_exists++;
03742 switch_null = new_exten();
03743 if (mother_exten && mother_exten->checked_switch) {
03744 switch_null->has_switch = mother_exten->has_switch;
03745 switch_null->checked_switch = mother_exten->checked_switch;
03746 }
03747 if (exten && exten->checked_switch) {
03748 switch_null->has_switch = exten->has_switch;
03749 switch_null->checked_switch = exten->checked_switch;
03750 }
03751 switch_null->context = this_context;
03752 switch_null->is_switch = 1;
03753 switch_empty = new_prio();
03754 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03755 switch_empty->app = strdup("Goto");
03756 switch_empty->appargs = strdup(buf1);
03757 linkprio(switch_null, switch_empty, mother_exten);
03758 snprintf(buf1,sizeof(buf1),"sw-%d-", local_control_statement_count);
03759 switch_null->name = strdup(buf1);
03760 switch_null->loop_break = exten->loop_break;
03761 switch_null->loop_continue = exten->loop_continue;
03762 linkexten(exten,switch_null);
03763
03764
03765 switch_case->loop_break = exten->loop_break;
03766 switch_case->loop_continue = exten->loop_continue;
03767 linkexten(exten,switch_case);
03768 snprintf(buf1,sizeof(buf1),"_sw-%d-.", local_control_statement_count);
03769 switch_case->name = strdup(buf1);
03770
03771 snprintf(new_label,sizeof(new_label),"sw-%s-default-%d", label, local_control_statement_count);
03772
03773 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context);
03774
03775
03776 for (p3=p2->u2.statements; p3; p3=p3->next) {
03777 if (!p3->next)
03778 break;
03779 }
03780
03781 if (!p3 || (p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03782
03783 if (p2->next && p2->next->type == PV_CASE) {
03784 fall_thru = new_prio();
03785 fall_thru->type = AEL_APPCALL;
03786 fall_thru->app = strdup("Goto");
03787 strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03788 buf2[sizeof(buf2)-1] = 0;
03789 substitute_commas(buf2);
03790 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03791 fall_thru->appargs = strdup(buf1);
03792 linkprio(switch_case, fall_thru, mother_exten);
03793 } else if (p2->next && p2->next->type == PV_PATTERN) {
03794 fall_thru = new_prio();
03795 fall_thru->type = AEL_APPCALL;
03796 fall_thru->app = strdup("Goto");
03797 gen_match_to_pattern(p2->next->u1.str, buf2);
03798 substitute_commas(buf2);
03799 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03800 fall_thru->appargs = strdup(buf1);
03801 linkprio(switch_case, fall_thru, mother_exten);
03802 } else if (p2->next && p2->next->type == PV_DEFAULT) {
03803 fall_thru = new_prio();
03804 fall_thru->type = AEL_APPCALL;
03805 fall_thru->app = strdup("Goto");
03806 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03807 fall_thru->appargs = strdup(buf1);
03808 linkprio(switch_case, fall_thru, mother_exten);
03809 } else if (!p2->next) {
03810 fall_thru = new_prio();
03811 fall_thru->type = AEL_CONTROL1;
03812 fall_thru->goto_true = switch_end;
03813 fall_thru->app = strdup("Goto");
03814 linkprio(switch_case, fall_thru, mother_exten);
03815 }
03816 }
03817 if (switch_case->return_needed) {
03818 char buf[2000];
03819 struct ael_priority *np2 = new_prio();
03820 np2->type = AEL_APPCALL;
03821 np2->app = strdup("NoOp");
03822 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03823 np2->appargs = strdup(buf);
03824 linkprio(switch_case, np2, mother_exten);
03825 switch_case-> return_target = np2;
03826 }
03827 } else {
03828
03829 }
03830 }
03831
03832 exten->loop_break = loop_break_save;
03833 exten->loop_continue = loop_continue_save;
03834 switch_test->origin = p;
03835 switch_end->origin = p;
03836 break;
03837
03838 case PV_MACRO_CALL:
03839 pr = new_prio();
03840 pr->type = AEL_APPCALL;
03841 snprintf(buf1,sizeof(buf1),"%s", p->u1.str);
03842 for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03843 strcat(buf1,"|");
03844 strcat(buf1,p2->u1.str);
03845 }
03846 pr->app = strdup("Macro");
03847 pr->appargs = strdup(buf1);
03848 pr->origin = p;
03849 linkprio(exten, pr, mother_exten);
03850 break;
03851
03852 case PV_APPLICATION_CALL:
03853 pr = new_prio();
03854 pr->type = AEL_APPCALL;
03855 buf1[0] = 0;
03856 for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03857 if (p2 != p->u2.arglist )
03858 strcat(buf1,"|");
03859 substitute_commas(p2->u1.str);
03860 strcat(buf1,p2->u1.str);
03861 }
03862 pr->app = strdup(p->u1.str);
03863 pr->appargs = strdup(buf1);
03864 pr->origin = p;
03865 linkprio(exten, pr, mother_exten);
03866 break;
03867
03868 case PV_BREAK:
03869 pr = new_prio();
03870 pr->type = AEL_CONTROL1;
03871 pr->goto_true = exten->loop_break;
03872 pr->origin = p;
03873 linkprio(exten, pr, mother_exten);
03874 break;
03875
03876 case PV_RETURN:
03877 pr = new_prio();
03878 pr->type = AEL_RETURN;
03879 exten->return_needed++;
03880 pr->app = strdup("Goto");
03881 pr->appargs = strdup("");
03882 pr->origin = p;
03883 linkprio(exten, pr, mother_exten);
03884 break;
03885
03886 case PV_CONTINUE:
03887 pr = new_prio();
03888 pr->type = AEL_CONTROL1;
03889 pr->goto_true = exten->loop_continue;
03890 pr->origin = p;
03891 linkprio(exten, pr, mother_exten);
03892 break;
03893
03894 #ifdef OLD_RAND_ACTION
03895 case PV_RANDOM:
03896 control_statement_count++;
03897 snprintf(new_label,sizeof(new_label),"rand-%s-%d", label, control_statement_count);
03898 rand_test = new_prio();
03899 rand_test->type = AEL_RAND_CONTROL;
03900 snprintf(buf1,sizeof(buf1),"$[%s]",
03901 p->u1.str );
03902 rand_test->app = 0;
03903 rand_test->appargs = strdup(buf1);
03904 rand_test->origin = p;
03905
03906 rand_end = new_prio();
03907 rand_end->type = AEL_APPCALL;
03908 snprintf(buf1,sizeof(buf1),"Finish rand-%s-%d", label, control_statement_count);
03909 rand_end->app = strdup("NoOp");
03910 rand_end->appargs = strdup(buf1);
03911
03912 rand_skip = new_prio();
03913 rand_skip->type = AEL_CONTROL1;
03914 rand_skip->goto_true = rand_end;
03915 rand_skip->origin = p;
03916
03917 rand_test->goto_true = rand_skip;
03918
03919 linkprio(exten, rand_test, mother_exten);
03920
03921 if (p->u3.else_statements) {
03922 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context);
03923 }
03924
03925 linkprio(exten, rand_skip, mother_exten);
03926
03927 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
03928
03929 linkprio(exten, rand_end, mother_exten);
03930
03931 break;
03932 #endif
03933
03934 case PV_IFTIME:
03935 control_statement_count++;
03936 snprintf(new_label,sizeof(new_label),"iftime-%s-%d", label, control_statement_count);
03937
03938 if_test = new_prio();
03939 if_test->type = AEL_IFTIME_CONTROL;
03940 snprintf(buf1,sizeof(buf1),"%s|%s|%s|%s",
03941 p->u1.list->u1.str,
03942 p->u1.list->next->u1.str,
03943 p->u1.list->next->next->u1.str,
03944 p->u1.list->next->next->next->u1.str);
03945 if_test->app = 0;
03946 if_test->appargs = strdup(buf1);
03947 if_test->origin = p;
03948
03949 if_end = new_prio();
03950 if_end->type = AEL_APPCALL;
03951 snprintf(buf1,sizeof(buf1),"Finish iftime-%s-%d", label, control_statement_count);
03952 if_end->app = strdup("NoOp");
03953 if_end->appargs = strdup(buf1);
03954
03955 if (p->u3.else_statements) {
03956 if_skip = new_prio();
03957 if_skip->type = AEL_CONTROL1;
03958 if_skip->goto_true = if_end;
03959 if_skip->origin = p;
03960
03961 } else {
03962 if_skip = 0;
03963
03964 if_test->goto_false = if_end;
03965 }
03966
03967 if_false = new_prio();
03968 if_false->type = AEL_CONTROL1;
03969 if (p->u3.else_statements) {
03970 if_false->goto_true = if_skip;
03971 } else {
03972 if_false->goto_true = if_end;
03973 }
03974
03975
03976 linkprio(exten, if_test, mother_exten);
03977 linkprio(exten, if_false, mother_exten);
03978
03979
03980
03981 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
03982
03983 if (p->u3.else_statements) {
03984 linkprio(exten, if_skip, mother_exten);
03985 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context);
03986
03987 }
03988
03989 linkprio(exten, if_end, mother_exten);
03990
03991 break;
03992
03993 case PV_RANDOM:
03994 case PV_IF:
03995 control_statement_count++;
03996 snprintf(new_label,sizeof(new_label),"if-%s-%d", label, control_statement_count);
03997
03998 if_test = new_prio();
03999 if_end = new_prio();
04000 if_test->type = AEL_IF_CONTROL;
04001 if_end->type = AEL_APPCALL;
04002 if ( p->type == PV_RANDOM )
04003 snprintf(buf1,sizeof(buf1),"$[${RAND(0|99)} < (%s)]",p->u1.str);
04004 else {
04005 char buf[8000];
04006 strcpy(buf,p->u1.str);
04007 substitute_commas(buf);
04008 snprintf(buf1,sizeof(buf1),"$[%s]",buf);
04009 }
04010
04011 if_test->app = 0;
04012 if_test->appargs = strdup(buf1);
04013 snprintf(buf1,sizeof(buf1),"Finish if-%s-%d", label, control_statement_count);
04014 if_end->app = strdup("NoOp");
04015 if_end->appargs = strdup(buf1);
04016 if_test->origin = p;
04017
04018 if (p->u3.else_statements) {
04019 if_skip = new_prio();
04020 if_skip->type = AEL_CONTROL1;
04021 if_skip->goto_true = if_end;
04022 if_test->goto_false = if_skip;;
04023 } else {
04024 if_skip = 0;
04025 if_test->goto_false = if_end;;
04026 }
04027
04028
04029 linkprio(exten, if_test, mother_exten);
04030
04031
04032
04033 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context);
04034
04035 if (p->u3.else_statements) {
04036 linkprio(exten, if_skip, mother_exten);
04037 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context);
04038
04039 }
04040
04041 linkprio(exten, if_end, mother_exten);
04042
04043 break;
04044
04045 case PV_STATEMENTBLOCK:
04046 gen_prios(exten, label, p->u1.list, mother_exten, this_context );
04047 break;
04048
04049 case PV_CATCH:
04050 control_statement_count++;
04051
04052
04053 switch_case = new_exten();
04054 if (mother_exten && mother_exten->checked_switch) {
04055 switch_case->has_switch = mother_exten->has_switch;
04056 switch_case->checked_switch = mother_exten->checked_switch;
04057 }
04058 if (exten && exten->checked_switch) {
04059 switch_case->has_switch = exten->has_switch;
04060 switch_case->checked_switch = exten->checked_switch;
04061 }
04062
04063 switch_case->context = this_context;
04064 linkexten(exten,switch_case);
04065 switch_case->name = strdup(p->u1.str);
04066 snprintf(new_label,sizeof(new_label),"catch-%s-%d",p->u1.str, control_statement_count);
04067
04068 gen_prios(switch_case, new_label, p->u2.statements,mother_exten,this_context);
04069 if (switch_case->return_needed) {
04070 char buf[2000];
04071 struct ael_priority *np2 = new_prio();
04072 np2->type = AEL_APPCALL;
04073 np2->app = strdup("NoOp");
04074 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
04075 np2->appargs = strdup(buf);
04076 linkprio(switch_case, np2, mother_exten);
04077 switch_case-> return_target = np2;
04078 }
04079
04080 break;
04081 default:
04082 break;
04083 }
04084 }
04085 }
04086
04087 void set_priorities(struct ael_extension *exten)
04088 {
04089 int i;
04090 struct ael_priority *pr;
04091 do {
04092 if (exten->is_switch)
04093 i = 10;
04094 else if (exten->regexten)
04095 i=2;
04096 else
04097 i=1;
04098
04099 for (pr=exten->plist; pr; pr=pr->next) {
04100 pr->priority_num = i;
04101
04102 if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) )
04103
04104
04105
04106 i++;
04107 }
04108
04109 exten = exten->next_exten;
04110 } while ( exten );
04111 }
04112
04113 void add_extensions(struct ael_extension *exten)
04114 {
04115 struct ael_priority *pr;
04116 char *label=0;
04117 char realext[AST_MAX_EXTENSION];
04118 if (!exten) {
04119 ast_log(LOG_WARNING, "This file is Empty!\n" );
04120 return;
04121 }
04122 do {
04123 struct ael_priority *last = 0;
04124
04125 memset(realext, '\0', sizeof(realext));
04126 pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
04127 if (exten->hints) {
04128 if (ast_add_extension2(exten->context, 0 , realext, PRIORITY_HINT, NULL, exten->cidmatch,
04129 exten->hints, NULL, ast_free_ptr, registrar)) {
04130 ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
04131 exten->name);
04132 }
04133 }
04134
04135 for (pr=exten->plist; pr; pr=pr->next) {
04136 char app[2000];
04137 char appargs[2000];
04138
04139
04140
04141
04142 if (pr->type == AEL_LABEL) {
04143 last = pr;
04144 continue;
04145 }
04146
04147 if (pr->app)
04148 strcpy(app, pr->app);
04149 else
04150 app[0] = 0;
04151 if (pr->appargs )
04152 strcpy(appargs, pr->appargs);
04153 else
04154 appargs[0] = 0;
04155 switch( pr->type ) {
04156 case AEL_APPCALL:
04157
04158 break;
04159
04160 case AEL_CONTROL1:
04161
04162 strcpy(app,"Goto");
04163 if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
04164 snprintf(appargs,sizeof(appargs),"%s|%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
04165 } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
04166 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
04167 } else
04168 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
04169 break;
04170
04171 case AEL_FOR_CONTROL:
04172 strcpy(app,"GotoIf");
04173 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04174 break;
04175
04176 case AEL_IF_CONTROL:
04177 strcpy(app,"GotoIf");
04178 if (pr->origin->u3.else_statements )
04179 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
04180 else
04181 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04182 break;
04183
04184 case AEL_RAND_CONTROL:
04185 strcpy(app,"Random");
04186 snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
04187 break;
04188
04189 case AEL_IFTIME_CONTROL:
04190 strcpy(app,"GotoIfTime");
04191 snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
04192 break;
04193
04194 case AEL_RETURN:
04195 strcpy(app,"Goto");
04196 snprintf(appargs,sizeof(appargs), "%d", exten->return_target->priority_num);
04197 break;
04198
04199 default:
04200 break;
04201 }
04202 if (last && last->type == AEL_LABEL ) {
04203 label = last->origin->u1.str;
04204 }
04205 else
04206 label = 0;
04207
04208 if (ast_add_extension2(exten->context, 0 , realext, pr->priority_num, (label?label:NULL), exten->cidmatch,
04209 app, strdup(appargs), ast_free_ptr, registrar)) {
04210 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num,
04211 exten->name);
04212 }
04213 last = pr;
04214 }
04215 exten = exten->next_exten;
04216 } while ( exten );
04217 }
04218
04219 static void attach_exten(struct ael_extension **list, struct ael_extension *newmem)
04220 {
04221
04222 struct ael_extension *lptr;
04223 if( !*list ) {
04224 *list = newmem;
04225 return;
04226 }
04227 lptr = *list;
04228
04229 while( lptr->next_exten ) {
04230 lptr = lptr->next_exten;
04231 }
04232
04233 lptr->next_exten = newmem;
04234 }
04235
04236 static pval *get_extension_or_contxt(pval *p)
04237 {
04238 while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
04239
04240 p = p->dad;
04241 }
04242
04243 return p;
04244 }
04245
04246 static pval *get_contxt(pval *p)
04247 {
04248 while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
04249
04250 p = p->dad;
04251 }
04252
04253 return p;
04254 }
04255
04256 static void fix_gotos_in_extensions(struct ael_extension *exten)
04257 {
04258 struct ael_extension *e;
04259 for(e=exten;e;e=e->next_exten) {
04260
04261 struct ael_priority *p;
04262 for(p=e->plist;p;p=p->next) {
04263
04264 if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) {
04265
04266
04267
04268 pval *target = p->origin->u2.goto_target;
04269 struct ael_extension *z = target->u3.compiled_label;
04270 pval *pv2 = p->origin;
04271 char buf1[500];
04272 char *apparg_save = p->appargs;
04273
04274 p->appargs = 0;
04275 if (!pv2->u1.list->next) {
04276 snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->u1.str);
04277 p->appargs = strdup(buf1);
04278
04279 } else if (pv2->u1.list->next && !pv2->u1.list->next->next) {
04280 snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->next->u1.str);
04281 p->appargs = strdup(buf1);
04282 } else if (pv2->u1.list->next && pv2->u1.list->next->next) {
04283 snprintf(buf1,sizeof(buf1),"%s|%s|%s", pv2->u1.list->u1.str,
04284 z->name,
04285 pv2->u1.list->next->next->u1.str);
04286 p->appargs = strdup(buf1);
04287 }
04288 else
04289 printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n");
04290
04291 if( apparg_save ) {
04292 free(apparg_save);
04293 }
04294 }
04295 }
04296 }
04297 }
04298
04299
04300 void ast_compile_ael2(struct ast_context **local_contexts, struct pval *root)
04301 {
04302 pval *p,*p2;
04303 struct ast_context *context;
04304 char buf[2000];
04305 struct ael_extension *exten;
04306 struct ael_extension *exten_list = 0;
04307
04308 for (p=root; p; p=p->next ) {
04309
04310 switch (p->type) {
04311 case PV_GLOBALS:
04312
04313 for (p2=p->u1.list; p2; p2=p2->next) {
04314 char buf2[2000];
04315 snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
04316 pbx_builtin_setvar(NULL, buf2);
04317 }
04318 break;
04319 default:
04320 break;
04321 }
04322 }
04323
04324 for (p=root; p; p=p->next ) {
04325 pval *lp;
04326 int argc;
04327
04328 switch (p->type) {
04329 case PV_MACRO:
04330 strcpy(buf,"macro-");
04331 strcat(buf,p->u1.str);
04332 context = ast_context_create(local_contexts, buf, registrar);
04333
04334 exten = new_exten();
04335 exten->context = context;
04336 exten->name = strdup("s");
04337 argc = 1;
04338 for (lp=p->u2.arglist; lp; lp=lp->next) {
04339
04340 struct ael_priority *np2 = new_prio();
04341 np2->type = AEL_APPCALL;
04342 np2->app = strdup("Set");
04343 snprintf(buf,sizeof(buf),"%s=${ARG%d}", lp->u1.str, argc++);
04344 remove_spaces_before_equals(buf);
04345 np2->appargs = strdup(buf);
04346 linkprio(exten, np2, NULL);
04347 }
04348
04349 for (p2=p->u3.macro_statements; p2; p2=p2->next) {
04350 pval *p3;
04351
04352 switch (p2->type) {
04353 case PV_INCLUDES:
04354 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04355 if ( p3->u2.arglist ) {
04356 snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s",
04357 p3->u1.str,
04358 p3->u2.arglist->u1.str,
04359 p3->u2.arglist->next->u1.str,
04360 p3->u2.arglist->next->next->u1.str,
04361 p3->u2.arglist->next->next->next->u1.str);
04362 ast_context_add_include2(context, buf, registrar);
04363 } else
04364 ast_context_add_include2(context, p3->u1.str, registrar);
04365 }
04366 break;
04367 default:
04368 break;
04369 }
04370 }
04371
04372 gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context );
04373 if (exten->return_needed) {
04374 struct ael_priority *np2 = new_prio();
04375 np2->type = AEL_APPCALL;
04376 np2->app = strdup("NoOp");
04377 snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
04378 np2->appargs = strdup(buf);
04379 linkprio(exten, np2, NULL);
04380 exten-> return_target = np2;
04381 }
04382
04383 set_priorities(exten);
04384 attach_exten(&exten_list, exten);
04385 break;
04386
04387 case PV_GLOBALS:
04388
04389 break;
04390
04391 case PV_CONTEXT:
04392 context = ast_context_find_or_create(local_contexts, p->u1.str, registrar);
04393
04394
04395 for (p2=p->u2.statements; p2; p2=p2->next) {
04396 pval *p3;
04397 char *s3;
04398
04399 switch (p2->type) {
04400 case PV_EXTENSION:
04401 exten = new_exten();
04402 exten->name = strdup(p2->u1.str);
04403 exten->context = context;
04404
04405 if( (s3=strchr(exten->name, '/') ) != 0 )
04406 {
04407 *s3 = 0;
04408 exten->cidmatch = s3+1;
04409 }
04410
04411 if ( p2->u3.hints )
04412 exten->hints = strdup(p2->u3.hints);
04413 exten->regexten = p2->u4.regexten;
04414 gen_prios(exten, p->u1.str, p2->u2.statements, 0, context );
04415 if (exten->return_needed) {
04416 struct ael_priority *np2 = new_prio();
04417 np2->type = AEL_APPCALL;
04418 np2->app = strdup("NoOp");
04419 snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
04420 np2->appargs = strdup(buf);
04421 linkprio(exten, np2, NULL);
04422 exten-> return_target = np2;
04423 }
04424
04425 if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
04426 struct ael_priority *np2 = new_prio();
04427 np2->type = AEL_APPCALL;
04428 np2->app = strdup("NoOp");
04429 snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
04430 np2->appargs = strdup(buf);
04431 linkprio(exten, np2, NULL);
04432 }
04433
04434 set_priorities(exten);
04435 attach_exten(&exten_list, exten);
04436 break;
04437
04438 case PV_IGNOREPAT:
04439 ast_context_add_ignorepat2(context, p2->u1.str, registrar);
04440 break;
04441
04442 case PV_INCLUDES:
04443 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04444 if ( p3->u2.arglist ) {
04445 snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s",
04446 p3->u1.str,
04447 p3->u2.arglist->u1.str,
04448 p3->u2.arglist->next->u1.str,
04449 p3->u2.arglist->next->next->u1.str,
04450 p3->u2.arglist->next->next->next->u1.str);
04451 ast_context_add_include2(context, buf, registrar);
04452 } else
04453 ast_context_add_include2(context, p3->u1.str, registrar);
04454 }
04455 break;
04456
04457 case PV_SWITCHES:
04458 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04459 char *c = strchr(p3->u1.str, '/');
04460 if (c) {
04461 *c = '\0';
04462 c++;
04463 } else
04464 c = "";
04465
04466 ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
04467 }
04468 break;
04469
04470 case PV_ESWITCHES:
04471 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04472 char *c = strchr(p3->u1.str, '/');
04473 if (c) {
04474 *c = '\0';
04475 c++;
04476 } else
04477 c = "";
04478
04479 ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
04480 }
04481 break;
04482 default:
04483 break;
04484 }
04485 }
04486
04487 break;
04488
04489 default:
04490
04491 break;
04492
04493 }
04494 }
04495
04496
04497
04498 fix_gotos_in_extensions(exten_list);
04499 add_extensions(exten_list);
04500 destroy_extensions(exten_list);
04501
04502 }
04503
04504
04505 static int aeldebug = 0;
04506
04507
04508
04509
04510
04511 static int pbx_load_module(void)
04512 {
04513 int errs=0, sem_err=0, sem_warn=0, sem_note=0;
04514 char *rfilename;
04515 struct ast_context *local_contexts=NULL, *con;
04516 struct pval *parse_tree;
04517
04518 ast_log(LOG_NOTICE, "Starting AEL load process.\n");
04519 if (config[0] == '/')
04520 rfilename = (char *)config;
04521 else {
04522 rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
04523 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
04524 }
04525 ast_log(LOG_NOTICE, "AEL load process: calculated config file name '%s'.\n", rfilename);
04526
04527 if (access(rfilename,R_OK) != 0) {
04528 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
04529 return AST_MODULE_LOAD_DECLINE;
04530 }
04531
04532 parse_tree = ael2_parse(rfilename, &errs);
04533 ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
04534 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
04535 if (errs == 0 && sem_err == 0) {
04536 ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
04537 ast_compile_ael2(&local_contexts, parse_tree);
04538 ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
04539
04540 ast_merge_contexts_and_delete(&local_contexts, registrar);
04541 ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
04542 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
04543 ast_context_verify_includes(con);
04544 ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
04545 } else {
04546 ast_log(LOG_ERROR, "Sorry, but %d syntax errors and %d semantic errors were detected. It doesn't make sense to compile.\n", errs, sem_err);
04547 destroy_pval(parse_tree);
04548 return AST_MODULE_LOAD_DECLINE;
04549 }
04550 destroy_pval(parse_tree);
04551
04552 return AST_MODULE_LOAD_SUCCESS;
04553 }
04554
04555
04556 static int ael2_debug_read(int fd, int argc, char *argv[])
04557 {
04558 aeldebug |= DEBUG_READ;
04559 return 0;
04560 }
04561
04562 static int ael2_debug_tokens(int fd, int argc, char *argv[])
04563 {
04564 aeldebug |= DEBUG_TOKENS;
04565 return 0;
04566 }
04567
04568 static int ael2_debug_macros(int fd, int argc, char *argv[])
04569 {
04570 aeldebug |= DEBUG_MACROS;
04571 return 0;
04572 }
04573
04574 static int ael2_debug_contexts(int fd, int argc, char *argv[])
04575 {
04576 aeldebug |= DEBUG_CONTEXTS;
04577 return 0;
04578 }
04579
04580 static int ael2_no_debug(int fd, int argc, char *argv[])
04581 {
04582 aeldebug = 0;
04583 return 0;
04584 }
04585
04586 static int ael2_reload(int fd, int argc, char *argv[])
04587 {
04588 return (pbx_load_module());
04589 }
04590
04591 static struct ast_cli_entry cli_ael_no_debug = {
04592 { "ael", "no", "debug", NULL },
04593 ael2_no_debug, NULL,
04594 NULL };
04595
04596 static struct ast_cli_entry cli_ael[] = {
04597 { { "ael", "reload", NULL },
04598 ael2_reload, "Reload AEL configuration" },
04599
04600 { { "ael", "debug", "read", NULL },
04601 ael2_debug_read, "Enable AEL read debug (does nothing)" },
04602
04603 { { "ael", "debug", "tokens", NULL },
04604 ael2_debug_tokens, "Enable AEL tokens debug (does nothing)" },
04605
04606 { { "ael", "debug", "macros", NULL },
04607 ael2_debug_macros, "Enable AEL macros debug (does nothing)" },
04608
04609 { { "ael", "debug", "contexts", NULL },
04610 ael2_debug_contexts, "Enable AEL contexts debug (does nothing)" },
04611
04612 { { "ael", "nodebug", NULL },
04613 ael2_no_debug, "Disable AEL debug messages",
04614 NULL, NULL, &cli_ael_no_debug },
04615 };
04616
04617 static int unload_module(void)
04618 {
04619 ast_context_destroy(NULL, registrar);
04620 ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04621 return 0;
04622 }
04623
04624 static int load_module(void)
04625 {
04626 ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04627 return (pbx_load_module());
04628 }
04629
04630 static int reload(void)
04631 {
04632 return pbx_load_module();
04633 }
04634
04635 #ifdef STANDALONE_AEL
04636 #define AST_MODULE "ael"
04637 int ael_external_load_module(void);
04638 int ael_external_load_module(void)
04639 {
04640 pbx_load_module();
04641 return 1;
04642 }
04643 #endif
04644
04645 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk Extension Language Compiler",
04646 .load = load_module,
04647 .unload = unload_module,
04648 .reload = reload,
04649 );
04650
04651
04652
04653
04654
04655
04656 void destroy_pval_item(pval *item)
04657 {
04658 if (item == NULL) {
04659 ast_log(LOG_WARNING, "null item\n");
04660 return;
04661 }
04662
04663 if (item->filename)
04664 free(item->filename);
04665
04666 switch (item->type) {
04667 case PV_WORD:
04668
04669 if (item->u1.str )
04670 free(item->u1.str);
04671 if ( item->u2.arglist )
04672 destroy_pval(item->u2.arglist);
04673 break;
04674
04675 case PV_MACRO:
04676
04677
04678
04679
04680
04681
04682
04683 destroy_pval(item->u2.arglist);
04684 if (item->u1.str )
04685 free(item->u1.str);
04686 destroy_pval(item->u3.macro_statements);
04687 break;
04688
04689 case PV_CONTEXT:
04690
04691
04692
04693
04694 if (item->u1.str)
04695 free(item->u1.str);
04696 destroy_pval(item->u2.statements);
04697 break;
04698
04699 case PV_MACRO_CALL:
04700
04701
04702
04703
04704
04705 if (item->u1.str)
04706 free(item->u1.str);
04707 destroy_pval(item->u2.arglist);
04708 break;
04709
04710 case PV_APPLICATION_CALL:
04711
04712
04713
04714
04715
04716 if (item->u1.str)
04717 free(item->u1.str);
04718 destroy_pval(item->u2.arglist);
04719 break;
04720
04721 case PV_CASE:
04722
04723
04724
04725 if (item->u1.str)
04726 free(item->u1.str);
04727 destroy_pval(item->u2.statements);
04728 break;
04729
04730 case PV_PATTERN:
04731
04732
04733
04734 if (item->u1.str)
04735 free(item->u1.str);
04736 destroy_pval(item->u2.statements);
04737 break;
04738
04739 case PV_DEFAULT:
04740
04741
04742
04743 destroy_pval(item->u2.statements);
04744 break;
04745
04746 case PV_CATCH:
04747
04748
04749
04750 if (item->u1.str)
04751 free(item->u1.str);
04752 destroy_pval(item->u2.statements);
04753 break;
04754
04755 case PV_SWITCHES:
04756
04757
04758 destroy_pval(item->u1.list);
04759 break;
04760
04761 case PV_ESWITCHES:
04762
04763
04764 destroy_pval(item->u1.list);
04765 break;
04766
04767 case PV_INCLUDES:
04768
04769
04770
04771 destroy_pval(item->u1.list);
04772 break;
04773
04774 case PV_STATEMENTBLOCK:
04775
04776
04777 destroy_pval(item->u1.list);
04778 break;
04779
04780 case PV_VARDEC:
04781
04782
04783
04784 if (item->u1.str)
04785 free(item->u1.str);
04786 if (item->u2.val)
04787 free(item->u2.val);
04788 break;
04789
04790 case PV_GOTO:
04791
04792
04793
04794
04795 destroy_pval(item->u1.list);
04796 break;
04797
04798 case PV_LABEL:
04799
04800
04801 if (item->u1.str)
04802 free(item->u1.str);
04803 break;
04804
04805 case PV_FOR:
04806
04807
04808
04809
04810
04811
04812 if (item->u1.for_init)
04813 free(item->u1.for_init);
04814 if (item->u2.for_test)
04815 free(item->u2.for_test);
04816 if (item->u3.for_inc)
04817 free(item->u3.for_inc);
04818 destroy_pval(item->u4.for_statements);
04819 break;
04820
04821 case PV_WHILE:
04822
04823
04824
04825
04826 if (item->u1.str)
04827 free(item->u1.str);
04828 destroy_pval(item->u2.statements);
04829 break;
04830
04831 case PV_BREAK:
04832
04833
04834 break;
04835
04836 case PV_RETURN:
04837
04838
04839 break;
04840
04841 case PV_CONTINUE:
04842
04843
04844 break;
04845
04846 case PV_IFTIME:
04847
04848
04849
04850
04851
04852
04853 destroy_pval(item->u1.list);
04854 destroy_pval(item->u2.statements);
04855 if (item->u3.else_statements) {
04856 destroy_pval(item->u3.else_statements);
04857 }
04858 break;
04859
04860 case PV_RANDOM:
04861
04862
04863
04864
04865
04866
04867 case PV_IF:
04868
04869
04870
04871
04872
04873
04874 if (item->u1.str)
04875 free(item->u1.str);
04876 destroy_pval(item->u2.statements);
04877 if (item->u3.else_statements) {
04878 destroy_pval(item->u3.else_statements);
04879 }
04880 break;
04881
04882 case PV_SWITCH:
04883
04884
04885
04886
04887
04888 if (item->u1.str)
04889 free(item->u1.str);
04890 destroy_pval(item->u2.statements);
04891 break;
04892
04893 case PV_EXTENSION:
04894
04895
04896
04897
04898
04899
04900 if (item->u1.str)
04901 free(item->u1.str);
04902 if (item->u3.hints)
04903 free(item->u3.hints);
04904 destroy_pval(item->u2.statements);
04905 break;
04906
04907 case PV_IGNOREPAT:
04908
04909
04910 if (item->u1.str)
04911 free(item->u1.str);
04912 break;
04913
04914 case PV_GLOBALS:
04915
04916
04917 destroy_pval(item->u1.statements);
04918 break;
04919 }
04920 free(item);
04921 }
04922
04923 void destroy_pval(pval *item)
04924 {
04925 pval *i,*nxt;
04926
04927 for (i=item; i; i=nxt) {
04928 nxt = i->next;
04929
04930 destroy_pval_item(i);
04931 }
04932 }
04933
04934 #ifdef AAL_ARGCHECK
04935 static char *ael_funclist[] =
04936 {
04937 "AGENT",
04938 "ARRAY",
04939 "BASE64_DECODE",
04940 "BASE64_ENCODE",
04941 "CALLERID",
04942 "CDR",
04943 "CHANNEL",
04944 "CHECKSIPDOMAIN",
04945 "CHECK_MD5",
04946 "CURL",
04947 "CUT",
04948 "DB",
04949 "DB_EXISTS",
04950 "DUNDILOOKUP",
04951 "ENUMLOOKUP",
04952 "ENV",
04953 "EVAL",
04954 "EXISTS",
04955 "FIELDQTY",
04956 "FILTER",
04957 "GROUP",
04958 "GROUP_COUNT",
04959 "GROUP_LIST",
04960 "GROUP_MATCH_COUNT",
04961 "IAXPEER",
04962 "IF",
04963 "IFTIME",
04964 "ISNULL",
04965 "KEYPADHASH",
04966 "LANGUAGE",
04967 "LEN",
04968 "MATH",
04969 "MD5",
04970 "MUSICCLASS",
04971 "QUEUEAGENTCOUNT",
04972 "QUEUE_MEMBER_COUNT",
04973 "QUEUE_MEMBER_LIST",
04974 "QUOTE",
04975 "RAND",
04976 "REGEX",
04977 "SET",
04978 "SHA1",
04979 "SIPCHANINFO",
04980 "SIPPEER",
04981 "SIP_HEADER",
04982 "SORT",
04983 "STAT",
04984 "STRFTIME",
04985 "STRPTIME",
04986 "TIMEOUT",
04987 "TXTCIDNAME",
04988 "URIDECODE",
04989 "URIENCODE",
04990 "VMCOUNT"
04991 };
04992
04993
04994 int ael_is_funcname(char *name)
04995 {
04996 int s,t;
04997 t = sizeof(ael_funclist)/sizeof(char*);
04998 s = 0;
04999 while ((s < t) && strcasecmp(name, ael_funclist[s]))
05000 s++;
05001 if ( s < t )
05002 return 1;
05003 else
05004 return 0;
05005 }
05006 #endif