Asterisk - The Open Source Telephony Project GIT-master-a358458
Macros | Functions | Variables
pbx_ael.c File Reference

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"
Include dependency graph for pbx_ael.c:

Go to the source code of this file.

Macros

#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)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
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 pvalfind_context (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_extensionnew_exten (void)
 
struct ael_prioritynew_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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .requires = "res_ael_share", }
 
static int aeldebug = 0
 
static char * aelsub = "AELSub"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry cli_ael []
 
static char * config = "extensions.ael"
 
static char * registrar = "pbx_ael"
 

Detailed Description

Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.

Definition in file pbx_ael.c.

Macro Definition Documentation

◆ DEBUG_CONTEXTS

#define DEBUG_CONTEXTS   (1 << 3)

Definition at line 75 of file pbx_ael.c.

◆ DEBUG_MACROS

#define DEBUG_MACROS   (1 << 2)

Definition at line 74 of file pbx_ael.c.

◆ DEBUG_READ

#define DEBUG_READ   (1 << 0)

Definition at line 72 of file pbx_ael.c.

◆ DEBUG_TOKENS

#define DEBUG_TOKENS   (1 << 1)

Definition at line 73 of file pbx_ael.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 299 of file pbx_ael.c.

303{

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 299 of file pbx_ael.c.

303{

◆ add_extensions()

void add_extensions ( struct ael_extension exten)

Definition at line 4213 of file pval.c.

4214{
4215 struct ael_priority *pr;
4216 char *label=0;
4217 char realext[AST_MAX_EXTENSION];
4218 if (!exten) {
4219 ast_log(LOG_WARNING, "This file is Empty!\n" );
4220 return;
4221 }
4222 do {
4223 struct ael_priority *last = 0;
4224
4225 pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
4226 if (exten->hints) {
4227 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch,
4229 ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
4230 exten->name);
4231 }
4232 }
4233
4234 for (pr=exten->plist; pr; pr=pr->next) {
4235 char app[2000];
4236 char appargs[2000];
4237
4238 /* before we can add the extension, we need to prep the app/appargs;
4239 the CONTROL types need to be done after the priority numbers are calculated.
4240 */
4241 if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
4242 last = pr;
4243 continue;
4244 }
4245
4246 if (pr->app)
4247 strcpy(app, pr->app);
4248 else
4249 app[0] = 0;
4250 if (pr->appargs )
4251 strcpy(appargs, pr->appargs);
4252 else
4253 appargs[0] = 0;
4254 switch( pr->type ) {
4255 case AEL_APPCALL:
4256 /* easy case. Everything is all set up */
4257 break;
4258
4259 case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
4260 /* simple, unconditional goto. */
4261 strcpy(app,"Goto");
4262 if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
4263 snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
4264 } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
4265 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
4266 } else
4267 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
4268 break;
4269
4270 case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */
4271 strcpy(app,"GotoIf");
4272 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
4273 break;
4274
4275 case AEL_IF_CONTROL:
4276 strcpy(app,"GotoIf");
4277 if (pr->origin->u3.else_statements )
4278 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
4279 else
4280 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
4281 break;
4282
4283 case AEL_RAND_CONTROL:
4284 strcpy(app,"Random");
4285 snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
4286 break;
4287
4288 case AEL_IFTIME_CONTROL:
4289 strcpy(app,"GotoIfTime");
4290 snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
4291 break;
4292
4293 case AEL_RETURN:
4294 strcpy(app,"Return");
4295 appargs[0] = 0;
4296 break;
4297
4298 default:
4299 break;
4300 }
4301 if (last && last->type == AEL_LABEL ) {
4302 label = last->origin->u1.str;
4303 }
4304 else
4305 label = 0;
4306
4307 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch,
4309 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num,
4310 exten->name);
4311 }
4312 last = pr;
4313 }
4315 } while ( exten );
4316}
@ AEL_FOR_CONTROL
Definition: ael_structs.h:84
@ AEL_RAND_CONTROL
Definition: ael_structs.h:84
@ AEL_RETURN
Definition: ael_structs.h:84
@ AEL_IF_CONTROL
Definition: ael_structs.h:84
@ AEL_IFTIME_CONTROL
Definition: ael_structs.h:84
@ AEL_CONTROL1
Definition: ael_structs.h:84
@ AEL_LABEL
Definition: ael_structs.h:84
@ AEL_APPCALL
Definition: ael_structs.h:84
static const char app[]
Definition: app_adsiprog.c:56
struct sla_ringing_trunk * last
Definition: app_sla.c:332
#define strdup(a)
Definition: astmm.h:163
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
#define ast_log
Definition: astobj2.c:42
#define AST_MAX_EXTENSION
Definition: channel.h:134
#define LOG_WARNING
int ast_add_extension2(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, const char *registrar_file, int registrar_line)
Add an extension to an extension context, this time with an ast_context *.
Definition: pbx.c:7257
#define PRIORITY_HINT
Definition: pbx.h:54
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
static char * registrar
Definition: pval.c:70
@ PV_SWITCH
Definition: pval.h:32
@ PV_IFTIME
Definition: pval.h:30
#define NULL
Definition: resample.c:96
struct ael_priority * plist
Definition: ael_structs.h:115
struct ast_context * context
Definition: ael_structs.h:113
char * cidmatch
Definition: ael_structs.h:106
struct ael_extension * next_exten
Definition: ael_structs.h:117
struct ael_priority * goto_false
Definition: ael_structs.h:99
struct ael_priority * goto_true
Definition: ael_structs.h:98
struct pval * origin
Definition: ael_structs.h:95
char * appargs
Definition: ael_structs.h:93
char * app
Definition: ael_structs.h:92
ael_priority_type type
Definition: ael_structs.h:90
struct ael_priority * next
Definition: ael_structs.h:100
int priority_num
Definition: ael_structs.h:89
struct ael_extension * exten
Definition: ael_structs.h:96
struct pval * else_statements
Definition: pval.h:78
union pval::@248 u3
pvaltype type
Definition: pval.h:50

Referenced by ast_compile_ael2().

◆ aelsub_exec()

static int aelsub_exec ( struct ast_channel chan,
const char *  vdata 
)
static

Definition at line 124 of file pbx_ael.c.

125{
126 char buf[256], *data = ast_strdupa(vdata);
127 struct ast_app *gosub = pbx_findapp("Gosub");
131 );
132
133 if (gosub) {
135 snprintf(buf, sizeof(buf), "%s,~~s~~,1(%s)", args.name, args.args);
136 return pbx_exec(chan, gosub, buf);
137 }
138 return -1;
139}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
#define AST_APP_ARG(name)
Define an application argument.
#define AST_STANDARD_RAW_ARGS(args, parse)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
ast_app: A registered application
Definition: pbx_app.c:45
const char * args

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_STANDARD_RAW_ARGS, ast_strdupa, buf, name, pbx_exec(), and pbx_findapp().

Referenced by load_module().

◆ ast_compile_ael2()

int ast_compile_ael2 ( struct ast_context **  local_contexts,
struct ast_hashtab local_table,
struct pval root 
)

Definition at line 4413 of file pval.c.

4414{
4415 pval *p,*p2;
4416 struct ast_context *context;
4417 char buf[2000];
4418 struct ael_extension *exten;
4419 struct ael_extension *exten_list = 0;
4420
4421 /* Reset the counter so that we get consistent labels between reloads */
4423
4424 for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there
4425 when we try to eval them */
4426 switch (p->type) {
4427 case PV_GLOBALS:
4428 /* just VARDEC elements */
4429 for (p2=p->u1.list; p2; p2=p2->next) {
4430 char buf2[2000];
4431 snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
4433 }
4434 break;
4435 default:
4436 break;
4437 }
4438 }
4439
4440 for (p=root; p; p=p->next ) {
4441 pval *lp;
4442 int argc;
4443
4444 switch (p->type) {
4445 case PV_MACRO:
4446
4448
4449 exten = new_exten();
4450 exten->context = context;
4451 exten->name = strdup("~~s~~");
4452 argc = 1;
4453 for (lp=p->u2.arglist; lp; lp=lp->next) {
4454 /* for each arg, set up a "Set" command */
4455 struct ael_priority *np2 = new_prio();
4456 np2->type = AEL_APPCALL;
4457 np2->app = strdup("MSet");
4458 snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++);
4460 np2->appargs = strdup(buf);
4461 linkprio(exten, np2, NULL);
4462 }
4463
4464 /* CONTAINS APPCALLS, CATCH, just like extensions... */
4465 if (gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context)) {
4466 return -1;
4467 }
4468 if (exten->return_needed) { /* most likely, this will go away */
4469 struct ael_priority *np2 = new_prio();
4470 np2->type = AEL_APPCALL;
4471 np2->app = strdup("NoOp");
4472 snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
4473 np2->appargs = strdup(buf);
4474 linkprio(exten, np2, NULL);
4475 exten-> return_target = np2;
4476 }
4477
4479 attach_exten(&exten_list, exten);
4480 break;
4481
4482 case PV_GLOBALS:
4483 /* already done */
4484 break;
4485
4486 case PV_CONTEXT:
4488
4489 /* contexts contain: ignorepat, includes, switches, eswitches, extensions, */
4490 for (p2=p->u2.statements; p2; p2=p2->next) {
4491 pval *p3;
4492 char *s3;
4493
4494 switch (p2->type) {
4495 case PV_EXTENSION:
4496 exten = new_exten();
4497 exten->name = strdup(p2->u1.str);
4499
4500 if( (s3=strchr(exten->name, '/') ) != 0 )
4501 {
4502 *s3 = 0;
4503 exten->cidmatch = s3+1;
4504 }
4505
4506 if ( p2->u3.hints )
4507 exten->hints = strdup(p2->u3.hints);
4508 exten->regexten = p2->u4.regexten;
4509 if (gen_prios(exten, p->u1.str, p2->u2.statements, 0, context)) {
4510 return -1;
4511 }
4512 if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
4513 struct ael_priority *np2 = new_prio();
4514 np2->type = AEL_APPCALL;
4515 np2->app = strdup("NoOp");
4516 snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
4517 np2->appargs = strdup(buf);
4518 linkprio(exten, np2, NULL);
4519 exten-> return_target = np2;
4520 }
4521 /* is the last priority in the extension a label? Then add a trailing no-op */
4522 if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
4523 struct ael_priority *np2 = new_prio();
4524 np2->type = AEL_APPCALL;
4525 np2->app = strdup("NoOp");
4526 snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
4527 np2->appargs = strdup(buf);
4528 linkprio(exten, np2, NULL);
4529 }
4530
4532 attach_exten(&exten_list, exten);
4533 break;
4534
4535 case PV_IGNOREPAT:
4537 break;
4538
4539 case PV_INCLUDES:
4540 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4541 if ( p3->u2.arglist ) {
4542 snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s",
4543 p3->u1.str,
4544 p3->u2.arglist->u1.str,
4545 p3->u2.arglist->next->u1.str,
4546 p3->u2.arglist->next->next->u1.str,
4547 p3->u2.arglist->next->next->next->u1.str);
4549 } else
4551 }
4552 break;
4553
4554 case PV_SWITCHES:
4555 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4556 char *c = strchr(p3->u1.str, '/');
4557 if (c) {
4558 *c = '\0';
4559 c++;
4560 } else
4561 c = "";
4562
4564 }
4565 break;
4566
4567 case PV_ESWITCHES:
4568 for (p3 = p2->u1.list; p3 ;p3=p3->next) {
4569 char *c = strchr(p3->u1.str, '/');
4570 if (c) {
4571 *c = '\0';
4572 c++;
4573 } else
4574 c = "";
4575
4577 }
4578 break;
4579 default:
4580 break;
4581 }
4582 }
4583
4584 break;
4585
4586 default:
4587 /* huh? what? */
4588 break;
4589
4590 }
4591 }
4592
4593 /* Create default "h" bubble context */
4594 if (ast_custom_function_find("DIALPLAN_EXISTS") && ast_custom_function_find("STACK_PEEK")) {
4595 int i;
4596 const char *h_context = "ael-builtin-h-bubble";
4597 struct ael_priority *np;
4598 struct {
4599 int priority;
4600 const char *app;
4601 const char *arg;
4602 } steps[] = {
4603 /* Start high, to avoid conflict with existing h extensions */
4604 { 1, "Goto", "9991" },
4605 /* Save the context, because after the StackPop, it disappears */
4606 { 9991, "Set", "~~parentcxt~~=${STACK_PEEK(1,c,1)}" },
4607 /* If we're not in a Gosub frame, exit */
4608 { 9992, "GotoIf", "$[\"${~~parentcxt~~}\"=\"\"]?9996" },
4609 /* Check for an "h" extension in that context */
4610 { 9993, "GotoIf", "${DIALPLAN_EXISTS(${~~parentcxt~~},h,1)}?9994:9996" },
4611 /* Pop off the stack frame to prevent an infinite loop */
4612 { 9994, "StackPop", "" },
4613 /* Finally, go there. */
4614 { 9995, "Goto", "${~~parentcxt~~},h,1" },
4615 /* Just an empty priority for jumping out early */
4616 { 9996, "NoOp", "" }
4617 };
4619 if (context_used(exten_list, context)) {
4620 int found = 0;
4621 while (!found) {
4622 /* Pick a new context name that is not used. */
4623 char h_context_template[] = "/tmp/ael-builtin-h-bubble-XXXXXX";
4624 int fd = mkstemp(h_context_template);
4625 unlink(h_context_template);
4626 close(fd);
4628 found = !context_used(exten_list, context);
4629 }
4630 h_context = ast_get_context_name(context);
4631 }
4632 exten = new_exten();
4633 exten->context = context;
4634 exten->name = strdup("h");
4635
4636 for (i = 0; i < ARRAY_LEN(steps); i++) {
4637 np = new_prio();
4638 np->type = AEL_APPCALL;
4639 np->priority_num = steps[i].priority;
4640 np->app = strdup(steps[i].app);
4641 np->appargs = strdup(steps[i].arg);
4642 linkprio(exten, np, NULL);
4643 }
4644 attach_exten(&exten_list, exten);
4645
4646 /* Include the default "h" bubble context in each macro context */
4647 for (exten = exten_list; exten; exten = exten->next_exten) {
4648 /* All macros contain a "~~s~~" extension, and it's the first created. If
4649 * we perchance get a non-macro context, it's no big deal; the logic is
4650 * designed to exit out smoothly if not called from within a Gosub. */
4651 if (!strcmp(exten->name, "~~s~~")) {
4652 ast_context_add_include2(exten->context, h_context, registrar);
4653 }
4654 }
4655 }
4656
4657 /* moved these from being done after a macro or extension were processed,
4658 to after all processing is done, for the sake of fixing gotos to labels inside cases... */
4659 /* I guess this would be considered 2nd pass of compiler now... */
4660 fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */
4661 add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */
4662 destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */
4663
4664 return 0;
4665}
static int priority
static struct ast_threadstorage buf2
int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
Parse and set a single channel variable, where the name and value are separated with an '=' character...
int ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
Add a context include.
Definition: ael_main.c:359
int ast_context_add_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
Definition: ael_main.c:348
struct ast_custom_function * ast_custom_function_find(const char *name)
Definition: ael_main.c:173
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:6149
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
int ast_context_add_switch2(struct ast_context *con, const char *sw, const char *data, int eval, const char *registrar)
Adds a switch (first param is a ast_context)
Definition: ael_main.c:370
static struct ast_context * local_contexts
Definition: pbx_config.c:113
static struct ast_hashtab * local_table
Definition: pbx_config.c:114
static void attach_exten(struct ael_extension **list, struct ael_extension *newmem)
Definition: pval.c:4318
struct ael_priority * new_prio(void)
Definition: pval.c:2924
static int context_used(struct ael_extension *exten_list, struct ast_context *context)
Definition: pval.c:4398
static void remove_spaces_before_equals(char *str)
Definition: pval.c:3038
void set_priorities(struct ael_extension *exten)
Definition: pval.c:4187
struct ael_extension * new_exten(void)
Definition: pval.c:2930
static int gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *this_context)
Definition: pval.c:3341
void destroy_extensions(struct ael_extension *exten)
Definition: pval.c:2978
void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
Definition: pval.c:2936
void add_extensions(struct ael_extension *exten)
Definition: pval.c:4213
static int control_statement_count
Definition: pval.c:2922
static void fix_gotos_in_extensions(struct ael_extension *exten)
Definition: pval.c:4355
@ PV_GLOBALS
Definition: pval.h:35
@ PV_CONTEXT
Definition: pval.h:10
@ PV_INCLUDES
Definition: pval.h:19
@ PV_MACRO
Definition: pval.h:9
@ PV_SWITCHES
Definition: pval.h:17
@ PV_IGNOREPAT
Definition: pval.h:34
@ PV_ESWITCHES
Definition: pval.h:18
@ PV_EXTENSION
Definition: pval.h:33
struct ael_priority * plist_last
Definition: ael_structs.h:116
ast_context: An extension context
Definition: pbx.c:284
Definition: pval.h:49
struct pval * arglist
Definition: pval.h:68
char * val
Definition: pval.h:70
struct pval * next
Definition: pval.h:93
char * hints
Definition: pval.h:81
struct pval * statements
Definition: pval.h:61
struct pval * macro_statements
Definition: pval.h:79
union pval::@246 u1
char * str
Definition: pval.h:59
union pval::@247 u2
union pval::@249 u4
int regexten
Definition: pval.h:90
struct pval * list
Definition: pval.h:60
static struct test_val c
#define ARRAY_LEN(a)
Definition: utils.h:666

Referenced by pbx_load_module().

◆ ast_expr_clear_extra_error_info()

void ast_expr_clear_extra_error_info ( void  )

Definition at line 2469 of file ast_expr2f.c.

2470{
2472 extra_error_message[0] = 0;
2473}
char extra_error_message[4095]
Definition: ast_expr2f.c:2458
int extra_error_message_supplied
Definition: ast_expr2f.c:2459

◆ ast_expr_register_extra_error_info()

void ast_expr_register_extra_error_info ( char *  errmsg)

Definition at line 2463 of file ast_expr2f.c.

2464{
2467}

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 299 of file pbx_ael.c.

303{

◆ check_app_args()

int check_app_args ( pval appcall,
pval arglist,
struct argapp app 
)

Definition at line 2130 of file pval.c.

2131{
2132#ifdef AAL_ARGCHECK
2133 struct argdesc *ad = app->args;
2134 pval *pa;
2135 int z;
2136
2137 for (pa = arglist; pa; pa=pa->next) {
2138 if (!ad) {
2139 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
2140 arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
2141 warns++;
2142 return 1;
2143 } else {
2144 /* find the first entry in the ad list that will match */
2145 do {
2146 if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */
2147 break;
2148
2149 z= option_matches( ad, pa, app);
2150 if (!z) {
2151 if ( !arglist )
2152 arglist=appcall;
2153
2154 if (ad->type == ARGD_REQUIRED) {
2155 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
2156 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
2157 warns++;
2158 return 1;
2159 }
2160 } else if (z && ad->dtype == ARGD_OPTIONSET) {
2161 option_matches_j( ad, pa, app);
2162 }
2163 ad = ad->next;
2164 } while (ad && !z);
2165 }
2166 }
2167 /* any app nodes left, that are not optional? */
2168 for ( ; ad; ad=ad->next) {
2169 if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
2170 if ( !arglist )
2171 arglist=appcall;
2172 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
2173 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
2174 warns++;
2175 return 1;
2176 }
2177 }
2178 return 0;
2179#else
2180 return 0;
2181#endif
2182}
static int warns
Definition: pval.c:65
int endline
Definition: pval.h:52
char * filename
Definition: pval.h:55
int startline
Definition: pval.h:51

Referenced by check_pval_item().

◆ check_pval()

void check_pval ( pval item,
struct argapp apps,
int  in_globals 
)

Definition at line 2865 of file pval.c.

2866{
2867 pval *i;
2868
2869 /* checks to do:
2870 1. Do goto's point to actual labels?
2871 2. Do macro calls reference a macro?
2872 3. Does the number of macro args match the definition?
2873 4. Is a macro call missing its & at the front?
2874 5. Application calls-- we could check syntax for existing applications,
2875 but I need some sort of universal description bnf for a general
2876 sort of method for checking arguments, in number, maybe even type, at least.
2877 Don't want to hand code checks for hundreds of applications.
2878 */
2879
2880 for (i=item; i; i=i->next) {
2881 check_pval_item(i,apps,in_globals);
2882 }
2883}
void check_pval_item(pval *item, struct argapp *apps, int in_globals)
Definition: pval.c:2357
Registered applications container.
Definition: pbx_app.c:67
static struct aco_type item
Definition: test_config.c:1463

Referenced by ael2_semantic_check(), and check_pval_item().

◆ check_pval_item()

void check_pval_item ( pval item,
struct argapp apps,
int  in_globals 
)

Definition at line 2357 of file pval.c.

2358{
2359 pval *lp;
2360#ifdef AAL_ARGCHECK
2361 struct argapp *app, *found;
2362#endif
2363 struct pval *macro_def;
2364 struct pval *app_def;
2365
2366 char errmsg[4096];
2367 char *strp;
2368
2369 switch (item->type) {
2370 case PV_WORD:
2371 /* fields: item->u1.str == string associated with this (word).
2372 item->u2.arglist == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */
2373 break;
2374
2375 case PV_MACRO:
2376 /* fields: item->u1.str == name of macro
2377 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
2378 item->u2.arglist->u1.str == argument
2379 item->u2.arglist->next == next arg
2380
2381 item->u3.macro_statements == pval list of statements in macro body.
2382 */
2386
2388
2389 for (lp=item->u2.arglist; lp; lp=lp->next) {
2390
2391 }
2392 check_pval(item->u3.macro_statements, apps,in_globals);
2393 break;
2394
2395 case PV_CONTEXT:
2396 /* fields: item->u1.str == name of context
2397 item->u2.statements == pval list of statements in context body
2398 item->u3.abstract == int 1 if an abstract keyword were present
2399 */
2402 if ( item->u3.abstract ) {
2405 } else
2407 check_pval(item->u2.statements, apps,in_globals);
2408 break;
2409
2410 case PV_MACRO_CALL:
2411 /* fields: item->u1.str == name of macro to call
2412 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
2413 item->u2.arglist->u1.str == argument
2414 item->u2.arglist->next == next arg
2415 */
2416#ifdef STANDALONE
2417 /* if this is a standalone, we will need to make sure the
2418 localized load of extensions.conf is done */
2419 if (!extensions_dot_conf_loaded) {
2421 extensions_dot_conf_loaded++;
2422 }
2423#endif
2424 macro_def = find_macro(item->u1.str);
2425 if (!macro_def) {
2426#ifdef STANDALONE
2427 struct pbx_find_info pfiq = {.stacklen = 0 };
2428 struct pbx_find_info pfiq2 = {.stacklen = 0 };
2429
2430 /* look for the macro in the extensions.conf world */
2431 pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH);
2432
2433 if (pfiq.status != STATUS_SUCCESS) {
2434 char namebuf2[256];
2435 snprintf(namebuf2, 256, "macro-%s", item->u1.str);
2436
2437 /* look for the macro in the extensions.conf world */
2438 pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH);
2439
2440 if (pfiq2.status == STATUS_SUCCESS) {
2441 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",
2442 item->filename, item->startline, item->endline, item->u1.str, item->u1.str);
2443 warns++;
2444 } else {
2445 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (Not even in the extensions.conf stuff!)\n",
2446 item->filename, item->startline, item->endline, item->u1.str);
2447 warns++;
2448 }
2449 }
2450#else
2451 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n",
2452 item->filename, item->startline, item->endline, item->u1.str);
2453 warns++;
2454
2455#endif
2456#ifdef THIS_IS_1DOT4
2457 char namebuf2[256];
2458 snprintf(namebuf2, 256, "macro-%s", item->u1.str);
2459
2460 /* look for the macro in the extensions.conf world */
2461 pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH);
2462
2463 if (pfiq.status != STATUS_SUCCESS) {
2464 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",
2465 item->filename, item->startline, item->endline, item->u1.str);
2466 warns++;
2467 }
2468
2469#endif
2470
2471 } else if (macro_def->type != PV_MACRO) {
2472 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n",
2473 item->filename, item->startline, item->endline, item->u1.str);
2474 errs++;
2475 } else {
2476 /* macro_def is a MACRO, so do the args match in number? */
2477 int hereargs = 0;
2478 int thereargs = 0;
2479
2480 for (lp=item->u2.arglist; lp; lp=lp->next) {
2481 hereargs++;
2482 }
2483 for (lp=macro_def->u2.arglist; lp; lp=lp->next) {
2484 thereargs++;
2485 }
2486 if (hereargs != thereargs ) {
2487 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",
2488 item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs);
2489 errs++;
2490 }
2491 }
2492 break;
2493
2495 /* fields: item->u1.str == name of application to call
2496 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
2497 item->u2.arglist->u1.str == argument
2498 item->u2.arglist->next == next arg
2499 */
2500 /* Need to check to see if the application is available! */
2501 app_def = find_context(item->u1.str);
2502 if (app_def && app_def->type == PV_MACRO) {
2503 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n",
2504 item->filename, item->startline, item->endline, item->u1.str);
2505 errs++;
2506 }
2507 if (strcasecmp(item->u1.str,"GotoIf") == 0
2508 || strcasecmp(item->u1.str,"GotoIfTime") == 0
2509 || strcasecmp(item->u1.str,"while") == 0
2510 || strcasecmp(item->u1.str,"endwhile") == 0
2511 || strcasecmp(item->u1.str,"random") == 0
2512 || strcasecmp(item->u1.str,"gosub") == 0
2513 || strcasecmp(item->u1.str,"gosubif") == 0
2514 || strcasecmp(item->u1.str,"continuewhile") == 0
2515 || strcasecmp(item->u1.str,"endwhile") == 0
2516 || strcasecmp(item->u1.str,"execif") == 0
2517 || strcasecmp(item->u1.str,"execiftime") == 0
2518 || strcasecmp(item->u1.str,"exitwhile") == 0
2519 || strcasecmp(item->u1.str,"goto") == 0
2520 || strcasecmp(item->u1.str,"macro") == 0
2521 || strcasecmp(item->u1.str,"macroexclusive") == 0
2522 || strcasecmp(item->u1.str,"macroif") == 0
2523 || strcasecmp(item->u1.str,"stackpop") == 0
2524 || strcasecmp(item->u1.str,"execIf") == 0 ) {
2525 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",
2526 item->filename, item->startline, item->endline, item->u1.str);
2527 warns++;
2528 }
2529 if (strcasecmp(item->u1.str,"macroexit") == 0) {
2530 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: I am converting the MacroExit call here to a return statement.\n",
2531 item->filename, item->startline, item->endline);
2532 item->type = PV_RETURN;
2533 free(item->u1.str);
2534 item->u1.str = 0;
2535 }
2536
2537#ifdef AAL_ARGCHECK
2538 found = 0;
2539 for (app=apps; app; app=app->next) {
2540 if (strcasecmp(app->name, item->u1.str) == 0) {
2541 found =app;
2542 break;
2543 }
2544 }
2545 if (!found) {
2546 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n",
2547 item->filename, item->startline, item->endline, item->u1.str);
2548 warns++;
2549 } else
2550 check_app_args(item, item->u2.arglist, app);
2551#endif
2552 break;
2553
2554 case PV_CASE:
2555 /* fields: item->u1.str == value of case
2556 item->u2.statements == pval list of statements under the case
2557 */
2558 /* Make sure sequence of statements under case is terminated with goto, return, or break */
2559 /* find the last statement */
2560 check_pval(item->u2.statements, apps,in_globals);
2561 break;
2562
2563 case PV_PATTERN:
2564 /* fields: item->u1.str == value of case
2565 item->u2.statements == pval list of statements under the case
2566 */
2567 /* Make sure sequence of statements under case is terminated with goto, return, or break */
2568 /* find the last statement */
2569
2570 check_pval(item->u2.statements, apps,in_globals);
2571 break;
2572
2573 case PV_DEFAULT:
2574 /* fields:
2575 item->u2.statements == pval list of statements under the case
2576 */
2577
2578 check_pval(item->u2.statements, apps,in_globals);
2579 break;
2580
2581 case PV_CATCH:
2582 /* fields: item->u1.str == name of extension to catch
2583 item->u2.statements == pval list of statements in context body
2584 */
2585 check_pval(item->u2.statements, apps,in_globals);
2586 break;
2587
2588 case PV_SWITCHES:
2589 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
2590 */
2591 check_pval(item->u1.list, apps,in_globals);
2592 break;
2593
2594 case PV_ESWITCHES:
2595 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
2596 */
2597 check_pval(item->u1.list, apps,in_globals);
2598 break;
2599
2600 case PV_INCLUDES:
2601 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
2602 */
2603 check_pval(item->u1.list, apps,in_globals);
2605 for (lp=item->u1.list; lp; lp=lp->next){
2606 char *incl_context = lp->u1.str;
2607 struct pval *that_context = find_context(incl_context);
2608
2609 if ( lp->u2.arglist ) {
2611 check_dow(lp->u2.arglist->next);
2612 check_day(lp->u2.arglist->next->next);
2614 }
2615
2616 if (that_context) {
2617 find_pval_gotos(that_context->u2.statements,0);
2618
2619 }
2620 }
2621 break;
2622
2623 case PV_STATEMENTBLOCK:
2624 /* fields: item->u1.list == pval list of statements in block, one per entry in the list
2625 */
2626 check_pval(item->u1.list, apps,in_globals);
2627 break;
2628
2629 case PV_VARDEC:
2630 /* fields: item->u1.str == variable name
2631 item->u2.val == variable value to assign
2632 */
2633 /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
2634 if( !in_globals ) { /* don't check stuff inside the globals context; no wrapping in $[ ] there... */
2635 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);
2637 ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
2639 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
2640 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2641 item->filename, item->startline, item->endline, item->u2.val);
2642 warns++;
2643 }
2644 check_expr2_input(item,item->u2.val);
2645 }
2646 break;
2647
2648 case PV_LOCALVARDEC:
2649 /* fields: item->u1.str == variable name
2650 item->u2.val == variable value to assign
2651 */
2652 /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
2653 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);
2655 ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
2657 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
2658 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2659 item->filename, item->startline, item->endline, item->u2.val);
2660 warns++;
2661 }
2662 check_expr2_input(item,item->u2.val);
2663 break;
2664
2665 case PV_GOTO:
2666 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
2667 item->u1.list->u1.str == where the data on a PV_WORD will always be.
2668 */
2669 /* don't check goto's in abstract contexts */
2670 if ( in_abstract_context )
2671 break;
2672
2674 break;
2675
2676 case PV_LABEL:
2677 /* fields: item->u1.str == label name
2678 */
2679 if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) {
2680 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n",
2681 item->filename, item->startline, item->endline, item->u1.str);
2682 warns++;
2683 }
2684
2686 break;
2687
2688 case PV_FOR:
2689 /* fields: item->u1.for_init == a string containing the initializer
2690 item->u2.for_test == a string containing the loop test
2691 item->u3.for_inc == a string containing the loop increment
2692
2693 item->u4.for_statements == a pval list of statements in the for ()
2694 */
2695 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);
2697
2698 strp = strchr(item->u1.for_init, '=');
2699 if (strp) {
2700 ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
2701 }
2702 ast_expr(item->u2.for_test, expr_output, sizeof(expr_output),NULL);
2703 strp = strchr(item->u3.for_inc, '=');
2704 if (strp) {
2705 ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
2706 }
2707 if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) {
2708 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2709 item->filename, item->startline, item->endline, item->u2.for_test);
2710 warns++;
2711 }
2712 if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) {
2713 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2714 item->filename, item->startline, item->endline, item->u3.for_inc);
2715 warns++;
2716 }
2717 check_expr2_input(item,item->u2.for_test);
2718 check_expr2_input(item,item->u3.for_inc);
2719
2721 check_pval(item->u4.for_statements, apps,in_globals);
2722 break;
2723
2724 case PV_WHILE:
2725 /* fields: item->u1.str == the while conditional, as supplied by user
2726
2727 item->u2.statements == a pval list of statements in the while ()
2728 */
2729 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);
2731 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
2733 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
2734 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
2735 item->filename, item->startline, item->endline, item->u1.str);
2736 warns++;
2737 }
2738 check_expr2_input(item,item->u1.str);
2739 check_pval(item->u2.statements, apps,in_globals);
2740 break;
2741
2742 case PV_BREAK:
2743 /* fields: none
2744 */
2746 break;
2747
2748 case PV_RETURN:
2749 /* fields: none
2750 */
2751 break;
2752
2753 case PV_CONTINUE:
2754 /* fields: none
2755 */
2757 break;
2758
2759 case PV_RANDOM:
2760 /* fields: item->u1.str == the random number expression, as supplied by user
2761
2762 item->u2.statements == a pval list of statements in the if ()
2763 item->u3.else_statements == a pval list of statements in the else
2764 (could be zero)
2765 */
2766 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);
2768 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
2770 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
2771 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n",
2772 item->filename, item->startline, item->endline, item->u1.str);
2773 warns++;
2774 }
2775 check_expr2_input(item,item->u1.str);
2776 check_pval(item->u2.statements, apps,in_globals);
2777 if (item->u3.else_statements) {
2778 check_pval(item->u3.else_statements, apps,in_globals);
2779 }
2780 break;
2781
2782 case PV_IFTIME:
2783 /* fields: item->u1.list == the if time values, 4 of them, each in PV_WORD, linked list
2784
2785 item->u2.statements == a pval list of statements in the if ()
2786 item->u3.else_statements == a pval list of statements in the else
2787 (could be zero)
2788 */
2789 if ( item->u2.arglist ) {
2790 check_timerange(item->u1.list);
2791 check_dow(item->u1.list->next);
2792 check_day(item->u1.list->next->next);
2793 check_month(item->u1.list->next->next->next);
2794 }
2795
2796 check_pval(item->u2.statements, apps,in_globals);
2797 if (item->u3.else_statements) {
2798 check_pval(item->u3.else_statements, apps,in_globals);
2799 }
2800 break;
2801
2802 case PV_IF:
2803 /* fields: item->u1.str == the if conditional, as supplied by user
2804
2805 item->u2.statements == a pval list of statements in the if ()
2806 item->u3.else_statements == a pval list of statements in the else
2807 (could be zero)
2808 */
2809 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);
2811 ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
2813 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
2814 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n",
2815 item->filename, item->startline, item->endline, item->u1.str);
2816 warns++;
2817 }
2818 check_expr2_input(item,item->u1.str);
2819 check_pval(item->u2.statements, apps,in_globals);
2820 if (item->u3.else_statements) {
2821 check_pval(item->u3.else_statements, apps,in_globals);
2822 }
2823 break;
2824
2825 case PV_SWITCH:
2826 /* fields: item->u1.str == the switch expression
2827
2828 item->u2.statements == a pval list of statements in the switch,
2829 (will be case statements, most likely!)
2830 */
2831 /* we can check the switch expression, see if it matches any of the app variables...
2832 if it does, then, are all the possible cases accounted for? */
2834 check_pval(item->u2.statements, apps,in_globals);
2835 break;
2836
2837 case PV_EXTENSION:
2838 /* fields: item->u1.str == the extension name, label, whatever it's called
2839
2840 item->u2.statements == a pval list of statements in the extension
2841 item->u3.hints == a char * hint argument
2842 item->u4.regexten == an int boolean. non-zero says that regexten was specified
2843 */
2845
2846 check_pval(item->u2.statements, apps,in_globals);
2847 break;
2848
2849 case PV_IGNOREPAT:
2850 /* fields: item->u1.str == the ignorepat data
2851 */
2852 break;
2853
2854 case PV_GLOBALS:
2855 /* fields: item->u1.statements == pval list of statements, usually vardecs
2856 */
2858 check_pval(item->u1.statements, apps, 1);
2859 break;
2860 default:
2861 break;
2862 }
2863}
int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
Evaluate the given expression.
Definition: ast_expr2f.c:2391
@ E_MATCH
Definition: extconf.h:217
#define STATUS_SUCCESS
Definition: extconf.h:248
void free()
#define LOG_ERROR
struct ast_exten * pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition: ael_main.c:152
static int check_continue(pval *item)
Definition: pval.c:1058
void check_switch_expr(pval *item, struct argapp *apps)
Definition: pval.c:2184
static void check_macro_returns(pval *macro)
Definition: pval.c:650
static void check_day(pval *DAY)
Definition: pval.c:937
struct pval * find_macro(char *name)
Definition: pval.c:1943
static void check_label(pval *item)
Definition: pval.c:1106
static void find_pval_gotos(pval *item, int lev)
Definition: pval.c:1550
int check_app_args(pval *appcall, pval *arglist, struct argapp *app)
Definition: pval.c:2130
static void check_dow(pval *DOW)
get_dow: Get day of week
Definition: pval.c:898
static void check_goto(pval *item)
Definition: pval.c:1225
static void check_abstract_reference(pval *abstract_context)
Definition: pval.c:2329
static void check_timerange(pval *p)
Definition: pval.c:830
static void check_includes(pval *includes)
Definition: pval.c:811
static void check_month(pval *MON)
Definition: pval.c:1000
static int errs
Definition: pval.c:65
void check_pval(pval *item, struct argapp *apps, int in_globals)
Definition: pval.c:2865
static int in_abstract_context
Definition: pval.c:79
static pval * current_context
Definition: pval.c:73
struct pval * find_context(char *name)
Definition: pval.c:1953
int localized_pbx_load_module(void)
Definition: extconf.c:5644
static pval * current_extension
Definition: pval.c:74
static void check_expr2_input(pval *expr, char *str)
Definition: pval.c:801
static int check_break(pval *item)
Definition: pval.c:1038
static char expr_output[2096]
Definition: pval.c:60
void ast_expr_clear_extra_error_info(void)
Definition: ast_expr2f.c:2469
@ PV_CATCH
Definition: pval.h:16
@ PV_WORD
Definition: pval.h:8
@ PV_LOCALVARDEC
Definition: pval.h:36
@ PV_DEFAULT
Definition: pval.h:15
@ PV_CASE
Definition: pval.h:13
@ PV_CONTINUE
Definition: pval.h:28
@ PV_BREAK
Definition: pval.h:26
@ PV_APPLICATION_CALL
Definition: pval.h:12
@ PV_PATTERN
Definition: pval.h:14
@ PV_RETURN
Definition: pval.h:27
@ PV_IF
Definition: pval.h:29
@ PV_VARDEC
Definition: pval.h:21
@ PV_MACRO_CALL
Definition: pval.h:11
@ PV_GOTO
Definition: pval.h:22
@ PV_LABEL
Definition: pval.h:23
@ PV_FOR
Definition: pval.h:24
@ PV_RANDOM
Definition: pval.h:31
@ PV_STATEMENTBLOCK
Definition: pval.h:20
@ PV_WHILE
Definition: pval.h:25
void ast_expr_register_extra_error_info(char *errmsg)
Definition: ast_expr2f.c:2463
enum aco_type_t type
Definition: pval.h:111
int stacklen
Definition: extconf.h:237

Referenced by check_pval().

◆ check_switch_expr()

void check_switch_expr ( pval item,
struct argapp apps 
)

Definition at line 2184 of file pval.c.

2185{
2186#ifdef AAL_ARGCHECK
2187 /* get and clean the variable name */
2188 char *buff1, *p;
2189 struct argapp *a,*a2;
2190 struct appsetvar *v,*v2;
2191 struct argchoice *c;
2192 pval *t;
2193
2194 p = item->u1.str;
2195 while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) )
2196 p++;
2197
2198 buff1 = ast_strdupa(p);
2199
2200 while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t'))
2201 buff1[strlen(buff1)-1] = 0;
2202 /* buff1 now contains the variable name */
2203 v = 0;
2204 for (a=apps; a; a=a->next) {
2205 for (v=a->setvars;v;v=v->next) {
2206 if (strcmp(v->name,buff1) == 0) {
2207 break;
2208 }
2209 }
2210 if ( v )
2211 break;
2212 }
2213 if (v && v->vals) {
2214 /* we have a match, to a variable that has a set of determined values */
2215 int def= 0;
2216 int pat = 0;
2217 int f1 = 0;
2218
2219 /* first of all, does this switch have a default case ? */
2220 for (t=item->u2.statements; t; t=t->next) {
2221 if (t->type == PV_DEFAULT) {
2222 def =1;
2223 break;
2224 }
2225 if (t->type == PV_PATTERN) {
2226 pat++;
2227 }
2228 }
2229 if (def || pat) /* nothing to check. All cases accounted for! */
2230 return;
2231 for (c=v->vals; c; c=c->next) {
2232 f1 = 0;
2233 for (t=item->u2.statements; t; t=t->next) {
2234 if (t->type == PV_CASE || t->type == PV_PATTERN) {
2235 if (!strcmp(t->u1.str,c->name)) {
2236 f1 = 1;
2237 break;
2238 }
2239 }
2240 }
2241 if (!f1) {
2242 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n",
2243 item->filename, item->startline, item->endline, item->u1.str, c->name);
2244 warns++;
2245 }
2246 }
2247 /* next, is there an app call in the current exten, that would set this var? */
2248 f1 = 0;
2250 if ( t && t->type == PV_STATEMENTBLOCK )
2251 t = t->u1.statements;
2252 for (; t && t != item; t=t->next) {
2253 if (t->type == PV_APPLICATION_CALL) {
2254 /* find the application that matches the u1.str */
2255 for (a2=apps; a2; a2=a2->next) {
2256 if (strcasecmp(a2->name, t->u1.str)==0) {
2257 for (v2=a2->setvars; v2; v2=v2->next) {
2258 if (strcmp(v2->name, buff1) == 0) {
2259 /* found an app that sets the var */
2260 f1 = 1;
2261 break;
2262 }
2263 }
2264 }
2265 if (f1)
2266 break;
2267 }
2268 }
2269 if (f1)
2270 break;
2271 }
2272
2273 /* see if it sets the var */
2274 if (!f1) {
2275 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",
2276 item->filename, item->startline, item->endline, item->u1.str);
2277 warns++;
2278 }
2279 }
2280#else
2281 pval *t,*tl=0,*p2;
2282 int def= 0;
2283
2284 /* first of all, does this switch have a default case ? */
2285 for (t=item->u2.statements; t; t=t->next) {
2286 if (t->type == PV_DEFAULT) {
2287 def =1;
2288 break;
2289 }
2290 tl = t;
2291 }
2292 if (def) /* nothing to check. All cases accounted for! */
2293 return;
2294 /* if no default, warn and insert a default case at the end */
2295 p2 = tl->next = calloc(1, sizeof(struct pval));
2296
2297 p2->type = PV_DEFAULT;
2298 p2->startline = tl->startline;
2299 p2->endline = tl->endline;
2300 p2->startcol = tl->startcol;
2301 p2->endcol = tl->endcol;
2302 p2->filename = strdup(tl->filename);
2303 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n",
2304 p2->filename, p2->startline, p2->endline);
2305 warns++;
2306
2307#endif
2308}
#define calloc(a, b)
Definition: astmm.h:155
struct argapp * next
Definition: pval.h:112
int startcol
Definition: pval.h:53
int endcol
Definition: pval.h:54
struct test_val * next
const char * name
static struct test_val a

Referenced by check_pval_item().

◆ destroy_extensions()

void destroy_extensions ( struct ael_extension exten)

Definition at line 2978 of file pval.c.

2979{
2980 struct ael_extension *ne, *nen;
2981 for (ne=exten; ne; ne=nen) {
2982 struct ael_priority *pe, *pen;
2983
2984 if (ne->name)
2985 free(ne->name);
2986
2987 /* cidmatch fields are allocated with name, and freed when
2988 the name field is freed. Don't do a free for this field,
2989 unless you LIKE to see a crash! */
2990
2991 if (ne->hints)
2992 free(ne->hints);
2993
2994 for (pe=ne->plist; pe; pe=pen) {
2995 pen = pe->next;
2996 if (pe->app)
2997 free(pe->app);
2998 pe->app = 0;
2999 if (pe->appargs)
3000 free(pe->appargs);
3001 pe->appargs = 0;
3002 pe->origin = 0;
3003 pe->goto_true = 0;
3004 pe->goto_false = 0;
3005 free(pe);
3006 }
3007 nen = ne->next_exten;
3008 ne->next_exten = 0;
3009 ne->plist =0;
3010 ne->plist_last = 0;
3011 ne->next_exten = 0;
3012 ne->loop_break = 0;
3013 ne->loop_continue = 0;
3014 free(ne);
3015 }
3016}
struct ael_priority * loop_break
Definition: ael_structs.h:119
struct ael_priority * loop_continue
Definition: ael_structs.h:120

Referenced by ast_compile_ael2().

◆ destroy_pval()

void destroy_pval ( pval item)

Definition at line 4940 of file pval.c.

4941{
4942 pval *i,*nxt;
4943
4944 for (i=item; i; i=nxt) {
4945 nxt = i->next;
4946
4948 }
4949}
void destroy_pval_item(pval *item)
Definition: pval.c:4672

Referenced by destroy_pval_item(), pbx_load_module(), pvalIfTimeSetCondition(), and pvalIncludesAddIncludeWithTimeConstraints().

◆ destroy_pval_item()

void destroy_pval_item ( pval item)

Definition at line 4672 of file pval.c.

4673{
4674 if (item == NULL) {
4675 ast_log(LOG_WARNING, "null item\n");
4676 return;
4677 }
4678
4679 if (item->filename)
4680 free(item->filename);
4681
4682 switch (item->type) {
4683 case PV_WORD:
4684 /* fields: item->u1.str == string associated with this (word). */
4685 if (item->u1.str )
4686 free(item->u1.str);
4687 if ( item->u2.arglist )
4688 destroy_pval(item->u2.arglist);
4689 break;
4690
4691 case PV_MACRO:
4692 /* fields: item->u1.str == name of macro
4693 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
4694 item->u2.arglist->u1.str == argument
4695 item->u2.arglist->next == next arg
4696
4697 item->u3.macro_statements == pval list of statements in macro body.
4698 */
4699 destroy_pval(item->u2.arglist);
4700 if (item->u1.str )
4701 free(item->u1.str);
4702 destroy_pval(item->u3.macro_statements);
4703 break;
4704
4705 case PV_CONTEXT:
4706 /* fields: item->u1.str == name of context
4707 item->u2.statements == pval list of statements in context body
4708 item->u3.abstract == int 1 if an abstract keyword were present
4709 */
4710 if (item->u1.str)
4711 free(item->u1.str);
4712 destroy_pval(item->u2.statements);
4713 break;
4714
4715 case PV_MACRO_CALL:
4716 /* fields: item->u1.str == name of macro to call
4717 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
4718 item->u2.arglist->u1.str == argument
4719 item->u2.arglist->next == next arg
4720 */
4721 if (item->u1.str)
4722 free(item->u1.str);
4723 destroy_pval(item->u2.arglist);
4724 break;
4725
4727 /* fields: item->u1.str == name of application to call
4728 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
4729 item->u2.arglist->u1.str == argument
4730 item->u2.arglist->next == next arg
4731 */
4732 if (item->u1.str)
4733 free(item->u1.str);
4734 destroy_pval(item->u2.arglist);
4735 break;
4736
4737 case PV_CASE:
4738 /* fields: item->u1.str == value of case
4739 item->u2.statements == pval list of statements under the case
4740 */
4741 if (item->u1.str)
4742 free(item->u1.str);
4743 destroy_pval(item->u2.statements);
4744 break;
4745
4746 case PV_PATTERN:
4747 /* fields: item->u1.str == value of case
4748 item->u2.statements == pval list of statements under the case
4749 */
4750 if (item->u1.str)
4751 free(item->u1.str);
4752 destroy_pval(item->u2.statements);
4753 break;
4754
4755 case PV_DEFAULT:
4756 /* fields:
4757 item->u2.statements == pval list of statements under the case
4758 */
4759 destroy_pval(item->u2.statements);
4760 break;
4761
4762 case PV_CATCH:
4763 /* fields: item->u1.str == name of extension to catch
4764 item->u2.statements == pval list of statements in context body
4765 */
4766 if (item->u1.str)
4767 free(item->u1.str);
4768 destroy_pval(item->u2.statements);
4769 break;
4770
4771 case PV_SWITCHES:
4772 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4773 */
4774 destroy_pval(item->u1.list);
4775 break;
4776
4777 case PV_ESWITCHES:
4778 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4779 */
4780 destroy_pval(item->u1.list);
4781 break;
4782
4783 case PV_INCLUDES:
4784 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
4785 item->u2.arglist == pval list of 4 PV_WORD elements for time values
4786 */
4787 destroy_pval(item->u1.list);
4788 break;
4789
4790 case PV_STATEMENTBLOCK:
4791 /* fields: item->u1.list == pval list of statements in block, one per entry in the list
4792 */
4793 destroy_pval(item->u1.list);
4794 break;
4795
4796 case PV_LOCALVARDEC:
4797 case PV_VARDEC:
4798 /* fields: item->u1.str == variable name
4799 item->u2.val == variable value to assign
4800 */
4801 if (item->u1.str)
4802 free(item->u1.str);
4803 if (item->u2.val)
4804 free(item->u2.val);
4805 break;
4806
4807 case PV_GOTO:
4808 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
4809 item->u1.list->u1.str == where the data on a PV_WORD will always be.
4810 */
4811
4812 destroy_pval(item->u1.list);
4813 break;
4814
4815 case PV_LABEL:
4816 /* fields: item->u1.str == label name
4817 */
4818 if (item->u1.str)
4819 free(item->u1.str);
4820 break;
4821
4822 case PV_FOR:
4823 /* fields: item->u1.for_init == a string containing the initializer
4824 item->u2.for_test == a string containing the loop test
4825 item->u3.for_inc == a string containing the loop increment
4826
4827 item->u4.for_statements == a pval list of statements in the for ()
4828 */
4829 if (item->u1.for_init)
4830 free(item->u1.for_init);
4831 if (item->u2.for_test)
4832 free(item->u2.for_test);
4833 if (item->u3.for_inc)
4834 free(item->u3.for_inc);
4835 destroy_pval(item->u4.for_statements);
4836 break;
4837
4838 case PV_WHILE:
4839 /* fields: item->u1.str == the while conditional, as supplied by user
4840
4841 item->u2.statements == a pval list of statements in the while ()
4842 */
4843 if (item->u1.str)
4844 free(item->u1.str);
4845 destroy_pval(item->u2.statements);
4846 break;
4847
4848 case PV_BREAK:
4849 /* fields: none
4850 */
4851 break;
4852
4853 case PV_RETURN:
4854 /* fields: none
4855 */
4856 break;
4857
4858 case PV_CONTINUE:
4859 /* fields: none
4860 */
4861 break;
4862
4863 case PV_IFTIME:
4864 /* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list
4865
4866 item->u2.statements == a pval list of statements in the if ()
4867 item->u3.else_statements == a pval list of statements in the else
4868 (could be zero)
4869 */
4870 destroy_pval(item->u1.list);
4871 destroy_pval(item->u2.statements);
4872 if (item->u3.else_statements) {
4873 destroy_pval(item->u3.else_statements);
4874 }
4875 break;
4876
4877 case PV_RANDOM:
4878 /* fields: item->u1.str == the random percentage, as supplied by user
4879
4880 item->u2.statements == a pval list of statements in the true part ()
4881 item->u3.else_statements == a pval list of statements in the else
4882 (could be zero)
4883 fall thru to If */
4884 case PV_IF:
4885 /* fields: item->u1.str == the if conditional, as supplied by user
4886
4887 item->u2.statements == a pval list of statements in the if ()
4888 item->u3.else_statements == a pval list of statements in the else
4889 (could be zero)
4890 */
4891 if (item->u1.str)
4892 free(item->u1.str);
4893 destroy_pval(item->u2.statements);
4894 if (item->u3.else_statements) {
4895 destroy_pval(item->u3.else_statements);
4896 }
4897 break;
4898
4899 case PV_SWITCH:
4900 /* fields: item->u1.str == the switch expression
4901
4902 item->u2.statements == a pval list of statements in the switch,
4903 (will be case statements, most likely!)
4904 */
4905 if (item->u1.str)
4906 free(item->u1.str);
4907 destroy_pval(item->u2.statements);
4908 break;
4909
4910 case PV_EXTENSION:
4911 /* fields: item->u1.str == the extension name, label, whatever it's called
4912
4913 item->u2.statements == a pval list of statements in the extension
4914 item->u3.hints == a char * hint argument
4915 item->u4.regexten == an int boolean. non-zero says that regexten was specified
4916 */
4917 if (item->u1.str)
4918 free(item->u1.str);
4919 if (item->u3.hints)
4920 free(item->u3.hints);
4921 destroy_pval(item->u2.statements);
4922 break;
4923
4924 case PV_IGNOREPAT:
4925 /* fields: item->u1.str == the ignorepat data
4926 */
4927 if (item->u1.str)
4928 free(item->u1.str);
4929 break;
4930
4931 case PV_GLOBALS:
4932 /* fields: item->u1.statements == pval list of statements, usually vardecs
4933 */
4934 destroy_pval(item->u1.statements);
4935 break;
4936 }
4937 free(item);
4938}
void destroy_pval(pval *item)
Definition: pval.c:4940

Referenced by destroy_pval().

◆ find_context()

struct pval * find_context ( char *  name)

Definition at line 1953 of file pval.c.

1954{
1956 count_labels = 0;
1958 match_exten = "*"; /* don't really need to set these, shouldn't be reached */
1959 match_label = "*";
1960 return match_pval(current_db);
1961}
static const char * match_context
Definition: pval.c:76
struct pval * match_pval(pval *item)
Definition: pval.c:1811
static pval * current_db
Definition: pval.c:72
static int count_labels
Definition: pval.c:80
static int return_on_context_match
Definition: pval.c:82
static const char * match_label
Definition: pval.c:78
static const char * match_exten
Definition: pval.c:77

Referenced by check_goto(), check_includes(), check_pval_item(), find_first_label_in_current_context(), find_label_in_current_context(), find_pval_goto_item(), and get_goto_target().

◆ handle_cli_ael_reload()

static char * handle_cli_ael_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 228 of file pbx_ael.c.

229{
230 switch (cmd) {
231 case CLI_INIT:
232 e->command = "ael reload";
233 e->usage =
234 "Usage: ael reload\n"
235 " Reloads AEL configuration.\n";
236 return NULL;
237 case CLI_GENERATE:
238 return NULL;
239 }
240
241 if (a->argc != 2)
242 return CLI_SHOWUSAGE;
243
244#ifndef STANDALONE
245 /* Lock-Protected reload. It is VERY BAD to have simultaneous ael load_module() executing at the same time */
247#else
248 /* Lock-Protected reload not needed (and not available) when running standalone (Example: via aelparse cli tool). No reload contention is possible */
250#endif
251}
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
@ AST_MODULE_RELOAD_SUCCESS
Definition: module.h:110
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:1567
static int pbx_load_module(void)
Definition: pbx_ael.c:144
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177

References a, ast_module_reload(), AST_MODULE_RELOAD_SUCCESS, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, pbx_load_module(), and ast_cli_entry::usage.

◆ handle_cli_ael_set_debug()

static char * handle_cli_ael_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 196 of file pbx_ael.c.

197{
198 switch (cmd) {
199 case CLI_INIT:
200 e->command = "ael set debug {read|tokens|contexts|off}";
201 e->usage =
202 "Usage: ael set debug {read|tokens|contexts|off}\n"
203 " Enable AEL read, token, or context debugging,\n"
204 " or disable all AEL debugging messages. Note: this\n"
205 " currently does nothing.\n";
206 return NULL;
207 case CLI_GENERATE:
208 return NULL;
209 }
210
211 if (a->argc != e->args)
212 return CLI_SHOWUSAGE;
213
214 if (!strcasecmp(a->argv[3], "read"))
216 else if (!strcasecmp(a->argv[3], "tokens"))
218 else if (!strcasecmp(a->argv[3], "contexts"))
220 else if (!strcasecmp(a->argv[3], "off"))
221 aeldebug = 0;
222 else
223 return CLI_SHOWUSAGE;
224
225 return CLI_SUCCESS;
226}
#define DEBUG_CONTEXTS
Definition: pbx_ael.c:75
#define DEBUG_TOKENS
Definition: pbx_ael.c:73
#define DEBUG_READ
Definition: pbx_ael.c:72
static int aeldebug
Definition: pbx_ael.c:117
int args
This gets set in ast_cli_register()
Definition: cli.h:185

References a, aeldebug, ast_cli_entry::args, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, DEBUG_CONTEXTS, DEBUG_READ, DEBUG_TOKENS, NULL, and ast_cli_entry::usage.

◆ is_empty()

int is_empty ( char *  arg)

Definition at line 1981 of file pval.c.

1982{
1983 if (!arg)
1984 return 1;
1985 if (*arg == 0)
1986 return 1;
1987 while (*arg) {
1988 if (*arg != ' ' && *arg != '\t')
1989 return 0;
1990 arg++;
1991 }
1992 return 1;
1993}

◆ is_float()

int is_float ( char *  arg)

Definition at line 1963 of file pval.c.

1964{
1965 char *s;
1966 for (s=arg; *s; s++) {
1967 if (*s != '.' && (*s < '0' || *s > '9'))
1968 return 0;
1969 }
1970 return 1;
1971}

◆ is_int()

int is_int ( char *  arg)

Definition at line 1972 of file pval.c.

1973{
1974 char *s;
1975 for (s=arg; *s; s++) {
1976 if (*s < '0' || *s > '9')
1977 return 0;
1978 }
1979 return 1;
1980}

◆ load_module()

static int load_module ( void  )
static

Definition at line 268 of file pbx_ael.c.

269{
271#ifndef STANDALONE
273#endif
274 return (pbx_load_module());
275}
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
static char * aelsub
Definition: pbx_ael.c:122
static struct ast_cli_entry cli_ael[]
Definition: pbx_ael.c:253
static int aelsub_exec(struct ast_channel *chan, const char *vdata)
Definition: pbx_ael.c:124

References aelsub, aelsub_exec(), ARRAY_LEN, ast_cli_register_multiple, ast_register_application_xml, cli_ael, and pbx_load_module().

◆ new_exten()

struct ael_extension * new_exten ( void  )

Definition at line 2930 of file pval.c.

2931{
2932 struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
2933 return x;
2934}

Referenced by ast_compile_ael2(), and gen_prios().

◆ new_prio()

struct ael_priority * new_prio ( void  )

Definition at line 2924 of file pval.c.

2925{
2926 struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
2927 return x;
2928}

Referenced by ast_compile_ael2(), and gen_prios().

◆ pbx_load_module()

static int pbx_load_module ( void  )
static

Definition at line 144 of file pbx_ael.c.

145{
146 int errs=0, sem_err=0, sem_warn=0, sem_note=0;
147 char *rfilename;
148 struct ast_context *local_contexts=NULL, *con;
150
151 struct pval *parse_tree;
152
153 ast_debug(1, "Starting AEL load process.\n");
154 if (config[0] == '/')
155 rfilename = (char *)config;
156 else {
157 rfilename = ast_alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
158 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
159 }
160 if (access(rfilename,R_OK) != 0) {
161 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
163 }
164
165 parse_tree = ael2_parse(rfilename, &errs);
166 ast_debug(1, "AEL load process: parsed config file name '%s'.\n", rfilename);
167 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
168 if (errs == 0 && sem_err == 0) {
169 ast_debug(1, "AEL load process: checked config file name '%s'.\n", rfilename);
171 if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) {
172 ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n");
173 destroy_pval(parse_tree); /* free up the memory */
175 }
176 ast_debug(1, "AEL load process: compiled config file name '%s'.\n", rfilename);
177
179 local_table = NULL; /* it's the dialplan global now */
181 ast_debug(1, "AEL load process: merged config file name '%s'.\n", rfilename);
182 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
184 ast_debug(1, "AEL load process: verified config file name '%s'.\n", rfilename);
185 } else {
186 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);
187 destroy_pval(parse_tree); /* free up the memory */
189 }
190 destroy_pval(parse_tree); /* free up the memory */
191
193}
struct pval * ael2_parse(char *fname, int *errs)
Definition: ael_lex.c:3344
void ael2_semantic_check(pval *item, int *errs, int *warns, int *notes)
Definition: pval.c:2885
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
int ast_hashtab_newsize_java(struct ast_hashtab *tab)
Create a prime number roughly 2x the current table size.
Definition: hashtab.c:127
#define ast_hashtab_create(initial_buckets, compare, resize, newsize, hash, do_locking)
Create the hashtable list.
Definition: hashtab.h:254
int ast_hashtab_resize_java(struct ast_hashtab *tab)
Determines if a table resize should occur using the Java algorithm (if the table load factor is 75% o...
Definition: hashtab.c:84
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_NOTICE
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:151
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: extconf.c:4024
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
hashtable functions for contexts
Definition: ael_main.c:589
unsigned int ast_hashtab_hash_contexts(const void *obj)
Definition: ael_main.c:596
void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
Merge the temporary contexts into a global contexts list and delete from the global list the ones tha...
Definition: pbx.c:6426
int ast_context_verify_includes(struct ast_context *con)
Verifies includes in an ast_contect structure.
Definition: pbx.c:8732
int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root)
Definition: pval.c:4413
static char * config
Definition: pbx_ael.c:77
void destroy_pval(pval *item)
Definition: pval.c:4940
static char * registrar
Definition: pbx_ael.c:78

References ael2_parse(), ael2_semantic_check(), ast_alloca, ast_compile_ael2(), ast_config_AST_CONFIG_DIR, ast_context_verify_includes(), ast_debug, 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(), config, destroy_pval(), errs, local_contexts, local_table, LOG_ERROR, LOG_NOTICE, NULL, and registrar.

Referenced by handle_cli_ael_reload(), load_module(), and reload().

◆ reload()

static int reload ( void  )
static

Definition at line 277 of file pbx_ael.c.

278{
279 /* Lock-Protected reload not needed because we're already being called from ast_module_reload() */
280 return pbx_load_module();
281}

References pbx_load_module().

◆ set_priorities()

void set_priorities ( struct ael_extension exten)

Definition at line 4187 of file pval.c.

4188{
4189 int i;
4190 struct ael_priority *pr;
4191 do {
4192 if (exten->is_switch)
4193 i = 10;
4194 else if (exten->regexten)
4195 i=2;
4196 else
4197 i=1;
4198
4199 for (pr=exten->plist; pr; pr=pr->next) {
4200 pr->priority_num = i;
4201
4202 if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
4203 but we want them to point to the right
4204 priority, which would be the next line
4205 after the label; */
4206 i++;
4207 }
4208
4210 } while ( exten );
4211}

Referenced by ast_compile_ael2().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 258 of file pbx_ael.c.

259{
262#ifndef STANDALONE
264#endif
265 return 0;
266}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Definition: pbx.c:8221

References aelsub, ARRAY_LEN, ast_cli_unregister_multiple(), ast_context_destroy(), ast_unregister_application(), cli_ael, NULL, and registrar.

Variable Documentation

◆ __mod_info

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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, .reload = reload, .requires = "res_ael_share", }
static

Definition at line 299 of file pbx_ael.c.

◆ aeldebug

int aeldebug = 0
static

Definition at line 117 of file pbx_ael.c.

Referenced by handle_cli_ael_set_debug().

◆ aelsub

char* aelsub = "AELSub"
static

Definition at line 122 of file pbx_ael.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 299 of file pbx_ael.c.

◆ cli_ael

struct ast_cli_entry cli_ael[]
static
Initial value:
= {
{ .handler = handle_cli_ael_reload , .summary = "Reload AEL configuration" ,},
{ .handler = handle_cli_ael_set_debug , .summary = "Enable AEL debugging flags" ,}
}
static char * handle_cli_ael_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_ael.c:196
static char * handle_cli_ael_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: pbx_ael.c:228

Definition at line 253 of file pbx_ael.c.

Referenced by load_module(), and unload_module().

◆ config

char* config = "extensions.ael"
static

Definition at line 77 of file pbx_ael.c.

Referenced by pbx_load_module().

◆ registrar

char* registrar = "pbx_ael"
static