#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) |
static int | aelsub_exec (struct ast_channel *chan, const char *vdata) |
int | 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) |
pval * | find_context (char *name) |
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) |
ael_extension * | new_exten (void) |
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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, } |
static int | aeldebug = 0 |
static char * | aelsub = "AELSub" |
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" |
Definition in file pbx_ael.c.
#define DEBUG_CONTEXTS (1 << 3) |
#define DEBUG_MACROS (1 << 2) |
#define DEBUG_READ (1 << 0) |
#define DEBUG_TOKENS (1 << 1) |
void add_extensions | ( | struct ael_extension * | exten | ) |
Definition at line 4241 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, app, ael_priority::app, ael_priority::appargs, ast_add_extension2(), ast_free_ptr, ast_log(), AST_MAX_EXTENSION, pval::else_statements, exten, ael_priority::exten, ael_priority::goto_false, ael_priority::goto_true, last, LOG_WARNING, ael_extension::name, ael_priority::next, ael_priority::origin, pbx_substitute_variables_helper(), PRIORITY_HINT, ael_priority::priority_num, PV_IFTIME, PV_SWITCH, strdup, ael_priority::type, pval::type, and pval::u3.
04242 { 04243 struct ael_priority *pr; 04244 char *label=0; 04245 char realext[AST_MAX_EXTENSION]; 04246 if (!exten) { 04247 ast_log(LOG_WARNING, "This file is Empty!\n" ); 04248 return; 04249 } 04250 do { 04251 struct ael_priority *last = 0; 04252 04253 pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1); 04254 if (exten->hints) { 04255 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, 04256 exten->hints, NULL, ast_free_ptr, registrar)) { 04257 ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n", 04258 exten->name); 04259 } 04260 } 04261 04262 for (pr=exten->plist; pr; pr=pr->next) { 04263 char app[2000]; 04264 char appargs[2000]; 04265 04266 /* before we can add the extension, we need to prep the app/appargs; 04267 the CONTROL types need to be done after the priority numbers are calculated. 04268 */ 04269 if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ { 04270 last = pr; 04271 continue; 04272 } 04273 04274 if (pr->app) 04275 strcpy(app, pr->app); 04276 else 04277 app[0] = 0; 04278 if (pr->appargs ) 04279 strcpy(appargs, pr->appargs); 04280 else 04281 appargs[0] = 0; 04282 switch( pr->type ) { 04283 case AEL_APPCALL: 04284 /* easy case. Everything is all set up */ 04285 break; 04286 04287 case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */ 04288 /* simple, unconditional goto. */ 04289 strcpy(app,"Goto"); 04290 if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) { 04291 snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num); 04292 } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) { 04293 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1); 04294 } else 04295 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num); 04296 break; 04297 04298 case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */ 04299 strcpy(app,"GotoIf"); 04300 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num); 04301 break; 04302 04303 case AEL_IF_CONTROL: 04304 strcpy(app,"GotoIf"); 04305 if (pr->origin->u3.else_statements ) 04306 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1); 04307 else 04308 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num); 04309 break; 04310 04311 case AEL_RAND_CONTROL: 04312 strcpy(app,"Random"); 04313 snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1); 04314 break; 04315 04316 case AEL_IFTIME_CONTROL: 04317 strcpy(app,"GotoIfTime"); 04318 snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2); 04319 break; 04320 04321 case AEL_RETURN: 04322 strcpy(app,"Return"); 04323 appargs[0] = 0; 04324 break; 04325 04326 default: 04327 break; 04328 } 04329 if (last && last->type == AEL_LABEL ) { 04330 label = last->origin->u1.str; 04331 } 04332 else 04333 label = 0; 04334 04335 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, 04336 app, strdup(appargs), ast_free_ptr, registrar)) { 04337 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, 04338 exten->name); 04339 } 04340 last = pr; 04341 } 04342 exten = exten->next_exten; 04343 } while ( exten ); 04344 }
static int aelsub_exec | ( | struct ast_channel * | chan, | |
const char * | vdata | |||
) | [static] |
Definition at line 135 of file pbx_ael.c.
References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_STANDARD_RAW_ARGS, ast_strdupa, name, pbx_exec(), and pbx_findapp().
Referenced by load_module().
00136 { 00137 char buf[256], *data = ast_strdupa(vdata); 00138 struct ast_app *gosub = pbx_findapp("Gosub"); 00139 AST_DECLARE_APP_ARGS(args, 00140 AST_APP_ARG(name); 00141 AST_APP_ARG(args); 00142 ); 00143 00144 if (gosub) { 00145 AST_STANDARD_RAW_ARGS(args, data); 00146 snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args); 00147 return pbx_exec(chan, gosub, buf); 00148 } 00149 return -1; 00150 }
int ast_compile_ael2 | ( | struct ast_context ** | local_contexts, | |
struct ast_hashtab * | local_table, | |||
struct pval * | root | |||
) |
Definition at line 4427 of file pval.c.
References buf2, context, exten, pval::list, pval::next, pbx_builtin_setvar(), PV_GLOBALS, pval::str, pval::type, pval::u1, pval::u2, and pval::val.
04428 { 04429 pval *p,*p2; 04430 struct ast_context *context; 04431 char buf[2000]; 04432 struct ael_extension *exten; 04433 struct ael_extension *exten_list = 0; 04434 04435 for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there 04436 when we try to eval them */ 04437 switch (p->type) { 04438 case PV_GLOBALS: 04439 /* just VARDEC elements */ 04440 for (p2=p->u1.list; p2; p2=p2->next) { 04441 char buf2[2000]; 04442 snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val); 04443 pbx_builtin_setvar(NULL, buf2); 04444 } 04445 break; 04446 default: 04447 break; 04448 } 04449 } 04450 04451 for (p=root; p; p=p->next ) { 04452 pval *lp; 04453 int argc; 04454 04455 switch (p->type) { 04456 case PV_MACRO: 04457 04458 context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar); 04459 04460 exten = new_exten(); 04461 exten->context = context; 04462 exten->name = strdup("~~s~~"); 04463 argc = 1; 04464 for (lp=p->u2.arglist; lp; lp=lp->next) { 04465 /* for each arg, set up a "Set" command */ 04466 struct ael_priority *np2 = new_prio(); 04467 np2->type = AEL_APPCALL; 04468 if (!ast_compat_app_set) { 04469 np2->app = strdup("MSet"); 04470 } else { 04471 np2->app = strdup("Set"); 04472 } 04473 snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++); 04474 remove_spaces_before_equals(buf); 04475 np2->appargs = strdup(buf); 04476 linkprio(exten, np2, NULL); 04477 } 04478 04479 /* CONTAINS APPCALLS, CATCH, just like extensions... */ 04480 if (gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context)) { 04481 return -1; 04482 } 04483 if (exten->return_needed) { /* most likely, this will go away */ 04484 struct ael_priority *np2 = new_prio(); 04485 np2->type = AEL_APPCALL; 04486 np2->app = strdup("NoOp"); 04487 snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name); 04488 np2->appargs = strdup(buf); 04489 linkprio(exten, np2, NULL); 04490 exten-> return_target = np2; 04491 } 04492 04493 set_priorities(exten); 04494 attach_exten(&exten_list, exten); 04495 break; 04496 04497 case PV_GLOBALS: 04498 /* already done */ 04499 break; 04500 04501 case PV_CONTEXT: 04502 context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar); 04503 04504 /* contexts contain: ignorepat, includes, switches, eswitches, extensions, */ 04505 for (p2=p->u2.statements; p2; p2=p2->next) { 04506 pval *p3; 04507 char *s3; 04508 04509 switch (p2->type) { 04510 case PV_EXTENSION: 04511 exten = new_exten(); 04512 exten->name = strdup(p2->u1.str); 04513 exten->context = context; 04514 04515 if( (s3=strchr(exten->name, '/') ) != 0 ) 04516 { 04517 *s3 = 0; 04518 exten->cidmatch = s3+1; 04519 } 04520 04521 if ( p2->u3.hints ) 04522 exten->hints = strdup(p2->u3.hints); 04523 exten->regexten = p2->u4.regexten; 04524 if (gen_prios(exten, p->u1.str, p2->u2.statements, 0, context)) { 04525 return -1; 04526 } 04527 if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */ 04528 struct ael_priority *np2 = new_prio(); 04529 np2->type = AEL_APPCALL; 04530 np2->app = strdup("NoOp"); 04531 snprintf(buf,sizeof(buf),"End of Extension %s", exten->name); 04532 np2->appargs = strdup(buf); 04533 linkprio(exten, np2, NULL); 04534 exten-> return_target = np2; 04535 } 04536 /* is the last priority in the extension a label? Then add a trailing no-op */ 04537 if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) { 04538 struct ael_priority *np2 = new_prio(); 04539 np2->type = AEL_APPCALL; 04540 np2->app = strdup("NoOp"); 04541 snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str); 04542 np2->appargs = strdup(buf); 04543 linkprio(exten, np2, NULL); 04544 } 04545 04546 set_priorities(exten); 04547 attach_exten(&exten_list, exten); 04548 break; 04549 04550 case PV_IGNOREPAT: 04551 ast_context_add_ignorepat2(context, p2->u1.str, registrar); 04552 break; 04553 04554 case PV_INCLUDES: 04555 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04556 if ( p3->u2.arglist ) { 04557 snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s", 04558 p3->u1.str, 04559 p3->u2.arglist->u1.str, 04560 p3->u2.arglist->next->u1.str, 04561 p3->u2.arglist->next->next->u1.str, 04562 p3->u2.arglist->next->next->next->u1.str); 04563 ast_context_add_include2(context, buf, registrar); 04564 } else 04565 ast_context_add_include2(context, p3->u1.str, registrar); 04566 } 04567 break; 04568 04569 case PV_SWITCHES: 04570 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04571 char *c = strchr(p3->u1.str, '/'); 04572 if (c) { 04573 *c = '\0'; 04574 c++; 04575 } else 04576 c = ""; 04577 04578 ast_context_add_switch2(context, p3->u1.str, c, 0, registrar); 04579 } 04580 break; 04581 04582 case PV_ESWITCHES: 04583 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04584 char *c = strchr(p3->u1.str, '/'); 04585 if (c) { 04586 *c = '\0'; 04587 c++; 04588 } else 04589 c = ""; 04590 04591 ast_context_add_switch2(context, p3->u1.str, c, 1, registrar); 04592 } 04593 break; 04594 default: 04595 break; 04596 } 04597 } 04598 04599 break; 04600 04601 default: 04602 /* huh? what? */ 04603 break; 04604 04605 } 04606 } 04607 /* moved these from being done after a macro or extension were processed, 04608 to after all processing is done, for the sake of fixing gotos to labels inside cases... */ 04609 /* I guess this would be considered 2nd pass of compiler now... */ 04610 fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */ 04611 add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */ 04612 destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */ 04613 04614 return 0; 04615 }
void ast_expr_clear_extra_error_info | ( | void | ) |
void ast_expr_register_extra_error_info | ( | char * | errmsg | ) |
Definition at line 2127 of file pval.c.
References app, ast_log(), pval::endline, pval::filename, LOG_WARNING, pval::next, pval::startline, pval::str, and pval::u1.
02128 { 02129 #ifdef AAL_ARGCHECK 02130 struct argdesc *ad = app->args; 02131 pval *pa; 02132 int z; 02133 02134 for (pa = arglist; pa; pa=pa->next) { 02135 if (!ad) { 02136 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n", 02137 arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name); 02138 warns++; 02139 return 1; 02140 } else { 02141 /* find the first entry in the ad list that will match */ 02142 do { 02143 if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */ 02144 break; 02145 02146 z= option_matches( ad, pa, app); 02147 if (!z) { 02148 if ( !arglist ) 02149 arglist=appcall; 02150 02151 if (ad->type == ARGD_REQUIRED) { 02152 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", 02153 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); 02154 warns++; 02155 return 1; 02156 } 02157 } else if (z && ad->dtype == ARGD_OPTIONSET) { 02158 option_matches_j( ad, pa, app); 02159 } 02160 ad = ad->next; 02161 } while (ad && !z); 02162 } 02163 } 02164 /* any app nodes left, that are not optional? */ 02165 for ( ; ad; ad=ad->next) { 02166 if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) { 02167 if ( !arglist ) 02168 arglist=appcall; 02169 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", 02170 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); 02171 warns++; 02172 return 1; 02173 } 02174 } 02175 return 0; 02176 #else 02177 return 0; 02178 #endif 02179 }
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 2354 of file pval.c.
References pval::abstract, app, 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(), current_context, current_extension, 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, 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.
02355 { 02356 pval *lp; 02357 #ifdef AAL_ARGCHECK 02358 struct argapp *app, *found; 02359 #endif 02360 struct pval *macro_def; 02361 struct pval *app_def; 02362 02363 char errmsg[4096]; 02364 char *strp; 02365 02366 switch (item->type) { 02367 case PV_WORD: 02368 /* fields: item->u1.str == string associated with this (word). 02369 item->u2.arglist == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */ 02370 break; 02371 02372 case PV_MACRO: 02373 /* fields: item->u1.str == name of macro 02374 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user 02375 item->u2.arglist->u1.str == argument 02376 item->u2.arglist->next == next arg 02377 02378 item->u3.macro_statements == pval list of statements in macro body. 02379 */ 02380 in_abstract_context = 0; 02381 current_context = item; 02382 current_extension = 0; 02383 02384 check_macro_returns(item); 02385 02386 for (lp=item->u2.arglist; lp; lp=lp->next) { 02387 02388 } 02389 check_pval(item->u3.macro_statements, apps,in_globals); 02390 break; 02391 02392 case PV_CONTEXT: 02393 /* fields: item->u1.str == name of context 02394 item->u2.statements == pval list of statements in context body 02395 item->u3.abstract == int 1 if an abstract keyword were present 02396 */ 02397 current_context = item; 02398 current_extension = 0; 02399 if ( item->u3.abstract ) { 02400 in_abstract_context = 1; 02401 check_abstract_reference(item); 02402 } else 02403 in_abstract_context = 0; 02404 check_pval(item->u2.statements, apps,in_globals); 02405 break; 02406 02407 case PV_MACRO_CALL: 02408 /* fields: item->u1.str == name of macro to call 02409 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 02410 item->u2.arglist->u1.str == argument 02411 item->u2.arglist->next == next arg 02412 */ 02413 #ifdef STANDALONE 02414 /* if this is a standalone, we will need to make sure the 02415 localized load of extensions.conf is done */ 02416 if (!extensions_dot_conf_loaded) { 02417 localized_pbx_load_module(); 02418 extensions_dot_conf_loaded++; 02419 } 02420 #endif 02421 macro_def = find_macro(item->u1.str); 02422 if (!macro_def) { 02423 #ifdef STANDALONE 02424 struct pbx_find_info pfiq = {.stacklen = 0 }; 02425 struct pbx_find_info pfiq2 = {.stacklen = 0 }; 02426 02427 /* look for the macro in the extensions.conf world */ 02428 pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH); 02429 02430 if (pfiq.status != STATUS_SUCCESS) { 02431 char namebuf2[256]; 02432 snprintf(namebuf2, 256, "macro-%s", item->u1.str); 02433 02434 /* look for the macro in the extensions.conf world */ 02435 pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH); 02436 02437 if (pfiq2.status == STATUS_SUCCESS) { 02438 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", 02439 item->filename, item->startline, item->endline, item->u1.str, item->u1.str); 02440 warns++; 02441 } else { 02442 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (Not even in the extensions.conf stuff!)\n", 02443 item->filename, item->startline, item->endline, item->u1.str); 02444 warns++; 02445 } 02446 } 02447 #else 02448 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n", 02449 item->filename, item->startline, item->endline, item->u1.str); 02450 warns++; 02451 02452 #endif 02453 #ifdef THIS_IS_1DOT4 02454 char namebuf2[256]; 02455 snprintf(namebuf2, 256, "macro-%s", item->u1.str); 02456 02457 /* look for the macro in the extensions.conf world */ 02458 pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH); 02459 02460 if (pfiq.status != STATUS_SUCCESS) { 02461 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", 02462 item->filename, item->startline, item->endline, item->u1.str); 02463 warns++; 02464 } 02465 02466 #endif 02467 02468 } else if (macro_def->type != PV_MACRO) { 02469 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n", 02470 item->filename, item->startline, item->endline, item->u1.str); 02471 errs++; 02472 } else { 02473 /* macro_def is a MACRO, so do the args match in number? */ 02474 int hereargs = 0; 02475 int thereargs = 0; 02476 02477 for (lp=item->u2.arglist; lp; lp=lp->next) { 02478 hereargs++; 02479 } 02480 for (lp=macro_def->u2.arglist; lp; lp=lp->next) { 02481 thereargs++; 02482 } 02483 if (hereargs != thereargs ) { 02484 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", 02485 item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs); 02486 errs++; 02487 } 02488 } 02489 break; 02490 02491 case PV_APPLICATION_CALL: 02492 /* fields: item->u1.str == name of application to call 02493 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 02494 item->u2.arglist->u1.str == argument 02495 item->u2.arglist->next == next arg 02496 */ 02497 /* Need to check to see if the application is available! */ 02498 app_def = find_context(item->u1.str); 02499 if (app_def && app_def->type == PV_MACRO) { 02500 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n", 02501 item->filename, item->startline, item->endline, item->u1.str); 02502 errs++; 02503 } 02504 if (strcasecmp(item->u1.str,"GotoIf") == 0 02505 || strcasecmp(item->u1.str,"GotoIfTime") == 0 02506 || strcasecmp(item->u1.str,"while") == 0 02507 || strcasecmp(item->u1.str,"endwhile") == 0 02508 || strcasecmp(item->u1.str,"random") == 0 02509 || strcasecmp(item->u1.str,"gosub") == 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 2181 of file pval.c.
References ast_strdupa, argapp::next, pval::str, and pval::u1.
02182 { 02183 #ifdef AAL_ARGCHECK 02184 /* get and clean the variable name */ 02185 char *buff1, *p; 02186 struct argapp *a,*a2; 02187 struct appsetvar *v,*v2; 02188 struct argchoice *c; 02189 pval *t; 02190 02191 p = item->u1.str; 02192 while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) ) 02193 p++; 02194 02195 buff1 = ast_strdupa(p); 02196 02197 while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t')) 02198 buff1[strlen(buff1)-1] = 0; 02199 /* buff1 now contains the variable name */ 02200 v = 0; 02201 for (a=apps; a; a=a->next) { 02202 for (v=a->setvars;v;v=v->next) { 02203 if (strcmp(v->name,buff1) == 0) { 02204 break; 02205 } 02206 } 02207 if ( v ) 02208 break; 02209 } 02210 if (v && v->vals) { 02211 /* we have a match, to a variable that has a set of determined values */ 02212 int def= 0; 02213 int pat = 0; 02214 int f1 = 0; 02215 02216 /* first of all, does this switch have a default case ? */ 02217 for (t=item->u2.statements; t; t=t->next) { 02218 if (t->type == PV_DEFAULT) { 02219 def =1; 02220 break; 02221 } 02222 if (t->type == PV_PATTERN) { 02223 pat++; 02224 } 02225 } 02226 if (def || pat) /* nothing to check. All cases accounted for! */ 02227 return; 02228 for (c=v->vals; c; c=c->next) { 02229 f1 = 0; 02230 for (t=item->u2.statements; t; t=t->next) { 02231 if (t->type == PV_CASE || t->type == PV_PATTERN) { 02232 if (!strcmp(t->u1.str,c->name)) { 02233 f1 = 1; 02234 break; 02235 } 02236 } 02237 } 02238 if (!f1) { 02239 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n", 02240 item->filename, item->startline, item->endline, item->u1.str, c->name); 02241 warns++; 02242 } 02243 } 02244 /* next, is there an app call in the current exten, that would set this var? */ 02245 f1 = 0; 02246 t = current_extension->u2.statements; 02247 if ( t && t->type == PV_STATEMENTBLOCK ) 02248 t = t->u1.statements; 02249 for (; t && t != item; t=t->next) { 02250 if (t->type == PV_APPLICATION_CALL) { 02251 /* find the application that matches the u1.str */ 02252 for (a2=apps; a2; a2=a2->next) { 02253 if (strcasecmp(a2->name, t->u1.str)==0) { 02254 for (v2=a2->setvars; v2; v2=v2->next) { 02255 if (strcmp(v2->name, buff1) == 0) { 02256 /* found an app that sets the var */ 02257 f1 = 1; 02258 break; 02259 } 02260 } 02261 } 02262 if (f1) 02263 break; 02264 } 02265 } 02266 if (f1) 02267 break; 02268 } 02269 02270 /* see if it sets the var */ 02271 if (!f1) { 02272 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", 02273 item->filename, item->startline, item->endline, item->u1.str); 02274 warns++; 02275 } 02276 } 02277 #else 02278 pval *t,*tl=0,*p2; 02279 int def= 0; 02280 02281 /* first of all, does this switch have a default case ? */ 02282 for (t=item->u2.statements; t; t=t->next) { 02283 if (t->type == PV_DEFAULT) { 02284 def =1; 02285 break; 02286 } 02287 tl = t; 02288 } 02289 if (def) /* nothing to check. All cases accounted for! */ 02290 return; 02291 /* if no default, warn and insert a default case at the end */ 02292 p2 = tl->next = calloc(1, sizeof(struct pval)); 02293 02294 p2->type = PV_DEFAULT; 02295 p2->startline = tl->startline; 02296 p2->endline = tl->endline; 02297 p2->startcol = tl->startcol; 02298 p2->endcol = tl->endcol; 02299 p2->filename = strdup(tl->filename); 02300 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n", 02301 p2->filename, p2->startline, p2->endline); 02302 warns++; 02303 02304 #endif 02305 }
void destroy_extensions | ( | struct ael_extension * | exten | ) |
Definition at line 2975 of file pval.c.
References ael_priority::app, ael_priority::appargs, exten, 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 4890 of file pval.c.
References destroy_pval_item(), and pval::next.
04891 { 04892 pval *i,*nxt; 04893 04894 for (i=item; i; i=nxt) { 04895 nxt = i->next; 04896 04897 destroy_pval_item(i); 04898 } 04899 }
void destroy_pval_item | ( | pval * | item | ) |
Definition at line 4622 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.
04623 { 04624 if (item == NULL) { 04625 ast_log(LOG_WARNING, "null item\n"); 04626 return; 04627 } 04628 04629 if (item->filename) 04630 free(item->filename); 04631 04632 switch (item->type) { 04633 case PV_WORD: 04634 /* fields: item->u1.str == string associated with this (word). */ 04635 if (item->u1.str ) 04636 free(item->u1.str); 04637 if ( item->u2.arglist ) 04638 destroy_pval(item->u2.arglist); 04639 break; 04640 04641 case PV_MACRO: 04642 /* fields: item->u1.str == name of macro 04643 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user 04644 item->u2.arglist->u1.str == argument 04645 item->u2.arglist->next == next arg 04646 04647 item->u3.macro_statements == pval list of statements in macro body. 04648 */ 04649 destroy_pval(item->u2.arglist); 04650 if (item->u1.str ) 04651 free(item->u1.str); 04652 destroy_pval(item->u3.macro_statements); 04653 break; 04654 04655 case PV_CONTEXT: 04656 /* fields: item->u1.str == name of context 04657 item->u2.statements == pval list of statements in context body 04658 item->u3.abstract == int 1 if an abstract keyword were present 04659 */ 04660 if (item->u1.str) 04661 free(item->u1.str); 04662 destroy_pval(item->u2.statements); 04663 break; 04664 04665 case PV_MACRO_CALL: 04666 /* fields: item->u1.str == name of macro to call 04667 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 04668 item->u2.arglist->u1.str == argument 04669 item->u2.arglist->next == next arg 04670 */ 04671 if (item->u1.str) 04672 free(item->u1.str); 04673 destroy_pval(item->u2.arglist); 04674 break; 04675 04676 case PV_APPLICATION_CALL: 04677 /* fields: item->u1.str == name of application to call 04678 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 04679 item->u2.arglist->u1.str == argument 04680 item->u2.arglist->next == next arg 04681 */ 04682 if (item->u1.str) 04683 free(item->u1.str); 04684 destroy_pval(item->u2.arglist); 04685 break; 04686 04687 case PV_CASE: 04688 /* fields: item->u1.str == value of case 04689 item->u2.statements == pval list of statements under the case 04690 */ 04691 if (item->u1.str) 04692 free(item->u1.str); 04693 destroy_pval(item->u2.statements); 04694 break; 04695 04696 case PV_PATTERN: 04697 /* fields: item->u1.str == value of case 04698 item->u2.statements == pval list of statements under the case 04699 */ 04700 if (item->u1.str) 04701 free(item->u1.str); 04702 destroy_pval(item->u2.statements); 04703 break; 04704 04705 case PV_DEFAULT: 04706 /* fields: 04707 item->u2.statements == pval list of statements under the case 04708 */ 04709 destroy_pval(item->u2.statements); 04710 break; 04711 04712 case PV_CATCH: 04713 /* fields: item->u1.str == name of extension to catch 04714 item->u2.statements == pval list of statements in context body 04715 */ 04716 if (item->u1.str) 04717 free(item->u1.str); 04718 destroy_pval(item->u2.statements); 04719 break; 04720 04721 case PV_SWITCHES: 04722 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04723 */ 04724 destroy_pval(item->u1.list); 04725 break; 04726 04727 case PV_ESWITCHES: 04728 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04729 */ 04730 destroy_pval(item->u1.list); 04731 break; 04732 04733 case PV_INCLUDES: 04734 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04735 item->u2.arglist == pval list of 4 PV_WORD elements for time values 04736 */ 04737 destroy_pval(item->u1.list); 04738 break; 04739 04740 case PV_STATEMENTBLOCK: 04741 /* fields: item->u1.list == pval list of statements in block, one per entry in the list 04742 */ 04743 destroy_pval(item->u1.list); 04744 break; 04745 04746 case PV_LOCALVARDEC: 04747 case PV_VARDEC: 04748 /* fields: item->u1.str == variable name 04749 item->u2.val == variable value to assign 04750 */ 04751 if (item->u1.str) 04752 free(item->u1.str); 04753 if (item->u2.val) 04754 free(item->u2.val); 04755 break; 04756 04757 case PV_GOTO: 04758 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. 04759 item->u1.list->u1.str == where the data on a PV_WORD will always be. 04760 */ 04761 04762 destroy_pval(item->u1.list); 04763 break; 04764 04765 case PV_LABEL: 04766 /* fields: item->u1.str == label name 04767 */ 04768 if (item->u1.str) 04769 free(item->u1.str); 04770 break; 04771 04772 case PV_FOR: 04773 /* fields: item->u1.for_init == a string containing the initalizer 04774 item->u2.for_test == a string containing the loop test 04775 item->u3.for_inc == a string containing the loop increment 04776 04777 item->u4.for_statements == a pval list of statements in the for () 04778 */ 04779 if (item->u1.for_init) 04780 free(item->u1.for_init); 04781 if (item->u2.for_test) 04782 free(item->u2.for_test); 04783 if (item->u3.for_inc) 04784 free(item->u3.for_inc); 04785 destroy_pval(item->u4.for_statements); 04786 break; 04787 04788 case PV_WHILE: 04789 /* fields: item->u1.str == the while conditional, as supplied by user 04790 04791 item->u2.statements == a pval list of statements in the while () 04792 */ 04793 if (item->u1.str) 04794 free(item->u1.str); 04795 destroy_pval(item->u2.statements); 04796 break; 04797 04798 case PV_BREAK: 04799 /* fields: none 04800 */ 04801 break; 04802 04803 case PV_RETURN: 04804 /* fields: none 04805 */ 04806 break; 04807 04808 case PV_CONTINUE: 04809 /* fields: none 04810 */ 04811 break; 04812 04813 case PV_IFTIME: 04814 /* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list 04815 04816 item->u2.statements == a pval list of statements in the if () 04817 item->u3.else_statements == a pval list of statements in the else 04818 (could be zero) 04819 */ 04820 destroy_pval(item->u1.list); 04821 destroy_pval(item->u2.statements); 04822 if (item->u3.else_statements) { 04823 destroy_pval(item->u3.else_statements); 04824 } 04825 break; 04826 04827 case PV_RANDOM: 04828 /* fields: item->u1.str == the random percentage, as supplied by user 04829 04830 item->u2.statements == a pval list of statements in the true part () 04831 item->u3.else_statements == a pval list of statements in the else 04832 (could be zero) 04833 fall thru to If */ 04834 case PV_IF: 04835 /* fields: item->u1.str == the if conditional, as supplied by user 04836 04837 item->u2.statements == a pval list of statements in the if () 04838 item->u3.else_statements == a pval list of statements in the else 04839 (could be zero) 04840 */ 04841 if (item->u1.str) 04842 free(item->u1.str); 04843 destroy_pval(item->u2.statements); 04844 if (item->u3.else_statements) { 04845 destroy_pval(item->u3.else_statements); 04846 } 04847 break; 04848 04849 case PV_SWITCH: 04850 /* fields: item->u1.str == the switch expression 04851 04852 item->u2.statements == a pval list of statements in the switch, 04853 (will be case statements, most likely!) 04854 */ 04855 if (item->u1.str) 04856 free(item->u1.str); 04857 destroy_pval(item->u2.statements); 04858 break; 04859 04860 case PV_EXTENSION: 04861 /* fields: item->u1.str == the extension name, label, whatever it's called 04862 04863 item->u2.statements == a pval list of statements in the extension 04864 item->u3.hints == a char * hint argument 04865 item->u4.regexten == an int boolean. non-zero says that regexten was specified 04866 */ 04867 if (item->u1.str) 04868 free(item->u1.str); 04869 if (item->u3.hints) 04870 free(item->u3.hints); 04871 destroy_pval(item->u2.statements); 04872 break; 04873 04874 case PV_IGNOREPAT: 04875 /* fields: item->u1.str == the ignorepat data 04876 */ 04877 if (item->u1.str) 04878 free(item->u1.str); 04879 break; 04880 04881 case PV_GLOBALS: 04882 /* fields: item->u1.statements == pval list of statements, usually vardecs 04883 */ 04884 destroy_pval(item->u1.statements); 04885 break; 04886 } 04887 free(item); 04888 }
struct pval* find_context | ( | char * | name | ) |
Definition at line 1950 of file pval.c.
References current_db, and match_pval().
01951 { 01952 return_on_context_match = 1; 01953 count_labels = 0; 01954 match_context = name; 01955 match_exten = "*"; /* don't really need to set these, shouldn't be reached */ 01956 match_label = "*"; 01957 return match_pval(current_db); 01958 }
struct pval* find_macro | ( | char * | name | ) |
Definition at line 1940 of file pval.c.
References current_db, and match_pval().
01941 { 01942 return_on_context_match = 1; 01943 count_labels = 0; 01944 match_context = name; 01945 match_exten = "*"; /* don't really need to set these, shouldn't be reached */ 01946 match_label = "*"; 01947 return match_pval(current_db); 01948 }
static char* handle_cli_ael_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 241 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.
00242 { 00243 switch (cmd) { 00244 case CLI_INIT: 00245 e->command = "ael reload"; 00246 e->usage = 00247 "Usage: ael reload\n" 00248 " Reloads AEL configuration.\n"; 00249 return NULL; 00250 case CLI_GENERATE: 00251 return NULL; 00252 } 00253 00254 if (a->argc != 2) 00255 return CLI_SHOWUSAGE; 00256 00257 return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS); 00258 }
static char* handle_cli_ael_set_debug | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 207 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.
00208 { 00209 switch (cmd) { 00210 case CLI_INIT: 00211 e->command = "ael set debug {read|tokens|macros|contexts|off}"; 00212 e->usage = 00213 "Usage: ael set debug {read|tokens|macros|contexts|off}\n" 00214 " Enable AEL read, token, macro, or context debugging,\n" 00215 " or disable all AEL debugging messages. Note: this\n" 00216 " currently does nothing.\n"; 00217 return NULL; 00218 case CLI_GENERATE: 00219 return NULL; 00220 } 00221 00222 if (a->argc != e->args) 00223 return CLI_SHOWUSAGE; 00224 00225 if (!strcasecmp(a->argv[3], "read")) 00226 aeldebug |= DEBUG_READ; 00227 else if (!strcasecmp(a->argv[3], "tokens")) 00228 aeldebug |= DEBUG_TOKENS; 00229 else if (!strcasecmp(a->argv[3], "macros")) 00230 aeldebug |= DEBUG_MACROS; 00231 else if (!strcasecmp(a->argv[3], "contexts")) 00232 aeldebug |= DEBUG_CONTEXTS; 00233 else if (!strcasecmp(a->argv[3], "off")) 00234 aeldebug = 0; 00235 else 00236 return CLI_SHOWUSAGE; 00237 00238 return CLI_SUCCESS; 00239 }
int is_empty | ( | char * | arg | ) |
int is_float | ( | char * | arg | ) |
int is_int | ( | char * | arg | ) |
static int load_module | ( | void | ) | [static] |
Definition at line 275 of file pbx_ael.c.
References aelsub_exec(), ARRAY_LEN, ast_cli_register_multiple(), ast_register_application_xml, cli_ael, and pbx_load_module().
00276 { 00277 ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael)); 00278 #ifndef STANDALONE 00279 ast_register_application_xml(aelsub, aelsub_exec); 00280 #endif 00281 return (pbx_load_module()); 00282 }
struct ael_extension* new_exten | ( | void | ) |
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 | ) |
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 155 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(), handle_cli_dialplan_reload(), load_module(), and reload().
00156 { 00157 int errs=0, sem_err=0, sem_warn=0, sem_note=0; 00158 char *rfilename; 00159 struct ast_context *local_contexts=NULL, *con; 00160 struct ast_hashtab *local_table=NULL; 00161 00162 struct pval *parse_tree; 00163 00164 ast_log(LOG_NOTICE, "Starting AEL load process.\n"); 00165 if (config[0] == '/') 00166 rfilename = (char *)config; 00167 else { 00168 rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2); 00169 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config); 00170 } 00171 if (access(rfilename,R_OK) != 0) { 00172 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename); 00173 return AST_MODULE_LOAD_DECLINE; 00174 } 00175 00176 parse_tree = ael2_parse(rfilename, &errs); 00177 ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename); 00178 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note); 00179 if (errs == 0 && sem_err == 0) { 00180 ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename); 00181 local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0); 00182 if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) { 00183 ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n"); 00184 destroy_pval(parse_tree); /* free up the memory */ 00185 return AST_MODULE_LOAD_DECLINE; 00186 } 00187 ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename); 00188 00189 ast_merge_contexts_and_delete(&local_contexts, local_table, registrar); 00190 local_table = NULL; /* it's the dialplan global now */ 00191 local_contexts = NULL; 00192 ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename); 00193 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con)) 00194 ast_context_verify_includes(con); 00195 ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename); 00196 } else { 00197 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); 00198 destroy_pval(parse_tree); /* free up the memory */ 00199 return AST_MODULE_LOAD_DECLINE; 00200 } 00201 destroy_pval(parse_tree); /* free up the memory */ 00202 00203 return AST_MODULE_LOAD_SUCCESS; 00204 }
static int reload | ( | void | ) | [static] |
Definition at line 284 of file pbx_ael.c.
References pbx_load_module().
00285 { 00286 return pbx_load_module(); 00287 }
void set_priorities | ( | struct ael_extension * | exten | ) |
Definition at line 4215 of file pval.c.
References exten, ael_priority::next, ael_priority::origin, ael_priority::priority_num, PV_LABEL, and pval::type.
04216 { 04217 int i; 04218 struct ael_priority *pr; 04219 do { 04220 if (exten->is_switch) 04221 i = 10; 04222 else if (exten->regexten) 04223 i=2; 04224 else 04225 i=1; 04226 04227 for (pr=exten->plist; pr; pr=pr->next) { 04228 pr->priority_num = i; 04229 04230 if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan, 04231 but we want them to point to the right 04232 priority, which would be the next line 04233 after the label; */ 04234 i++; 04235 } 04236 04237 exten = exten->next_exten; 04238 } while ( exten ); 04239 }
static int unload_module | ( | void | ) | [static] |
Definition at line 265 of file pbx_ael.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), ast_context_destroy(), ast_unregister_application(), and cli_ael.
00266 { 00267 ast_context_destroy(NULL, registrar); 00268 ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael)); 00269 #ifndef STANDALONE 00270 ast_unregister_application(aelsub); 00271 #endif 00272 return 0; 00273 }
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 = "88eaa8f5c1bd988bedd71113385e0886" , .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] |
Initial value:
{ { .handler = handle_cli_ael_reload , .summary = "Reload AEL configuration" ,__VA_ARGS__ }, { .handler = handle_cli_ael_set_debug , .summary = "Enable AEL debugging flags" ,__VA_ARGS__ } }
Definition at line 260 of file pbx_ael.c.
Referenced by load_module(), and unload_module().