Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2. More...
#include "asterisk.h"#include <ctype.h>#include <regex.h>#include <sys/stat.h>#include "asterisk/pbx.h"#include "asterisk/config.h"#include "asterisk/module.h"#include "asterisk/logger.h"#include "asterisk/cli.h"#include "asterisk/app.h"#include "asterisk/callerid.h"#include "asterisk/hashtab.h"#include "asterisk/ael_structs.h"#include "asterisk/pval.h"
Go to the source code of this file.
Defines | |
| #define | DEBUG_CONTEXTS (1 << 3) |
| #define | DEBUG_MACROS (1 << 2) |
| #define | DEBUG_READ (1 << 0) |
| #define | DEBUG_TOKENS (1 << 1) |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| void | add_extensions (struct ael_extension *exten) |
| void | ast_compile_ael2 (struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root) |
| void | ast_expr_clear_extra_error_info (void) |
| void | ast_expr_register_extra_error_info (char *errmsg) |
| int | check_app_args (pval *appcall, pval *arglist, struct argapp *app) |
| void | check_pval (pval *item, struct argapp *apps, int in_globals) |
| void | check_pval_item (pval *item, struct argapp *apps, int in_globals) |
| void | check_switch_expr (pval *item, struct argapp *apps) |
| void | destroy_extensions (struct ael_extension *exten) |
| void | destroy_pval (pval *item) |
| void | destroy_pval_item (pval *item) |
| struct pval * | find_context (char *name) |
| struct pval * | find_macro (char *name) |
| static char * | handle_cli_ael_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_cli_ael_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| int | is_empty (char *arg) |
| int | is_float (char *arg) |
| int | is_int (char *arg) |
| static int | load_module (void) |
| struct ael_extension * | new_exten (void) |
| struct ael_priority * | new_prio (void) |
| static int | pbx_load_module (void) |
| static int | reload (void) |
| void | set_priorities (struct ael_extension *exten) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Asterisk Extension Language Compiler" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
| static int | aeldebug = 0 |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_cli_entry | cli_ael [] |
| static char * | config = "extensions.ael" |
| static char * | registrar = "pbx_ael" |
Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.
Definition in file pbx_ael.c.
| #define DEBUG_CONTEXTS (1 << 3) |
Definition at line 63 of file pbx_ael.c.
Referenced by handle_cli_ael_set_debug().
| #define DEBUG_MACROS (1 << 2) |
Definition at line 62 of file pbx_ael.c.
Referenced by handle_cli_ael_set_debug().
| #define DEBUG_READ (1 << 0) |
Definition at line 60 of file pbx_ael.c.
Referenced by handle_cli_ael_set_debug().
| #define DEBUG_TOKENS (1 << 1) |
Definition at line 61 of file pbx_ael.c.
Referenced by handle_cli_ael_set_debug().
| void add_extensions | ( | struct ael_extension * | exten | ) |
Definition at line 4207 of file pval.c.
References AEL_APPCALL, AEL_CONTROL1, AEL_FOR_CONTROL, AEL_IF_CONTROL, AEL_IFTIME_CONTROL, AEL_LABEL, AEL_RAND_CONTROL, AEL_RETURN, ael_priority::app, ael_priority::appargs, ast_add_extension2(), ast_free_ptr(), ast_log(), AST_MAX_EXTENSION, ael_extension::cidmatch, ael_extension::context, pval::else_statements, ael_priority::exten, ael_priority::goto_false, ael_priority::goto_true, ael_extension::hints, last, LOG_WARNING, ael_extension::name, ael_priority::next, ael_extension::next_exten, ael_priority::origin, pbx_substitute_variables_helper(), ael_extension::plist, PRIORITY_HINT, ael_priority::priority_num, PV_IFTIME, PV_SWITCH, pval::str, strdup, pval::type, ael_priority::type, pval::u1, and pval::u3.
04208 { 04209 struct ael_priority *pr; 04210 char *label=0; 04211 char realext[AST_MAX_EXTENSION]; 04212 if (!exten) { 04213 ast_log(LOG_WARNING, "This file is Empty!\n" ); 04214 return; 04215 } 04216 do { 04217 struct ael_priority *last = 0; 04218 04219 pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1); 04220 if (exten->hints) { 04221 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, 04222 exten->hints, NULL, ast_free_ptr, registrar)) { 04223 ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n", 04224 exten->name); 04225 } 04226 } 04227 04228 for (pr=exten->plist; pr; pr=pr->next) { 04229 char app[2000]; 04230 char appargs[2000]; 04231 04232 /* before we can add the extension, we need to prep the app/appargs; 04233 the CONTROL types need to be done after the priority numbers are calculated. 04234 */ 04235 if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ { 04236 last = pr; 04237 continue; 04238 } 04239 04240 if (pr->app) 04241 strcpy(app, pr->app); 04242 else 04243 app[0] = 0; 04244 if (pr->appargs ) 04245 strcpy(appargs, pr->appargs); 04246 else 04247 appargs[0] = 0; 04248 switch( pr->type ) { 04249 case AEL_APPCALL: 04250 /* easy case. Everything is all set up */ 04251 break; 04252 04253 case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */ 04254 /* simple, unconditional goto. */ 04255 strcpy(app,"Goto"); 04256 if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) { 04257 snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num); 04258 } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) { 04259 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1); 04260 } else 04261 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num); 04262 break; 04263 04264 case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */ 04265 strcpy(app,"GotoIf"); 04266 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num); 04267 break; 04268 04269 case AEL_IF_CONTROL: 04270 strcpy(app,"GotoIf"); 04271 if (pr->origin->u3.else_statements ) 04272 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1); 04273 else 04274 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num); 04275 break; 04276 04277 case AEL_RAND_CONTROL: 04278 strcpy(app,"Random"); 04279 snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1); 04280 break; 04281 04282 case AEL_IFTIME_CONTROL: 04283 strcpy(app,"GotoIfTime"); 04284 snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2); 04285 break; 04286 04287 case AEL_RETURN: 04288 strcpy(app,"Return"); 04289 appargs[0] = 0; 04290 break; 04291 04292 default: 04293 break; 04294 } 04295 if (last && last->type == AEL_LABEL ) { 04296 label = last->origin->u1.str; 04297 } 04298 else 04299 label = 0; 04300 04301 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, 04302 app, strdup(appargs), ast_free_ptr, registrar)) { 04303 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, 04304 exten->name); 04305 } 04306 last = pr; 04307 } 04308 exten = exten->next_exten; 04309 } while ( exten ); 04310 }
| void ast_compile_ael2 | ( | struct ast_context ** | local_contexts, | |
| struct ast_hashtab * | local_table, | |||
| struct pval * | root | |||
| ) |
Definition at line 4393 of file pval.c.
References add_extensions(), AEL_APPCALL, AEL_LABEL, ael_priority::app, ael_priority::appargs, pval::arglist, ast_compat_app_set, ast_context_add_ignorepat2(), ast_context_add_include2(), ast_context_add_switch2(), ast_context_find_or_create(), attach_exten(), buf, buf2, ael_extension::cidmatch, ael_extension::context, context, destroy_extensions(), exten, fix_gotos_in_extensions(), gen_prios(), ael_extension::hints, pval::hints, linkprio(), pval::list, pval::macro_statements, ael_extension::name, new_exten(), new_prio(), pval::next, ael_priority::origin, pbx_builtin_setvar(), ael_extension::plist_last, PV_CONTEXT, PV_ESWITCHES, PV_EXTENSION, PV_GLOBALS, PV_IGNOREPAT, PV_INCLUDES, PV_MACRO, PV_SWITCHES, pval::regexten, ael_extension::regexten, remove_spaces_before_equals(), ael_extension::return_needed, set_priorities(), pval::statements, pval::str, strdup, ael_priority::type, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.
04394 { 04395 pval *p,*p2; 04396 struct ast_context *context; 04397 char buf[2000]; 04398 struct ael_extension *exten; 04399 struct ael_extension *exten_list = 0; 04400 04401 for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there 04402 when we try to eval them */ 04403 switch (p->type) { 04404 case PV_GLOBALS: 04405 /* just VARDEC elements */ 04406 for (p2=p->u1.list; p2; p2=p2->next) { 04407 char buf2[2000]; 04408 snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val); 04409 pbx_builtin_setvar(NULL, buf2); 04410 } 04411 break; 04412 default: 04413 break; 04414 } 04415 } 04416 04417 for (p=root; p; p=p->next ) { 04418 pval *lp; 04419 int argc; 04420 04421 switch (p->type) { 04422 case PV_MACRO: 04423 04424 context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar); 04425 04426 exten = new_exten(); 04427 exten->context = context; 04428 exten->name = strdup("s"); 04429 argc = 1; 04430 for (lp=p->u2.arglist; lp; lp=lp->next) { 04431 /* for each arg, set up a "Set" command */ 04432 struct ael_priority *np2 = new_prio(); 04433 np2->type = AEL_APPCALL; 04434 if (!ast_compat_app_set) { 04435 np2->app = strdup("MSet"); 04436 } else { 04437 np2->app = strdup("Set"); 04438 } 04439 snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++); 04440 remove_spaces_before_equals(buf); 04441 np2->appargs = strdup(buf); 04442 linkprio(exten, np2, NULL); 04443 } 04444 04445 /* CONTAINS APPCALLS, CATCH, just like extensions... */ 04446 gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context ); 04447 if (exten->return_needed) { /* most likely, this will go away */ 04448 struct ael_priority *np2 = new_prio(); 04449 np2->type = AEL_APPCALL; 04450 np2->app = strdup("NoOp"); 04451 snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name); 04452 np2->appargs = strdup(buf); 04453 linkprio(exten, np2, NULL); 04454 exten-> return_target = np2; 04455 } 04456 04457 set_priorities(exten); 04458 attach_exten(&exten_list, exten); 04459 break; 04460 04461 case PV_GLOBALS: 04462 /* already done */ 04463 break; 04464 04465 case PV_CONTEXT: 04466 context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar); 04467 04468 /* contexts contain: ignorepat, includes, switches, eswitches, extensions, */ 04469 for (p2=p->u2.statements; p2; p2=p2->next) { 04470 pval *p3; 04471 char *s3; 04472 04473 switch (p2->type) { 04474 case PV_EXTENSION: 04475 exten = new_exten(); 04476 exten->name = strdup(p2->u1.str); 04477 exten->context = context; 04478 04479 if( (s3=strchr(exten->name, '/') ) != 0 ) 04480 { 04481 *s3 = 0; 04482 exten->cidmatch = s3+1; 04483 } 04484 04485 if ( p2->u3.hints ) 04486 exten->hints = strdup(p2->u3.hints); 04487 exten->regexten = p2->u4.regexten; 04488 gen_prios(exten, p->u1.str, p2->u2.statements, 0, context ); 04489 if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */ 04490 struct ael_priority *np2 = new_prio(); 04491 np2->type = AEL_APPCALL; 04492 np2->app = strdup("NoOp"); 04493 snprintf(buf,sizeof(buf),"End of Extension %s", exten->name); 04494 np2->appargs = strdup(buf); 04495 linkprio(exten, np2, NULL); 04496 exten-> return_target = np2; 04497 } 04498 /* is the last priority in the extension a label? Then add a trailing no-op */ 04499 if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) { 04500 struct ael_priority *np2 = new_prio(); 04501 np2->type = AEL_APPCALL; 04502 np2->app = strdup("NoOp"); 04503 snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str); 04504 np2->appargs = strdup(buf); 04505 linkprio(exten, np2, NULL); 04506 } 04507 04508 set_priorities(exten); 04509 attach_exten(&exten_list, exten); 04510 break; 04511 04512 case PV_IGNOREPAT: 04513 ast_context_add_ignorepat2(context, p2->u1.str, registrar); 04514 break; 04515 04516 case PV_INCLUDES: 04517 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04518 if ( p3->u2.arglist ) { 04519 snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s", 04520 p3->u1.str, 04521 p3->u2.arglist->u1.str, 04522 p3->u2.arglist->next->u1.str, 04523 p3->u2.arglist->next->next->u1.str, 04524 p3->u2.arglist->next->next->next->u1.str); 04525 ast_context_add_include2(context, buf, registrar); 04526 } else 04527 ast_context_add_include2(context, p3->u1.str, registrar); 04528 } 04529 break; 04530 04531 case PV_SWITCHES: 04532 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04533 char *c = strchr(p3->u1.str, '/'); 04534 if (c) { 04535 *c = '\0'; 04536 c++; 04537 } else 04538 c = ""; 04539 04540 ast_context_add_switch2(context, p3->u1.str, c, 0, registrar); 04541 } 04542 break; 04543 04544 case PV_ESWITCHES: 04545 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04546 char *c = strchr(p3->u1.str, '/'); 04547 if (c) { 04548 *c = '\0'; 04549 c++; 04550 } else 04551 c = ""; 04552 04553 ast_context_add_switch2(context, p3->u1.str, c, 1, registrar); 04554 } 04555 break; 04556 default: 04557 break; 04558 } 04559 } 04560 04561 break; 04562 04563 default: 04564 /* huh? what? */ 04565 break; 04566 04567 } 04568 } 04569 /* moved these from being done after a macro or extension were processed, 04570 to after all processing is done, for the sake of fixing gotos to labels inside cases... */ 04571 /* I guess this would be considered 2nd pass of compiler now... */ 04572 fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */ 04573 add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */ 04574 destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */ 04575 04576 }
| void ast_expr_clear_extra_error_info | ( | void | ) |
Definition at line 2456 of file ast_expr2f.c.
02457 { 02458 extra_error_message_supplied=0; 02459 extra_error_message[0] = 0; 02460 }
| void ast_expr_register_extra_error_info | ( | char * | errmsg | ) |
Definition at line 2450 of file ast_expr2f.c.
02451 { 02452 extra_error_message_supplied=1; 02453 strcpy(extra_error_message, message); 02454 }
Definition at line 2126 of file pval.c.
References ast_log(), pval::endline, pval::filename, LOG_WARNING, pval::next, pval::startline, pval::str, and pval::u1.
02127 { 02128 #ifdef AAL_ARGCHECK 02129 struct argdesc *ad = app->args; 02130 pval *pa; 02131 int z; 02132 02133 for (pa = arglist; pa; pa=pa->next) { 02134 if (!ad) { 02135 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n", 02136 arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name); 02137 warns++; 02138 return 1; 02139 } else { 02140 /* find the first entry in the ad list that will match */ 02141 do { 02142 if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */ 02143 break; 02144 02145 z= option_matches( ad, pa, app); 02146 if (!z) { 02147 if ( !arglist ) 02148 arglist=appcall; 02149 02150 if (ad->type == ARGD_REQUIRED) { 02151 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", 02152 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); 02153 warns++; 02154 return 1; 02155 } 02156 } else if (z && ad->dtype == ARGD_OPTIONSET) { 02157 option_matches_j( ad, pa, app); 02158 } 02159 ad = ad->next; 02160 } while (ad && !z); 02161 } 02162 } 02163 /* any app nodes left, that are not optional? */ 02164 for ( ; ad; ad=ad->next) { 02165 if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) { 02166 if ( !arglist ) 02167 arglist=appcall; 02168 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", 02169 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); 02170 warns++; 02171 return 1; 02172 } 02173 } 02174 return 0; 02175 #else 02176 return 0; 02177 #endif 02178 }
Definition at line 2862 of file pval.c.
References check_pval_item(), and pval::next.
02863 { 02864 pval *i; 02865 02866 /* checks to do: 02867 1. Do goto's point to actual labels? 02868 2. Do macro calls reference a macro? 02869 3. Does the number of macro args match the definition? 02870 4. Is a macro call missing its & at the front? 02871 5. Application calls-- we could check syntax for existing applications, 02872 but I need some some sort of universal description bnf for a general 02873 sort of method for checking arguments, in number, maybe even type, at least. 02874 Don't want to hand code checks for hundreds of applications. 02875 */ 02876 02877 for (i=item; i; i=i->next) { 02878 check_pval_item(i,apps,in_globals); 02879 } 02880 }
Definition at line 2353 of file pval.c.
References pval::abstract, pval::arglist, ast_expr(), ast_expr_clear_extra_error_info(), ast_expr_register_extra_error_info(), ast_log(), check_abstract_reference(), check_app_args(), check_break(), check_continue(), check_day(), check_dow(), check_expr2_input(), check_goto(), check_includes(), check_label(), check_macro_returns(), check_month(), check_pval(), check_switch_expr(), check_timerange(), E_MATCH, pval::else_statements, pval::endcol, pval::endline, pval::filename, find_context(), find_macro(), find_pval_gotos(), pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, free, pval::list, localized_pbx_load_module(), LOG_ERROR, LOG_WARNING, pval::macro_statements, argapp::next, pval::next, pbx_find_extension(), PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTEXT, PV_CONTINUE, PV_DEFAULT, PV_ESWITCHES, PV_EXTENSION, PV_FOR, PV_GLOBALS, PV_GOTO, PV_IF, PV_IFTIME, PV_IGNOREPAT, PV_INCLUDES, PV_LABEL, PV_LOCALVARDEC, PV_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pbx_find_info::stacklen, pval::startcol, pval::startline, pval::statements, pbx_find_info::status, STATUS_SUCCESS, pval::str, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.
02354 { 02355 pval *lp; 02356 #ifdef AAL_ARGCHECK 02357 struct argapp *app, *found; 02358 #endif 02359 struct pval *macro_def; 02360 struct pval *app_def; 02361 02362 char errmsg[4096]; 02363 char *strp; 02364 02365 switch (item->type) { 02366 case PV_WORD: 02367 /* fields: item->u1.str == string associated with this (word). 02368 item->u2.arglist == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */ 02369 break; 02370 02371 case PV_MACRO: 02372 /* fields: item->u1.str == name of macro 02373 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user 02374 item->u2.arglist->u1.str == argument 02375 item->u2.arglist->next == next arg 02376 02377 item->u3.macro_statements == pval list of statements in macro body. 02378 */ 02379 in_abstract_context = 0; 02380 current_context = item; 02381 current_extension = 0; 02382 02383 check_macro_returns(item); 02384 02385 for (lp=item->u2.arglist; lp; lp=lp->next) { 02386 02387 } 02388 check_pval(item->u3.macro_statements, apps,in_globals); 02389 break; 02390 02391 case PV_CONTEXT: 02392 /* fields: item->u1.str == name of context 02393 item->u2.statements == pval list of statements in context body 02394 item->u3.abstract == int 1 if an abstract keyword were present 02395 */ 02396 current_context = item; 02397 current_extension = 0; 02398 if ( item->u3.abstract ) { 02399 in_abstract_context = 1; 02400 check_abstract_reference(item); 02401 } else 02402 in_abstract_context = 0; 02403 check_pval(item->u2.statements, apps,in_globals); 02404 break; 02405 02406 case PV_MACRO_CALL: 02407 /* fields: item->u1.str == name of macro to call 02408 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 02409 item->u2.arglist->u1.str == argument 02410 item->u2.arglist->next == next arg 02411 */ 02412 #ifdef STANDALONE 02413 /* if this is a standalone, we will need to make sure the 02414 localized load of extensions.conf is done */ 02415 if (!extensions_dot_conf_loaded) { 02416 localized_pbx_load_module(); 02417 extensions_dot_conf_loaded++; 02418 } 02419 #endif 02420 macro_def = find_macro(item->u1.str); 02421 if (!macro_def) { 02422 #ifdef STANDALONE 02423 struct pbx_find_info pfiq = {.stacklen = 0 }; 02424 struct pbx_find_info pfiq2 = {.stacklen = 0 }; 02425 02426 /* look for the macro in the extensions.conf world */ 02427 pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH); 02428 02429 if (pfiq.status != STATUS_SUCCESS) { 02430 char namebuf2[256]; 02431 snprintf(namebuf2, 256, "macro-%s", item->u1.str); 02432 02433 /* look for the macro in the extensions.conf world */ 02434 pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH); 02435 02436 if (pfiq2.status == STATUS_SUCCESS) { 02437 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (macro-%s was found in the extensions.conf stuff, but we are using gosubs!)\n", 02438 item->filename, item->startline, item->endline, item->u1.str, item->u1.str); 02439 warns++; 02440 } else { 02441 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (Not even in the extensions.conf stuff!)\n", 02442 item->filename, item->startline, item->endline, item->u1.str); 02443 warns++; 02444 } 02445 } 02446 #else 02447 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n", 02448 item->filename, item->startline, item->endline, item->u1.str); 02449 warns++; 02450 02451 #endif 02452 #ifdef THIS_IS_1DOT4 02453 char namebuf2[256]; 02454 snprintf(namebuf2, 256, "macro-%s", item->u1.str); 02455 02456 /* look for the macro in the extensions.conf world */ 02457 pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH); 02458 02459 if (pfiq.status != STATUS_SUCCESS) { 02460 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s was not found in the AEL, nor the extensions.conf !\n", 02461 item->filename, item->startline, item->endline, item->u1.str); 02462 warns++; 02463 } 02464 02465 #endif 02466 02467 } else if (macro_def->type != PV_MACRO) { 02468 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n", 02469 item->filename, item->startline, item->endline, item->u1.str); 02470 errs++; 02471 } else { 02472 /* macro_def is a MACRO, so do the args match in number? */ 02473 int hereargs = 0; 02474 int thereargs = 0; 02475 02476 for (lp=item->u2.arglist; lp; lp=lp->next) { 02477 hereargs++; 02478 } 02479 for (lp=macro_def->u2.arglist; lp; lp=lp->next) { 02480 thereargs++; 02481 } 02482 if (hereargs != thereargs ) { 02483 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", 02484 item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs); 02485 errs++; 02486 } 02487 } 02488 break; 02489 02490 case PV_APPLICATION_CALL: 02491 /* fields: item->u1.str == name of application to call 02492 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 02493 item->u2.arglist->u1.str == argument 02494 item->u2.arglist->next == next arg 02495 */ 02496 /* Need to check to see if the application is available! */ 02497 app_def = find_context(item->u1.str); 02498 if (app_def && app_def->type == PV_MACRO) { 02499 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n", 02500 item->filename, item->startline, item->endline, item->u1.str); 02501 errs++; 02502 } 02503 if (strcasecmp(item->u1.str,"GotoIf") == 0 02504 || strcasecmp(item->u1.str,"GotoIfTime") == 0 02505 || strcasecmp(item->u1.str,"while") == 0 02506 || strcasecmp(item->u1.str,"endwhile") == 0 02507 || strcasecmp(item->u1.str,"random") == 0 02508 || strcasecmp(item->u1.str,"gosub") == 0 02509 || strcasecmp(item->u1.str,"return") == 0 02510 || strcasecmp(item->u1.str,"gosubif") == 0 02511 || strcasecmp(item->u1.str,"continuewhile") == 0 02512 || strcasecmp(item->u1.str,"endwhile") == 0 02513 || strcasecmp(item->u1.str,"execif") == 0 02514 || strcasecmp(item->u1.str,"execiftime") == 0 02515 || strcasecmp(item->u1.str,"exitwhile") == 0 02516 || strcasecmp(item->u1.str,"goto") == 0 02517 || strcasecmp(item->u1.str,"macro") == 0 02518 || strcasecmp(item->u1.str,"macroexclusive") == 0 02519 || strcasecmp(item->u1.str,"macroif") == 0 02520 || strcasecmp(item->u1.str,"stackpop") == 0 02521 || strcasecmp(item->u1.str,"execIf") == 0 ) { 02522 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!\n", 02523 item->filename, item->startline, item->endline, item->u1.str); 02524 warns++; 02525 } 02526 if (strcasecmp(item->u1.str,"macroexit") == 0) { 02527 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: I am converting the MacroExit call here to a return statement.\n", 02528 item->filename, item->startline, item->endline); 02529 item->type = PV_RETURN; 02530 free(item->u1.str); 02531 item->u1.str = 0; 02532 } 02533 02534 #ifdef AAL_ARGCHECK 02535 found = 0; 02536 for (app=apps; app; app=app->next) { 02537 if (strcasecmp(app->name, item->u1.str) == 0) { 02538 found =app; 02539 break; 02540 } 02541 } 02542 if (!found) { 02543 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n", 02544 item->filename, item->startline, item->endline, item->u1.str); 02545 warns++; 02546 } else 02547 check_app_args(item, item->u2.arglist, app); 02548 #endif 02549 break; 02550 02551 case PV_CASE: 02552 /* fields: item->u1.str == value of case 02553 item->u2.statements == pval list of statements under the case 02554 */ 02555 /* Make sure sequence of statements under case is terminated with goto, return, or break */ 02556 /* find the last statement */ 02557 check_pval(item->u2.statements, apps,in_globals); 02558 break; 02559 02560 case PV_PATTERN: 02561 /* fields: item->u1.str == value of case 02562 item->u2.statements == pval list of statements under the case 02563 */ 02564 /* Make sure sequence of statements under case is terminated with goto, return, or break */ 02565 /* find the last statement */ 02566 02567 check_pval(item->u2.statements, apps,in_globals); 02568 break; 02569 02570 case PV_DEFAULT: 02571 /* fields: 02572 item->u2.statements == pval list of statements under the case 02573 */ 02574 02575 check_pval(item->u2.statements, apps,in_globals); 02576 break; 02577 02578 case PV_CATCH: 02579 /* fields: item->u1.str == name of extension to catch 02580 item->u2.statements == pval list of statements in context body 02581 */ 02582 check_pval(item->u2.statements, apps,in_globals); 02583 break; 02584 02585 case PV_SWITCHES: 02586 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 02587 */ 02588 check_pval(item->u1.list, apps,in_globals); 02589 break; 02590 02591 case PV_ESWITCHES: 02592 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 02593 */ 02594 check_pval(item->u1.list, apps,in_globals); 02595 break; 02596 02597 case PV_INCLUDES: 02598 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 02599 */ 02600 check_pval(item->u1.list, apps,in_globals); 02601 check_includes(item); 02602 for (lp=item->u1.list; lp; lp=lp->next){ 02603 char *incl_context = lp->u1.str; 02604 struct pval *that_context = find_context(incl_context); 02605 02606 if ( lp->u2.arglist ) { 02607 check_timerange(lp->u2.arglist); 02608 check_dow(lp->u2.arglist->next); 02609 check_day(lp->u2.arglist->next->next); 02610 check_month(lp->u2.arglist->next->next->next); 02611 } 02612 02613 if (that_context) { 02614 find_pval_gotos(that_context->u2.statements,0); 02615 02616 } 02617 } 02618 break; 02619 02620 case PV_STATEMENTBLOCK: 02621 /* fields: item->u1.list == pval list of statements in block, one per entry in the list 02622 */ 02623 check_pval(item->u1.list, apps,in_globals); 02624 break; 02625 02626 case PV_VARDEC: 02627 /* fields: item->u1.str == variable name 02628 item->u2.val == variable value to assign 02629 */ 02630 /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */ 02631 if( !in_globals ) { /* don't check stuff inside the globals context; no wrapping in $[ ] there... */ 02632 snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.val); 02633 ast_expr_register_extra_error_info(errmsg); 02634 ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL); 02635 ast_expr_clear_extra_error_info(); 02636 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) { 02637 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02638 item->filename, item->startline, item->endline, item->u2.val); 02639 warns++; 02640 } 02641 check_expr2_input(item,item->u2.val); 02642 } 02643 break; 02644 02645 case PV_LOCALVARDEC: 02646 /* fields: item->u1.str == variable name 02647 item->u2.val == variable value to assign 02648 */ 02649 /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */ 02650 snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.val); 02651 ast_expr_register_extra_error_info(errmsg); 02652 ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL); 02653 ast_expr_clear_extra_error_info(); 02654 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) { 02655 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02656 item->filename, item->startline, item->endline, item->u2.val); 02657 warns++; 02658 } 02659 check_expr2_input(item,item->u2.val); 02660 break; 02661 02662 case PV_GOTO: 02663 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. 02664 item->u1.list->u1.str == where the data on a PV_WORD will always be. 02665 */ 02666 /* don't check goto's in abstract contexts */ 02667 if ( in_abstract_context ) 02668 break; 02669 02670 check_goto(item); 02671 break; 02672 02673 case PV_LABEL: 02674 /* fields: item->u1.str == label name 02675 */ 02676 if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) { 02677 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n", 02678 item->filename, item->startline, item->endline, item->u1.str); 02679 warns++; 02680 } 02681 02682 check_label(item); 02683 break; 02684 02685 case PV_FOR: 02686 /* fields: item->u1.for_init == a string containing the initalizer 02687 item->u2.for_test == a string containing the loop test 02688 item->u3.for_inc == a string containing the loop increment 02689 02690 item->u4.for_statements == a pval list of statements in the for () 02691 */ 02692 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, for test expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.for_test); 02693 ast_expr_register_extra_error_info(errmsg); 02694 02695 strp = strchr(item->u1.for_init, '='); 02696 if (strp) { 02697 ast_expr(strp+1, expr_output, sizeof(expr_output),NULL); 02698 } 02699 ast_expr(item->u2.for_test, expr_output, sizeof(expr_output),NULL); 02700 strp = strchr(item->u3.for_inc, '='); 02701 if (strp) { 02702 ast_expr(strp+1, expr_output, sizeof(expr_output),NULL); 02703 } 02704 if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) { 02705 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02706 item->filename, item->startline, item->endline, item->u2.for_test); 02707 warns++; 02708 } 02709 if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) { 02710 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02711 item->filename, item->startline, item->endline, item->u3.for_inc); 02712 warns++; 02713 } 02714 check_expr2_input(item,item->u2.for_test); 02715 check_expr2_input(item,item->u3.for_inc); 02716 02717 ast_expr_clear_extra_error_info(); 02718 check_pval(item->u4.for_statements, apps,in_globals); 02719 break; 02720 02721 case PV_WHILE: 02722 /* fields: item->u1.str == the while conditional, as supplied by user 02723 02724 item->u2.statements == a pval list of statements in the while () 02725 */ 02726 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, while expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str); 02727 ast_expr_register_extra_error_info(errmsg); 02728 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL); 02729 ast_expr_clear_extra_error_info(); 02730 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { 02731 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02732 item->filename, item->startline, item->endline, item->u1.str); 02733 warns++; 02734 } 02735 check_expr2_input(item,item->u1.str); 02736 check_pval(item->u2.statements, apps,in_globals); 02737 break; 02738 02739 case PV_BREAK: 02740 /* fields: none 02741 */ 02742 check_break(item); 02743 break; 02744 02745 case PV_RETURN: 02746 /* fields: none 02747 */ 02748 break; 02749 02750 case PV_CONTINUE: 02751 /* fields: none 02752 */ 02753 check_continue(item); 02754 break; 02755 02756 case PV_RANDOM: 02757 /* fields: item->u1.str == the random number expression, as supplied by user 02758 02759 item->u2.statements == a pval list of statements in the if () 02760 item->u3.else_statements == a pval list of statements in the else 02761 (could be zero) 02762 */ 02763 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, random expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str); 02764 ast_expr_register_extra_error_info(errmsg); 02765 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL); 02766 ast_expr_clear_extra_error_info(); 02767 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { 02768 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n", 02769 item->filename, item->startline, item->endline, item->u1.str); 02770 warns++; 02771 } 02772 check_expr2_input(item,item->u1.str); 02773 check_pval(item->u2.statements, apps,in_globals); 02774 if (item->u3.else_statements) { 02775 check_pval(item->u3.else_statements, apps,in_globals); 02776 } 02777 break; 02778 02779 case PV_IFTIME: 02780 /* fields: item->u1.list == the if time values, 4 of them, each in PV_WORD, linked list 02781 02782 item->u2.statements == a pval list of statements in the if () 02783 item->u3.else_statements == a pval list of statements in the else 02784 (could be zero) 02785 */ 02786 if ( item->u2.arglist ) { 02787 check_timerange(item->u1.list); 02788 check_dow(item->u1.list->next); 02789 check_day(item->u1.list->next->next); 02790 check_month(item->u1.list->next->next->next); 02791 } 02792 02793 check_pval(item->u2.statements, apps,in_globals); 02794 if (item->u3.else_statements) { 02795 check_pval(item->u3.else_statements, apps,in_globals); 02796 } 02797 break; 02798 02799 case PV_IF: 02800 /* fields: item->u1.str == the if conditional, as supplied by user 02801 02802 item->u2.statements == a pval list of statements in the if () 02803 item->u3.else_statements == a pval list of statements in the else 02804 (could be zero) 02805 */ 02806 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, if expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str); 02807 ast_expr_register_extra_error_info(errmsg); 02808 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL); 02809 ast_expr_clear_extra_error_info(); 02810 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { 02811 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n", 02812 item->filename, item->startline, item->endline, item->u1.str); 02813 warns++; 02814 } 02815 check_expr2_input(item,item->u1.str); 02816 check_pval(item->u2.statements, apps,in_globals); 02817 if (item->u3.else_statements) { 02818 check_pval(item->u3.else_statements, apps,in_globals); 02819 } 02820 break; 02821 02822 case PV_SWITCH: 02823 /* fields: item->u1.str == the switch expression 02824 02825 item->u2.statements == a pval list of statements in the switch, 02826 (will be case statements, most likely!) 02827 */ 02828 /* we can check the switch expression, see if it matches any of the app variables... 02829 if it does, then, are all the possible cases accounted for? */ 02830 check_switch_expr(item, apps); 02831 check_pval(item->u2.statements, apps,in_globals); 02832 break; 02833 02834 case PV_EXTENSION: 02835 /* fields: item->u1.str == the extension name, label, whatever it's called 02836 02837 item->u2.statements == a pval list of statements in the extension 02838 item->u3.hints == a char * hint argument 02839 item->u4.regexten == an int boolean. non-zero says that regexten was specified 02840 */ 02841 current_extension = item ; 02842 02843 check_pval(item->u2.statements, apps,in_globals); 02844 break; 02845 02846 case PV_IGNOREPAT: 02847 /* fields: item->u1.str == the ignorepat data 02848 */ 02849 break; 02850 02851 case PV_GLOBALS: 02852 /* fields: item->u1.statements == pval list of statements, usually vardecs 02853 */ 02854 in_abstract_context = 0; 02855 check_pval(item->u1.statements, apps, 1); 02856 break; 02857 default: 02858 break; 02859 } 02860 }
Definition at line 2180 of file pval.c.
References ast_log(), calloc, pval::endcol, pval::endline, pval::filename, LOG_WARNING, pval::next, argapp::next, PV_APPLICATION_CALL, PV_CASE, PV_DEFAULT, PV_PATTERN, PV_STATEMENTBLOCK, pval::startcol, pval::startline, pval::statements, pval::str, strdup, pval::type, pval::u1, and pval::u2.
02181 { 02182 #ifdef AAL_ARGCHECK 02183 /* get and clean the variable name */ 02184 char *buff1, *p; 02185 struct argapp *a,*a2; 02186 struct appsetvar *v,*v2; 02187 struct argchoice *c; 02188 pval *t; 02189 02190 p = item->u1.str; 02191 while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) ) 02192 p++; 02193 02194 buff1 = ast_strdupa(p); 02195 02196 while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t')) 02197 buff1[strlen(buff1)-1] = 0; 02198 /* buff1 now contains the variable name */ 02199 v = 0; 02200 for (a=apps; a; a=a->next) { 02201 for (v=a->setvars;v;v=v->next) { 02202 if (strcmp(v->name,buff1) == 0) { 02203 break; 02204 } 02205 } 02206 if ( v ) 02207 break; 02208 } 02209 if (v && v->vals) { 02210 /* we have a match, to a variable that has a set of determined values */ 02211 int def= 0; 02212 int pat = 0; 02213 int f1 = 0; 02214 02215 /* first of all, does this switch have a default case ? */ 02216 for (t=item->u2.statements; t; t=t->next) { 02217 if (t->type == PV_DEFAULT) { 02218 def =1; 02219 break; 02220 } 02221 if (t->type == PV_PATTERN) { 02222 pat++; 02223 } 02224 } 02225 if (def || pat) /* nothing to check. All cases accounted for! */ 02226 return; 02227 for (c=v->vals; c; c=c->next) { 02228 f1 = 0; 02229 for (t=item->u2.statements; t; t=t->next) { 02230 if (t->type == PV_CASE || t->type == PV_PATTERN) { 02231 if (!strcmp(t->u1.str,c->name)) { 02232 f1 = 1; 02233 break; 02234 } 02235 } 02236 } 02237 if (!f1) { 02238 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n", 02239 item->filename, item->startline, item->endline, item->u1.str, c->name); 02240 warns++; 02241 } 02242 } 02243 /* next, is there an app call in the current exten, that would set this var? */ 02244 f1 = 0; 02245 t = current_extension->u2.statements; 02246 if ( t && t->type == PV_STATEMENTBLOCK ) 02247 t = t->u1.statements; 02248 for (; t && t != item; t=t->next) { 02249 if (t->type == PV_APPLICATION_CALL) { 02250 /* find the application that matches the u1.str */ 02251 for (a2=apps; a2; a2=a2->next) { 02252 if (strcasecmp(a2->name, t->u1.str)==0) { 02253 for (v2=a2->setvars; v2; v2=v2->next) { 02254 if (strcmp(v2->name, buff1) == 0) { 02255 /* found an app that sets the var */ 02256 f1 = 1; 02257 break; 02258 } 02259 } 02260 } 02261 if (f1) 02262 break; 02263 } 02264 } 02265 if (f1) 02266 break; 02267 } 02268 02269 /* see if it sets the var */ 02270 if (!f1) { 02271 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", 02272 item->filename, item->startline, item->endline, item->u1.str); 02273 warns++; 02274 } 02275 } 02276 #else 02277 pval *t,*tl=0,*p2; 02278 int def= 0; 02279 02280 /* first of all, does this switch have a default case ? */ 02281 for (t=item->u2.statements; t; t=t->next) { 02282 if (t->type == PV_DEFAULT) { 02283 def =1; 02284 break; 02285 } 02286 tl = t; 02287 } 02288 if (def) /* nothing to check. All cases accounted for! */ 02289 return; 02290 /* if no default, warn and insert a default case at the end */ 02291 p2 = tl->next = calloc(1, sizeof(struct pval)); 02292 02293 p2->type = PV_DEFAULT; 02294 p2->startline = tl->startline; 02295 p2->endline = tl->endline; 02296 p2->startcol = tl->startcol; 02297 p2->endcol = tl->endcol; 02298 p2->filename = strdup(tl->filename); 02299 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n", 02300 p2->filename, p2->startline, p2->endline); 02301 warns++; 02302 02303 #endif 02304 }
| void destroy_extensions | ( | struct ael_extension * | exten | ) |
Definition at line 2975 of file pval.c.
References ael_priority::app, ael_priority::appargs, free, ael_priority::goto_false, ael_priority::goto_true, ael_extension::hints, ael_extension::loop_break, ael_extension::loop_continue, ael_extension::name, ael_priority::next, ael_extension::next_exten, ael_priority::origin, ael_extension::plist, and ael_extension::plist_last.
02976 { 02977 struct ael_extension *ne, *nen; 02978 for (ne=exten; ne; ne=nen) { 02979 struct ael_priority *pe, *pen; 02980 02981 if (ne->name) 02982 free(ne->name); 02983 02984 /* cidmatch fields are allocated with name, and freed when 02985 the name field is freed. Don't do a free for this field, 02986 unless you LIKE to see a crash! */ 02987 02988 if (ne->hints) 02989 free(ne->hints); 02990 02991 for (pe=ne->plist; pe; pe=pen) { 02992 pen = pe->next; 02993 if (pe->app) 02994 free(pe->app); 02995 pe->app = 0; 02996 if (pe->appargs) 02997 free(pe->appargs); 02998 pe->appargs = 0; 02999 pe->origin = 0; 03000 pe->goto_true = 0; 03001 pe->goto_false = 0; 03002 free(pe); 03003 } 03004 nen = ne->next_exten; 03005 ne->next_exten = 0; 03006 ne->plist =0; 03007 ne->plist_last = 0; 03008 ne->next_exten = 0; 03009 ne->loop_break = 0; 03010 ne->loop_continue = 0; 03011 free(ne); 03012 } 03013 }
| void destroy_pval | ( | pval * | item | ) |
Definition at line 4851 of file pval.c.
References destroy_pval_item(), and pval::next.
04852 { 04853 pval *i,*nxt; 04854 04855 for (i=item; i; i=nxt) { 04856 nxt = i->next; 04857 04858 destroy_pval_item(i); 04859 } 04860 }
| void destroy_pval_item | ( | pval * | item | ) |
Definition at line 4583 of file pval.c.
References pval::arglist, ast_log(), destroy_pval(), pval::else_statements, pval::filename, pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, free, pval::hints, pval::list, LOG_WARNING, pval::macro_statements, PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTEXT, PV_CONTINUE, PV_DEFAULT, PV_ESWITCHES, PV_EXTENSION, PV_FOR, PV_GLOBALS, PV_GOTO, PV_IF, PV_IFTIME, PV_IGNOREPAT, PV_INCLUDES, PV_LABEL, PV_LOCALVARDEC, PV_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pval::statements, pval::str, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.
04584 { 04585 if (item == NULL) { 04586 ast_log(LOG_WARNING, "null item\n"); 04587 return; 04588 } 04589 04590 if (item->filename) 04591 free(item->filename); 04592 04593 switch (item->type) { 04594 case PV_WORD: 04595 /* fields: item->u1.str == string associated with this (word). */ 04596 if (item->u1.str ) 04597 free(item->u1.str); 04598 if ( item->u2.arglist ) 04599 destroy_pval(item->u2.arglist); 04600 break; 04601 04602 case PV_MACRO: 04603 /* fields: item->u1.str == name of macro 04604 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user 04605 item->u2.arglist->u1.str == argument 04606 item->u2.arglist->next == next arg 04607 04608 item->u3.macro_statements == pval list of statements in macro body. 04609 */ 04610 destroy_pval(item->u2.arglist); 04611 if (item->u1.str ) 04612 free(item->u1.str); 04613 destroy_pval(item->u3.macro_statements); 04614 break; 04615 04616 case PV_CONTEXT: 04617 /* fields: item->u1.str == name of context 04618 item->u2.statements == pval list of statements in context body 04619 item->u3.abstract == int 1 if an abstract keyword were present 04620 */ 04621 if (item->u1.str) 04622 free(item->u1.str); 04623 destroy_pval(item->u2.statements); 04624 break; 04625 04626 case PV_MACRO_CALL: 04627 /* fields: item->u1.str == name of macro to call 04628 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 04629 item->u2.arglist->u1.str == argument 04630 item->u2.arglist->next == next arg 04631 */ 04632 if (item->u1.str) 04633 free(item->u1.str); 04634 destroy_pval(item->u2.arglist); 04635 break; 04636 04637 case PV_APPLICATION_CALL: 04638 /* fields: item->u1.str == name of application to call 04639 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 04640 item->u2.arglist->u1.str == argument 04641 item->u2.arglist->next == next arg 04642 */ 04643 if (item->u1.str) 04644 free(item->u1.str); 04645 destroy_pval(item->u2.arglist); 04646 break; 04647 04648 case PV_CASE: 04649 /* fields: item->u1.str == value of case 04650 item->u2.statements == pval list of statements under the case 04651 */ 04652 if (item->u1.str) 04653 free(item->u1.str); 04654 destroy_pval(item->u2.statements); 04655 break; 04656 04657 case PV_PATTERN: 04658 /* fields: item->u1.str == value of case 04659 item->u2.statements == pval list of statements under the case 04660 */ 04661 if (item->u1.str) 04662 free(item->u1.str); 04663 destroy_pval(item->u2.statements); 04664 break; 04665 04666 case PV_DEFAULT: 04667 /* fields: 04668 item->u2.statements == pval list of statements under the case 04669 */ 04670 destroy_pval(item->u2.statements); 04671 break; 04672 04673 case PV_CATCH: 04674 /* fields: item->u1.str == name of extension to catch 04675 item->u2.statements == pval list of statements in context body 04676 */ 04677 if (item->u1.str) 04678 free(item->u1.str); 04679 destroy_pval(item->u2.statements); 04680 break; 04681 04682 case PV_SWITCHES: 04683 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04684 */ 04685 destroy_pval(item->u1.list); 04686 break; 04687 04688 case PV_ESWITCHES: 04689 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04690 */ 04691 destroy_pval(item->u1.list); 04692 break; 04693 04694 case PV_INCLUDES: 04695 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04696 item->u2.arglist == pval list of 4 PV_WORD elements for time values 04697 */ 04698 destroy_pval(item->u1.list); 04699 break; 04700 04701 case PV_STATEMENTBLOCK: 04702 /* fields: item->u1.list == pval list of statements in block, one per entry in the list 04703 */ 04704 destroy_pval(item->u1.list); 04705 break; 04706 04707 case PV_LOCALVARDEC: 04708 case PV_VARDEC: 04709 /* fields: item->u1.str == variable name 04710 item->u2.val == variable value to assign 04711 */ 04712 if (item->u1.str) 04713 free(item->u1.str); 04714 if (item->u2.val) 04715 free(item->u2.val); 04716 break; 04717 04718 case PV_GOTO: 04719 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. 04720 item->u1.list->u1.str == where the data on a PV_WORD will always be. 04721 */ 04722 04723 destroy_pval(item->u1.list); 04724 break; 04725 04726 case PV_LABEL: 04727 /* fields: item->u1.str == label name 04728 */ 04729 if (item->u1.str) 04730 free(item->u1.str); 04731 break; 04732 04733 case PV_FOR: 04734 /* fields: item->u1.for_init == a string containing the initalizer 04735 item->u2.for_test == a string containing the loop test 04736 item->u3.for_inc == a string containing the loop increment 04737 04738 item->u4.for_statements == a pval list of statements in the for () 04739 */ 04740 if (item->u1.for_init) 04741 free(item->u1.for_init); 04742 if (item->u2.for_test) 04743 free(item->u2.for_test); 04744 if (item->u3.for_inc) 04745 free(item->u3.for_inc); 04746 destroy_pval(item->u4.for_statements); 04747 break; 04748 04749 case PV_WHILE: 04750 /* fields: item->u1.str == the while conditional, as supplied by user 04751 04752 item->u2.statements == a pval list of statements in the while () 04753 */ 04754 if (item->u1.str) 04755 free(item->u1.str); 04756 destroy_pval(item->u2.statements); 04757 break; 04758 04759 case PV_BREAK: 04760 /* fields: none 04761 */ 04762 break; 04763 04764 case PV_RETURN: 04765 /* fields: none 04766 */ 04767 break; 04768 04769 case PV_CONTINUE: 04770 /* fields: none 04771 */ 04772 break; 04773 04774 case PV_IFTIME: 04775 /* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list 04776 04777 item->u2.statements == a pval list of statements in the if () 04778 item->u3.else_statements == a pval list of statements in the else 04779 (could be zero) 04780 */ 04781 destroy_pval(item->u1.list); 04782 destroy_pval(item->u2.statements); 04783 if (item->u3.else_statements) { 04784 destroy_pval(item->u3.else_statements); 04785 } 04786 break; 04787 04788 case PV_RANDOM: 04789 /* fields: item->u1.str == the random percentage, as supplied by user 04790 04791 item->u2.statements == a pval list of statements in the true part () 04792 item->u3.else_statements == a pval list of statements in the else 04793 (could be zero) 04794 fall thru to If */ 04795 case PV_IF: 04796 /* fields: item->u1.str == the if conditional, as supplied by user 04797 04798 item->u2.statements == a pval list of statements in the if () 04799 item->u3.else_statements == a pval list of statements in the else 04800 (could be zero) 04801 */ 04802 if (item->u1.str) 04803 free(item->u1.str); 04804 destroy_pval(item->u2.statements); 04805 if (item->u3.else_statements) { 04806 destroy_pval(item->u3.else_statements); 04807 } 04808 break; 04809 04810 case PV_SWITCH: 04811 /* fields: item->u1.str == the switch expression 04812 04813 item->u2.statements == a pval list of statements in the switch, 04814 (will be case statements, most likely!) 04815 */ 04816 if (item->u1.str) 04817 free(item->u1.str); 04818 destroy_pval(item->u2.statements); 04819 break; 04820 04821 case PV_EXTENSION: 04822 /* fields: item->u1.str == the extension name, label, whatever it's called 04823 04824 item->u2.statements == a pval list of statements in the extension 04825 item->u3.hints == a char * hint argument 04826 item->u4.regexten == an int boolean. non-zero says that regexten was specified 04827 */ 04828 if (item->u1.str) 04829 free(item->u1.str); 04830 if (item->u3.hints) 04831 free(item->u3.hints); 04832 destroy_pval(item->u2.statements); 04833 break; 04834 04835 case PV_IGNOREPAT: 04836 /* fields: item->u1.str == the ignorepat data 04837 */ 04838 if (item->u1.str) 04839 free(item->u1.str); 04840 break; 04841 04842 case PV_GLOBALS: 04843 /* fields: item->u1.statements == pval list of statements, usually vardecs 04844 */ 04845 destroy_pval(item->u1.statements); 04846 break; 04847 } 04848 free(item); 04849 }
| struct pval* find_context | ( | char * | name | ) | [read] |
Definition at line 1949 of file pval.c.
References match_pval().
01950 { 01951 return_on_context_match = 1; 01952 count_labels = 0; 01953 match_context = name; 01954 match_exten = "*"; /* don't really need to set these, shouldn't be reached */ 01955 match_label = "*"; 01956 return match_pval(current_db); 01957 }
| struct pval* find_macro | ( | char * | name | ) | [read] |
Definition at line 1939 of file pval.c.
References match_pval().
01940 { 01941 return_on_context_match = 1; 01942 count_labels = 0; 01943 match_context = name; 01944 match_exten = "*"; /* don't really need to set these, shouldn't be reached */ 01945 match_label = "*"; 01946 return match_pval(current_db); 01947 }
| static char* handle_cli_ael_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 195 of file pbx_ael.c.
References ast_cli_args::argc, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, pbx_load_module(), and ast_cli_entry::usage.
00196 { 00197 switch (cmd) { 00198 case CLI_INIT: 00199 e->command = "ael reload"; 00200 e->usage = 00201 "Usage: ael reload\n" 00202 " Reloads AEL configuration.\n"; 00203 return NULL; 00204 case CLI_GENERATE: 00205 return NULL; 00206 } 00207 00208 if (a->argc != 2) 00209 return CLI_SHOWUSAGE; 00210 00211 return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS); 00212 }
| static char* handle_cli_ael_set_debug | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 161 of file pbx_ael.c.
References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, DEBUG_CONTEXTS, DEBUG_MACROS, DEBUG_READ, DEBUG_TOKENS, and ast_cli_entry::usage.
00162 { 00163 switch (cmd) { 00164 case CLI_INIT: 00165 e->command = "ael set debug {read|tokens|macros|contexts|off}"; 00166 e->usage = 00167 "Usage: ael set debug {read|tokens|macros|contexts|off}\n" 00168 " Enable AEL read, token, macro, or context debugging,\n" 00169 " or disable all AEL debugging messages. Note: this\n" 00170 " currently does nothing.\n"; 00171 return NULL; 00172 case CLI_GENERATE: 00173 return NULL; 00174 } 00175 00176 if (a->argc != e->args) 00177 return CLI_SHOWUSAGE; 00178 00179 if (!strcasecmp(a->argv[3], "read")) 00180 aeldebug |= DEBUG_READ; 00181 else if (!strcasecmp(a->argv[3], "tokens")) 00182 aeldebug |= DEBUG_TOKENS; 00183 else if (!strcasecmp(a->argv[3], "macros")) 00184 aeldebug |= DEBUG_MACROS; 00185 else if (!strcasecmp(a->argv[3], "contexts")) 00186 aeldebug |= DEBUG_CONTEXTS; 00187 else if (!strcasecmp(a->argv[3], "off")) 00188 aeldebug = 0; 00189 else 00190 return CLI_SHOWUSAGE; 00191 00192 return CLI_SUCCESS; 00193 }
| int is_empty | ( | char * | arg | ) |
| int is_float | ( | char * | arg | ) |
| int is_int | ( | char * | arg | ) |
| static int load_module | ( | void | ) | [static] |
Definition at line 226 of file pbx_ael.c.
References ARRAY_LEN, ast_cli_register_multiple(), and pbx_load_module().
00227 { 00228 ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael)); 00229 return (pbx_load_module()); 00230 }
| struct ael_extension* new_exten | ( | void | ) | [read] |
Definition at line 2927 of file pval.c.
References calloc.
02928 { 02929 struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1); 02930 return x; 02931 }
| struct ael_priority* new_prio | ( | void | ) | [read] |
Definition at line 2921 of file pval.c.
References calloc.
02922 { 02923 struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1); 02924 return x; 02925 }
| static int pbx_load_module | ( | void | ) | [static] |
Definition at line 113 of file pbx_ael.c.
References ael2_parse(), ael2_semantic_check(), ast_compile_ael2(), ast_config_AST_CONFIG_DIR, ast_context_verify_includes(), ast_hashtab_compare_contexts(), ast_hashtab_create(), ast_hashtab_hash_contexts(), ast_hashtab_newsize_java(), ast_hashtab_resize_java(), ast_log(), ast_merge_contexts_and_delete(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_walk_contexts(), destroy_pval(), errs, local_contexts, local_table, LOG_ERROR, and LOG_NOTICE.
Referenced by handle_cli_ael_reload(), load_module(), and reload().
00114 { 00115 int errs=0, sem_err=0, sem_warn=0, sem_note=0; 00116 char *rfilename; 00117 struct ast_context *local_contexts=NULL, *con; 00118 struct ast_hashtab *local_table=NULL; 00119 00120 struct pval *parse_tree; 00121 00122 ast_log(LOG_NOTICE, "Starting AEL load process.\n"); 00123 if (config[0] == '/') 00124 rfilename = (char *)config; 00125 else { 00126 rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2); 00127 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config); 00128 } 00129 if (access(rfilename,R_OK) != 0) { 00130 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename); 00131 return AST_MODULE_LOAD_DECLINE; 00132 } 00133 00134 parse_tree = ael2_parse(rfilename, &errs); 00135 ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename); 00136 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note); 00137 if (errs == 0 && sem_err == 0) { 00138 ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename); 00139 local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0); 00140 ast_compile_ael2(&local_contexts, local_table, parse_tree); 00141 ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename); 00142 00143 ast_merge_contexts_and_delete(&local_contexts, local_table, registrar); 00144 local_table = NULL; /* it's the dialplan global now */ 00145 local_contexts = NULL; 00146 ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename); 00147 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con)) 00148 ast_context_verify_includes(con); 00149 ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename); 00150 } else { 00151 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); 00152 destroy_pval(parse_tree); /* free up the memory */ 00153 return AST_MODULE_LOAD_DECLINE; 00154 } 00155 destroy_pval(parse_tree); /* free up the memory */ 00156 00157 return AST_MODULE_LOAD_SUCCESS; 00158 }
| static int reload | ( | void | ) | [static] |
Definition at line 232 of file pbx_ael.c.
References pbx_load_module().
00233 { 00234 return pbx_load_module(); 00235 }
| void set_priorities | ( | struct ael_extension * | exten | ) |
Definition at line 4181 of file pval.c.
References ael_extension::is_switch, ael_priority::next, ael_extension::next_exten, ael_priority::origin, ael_extension::plist, ael_priority::priority_num, PV_LABEL, ael_extension::regexten, and pval::type.
04182 { 04183 int i; 04184 struct ael_priority *pr; 04185 do { 04186 if (exten->is_switch) 04187 i = 10; 04188 else if (exten->regexten) 04189 i=2; 04190 else 04191 i=1; 04192 04193 for (pr=exten->plist; pr; pr=pr->next) { 04194 pr->priority_num = i; 04195 04196 if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan, 04197 but we want them to point to the right 04198 priority, which would be the next line 04199 after the label; */ 04200 i++; 04201 } 04202 04203 exten = exten->next_exten; 04204 } while ( exten ); 04205 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 219 of file pbx_ael.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), and ast_context_destroy().
00220 { 00221 ast_context_destroy(NULL, registrar); 00222 ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael)); 00223 return 0; 00224 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Asterisk Extension Language Compiler" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
struct ast_module_info* ast_module_info = &__mod_info [static] |
struct ast_cli_entry cli_ael[] [static] |
{
AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags")
}
1.6.2