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