Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2. More...
#include "asterisk.h"#include <ctype.h>#include <regex.h>#include <sys/stat.h>#include "asterisk/pbx.h"#include "asterisk/config.h"#include "asterisk/module.h"#include "asterisk/logger.h"#include "asterisk/cli.h"#include "asterisk/app.h"#include "asterisk/callerid.h"#include "asterisk/hashtab.h"#include "asterisk/ael_structs.h"#include "asterisk/pval.h"
Go to the source code of this file.
Defines | |
| #define | DEBUG_CONTEXTS (1 << 3) |
| #define | DEBUG_MACROS (1 << 2) |
| #define | DEBUG_READ (1 << 0) |
| #define | DEBUG_TOKENS (1 << 1) |
Functions | |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| void | add_extensions (struct ael_extension *exten) |
| 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) |
| struct pval * | find_context (char *name) |
| struct pval * | find_macro (char *name) |
| static char * | handle_cli_ael_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | handle_cli_ael_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| int | is_empty (char *arg) |
| int | is_float (char *arg) |
| int | is_int (char *arg) |
| static int | load_module (void) |
| struct ael_extension * | new_exten (void) |
| struct ael_priority * | new_prio (void) |
| static int | pbx_load_module (void) |
| static int | reload (void) |
| void | set_priorities (struct ael_extension *exten) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info __MODULE_INFO_SECTION | __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Asterisk Extension Language Compiler" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } |
| static int | aeldebug = 0 |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_cli_entry | cli_ael [] |
| static char * | config = "extensions.ael" |
| static char * | registrar = "pbx_ael" |
Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.
Definition in file pbx_ael.c.
| #define DEBUG_CONTEXTS (1 << 3) |
Definition at line 63 of file pbx_ael.c.
Referenced by handle_cli_ael_set_debug().
| #define DEBUG_MACROS (1 << 2) |
Definition at line 62 of file pbx_ael.c.
Referenced by handle_cli_ael_set_debug().
| #define DEBUG_READ (1 << 0) |
Definition at line 60 of file pbx_ael.c.
Referenced by handle_cli_ael_set_debug().
| #define DEBUG_TOKENS (1 << 1) |
Definition at line 61 of file pbx_ael.c.
Referenced by handle_cli_ael_set_debug().
| void add_extensions | ( | struct ael_extension * | exten | ) |
Definition at line 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, ael_priority::app, ael_priority::appargs, ast_add_extension2(), ast_free_ptr, ast_log(), AST_MAX_EXTENSION, ael_extension::cidmatch, ael_extension::context, pval::else_statements, ael_priority::exten, ael_priority::goto_false, ael_priority::goto_true, ael_extension::hints, last, LOG_WARNING, ael_extension::name, ael_priority::next, ael_extension::next_exten, ael_priority::origin, pbx_substitute_variables_helper(), ael_extension::plist, PRIORITY_HINT, ael_priority::priority_num, PV_IFTIME, PV_SWITCH, pval::str, strdup, pval::type, ael_priority::type, pval::u1, and pval::u3.
{
struct ael_priority *pr;
char *label=0;
char realext[AST_MAX_EXTENSION];
if (!exten) {
ast_log(LOG_WARNING, "This file is Empty!\n" );
return;
}
do {
struct ael_priority *last = 0;
pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
if (exten->hints) {
if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch,
exten->hints, NULL, ast_free_ptr, registrar)) {
ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
exten->name);
}
}
for (pr=exten->plist; pr; pr=pr->next) {
char app[2000];
char appargs[2000];
/* before we can add the extension, we need to prep the app/appargs;
the CONTROL types need to be done after the priority numbers are calculated.
*/
if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
last = pr;
continue;
}
if (pr->app)
strcpy(app, pr->app);
else
app[0] = 0;
if (pr->appargs )
strcpy(appargs, pr->appargs);
else
appargs[0] = 0;
switch( pr->type ) {
case AEL_APPCALL:
/* easy case. Everything is all set up */
break;
case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
/* simple, unconditional goto. */
strcpy(app,"Goto");
if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
} else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
} else
snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
break;
case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */
strcpy(app,"GotoIf");
snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
break;
case AEL_IF_CONTROL:
strcpy(app,"GotoIf");
if (pr->origin->u3.else_statements )
snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
else
snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
break;
case AEL_RAND_CONTROL:
strcpy(app,"Random");
snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
break;
case AEL_IFTIME_CONTROL:
strcpy(app,"GotoIfTime");
snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
break;
case AEL_RETURN:
strcpy(app,"Return");
appargs[0] = 0;
break;
default:
break;
}
if (last && last->type == AEL_LABEL ) {
label = last->origin->u1.str;
}
else
label = 0;
if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch,
app, strdup(appargs), ast_free_ptr, registrar)) {
ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num,
exten->name);
}
last = pr;
}
exten = exten->next_exten;
} while ( exten );
}
| 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 add_extensions(), AEL_APPCALL, AEL_LABEL, ael_priority::app, ael_priority::appargs, pval::arglist, ast_compat_app_set, ast_context_add_ignorepat2(), ast_context_add_include2(), ast_context_add_switch2(), ast_context_find_or_create(), attach_exten(), buf, ael_extension::cidmatch, ael_extension::context, context, destroy_extensions(), exten, fix_gotos_in_extensions(), gen_prios(), ael_extension::hints, pval::hints, linkprio(), pval::list, pval::macro_statements, ael_extension::name, new_exten(), new_prio(), pval::next, ael_priority::origin, pbx_builtin_setvar(), ael_extension::plist_last, PV_CONTEXT, PV_ESWITCHES, PV_EXTENSION, PV_GLOBALS, PV_IGNOREPAT, PV_INCLUDES, PV_MACRO, PV_SWITCHES, pval::regexten, ael_extension::regexten, remove_spaces_before_equals(), ael_extension::return_needed, set_priorities(), pval::statements, pval::str, strdup, ael_priority::type, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.
{
pval *p,*p2;
struct ast_context *context;
char buf[2000];
struct ael_extension *exten;
struct ael_extension *exten_list = 0;
for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there
when we try to eval them */
switch (p->type) {
case PV_GLOBALS:
/* just VARDEC elements */
for (p2=p->u1.list; p2; p2=p2->next) {
char buf2[2000];
snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
pbx_builtin_setvar(NULL, buf2);
}
break;
default:
break;
}
}
for (p=root; p; p=p->next ) {
pval *lp;
int argc;
switch (p->type) {
case PV_MACRO:
context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
exten = new_exten();
exten->context = context;
exten->name = strdup("~~s~~");
argc = 1;
for (lp=p->u2.arglist; lp; lp=lp->next) {
/* for each arg, set up a "Set" command */
struct ael_priority *np2 = new_prio();
np2->type = AEL_APPCALL;
if (!ast_compat_app_set) {
np2->app = strdup("MSet");
} else {
np2->app = strdup("Set");
}
snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++);
remove_spaces_before_equals(buf);
np2->appargs = strdup(buf);
linkprio(exten, np2, NULL);
}
/* CONTAINS APPCALLS, CATCH, just like extensions... */
if (gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context)) {
return -1;
}
if (exten->return_needed) { /* most likely, this will go away */
struct ael_priority *np2 = new_prio();
np2->type = AEL_APPCALL;
np2->app = strdup("NoOp");
snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
np2->appargs = strdup(buf);
linkprio(exten, np2, NULL);
exten-> return_target = np2;
}
set_priorities(exten);
attach_exten(&exten_list, exten);
break;
case PV_GLOBALS:
/* already done */
break;
case PV_CONTEXT:
context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
/* contexts contain: ignorepat, includes, switches, eswitches, extensions, */
for (p2=p->u2.statements; p2; p2=p2->next) {
pval *p3;
char *s3;
switch (p2->type) {
case PV_EXTENSION:
exten = new_exten();
exten->name = strdup(p2->u1.str);
exten->context = context;
if( (s3=strchr(exten->name, '/') ) != 0 )
{
*s3 = 0;
exten->cidmatch = s3+1;
}
if ( p2->u3.hints )
exten->hints = strdup(p2->u3.hints);
exten->regexten = p2->u4.regexten;
if (gen_prios(exten, p->u1.str, p2->u2.statements, 0, context)) {
return -1;
}
if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
struct ael_priority *np2 = new_prio();
np2->type = AEL_APPCALL;
np2->app = strdup("NoOp");
snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
np2->appargs = strdup(buf);
linkprio(exten, np2, NULL);
exten-> return_target = np2;
}
/* is the last priority in the extension a label? Then add a trailing no-op */
if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
struct ael_priority *np2 = new_prio();
np2->type = AEL_APPCALL;
np2->app = strdup("NoOp");
snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
np2->appargs = strdup(buf);
linkprio(exten, np2, NULL);
}
set_priorities(exten);
attach_exten(&exten_list, exten);
break;
case PV_IGNOREPAT:
ast_context_add_ignorepat2(context, p2->u1.str, registrar);
break;
case PV_INCLUDES:
for (p3 = p2->u1.list; p3 ;p3=p3->next) {
if ( p3->u2.arglist ) {
snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s",
p3->u1.str,
p3->u2.arglist->u1.str,
p3->u2.arglist->next->u1.str,
p3->u2.arglist->next->next->u1.str,
p3->u2.arglist->next->next->next->u1.str);
ast_context_add_include2(context, buf, registrar);
} else
ast_context_add_include2(context, p3->u1.str, registrar);
}
break;
case PV_SWITCHES:
for (p3 = p2->u1.list; p3 ;p3=p3->next) {
char *c = strchr(p3->u1.str, '/');
if (c) {
*c = '\0';
c++;
} else
c = "";
ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
}
break;
case PV_ESWITCHES:
for (p3 = p2->u1.list; p3 ;p3=p3->next) {
char *c = strchr(p3->u1.str, '/');
if (c) {
*c = '\0';
c++;
} else
c = "";
ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
}
break;
default:
break;
}
}
break;
default:
/* huh? what? */
break;
}
}
/* moved these from being done after a macro or extension were processed,
to after all processing is done, for the sake of fixing gotos to labels inside cases... */
/* I guess this would be considered 2nd pass of compiler now... */
fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */
add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */
destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */
return 0;
}
| void ast_expr_clear_extra_error_info | ( | void | ) |
Definition at line 2456 of file ast_expr2f.c.
{
extra_error_message_supplied=0;
extra_error_message[0] = 0;
}
| void ast_expr_register_extra_error_info | ( | char * | errmsg | ) |
Definition at line 2450 of file ast_expr2f.c.
{
extra_error_message_supplied=1;
strcpy(extra_error_message, message);
}
Definition at line 2127 of file pval.c.
References ast_log(), pval::endline, pval::filename, LOG_WARNING, pval::next, pval::startline, pval::str, and pval::u1.
{
#ifdef AAL_ARGCHECK
struct argdesc *ad = app->args;
pval *pa;
int z;
for (pa = arglist; pa; pa=pa->next) {
if (!ad) {
ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
warns++;
return 1;
} else {
/* find the first entry in the ad list that will match */
do {
if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */
break;
z= option_matches( ad, pa, app);
if (!z) {
if ( !arglist )
arglist=appcall;
if (ad->type == ARGD_REQUIRED) {
ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
warns++;
return 1;
}
} else if (z && ad->dtype == ARGD_OPTIONSET) {
option_matches_j( ad, pa, app);
}
ad = ad->next;
} while (ad && !z);
}
}
/* any app nodes left, that are not optional? */
for ( ; ad; ad=ad->next) {
if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
if ( !arglist )
arglist=appcall;
ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
warns++;
return 1;
}
}
return 0;
#else
return 0;
#endif
}
Definition at line 2862 of file pval.c.
References check_pval_item(), and pval::next.
{
pval *i;
/* checks to do:
1. Do goto's point to actual labels?
2. Do macro calls reference a macro?
3. Does the number of macro args match the definition?
4. Is a macro call missing its & at the front?
5. Application calls-- we could check syntax for existing applications,
but I need some some sort of universal description bnf for a general
sort of method for checking arguments, in number, maybe even type, at least.
Don't want to hand code checks for hundreds of applications.
*/
for (i=item; i; i=i->next) {
check_pval_item(i,apps,in_globals);
}
}
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(), E_MATCH, pval::else_statements, pval::endcol, pval::endline, pval::filename, find_context(), find_macro(), find_pval_gotos(), pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, free, pval::list, localized_pbx_load_module(), LOG_ERROR, LOG_WARNING, pval::macro_statements, argapp::next, pval::next, pbx_find_extension(), PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTEXT, PV_CONTINUE, PV_DEFAULT, PV_ESWITCHES, PV_EXTENSION, PV_FOR, PV_GLOBALS, PV_GOTO, PV_IF, PV_IFTIME, PV_IGNOREPAT, PV_INCLUDES, PV_LABEL, PV_LOCALVARDEC, PV_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pbx_find_info::stacklen, pval::startcol, pval::startline, pval::statements, pbx_find_info::status, STATUS_SUCCESS, pval::str, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.
{
pval *lp;
#ifdef AAL_ARGCHECK
struct argapp *app, *found;
#endif
struct pval *macro_def;
struct pval *app_def;
char errmsg[4096];
char *strp;
switch (item->type) {
case PV_WORD:
/* fields: item->u1.str == string associated with this (word).
item->u2.arglist == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */
break;
case PV_MACRO:
/* fields: item->u1.str == name of macro
item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
item->u2.arglist->u1.str == argument
item->u2.arglist->next == next arg
item->u3.macro_statements == pval list of statements in macro body.
*/
in_abstract_context = 0;
current_context = item;
current_extension = 0;
check_macro_returns(item);
for (lp=item->u2.arglist; lp; lp=lp->next) {
}
check_pval(item->u3.macro_statements, apps,in_globals);
break;
case PV_CONTEXT:
/* fields: item->u1.str == name of context
item->u2.statements == pval list of statements in context body
item->u3.abstract == int 1 if an abstract keyword were present
*/
current_context = item;
current_extension = 0;
if ( item->u3.abstract ) {
in_abstract_context = 1;
check_abstract_reference(item);
} else
in_abstract_context = 0;
check_pval(item->u2.statements, apps,in_globals);
break;
case PV_MACRO_CALL:
/* fields: item->u1.str == name of macro to call
item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
item->u2.arglist->u1.str == argument
item->u2.arglist->next == next arg
*/
#ifdef STANDALONE
/* if this is a standalone, we will need to make sure the
localized load of extensions.conf is done */
if (!extensions_dot_conf_loaded) {
localized_pbx_load_module();
extensions_dot_conf_loaded++;
}
#endif
macro_def = find_macro(item->u1.str);
if (!macro_def) {
#ifdef STANDALONE
struct pbx_find_info pfiq = {.stacklen = 0 };
struct pbx_find_info pfiq2 = {.stacklen = 0 };
/* look for the macro in the extensions.conf world */
pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH);
if (pfiq.status != STATUS_SUCCESS) {
char namebuf2[256];
snprintf(namebuf2, 256, "macro-%s", item->u1.str);
/* look for the macro in the extensions.conf world */
pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH);
if (pfiq2.status == STATUS_SUCCESS) {
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",
item->filename, item->startline, item->endline, item->u1.str, item->u1.str);
warns++;
} else {
ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (Not even in the extensions.conf stuff!)\n",
item->filename, item->startline, item->endline, item->u1.str);
warns++;
}
}
#else
ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n",
item->filename, item->startline, item->endline, item->u1.str);
warns++;
#endif
#ifdef THIS_IS_1DOT4
char namebuf2[256];
snprintf(namebuf2, 256, "macro-%s", item->u1.str);
/* look for the macro in the extensions.conf world */
pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH);
if (pfiq.status != STATUS_SUCCESS) {
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",
item->filename, item->startline, item->endline, item->u1.str);
warns++;
}
#endif
} else if (macro_def->type != PV_MACRO) {
ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n",
item->filename, item->startline, item->endline, item->u1.str);
errs++;
} else {
/* macro_def is a MACRO, so do the args match in number? */
int hereargs = 0;
int thereargs = 0;
for (lp=item->u2.arglist; lp; lp=lp->next) {
hereargs++;
}
for (lp=macro_def->u2.arglist; lp; lp=lp->next) {
thereargs++;
}
if (hereargs != thereargs ) {
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",
item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs);
errs++;
}
}
break;
case PV_APPLICATION_CALL:
/* fields: item->u1.str == name of application to call
item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
item->u2.arglist->u1.str == argument
item->u2.arglist->next == next arg
*/
/* Need to check to see if the application is available! */
app_def = find_context(item->u1.str);
if (app_def && app_def->type == PV_MACRO) {
ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n",
item->filename, item->startline, item->endline, item->u1.str);
errs++;
}
if (strcasecmp(item->u1.str,"GotoIf") == 0
|| strcasecmp(item->u1.str,"GotoIfTime") == 0
|| strcasecmp(item->u1.str,"while") == 0
|| strcasecmp(item->u1.str,"endwhile") == 0
|| strcasecmp(item->u1.str,"random") == 0
|| strcasecmp(item->u1.str,"gosub") == 0
|| strcasecmp(item->u1.str,"gosubif") == 0
|| strcasecmp(item->u1.str,"continuewhile") == 0
|| strcasecmp(item->u1.str,"endwhile") == 0
|| strcasecmp(item->u1.str,"execif") == 0
|| strcasecmp(item->u1.str,"execiftime") == 0
|| strcasecmp(item->u1.str,"exitwhile") == 0
|| strcasecmp(item->u1.str,"goto") == 0
|| strcasecmp(item->u1.str,"macro") == 0
|| strcasecmp(item->u1.str,"macroexclusive") == 0
|| strcasecmp(item->u1.str,"macroif") == 0
|| strcasecmp(item->u1.str,"stackpop") == 0
|| strcasecmp(item->u1.str,"execIf") == 0 ) {
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",
item->filename, item->startline, item->endline, item->u1.str);
warns++;
}
if (strcasecmp(item->u1.str,"macroexit") == 0) {
ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: I am converting the MacroExit call here to a return statement.\n",
item->filename, item->startline, item->endline);
item->type = PV_RETURN;
free(item->u1.str);
item->u1.str = 0;
}
#ifdef AAL_ARGCHECK
found = 0;
for (app=apps; app; app=app->next) {
if (strcasecmp(app->name, item->u1.str) == 0) {
found =app;
break;
}
}
if (!found) {
ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n",
item->filename, item->startline, item->endline, item->u1.str);
warns++;
} else
check_app_args(item, item->u2.arglist, app);
#endif
break;
case PV_CASE:
/* fields: item->u1.str == value of case
item->u2.statements == pval list of statements under the case
*/
/* Make sure sequence of statements under case is terminated with goto, return, or break */
/* find the last statement */
check_pval(item->u2.statements, apps,in_globals);
break;
case PV_PATTERN:
/* fields: item->u1.str == value of case
item->u2.statements == pval list of statements under the case
*/
/* Make sure sequence of statements under case is terminated with goto, return, or break */
/* find the last statement */
check_pval(item->u2.statements, apps,in_globals);
break;
case PV_DEFAULT:
/* fields:
item->u2.statements == pval list of statements under the case
*/
check_pval(item->u2.statements, apps,in_globals);
break;
case PV_CATCH:
/* fields: item->u1.str == name of extension to catch
item->u2.statements == pval list of statements in context body
*/
check_pval(item->u2.statements, apps,in_globals);
break;
case PV_SWITCHES:
/* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
*/
check_pval(item->u1.list, apps,in_globals);
break;
case PV_ESWITCHES:
/* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
*/
check_pval(item->u1.list, apps,in_globals);
break;
case PV_INCLUDES:
/* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
*/
check_pval(item->u1.list, apps,in_globals);
check_includes(item);
for (lp=item->u1.list; lp; lp=lp->next){
char *incl_context = lp->u1.str;
struct pval *that_context = find_context(incl_context);
if ( lp->u2.arglist ) {
check_timerange(lp->u2.arglist);
check_dow(lp->u2.arglist->next);
check_day(lp->u2.arglist->next->next);
check_month(lp->u2.arglist->next->next->next);
}
if (that_context) {
find_pval_gotos(that_context->u2.statements,0);
}
}
break;
case PV_STATEMENTBLOCK:
/* fields: item->u1.list == pval list of statements in block, one per entry in the list
*/
check_pval(item->u1.list, apps,in_globals);
break;
case PV_VARDEC:
/* fields: item->u1.str == variable name
item->u2.val == variable value to assign
*/
/* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
if( !in_globals ) { /* don't check stuff inside the globals context; no wrapping in $[ ] there... */
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);
ast_expr_register_extra_error_info(errmsg);
ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
ast_expr_clear_extra_error_info();
if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
item->filename, item->startline, item->endline, item->u2.val);
warns++;
}
check_expr2_input(item,item->u2.val);
}
break;
case PV_LOCALVARDEC:
/* fields: item->u1.str == variable name
item->u2.val == variable value to assign
*/
/* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
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);
ast_expr_register_extra_error_info(errmsg);
ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
ast_expr_clear_extra_error_info();
if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
item->filename, item->startline, item->endline, item->u2.val);
warns++;
}
check_expr2_input(item,item->u2.val);
break;
case PV_GOTO:
/* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
item->u1.list->u1.str == where the data on a PV_WORD will always be.
*/
/* don't check goto's in abstract contexts */
if ( in_abstract_context )
break;
check_goto(item);
break;
case PV_LABEL:
/* fields: item->u1.str == label name
*/
if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) {
ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n",
item->filename, item->startline, item->endline, item->u1.str);
warns++;
}
check_label(item);
break;
case PV_FOR:
/* fields: item->u1.for_init == a string containing the initalizer
item->u2.for_test == a string containing the loop test
item->u3.for_inc == a string containing the loop increment
item->u4.for_statements == a pval list of statements in the for ()
*/
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);
ast_expr_register_extra_error_info(errmsg);
strp = strchr(item->u1.for_init, '=');
if (strp) {
ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
}
ast_expr(item->u2.for_test, expr_output, sizeof(expr_output),NULL);
strp = strchr(item->u3.for_inc, '=');
if (strp) {
ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
}
if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) {
ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
item->filename, item->startline, item->endline, item->u2.for_test);
warns++;
}
if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) {
ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
item->filename, item->startline, item->endline, item->u3.for_inc);
warns++;
}
check_expr2_input(item,item->u2.for_test);
check_expr2_input(item,item->u3.for_inc);
ast_expr_clear_extra_error_info();
check_pval(item->u4.for_statements, apps,in_globals);
break;
case PV_WHILE:
/* fields: item->u1.str == the while conditional, as supplied by user
item->u2.statements == a pval list of statements in the while ()
*/
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);
ast_expr_register_extra_error_info(errmsg);
ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
ast_expr_clear_extra_error_info();
if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
item->filename, item->startline, item->endline, item->u1.str);
warns++;
}
check_expr2_input(item,item->u1.str);
check_pval(item->u2.statements, apps,in_globals);
break;
case PV_BREAK:
/* fields: none
*/
check_break(item);
break;
case PV_RETURN:
/* fields: none
*/
break;
case PV_CONTINUE:
/* fields: none
*/
check_continue(item);
break;
case PV_RANDOM:
/* fields: item->u1.str == the random number expression, as supplied by user
item->u2.statements == a pval list of statements in the if ()
item->u3.else_statements == a pval list of statements in the else
(could be zero)
*/
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);
ast_expr_register_extra_error_info(errmsg);
ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
ast_expr_clear_extra_error_info();
if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n",
item->filename, item->startline, item->endline, item->u1.str);
warns++;
}
check_expr2_input(item,item->u1.str);
check_pval(item->u2.statements, apps,in_globals);
if (item->u3.else_statements) {
check_pval(item->u3.else_statements, apps,in_globals);
}
break;
case PV_IFTIME:
/* fields: item->u1.list == the if time values, 4 of them, each in PV_WORD, linked list
item->u2.statements == a pval list of statements in the if ()
item->u3.else_statements == a pval list of statements in the else
(could be zero)
*/
if ( item->u2.arglist ) {
check_timerange(item->u1.list);
check_dow(item->u1.list->next);
check_day(item->u1.list->next->next);
check_month(item->u1.list->next->next->next);
}
check_pval(item->u2.statements, apps,in_globals);
if (item->u3.else_statements) {
check_pval(item->u3.else_statements, apps,in_globals);
}
break;
case PV_IF:
/* fields: item->u1.str == the if conditional, as supplied by user
item->u2.statements == a pval list of statements in the if ()
item->u3.else_statements == a pval list of statements in the else
(could be zero)
*/
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);
ast_expr_register_extra_error_info(errmsg);
ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
ast_expr_clear_extra_error_info();
if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n",
item->filename, item->startline, item->endline, item->u1.str);
warns++;
}
check_expr2_input(item,item->u1.str);
check_pval(item->u2.statements, apps,in_globals);
if (item->u3.else_statements) {
check_pval(item->u3.else_statements, apps,in_globals);
}
break;
case PV_SWITCH:
/* fields: item->u1.str == the switch expression
item->u2.statements == a pval list of statements in the switch,
(will be case statements, most likely!)
*/
/* we can check the switch expression, see if it matches any of the app variables...
if it does, then, are all the possible cases accounted for? */
check_switch_expr(item, apps);
check_pval(item->u2.statements, apps,in_globals);
break;
case PV_EXTENSION:
/* fields: item->u1.str == the extension name, label, whatever it's called
item->u2.statements == a pval list of statements in the extension
item->u3.hints == a char * hint argument
item->u4.regexten == an int boolean. non-zero says that regexten was specified
*/
current_extension = item ;
check_pval(item->u2.statements, apps,in_globals);
break;
case PV_IGNOREPAT:
/* fields: item->u1.str == the ignorepat data
*/
break;
case PV_GLOBALS:
/* fields: item->u1.statements == pval list of statements, usually vardecs
*/
in_abstract_context = 0;
check_pval(item->u1.statements, apps, 1);
break;
default:
break;
}
}
Definition at line 2181 of file pval.c.
References ast_log(), ast_strdupa, calloc, pval::endcol, pval::endline, pval::filename, LOG_WARNING, pval::next, argapp::next, PV_APPLICATION_CALL, PV_CASE, PV_DEFAULT, PV_PATTERN, PV_STATEMENTBLOCK, pval::startcol, pval::startline, pval::statements, pval::str, strdup, pval::type, pval::u1, and pval::u2.
{
#ifdef AAL_ARGCHECK
/* get and clean the variable name */
char *buff1, *p;
struct argapp *a,*a2;
struct appsetvar *v,*v2;
struct argchoice *c;
pval *t;
p = item->u1.str;
while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) )
p++;
buff1 = ast_strdupa(p);
while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t'))
buff1[strlen(buff1)-1] = 0;
/* buff1 now contains the variable name */
v = 0;
for (a=apps; a; a=a->next) {
for (v=a->setvars;v;v=v->next) {
if (strcmp(v->name,buff1) == 0) {
break;
}
}
if ( v )
break;
}
if (v && v->vals) {
/* we have a match, to a variable that has a set of determined values */
int def= 0;
int pat = 0;
int f1 = 0;
/* first of all, does this switch have a default case ? */
for (t=item->u2.statements; t; t=t->next) {
if (t->type == PV_DEFAULT) {
def =1;
break;
}
if (t->type == PV_PATTERN) {
pat++;
}
}
if (def || pat) /* nothing to check. All cases accounted for! */
return;
for (c=v->vals; c; c=c->next) {
f1 = 0;
for (t=item->u2.statements; t; t=t->next) {
if (t->type == PV_CASE || t->type == PV_PATTERN) {
if (!strcmp(t->u1.str,c->name)) {
f1 = 1;
break;
}
}
}
if (!f1) {
ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n",
item->filename, item->startline, item->endline, item->u1.str, c->name);
warns++;
}
}
/* next, is there an app call in the current exten, that would set this var? */
f1 = 0;
t = current_extension->u2.statements;
if ( t && t->type == PV_STATEMENTBLOCK )
t = t->u1.statements;
for (; t && t != item; t=t->next) {
if (t->type == PV_APPLICATION_CALL) {
/* find the application that matches the u1.str */
for (a2=apps; a2; a2=a2->next) {
if (strcasecmp(a2->name, t->u1.str)==0) {
for (v2=a2->setvars; v2; v2=v2->next) {
if (strcmp(v2->name, buff1) == 0) {
/* found an app that sets the var */
f1 = 1;
break;
}
}
}
if (f1)
break;
}
}
if (f1)
break;
}
/* see if it sets the var */
if (!f1) {
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",
item->filename, item->startline, item->endline, item->u1.str);
warns++;
}
}
#else
pval *t,*tl=0,*p2;
int def= 0;
/* first of all, does this switch have a default case ? */
for (t=item->u2.statements; t; t=t->next) {
if (t->type == PV_DEFAULT) {
def =1;
break;
}
tl = t;
}
if (def) /* nothing to check. All cases accounted for! */
return;
/* if no default, warn and insert a default case at the end */
p2 = tl->next = calloc(1, sizeof(struct pval));
p2->type = PV_DEFAULT;
p2->startline = tl->startline;
p2->endline = tl->endline;
p2->startcol = tl->startcol;
p2->endcol = tl->endcol;
p2->filename = strdup(tl->filename);
ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n",
p2->filename, p2->startline, p2->endline);
warns++;
#endif
}
| void destroy_extensions | ( | struct ael_extension * | exten | ) |
Definition at line 2975 of file pval.c.
References ael_priority::app, ael_priority::appargs, free, ael_priority::goto_false, ael_priority::goto_true, ael_extension::hints, ael_extension::loop_break, ael_extension::loop_continue, ael_extension::name, ael_priority::next, ael_extension::next_exten, ael_priority::origin, ael_extension::plist, and ael_extension::plist_last.
{
struct ael_extension *ne, *nen;
for (ne=exten; ne; ne=nen) {
struct ael_priority *pe, *pen;
if (ne->name)
free(ne->name);
/* cidmatch fields are allocated with name, and freed when
the name field is freed. Don't do a free for this field,
unless you LIKE to see a crash! */
if (ne->hints)
free(ne->hints);
for (pe=ne->plist; pe; pe=pen) {
pen = pe->next;
if (pe->app)
free(pe->app);
pe->app = 0;
if (pe->appargs)
free(pe->appargs);
pe->appargs = 0;
pe->origin = 0;
pe->goto_true = 0;
pe->goto_false = 0;
free(pe);
}
nen = ne->next_exten;
ne->next_exten = 0;
ne->plist =0;
ne->plist_last = 0;
ne->next_exten = 0;
ne->loop_break = 0;
ne->loop_continue = 0;
free(ne);
}
}
| void destroy_pval | ( | pval * | item | ) |
Definition at line 4890 of file pval.c.
References destroy_pval_item(), and pval::next.
{
pval *i,*nxt;
for (i=item; i; i=nxt) {
nxt = i->next;
destroy_pval_item(i);
}
}
| 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.
{
if (item == NULL) {
ast_log(LOG_WARNING, "null item\n");
return;
}
if (item->filename)
free(item->filename);
switch (item->type) {
case PV_WORD:
/* fields: item->u1.str == string associated with this (word). */
if (item->u1.str )
free(item->u1.str);
if ( item->u2.arglist )
destroy_pval(item->u2.arglist);
break;
case PV_MACRO:
/* fields: item->u1.str == name of macro
item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
item->u2.arglist->u1.str == argument
item->u2.arglist->next == next arg
item->u3.macro_statements == pval list of statements in macro body.
*/
destroy_pval(item->u2.arglist);
if (item->u1.str )
free(item->u1.str);
destroy_pval(item->u3.macro_statements);
break;
case PV_CONTEXT:
/* fields: item->u1.str == name of context
item->u2.statements == pval list of statements in context body
item->u3.abstract == int 1 if an abstract keyword were present
*/
if (item->u1.str)
free(item->u1.str);
destroy_pval(item->u2.statements);
break;
case PV_MACRO_CALL:
/* fields: item->u1.str == name of macro to call
item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
item->u2.arglist->u1.str == argument
item->u2.arglist->next == next arg
*/
if (item->u1.str)
free(item->u1.str);
destroy_pval(item->u2.arglist);
break;
case PV_APPLICATION_CALL:
/* fields: item->u1.str == name of application to call
item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
item->u2.arglist->u1.str == argument
item->u2.arglist->next == next arg
*/
if (item->u1.str)
free(item->u1.str);
destroy_pval(item->u2.arglist);
break;
case PV_CASE:
/* fields: item->u1.str == value of case
item->u2.statements == pval list of statements under the case
*/
if (item->u1.str)
free(item->u1.str);
destroy_pval(item->u2.statements);
break;
case PV_PATTERN:
/* fields: item->u1.str == value of case
item->u2.statements == pval list of statements under the case
*/
if (item->u1.str)
free(item->u1.str);
destroy_pval(item->u2.statements);
break;
case PV_DEFAULT:
/* fields:
item->u2.statements == pval list of statements under the case
*/
destroy_pval(item->u2.statements);
break;
case PV_CATCH:
/* fields: item->u1.str == name of extension to catch
item->u2.statements == pval list of statements in context body
*/
if (item->u1.str)
free(item->u1.str);
destroy_pval(item->u2.statements);
break;
case PV_SWITCHES:
/* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
*/
destroy_pval(item->u1.list);
break;
case PV_ESWITCHES:
/* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
*/
destroy_pval(item->u1.list);
break;
case PV_INCLUDES:
/* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
item->u2.arglist == pval list of 4 PV_WORD elements for time values
*/
destroy_pval(item->u1.list);
break;
case PV_STATEMENTBLOCK:
/* fields: item->u1.list == pval list of statements in block, one per entry in the list
*/
destroy_pval(item->u1.list);
break;
case PV_LOCALVARDEC:
case PV_VARDEC:
/* fields: item->u1.str == variable name
item->u2.val == variable value to assign
*/
if (item->u1.str)
free(item->u1.str);
if (item->u2.val)
free(item->u2.val);
break;
case PV_GOTO:
/* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
item->u1.list->u1.str == where the data on a PV_WORD will always be.
*/
destroy_pval(item->u1.list);
break;
case PV_LABEL:
/* fields: item->u1.str == label name
*/
if (item->u1.str)
free(item->u1.str);
break;
case PV_FOR:
/* fields: item->u1.for_init == a string containing the initalizer
item->u2.for_test == a string containing the loop test
item->u3.for_inc == a string containing the loop increment
item->u4.for_statements == a pval list of statements in the for ()
*/
if (item->u1.for_init)
free(item->u1.for_init);
if (item->u2.for_test)
free(item->u2.for_test);
if (item->u3.for_inc)
free(item->u3.for_inc);
destroy_pval(item->u4.for_statements);
break;
case PV_WHILE:
/* fields: item->u1.str == the while conditional, as supplied by user
item->u2.statements == a pval list of statements in the while ()
*/
if (item->u1.str)
free(item->u1.str);
destroy_pval(item->u2.statements);
break;
case PV_BREAK:
/* fields: none
*/
break;
case PV_RETURN:
/* fields: none
*/
break;
case PV_CONTINUE:
/* fields: none
*/
break;
case PV_IFTIME:
/* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list
item->u2.statements == a pval list of statements in the if ()
item->u3.else_statements == a pval list of statements in the else
(could be zero)
*/
destroy_pval(item->u1.list);
destroy_pval(item->u2.statements);
if (item->u3.else_statements) {
destroy_pval(item->u3.else_statements);
}
break;
case PV_RANDOM:
/* fields: item->u1.str == the random percentage, as supplied by user
item->u2.statements == a pval list of statements in the true part ()
item->u3.else_statements == a pval list of statements in the else
(could be zero)
fall thru to If */
case PV_IF:
/* fields: item->u1.str == the if conditional, as supplied by user
item->u2.statements == a pval list of statements in the if ()
item->u3.else_statements == a pval list of statements in the else
(could be zero)
*/
if (item->u1.str)
free(item->u1.str);
destroy_pval(item->u2.statements);
if (item->u3.else_statements) {
destroy_pval(item->u3.else_statements);
}
break;
case PV_SWITCH:
/* fields: item->u1.str == the switch expression
item->u2.statements == a pval list of statements in the switch,
(will be case statements, most likely!)
*/
if (item->u1.str)
free(item->u1.str);
destroy_pval(item->u2.statements);
break;
case PV_EXTENSION:
/* fields: item->u1.str == the extension name, label, whatever it's called
item->u2.statements == a pval list of statements in the extension
item->u3.hints == a char * hint argument
item->u4.regexten == an int boolean. non-zero says that regexten was specified
*/
if (item->u1.str)
free(item->u1.str);
if (item->u3.hints)
free(item->u3.hints);
destroy_pval(item->u2.statements);
break;
case PV_IGNOREPAT:
/* fields: item->u1.str == the ignorepat data
*/
if (item->u1.str)
free(item->u1.str);
break;
case PV_GLOBALS:
/* fields: item->u1.statements == pval list of statements, usually vardecs
*/
destroy_pval(item->u1.statements);
break;
}
free(item);
}
| struct pval* find_context | ( | char * | name | ) | [read] |
Definition at line 1950 of file pval.c.
References match_pval(), and name.
{
return_on_context_match = 1;
count_labels = 0;
match_context = name;
match_exten = "*"; /* don't really need to set these, shouldn't be reached */
match_label = "*";
return match_pval(current_db);
}
| struct pval* find_macro | ( | char * | name | ) | [read] |
Definition at line 1940 of file pval.c.
References match_pval(), and name.
{
return_on_context_match = 1;
count_labels = 0;
match_context = name;
match_exten = "*"; /* don't really need to set these, shouldn't be reached */
match_label = "*";
return match_pval(current_db);
}
| static char* handle_cli_ael_reload | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 199 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.
{
switch (cmd) {
case CLI_INIT:
e->command = "ael reload";
e->usage =
"Usage: ael reload\n"
" Reloads AEL configuration.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 2)
return CLI_SHOWUSAGE;
return (pbx_load_module() ? CLI_FAILURE : CLI_SUCCESS);
}
| static char* handle_cli_ael_set_debug | ( | struct ast_cli_entry * | e, |
| int | cmd, | ||
| struct ast_cli_args * | a | ||
| ) | [static] |
Definition at line 165 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.
{
switch (cmd) {
case CLI_INIT:
e->command = "ael set debug {read|tokens|macros|contexts|off}";
e->usage =
"Usage: ael set debug {read|tokens|macros|contexts|off}\n"
" Enable AEL read, token, macro, or context debugging,\n"
" or disable all AEL debugging messages. Note: this\n"
" currently does nothing.\n";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != e->args)
return CLI_SHOWUSAGE;
if (!strcasecmp(a->argv[3], "read"))
aeldebug |= DEBUG_READ;
else if (!strcasecmp(a->argv[3], "tokens"))
aeldebug |= DEBUG_TOKENS;
else if (!strcasecmp(a->argv[3], "macros"))
aeldebug |= DEBUG_MACROS;
else if (!strcasecmp(a->argv[3], "contexts"))
aeldebug |= DEBUG_CONTEXTS;
else if (!strcasecmp(a->argv[3], "off"))
aeldebug = 0;
else
return CLI_SHOWUSAGE;
return CLI_SUCCESS;
}
| int is_empty | ( | char * | arg | ) |
| int is_float | ( | char * | arg | ) |
| int is_int | ( | char * | arg | ) |
| static int load_module | ( | void | ) | [static] |
Definition at line 230 of file pbx_ael.c.
References ARRAY_LEN, ast_cli_register_multiple(), and pbx_load_module().
{
ast_cli_register_multiple(cli_ael, ARRAY_LEN(cli_ael));
return (pbx_load_module());
}
| struct ael_extension* new_exten | ( | void | ) | [read] |
Definition at line 2927 of file pval.c.
References calloc.
{
struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
return x;
}
| struct ael_priority* new_prio | ( | void | ) | [read] |
Definition at line 2921 of file pval.c.
References calloc.
{
struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
return x;
}
| static int pbx_load_module | ( | void | ) | [static] |
Definition at line 113 of file pbx_ael.c.
References ael2_parse(), ael2_semantic_check(), ast_compile_ael2(), ast_config_AST_CONFIG_DIR, ast_context_verify_includes(), ast_hashtab_compare_contexts(), ast_hashtab_create(), ast_hashtab_hash_contexts(), ast_hashtab_newsize_java(), ast_hashtab_resize_java(), ast_log(), ast_merge_contexts_and_delete(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_walk_contexts(), destroy_pval(), errs, local_contexts, local_table, LOG_ERROR, LOG_NOTICE, and R_OK.
Referenced by handle_cli_ael_reload(), load_module(), and reload().
{
int errs=0, sem_err=0, sem_warn=0, sem_note=0;
char *rfilename;
struct ast_context *local_contexts=NULL, *con;
struct ast_hashtab *local_table=NULL;
struct pval *parse_tree;
ast_log(LOG_NOTICE, "Starting AEL load process.\n");
if (config[0] == '/')
rfilename = (char *)config;
else {
rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
}
if (access(rfilename,R_OK) != 0) {
ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
return AST_MODULE_LOAD_DECLINE;
}
parse_tree = ael2_parse(rfilename, &errs);
ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
if (errs == 0 && sem_err == 0) {
ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
local_table = ast_hashtab_create(11, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
if (ast_compile_ael2(&local_contexts, local_table, parse_tree)) {
ast_log(LOG_ERROR, "AEL compile failed! Aborting.\n");
destroy_pval(parse_tree); /* free up the memory */
return AST_MODULE_LOAD_DECLINE;
}
ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
local_table = NULL; /* it's the dialplan global now */
local_contexts = NULL;
ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
ast_context_verify_includes(con);
ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
} else {
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);
destroy_pval(parse_tree); /* free up the memory */
return AST_MODULE_LOAD_DECLINE;
}
destroy_pval(parse_tree); /* free up the memory */
return AST_MODULE_LOAD_SUCCESS;
}
| static int reload | ( | void | ) | [static] |
Definition at line 236 of file pbx_ael.c.
References pbx_load_module().
{
return pbx_load_module();
}
| void set_priorities | ( | struct ael_extension * | exten | ) |
Definition at line 4215 of file pval.c.
References ael_extension::is_switch, ael_priority::next, ael_extension::next_exten, ael_priority::origin, ael_extension::plist, ael_priority::priority_num, PV_LABEL, ael_extension::regexten, and pval::type.
{
int i;
struct ael_priority *pr;
do {
if (exten->is_switch)
i = 10;
else if (exten->regexten)
i=2;
else
i=1;
for (pr=exten->plist; pr; pr=pr->next) {
pr->priority_num = i;
if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
but we want them to point to the right
priority, which would be the next line
after the label; */
i++;
}
exten = exten->next_exten;
} while ( exten );
}
| static int unload_module | ( | void | ) | [static] |
Definition at line 223 of file pbx_ael.c.
References ARRAY_LEN, ast_cli_unregister_multiple(), and ast_context_destroy().
{
ast_context_destroy(NULL, registrar);
ast_cli_unregister_multiple(cli_ael, ARRAY_LEN(cli_ael));
return 0;
}
struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Asterisk Extension Language Compiler" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static] |
struct ast_module_info* ast_module_info = &__mod_info [static] |
struct ast_cli_entry cli_ael[] [static] |
{
AST_CLI_DEFINE(handle_cli_ael_reload, "Reload AEL configuration"),
AST_CLI_DEFINE(handle_cli_ael_set_debug, "Enable AEL debugging flags")
}