Asterisk - The Open Source Telephony Project GIT-master-2070bb5
Macros | Functions | Variables
pval.c File Reference

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

#include "asterisk.h"
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.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/channel.h"
#include "asterisk/callerid.h"
#include "asterisk/pval.h"
#include "asterisk/ael_structs.h"
#include "asterisk/utils.h"
Include dependency graph for pval.c:

Go to the source code of this file.

Macros

#define ASTMM_LIBC   ASTMM_REDIRECT
 
#define BUF_SIZE   2000
 

Functions

void add_extensions (struct ael_extension *exten)
 
void ael2_print (char *fname, pval *tree)
 
void ael2_semantic_check (pval *item, int *arg_errs, int *arg_warns, int *arg_notes)
 
int ast_compile_ael2 (struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root)
 
static void attach_exten (struct ael_extension **list, struct ael_extension *newmem)
 
static void check_abstract_reference (pval *abstract_context)
 
int check_app_args (pval *appcall, pval *arglist, struct argapp *app)
 
static int check_break (pval *item)
 
static void check_context_names (void)
 
static int check_continue (pval *item)
 
static void check_day (pval *DAY)
 
static void check_dow (pval *DOW)
 get_dow: Get day of week More...
 
static void check_expr2_input (pval *expr, char *str)
 
static void check_goto (pval *item)
 
static void check_includes (pval *includes)
 
static void check_label (pval *item)
 
static void check_macro_returns (pval *macro)
 
static void check_month (pval *MON)
 
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)
 
static void check_timerange (pval *p)
 
int contains_switch (pval *item)
 
static int context_used (struct ael_extension *exten_list, struct ast_context *context)
 
void destroy_extensions (struct ael_extension *exten)
 
void destroy_pval (pval *item)
 
void destroy_pval_item (pval *item)
 
static int extension_matches (pval *here, const char *exten, const char *pattern)
 
struct pvalfind_context (char *name)
 
static struct pvalfind_first_label_in_current_context (char *label, pval *curr_cont)
 
static struct pvalfind_label_in_current_context (char *exten, char *label, pval *curr_cont)
 
static struct pvalfind_label_in_current_db (const char *context, const char *exten, const char *label)
 
static struct pvalfind_label_in_current_extension (const char *label, pval *curr_ext)
 
struct pvalfind_macro (char *name)
 
static void find_pval_goto_item (pval *item, int lev)
 
static void find_pval_gotos (pval *item, int lev)
 
int find_switch_item (pval *item)
 
static void fix_gotos_in_extensions (struct ael_extension *exten)
 
static void gen_match_to_pattern (char *pattern, char *result)
 
static int gen_prios (struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *this_context)
 
static pvalget_contxt (pval *p)
 
static pvalget_extension_or_contxt (pval *p)
 
static pvalget_goto_target (pval *item)
 
static struct pvalin_context (pval *item)
 
static struct pvalin_macro (pval *item)
 
int is_empty (char *arg)
 
int is_float (char *arg)
 
int is_int (char *arg)
 
static int label_inside_case (pval *label)
 
static void linkexten (struct ael_extension *exten, struct ael_extension *add)
 
void linkprio (struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
 
pvallinku1 (pval *head, pval *tail)
 
int localized_pbx_load_module (void)
 
struct pvalmatch_pval (pval *item)
 
static struct pvalmatch_pval_item (pval *item)
 
struct ael_extensionnew_exten (void)
 
struct ael_prioritynew_prio (void)
 
static void print_pval (FILE *fin, pval *item, int depth)
 
static void print_pval_list (FILE *fin, pval *item, int depth)
 
void pvalAppCallAddArg (pval *p, pval *arg)
 
char * pvalAppCallGetAppName (pval *p)
 
void pvalAppCallSetAppName (pval *p, char *name)
 
void pvalAppCallSetArglist (pval *p, pval *arglist)
 
pvalpvalAppCallWalkArgs (pval *p, pval **args)
 
void pvalCasePatDefAddStatement (pval *p, pval *statement)
 
pvalpvalCasePatDefWalkStatements (pval *p, pval **statement)
 
char * pvalCasePatGetVal (pval *p)
 
void pvalCasePatSetVal (pval *p, char *val)
 
char * pvalCatchGetExtName (pval *p)
 
pvalpvalCatchGetStatement (pval *p)
 
void pvalCatchSetExtName (pval *p, char *name)
 
void pvalCatchSetStatement (pval *p, pval *statement)
 
int pvalCheckType (pval *p, char *funcname, pvaltype type)
 
pvalpvalConditionalGetElseStatement (pval *p)
 
pvalpvalConditionalGetThenStatement (pval *p)
 
void pvalConditionalSetElseStatement (pval *p, pval *statement)
 
void pvalConditionalSetThenStatement (pval *p, pval *statement)
 
void pvalContextAddStatement (pval *p, pval *statement)
 
int pvalContextGetAbstract (pval *p)
 
char * pvalContextGetName (pval *p)
 
void pvalContextSetAbstract (pval *p)
 
void pvalContextSetName (pval *p, char *name)
 
void pvalContextUnsetAbstract (pval *p)
 
pvalpvalContextWalkStatements (pval *p, pval **statements)
 
pvalpvalCreateNode (pvaltype type)
 
void pvalESwitchesAddSwitch (pval *p, char *name)
 
char * pvalESwitchesWalkNames (pval *p, pval **next_item)
 
char * pvalExtenGetHints (pval *p)
 
char * pvalExtenGetName (pval *p)
 
int pvalExtenGetRegexten (pval *p)
 
pvalpvalExtenGetStatement (pval *p)
 
void pvalExtenSetHints (pval *p, char *hints)
 
void pvalExtenSetName (pval *p, char *name)
 
void pvalExtenSetRegexten (pval *p)
 
void pvalExtenSetStatement (pval *p, pval *statement)
 
void pvalExtenUnSetRegexten (pval *p)
 
char * pvalForGetInc (pval *p)
 
char * pvalForGetInit (pval *p)
 
pvalpvalForGetStatement (pval *p)
 
char * pvalForGetTest (pval *p)
 
void pvalForSetInc (pval *p, char *inc)
 
void pvalForSetInit (pval *p, char *init)
 
void pvalForSetStatement (pval *p, pval *statement)
 
void pvalForSetTest (pval *p, char *test)
 
void pvalGlobalsAddStatement (pval *p, pval *statement)
 
pvalpvalGlobalsWalkStatements (pval *p, pval **next_statement)
 
void pvalGotoGetTarget (pval *p, char **context, char **exten, char **label)
 
void pvalGotoSetTarget (pval *p, char *context, char *exten, char *label)
 
char * pvalIfGetCondition (pval *p)
 
void pvalIfSetCondition (pval *p, char *expr)
 
void pvalIfTimeGetCondition (pval *p, char **hour_range, char **dow_range, char **dom_range, char **month_range)
 
void pvalIfTimeSetCondition (pval *p, char *hour_range, char *dow_range, char *dom_range, char *mon_range)
 
char * pvalIgnorePatGetPattern (pval *p)
 
void pvalIgnorePatSetPattern (pval *p, char *pat)
 
void pvalIncludeGetTimeConstraints (pval *p, char **hour_range, char **dom_range, char **dow_range, char **month_range)
 
void pvalIncludesAddInclude (pval *p, const char *include)
 
void pvalIncludesAddIncludeWithTimeConstraints (pval *p, const char *include, char *hour_range, char *dom_range, char *dow_range, char *month_range)
 
char * pvalIncludesWalk (pval *p, pval **next_item)
 
char * pvalLabelGetName (pval *p)
 
void pvalLabelSetName (pval *p, char *name)
 
void pvalMacroAddArg (pval *p, pval *arg)
 
void pvalMacroAddStatement (pval *p, pval *statement)
 
void pvalMacroCallAddArg (pval *p, pval *arg)
 
char * pvalMacroCallGetMacroName (pval *p)
 
void pvalMacroCallSetArglist (pval *p, pval *arglist)
 
void pvalMacroCallSetMacroName (pval *p, char *name)
 
pvalpvalMacroCallWalkArgs (pval *p, pval **args)
 
char * pvalMacroGetName (pval *p)
 
void pvalMacroSetArglist (pval *p, pval *arglist)
 
void pvalMacroSetName (pval *p, char *name)
 
pvalpvalMacroWalkArgs (pval *p, pval **arg)
 
pvalpvalMacroWalkStatements (pval *p, pval **next_statement)
 
pvaltype pvalObjectGetType (pval *p)
 
char * pvalRandomGetCondition (pval *p)
 
void pvalRandomSetCondition (pval *p, char *percent)
 
void pvalStatementBlockAddStatement (pval *p, pval *statement)
 
pvalpvalStatementBlockWalkStatements (pval *p, pval **next_statement)
 
void pvalSwitchAddCase (pval *p, pval *Case)
 
void pvalSwitchesAddSwitch (pval *p, char *name)
 
char * pvalSwitchesWalkNames (pval *p, pval **next_item)
 
char * pvalSwitchGetTestexpr (pval *p)
 
void pvalSwitchSetTestexpr (pval *p, char *expr)
 
pvalpvalSwitchWalkCases (pval *p, pval **next_case)
 
void pvalTopLevAddObject (pval *p, pval *contextOrObj)
 
pvalpvalTopLevWalkObjects (pval *p, pval **next_obj)
 
char * pvalVarDecGetValue (pval *p)
 
char * pvalVarDecGetVarname (pval *p)
 
void pvalVarDecSetValue (pval *p, char *value)
 
void pvalVarDecSetVarname (pval *p, char *name)
 
char * pvalWordGetString (pval *p)
 
void pvalWordSetString (pval *p, char *str)
 
static void remove_spaces_before_equals (char *str)
 
void set_priorities (struct ael_extension *exten)
 
void traverse_pval_item_template (pval *item, int depth)
 
void traverse_pval_template (pval *item, int depth)
 

Variables

static int control_statement_count
 
static int count_labels
 
static pvalcurrent_context
 
static pvalcurrent_db
 
static pvalcurrent_extension
 
static char * days []
 
static int errs
 
static char expr_output [2096]
 
static int in_abstract_context
 
static int label_count
 
static pvallast_matched_label
 
static const char * match_context
 
static const char * match_exten
 
static const char * match_label
 
static char * months []
 
static int notes
 
static char * registrar = "pbx_ael"
 
static int return_on_context_match
 
static int warns
 

Detailed Description

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

Definition in file pval.c.

Macro Definition Documentation

◆ ASTMM_LIBC

#define ASTMM_LIBC   ASTMM_REDIRECT

Definition at line 30 of file pval.c.

◆ BUF_SIZE

#define BUF_SIZE   2000

Definition at line 61 of file pval.c.

Function Documentation

◆ 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

References AEL_APPCALL, AEL_CONTROL1, AEL_FOR_CONTROL, AEL_IF_CONTROL, AEL_IFTIME_CONTROL, AEL_LABEL, AEL_RAND_CONTROL, AEL_RETURN, app, ael_priority::app, ael_priority::appargs, ast_add_extension2(), ast_free_ptr(), ast_log, AST_MAX_EXTENSION, 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, NULL, ael_priority::origin, pbx_substitute_variables_helper(), ael_extension::plist, PRIORITY_HINT, ael_priority::priority_num, PV_IFTIME, PV_SWITCH, registrar, strdup, ael_priority::type, pval::type, and pval::u3.

Referenced by ast_compile_ael2().

◆ ael2_print()

void ael2_print ( char *  fname,
pval tree 
)

Definition at line 382 of file pval.c.

383{
384 FILE *fin = fopen(fname,"w");
385 if ( !fin ) {
386 ast_log(LOG_ERROR, "Couldn't open %s for writing.\n", fname);
387 return;
388 }
389 print_pval_list(fin, tree, 0);
390 fclose(fin);
391}
#define LOG_ERROR
static void print_pval_list(FILE *fin, pval *item, int depth)
Definition: pval.c:373

References ast_log, LOG_ERROR, and print_pval_list().

◆ ael2_semantic_check()

void ael2_semantic_check ( pval item,
int *  arg_errs,
int *  arg_warns,
int *  arg_notes 
)

Definition at line 2885 of file pval.c.

2886{
2887
2888#ifdef AAL_ARGCHECK
2889 int argapp_errs =0;
2890 char *rfilename;
2891#endif
2892 struct argapp *apps=0;
2893
2894 if (!item)
2895 return; /* don't check an empty tree */
2896#ifdef AAL_ARGCHECK
2897 rfilename = ast_alloca(10 + strlen(ast_config_AST_VAR_DIR));
2898 sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR);
2899
2900 apps = argdesc_parse(rfilename, &argapp_errs); /* giveth */
2901#endif
2902 current_db = item;
2903 errs = warns = notes = 0;
2904
2906 check_pval(item, apps, 0);
2907
2908#ifdef AAL_ARGCHECK
2909 argdesc_destroy(apps); /* taketh away */
2910#endif
2911 current_db = 0;
2912
2913 *arg_errs = errs;
2914 *arg_warns = warns;
2915 *arg_notes = notes;
2916}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
const char * ast_config_AST_VAR_DIR
Definition: options.c:157
static pval * current_db
Definition: pval.c:72
static int notes
Definition: pval.c:66
static int warns
Definition: pval.c:65
static int errs
Definition: pval.c:65
void check_pval(pval *item, struct argapp *apps, int in_globals)
Definition: pval.c:2865
static void check_context_names(void)
Definition: pval.c:2310
Registered applications container.
Definition: pbx_app.c:67
Definition: pval.h:111
static struct aco_type item
Definition: test_config.c:1463

References ast_alloca, ast_config_AST_VAR_DIR, check_context_names(), check_pval(), current_db, errs, item, notes, and warns.

Referenced by pbx_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
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
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

References add_extensions(), AEL_APPCALL, AEL_LABEL, app, ael_priority::app, ael_priority::appargs, pval::arglist, ARRAY_LEN, ast_context_add_ignorepat2(), ast_context_add_include2(), ast_context_add_switch2(), ast_context_find_or_create(), ast_custom_function_find(), ast_get_context_name(), attach_exten(), buf, buf2, c, ael_extension::cidmatch, voicemailpwcheck::context, ael_extension::context, context_used(), control_statement_count, destroy_extensions(), ael_priority::exten, fix_gotos_in_extensions(), gen_prios(), ael_extension::hints, pval::hints, linkprio(), pval::list, local_contexts, local_table, pval::macro_statements, ael_extension::name, new_exten(), new_prio(), pval::next, ael_extension::next_exten, NULL, ael_priority::origin, pbx_builtin_setvar(), ael_extension::plist_last, priority, ael_priority::priority_num, PV_CONTEXT, PV_ESWITCHES, PV_EXTENSION, PV_GLOBALS, PV_IGNOREPAT, PV_INCLUDES, PV_MACRO, PV_SWITCHES, ael_extension::regexten, pval::regexten, registrar, 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.

Referenced by pbx_load_module().

◆ attach_exten()

static void attach_exten ( struct ael_extension **  list,
struct ael_extension newmem 
)
static

Definition at line 4318 of file pval.c.

4319{
4320 /* travel to the end of the list... */
4321 struct ael_extension *lptr;
4322 if( !*list ) {
4323 *list = newmem;
4324 return;
4325 }
4326 lptr = *list;
4327
4328 while( lptr->next_exten ) {
4329 lptr = lptr->next_exten;
4330 }
4331 /* lptr should now pointing to the last element in the list; it has a null next_exten pointer */
4332 lptr->next_exten = newmem;
4333}

References ael_extension::next_exten.

Referenced by ast_compile_ael2().

◆ check_abstract_reference()

static void check_abstract_reference ( pval abstract_context)
static

Definition at line 2329 of file pval.c.

2330{
2331 pval *i,*j;
2332 /* find some context includes that reference this context */
2333
2334
2335 /* otherwise, print out a warning */
2336 for (i=current_db; i; i=i->next) {
2337 if (i->type == PV_CONTEXT) {
2338 for (j=i->u2. statements; j; j=j->next) {
2339 if ( j->type == PV_INCLUDES ) {
2340 struct pval *p4;
2341 for (p4=j->u1.list; p4; p4=p4->next) {
2342 /* for each context pointed to, find it, then find a context/label that matches the
2343 target here! */
2344 if ( !strcmp(p4->u1.str, abstract_context->u1.str) )
2345 return; /* found a match! */
2346 }
2347 }
2348 }
2349 }
2350 }
2351 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: Couldn't find a reference to this abstract context (%s) in any other context!\n",
2352 abstract_context->filename, abstract_context->startline, abstract_context->endline, abstract_context->u1.str);
2353 warns++;
2354}
int endline
Definition: pval.h:52
char * filename
Definition: pval.h:55
int startline
Definition: pval.h:51

References ast_log, current_db, pval::endline, pval::filename, pval::list, LOG_WARNING, pval::next, PV_CONTEXT, PV_INCLUDES, pval::startline, pval::str, pval::type, pval::u1, pval::u2, and warns.

Referenced by check_pval_item().

◆ 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}

References app, ast_log, pval::endline, pval::filename, LOG_WARNING, pval::next, pval::startline, pval::str, pval::u1, and warns.

Referenced by check_pval_item().

◆ check_break()

static int check_break ( pval item)
static

Definition at line 1038 of file pval.c.

1039{
1040 pval *p = item;
1041
1042 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
1043 /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make
1044 no sense */
1045 if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN
1046 || p->type == PV_WHILE || p->type == PV_FOR ) {
1047 return 1;
1048 }
1049 p = p->dad;
1050 }
1051 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'break' not in switch, for, or while statement!\n",
1052 item->filename, item->startline, item->endline);
1053 errs++;
1054
1055 return 0;
1056}
@ PV_DEFAULT
Definition: pval.h:15
@ PV_CASE
Definition: pval.h:13
@ PV_PATTERN
Definition: pval.h:14
@ PV_FOR
Definition: pval.h:24
@ PV_WHILE
Definition: pval.h:25
struct pval * dad
Definition: pval.h:96

References ast_log, pval::dad, errs, item, LOG_ERROR, PV_CASE, PV_CONTEXT, PV_DEFAULT, PV_FOR, PV_MACRO, PV_PATTERN, PV_WHILE, and pval::type.

Referenced by check_pval_item().

◆ check_context_names()

static void check_context_names ( void  )
static

Definition at line 2310 of file pval.c.

2311{
2312 pval *i,*j;
2313 for (i=current_db; i; i=i->next) {
2314 if (i->type == PV_CONTEXT || i->type == PV_MACRO) {
2315 for (j=i->next; j; j=j->next) {
2316 if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) {
2317 if ( !strcmp(i->u1.str, j->u1.str) && !(i->u3.abstract&2) && !(j->u3.abstract&2) )
2318 {
2319 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: The context name (%s) is also declared in file %s, line %d-%d! (and neither is marked 'extend')\n",
2320 i->filename, i->startline, i->endline, i->u1.str, j->filename, j->startline, j->endline);
2321 warns++;
2322 }
2323 }
2324 }
2325 }
2326 }
2327}
int abstract
Definition: pval.h:80

References pval::abstract, ast_log, current_db, pval::endline, pval::filename, LOG_WARNING, pval::next, PV_CONTEXT, PV_MACRO, pval::startline, pval::str, pval::type, pval::u1, pval::u3, and warns.

Referenced by ael2_semantic_check().

◆ check_continue()

static int check_continue ( pval item)
static

Definition at line 1058 of file pval.c.

1059{
1060 pval *p = item;
1061
1062 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
1063 /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make
1064 no sense */
1065 if( p->type == PV_WHILE || p->type == PV_FOR ) {
1066 return 1;
1067 }
1068 p = p->dad;
1069 }
1070 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'continue' not in 'for' or 'while' statement!\n",
1071 item->filename, item->startline, item->endline);
1072 errs++;
1073
1074 return 0;
1075}

References ast_log, pval::dad, errs, item, LOG_ERROR, PV_CONTEXT, PV_FOR, PV_MACRO, PV_WHILE, and pval::type.

Referenced by check_pval_item().

◆ check_day()

static void check_day ( pval DAY)
static

Definition at line 937 of file pval.c.

938{
939 char *day;
940 char *c;
941 /* The following line is coincidence, really! */
942 int s, e;
943
944 day = ast_strdupa(DAY->u1.str);
945
946 /* Check for all days */
947 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
948 return;
949 }
950 /* Get start and ending days */
951 c = strchr(day, '-');
952 if (c) {
953 *c = '\0';
954 c++;
955 }
956 /* Find the start */
957 if (sscanf(day, "%2d", &s) != 1) {
958 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number!\n",
959 DAY->filename, DAY->startline, DAY->endline, day);
960 warns++;
961 }
962 else if ((s < 1) || (s > 31)) {
963 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number in the range [1-31]!\n",
964 DAY->filename, DAY->startline, DAY->endline, day);
965 warns++;
966 }
967 s--;
968 if (c) {
969 if (sscanf(c, "%2d", &e) != 1) {
970 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number!\n",
971 DAY->filename, DAY->startline, DAY->endline, c);
972 warns++;
973 }
974 else if ((e < 1) || (e > 31)) {
975 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number in the range [1-31]!\n",
976 DAY->filename, DAY->startline, DAY->endline, day);
977 warns++;
978 }
979 e--;
980 } else
981 e = s;
982}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define DAY
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65

References ast_log, ast_strdupa, ast_strlen_zero(), c, DAY, LOG_WARNING, and warns.

Referenced by check_pval_item().

◆ check_dow()

static void check_dow ( pval DOW)
static

get_dow: Get day of week

Definition at line 898 of file pval.c.

899{
900 char *dow;
901 char *c;
902 /* The following line is coincidence, really! */
903 int s, e;
904
905 dow = ast_strdupa(DOW->u1.str);
906
907 /* Check for all days */
908 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
909 return;
910 /* Get start and ending days */
911 c = strchr(dow, '-');
912 if (c) {
913 *c = '\0';
914 c++;
915 } else
916 c = NULL;
917 /* Find the start */
918 s = 0;
919 while ((s < 7) && strcasecmp(dow, days[s])) s++;
920 if (s >= 7) {
921 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n",
922 DOW->filename, DOW->startline, DOW->endline, dow);
923 warns++;
924 }
925 if (c) {
926 e = 0;
927 while ((e < 7) && strcasecmp(c, days[e])) e++;
928 if (e >= 7) {
929 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n",
930 DOW->filename, DOW->startline, DOW->endline, c);
931 warns++;
932 }
933 } else
934 e = s;
935}
static char * days[]
Definition: pval.c:886

References ast_log, ast_strdupa, ast_strlen_zero(), c, days, pval::endline, pval::filename, LOG_WARNING, NULL, pval::startline, pval::str, pval::u1, and warns.

Referenced by check_pval_item().

◆ check_expr2_input()

static void check_expr2_input ( pval expr,
char *  str 
)
static

Definition at line 801 of file pval.c.

802{
803 int spaces = strspn(str,"\t \n");
804 if ( !strncmp(str+spaces,"$[",2) ) {
805 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The expression '%s' is redundantly wrapped in '$[ ]'. \n",
806 expr->filename, expr->startline, expr->endline, str);
807 warns++;
808 }
809}
const char * str
Definition: app_jack.c:147

References ast_log, pval::endline, pval::filename, LOG_WARNING, pval::startline, str, and warns.

Referenced by check_pval_item().

◆ check_goto()

static void check_goto ( pval item)
static

Definition at line 1225 of file pval.c.

1226{
1227 if (!item->u1.list) {
1228 return;
1229 }
1230
1231 /* check for the target of the goto-- does it exist? */
1232 if ( !(item->u1.list)->next && !(item->u1.list)->u1.str ) {
1233 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: empty label reference found!\n",
1234 item->filename, item->startline, item->endline);
1235 errs++;
1236 }
1237
1238 /* just one item-- the label should be in the current extension */
1239 if (!item->u1.list->next && !strstr(item->u1.list->u1.str,"${")) {
1240 struct pval *z = get_extension_or_contxt(item);
1241 struct pval *x = 0;
1242 if (z)
1243 x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), z); /* if in macro, use current context instead */
1244 /* printf("Called find_label_in_current_extension with arg %s; current_extension is %x: %d\n",
1245 (char*)((item->u1.list)->u1.str), current_extension?current_extension:current_context, current_extension?current_extension->type:current_context->type); */
1246 if (!x) {
1247 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s exists in the current extension!\n",
1248 item->filename, item->startline, item->endline, item->u1.list->u1.str);
1249 errs++;
1250 }
1251 else
1252 return;
1253 }
1254
1255 /* TWO items */
1256 if (item->u1.list->next && !item->u1.list->next->next) {
1257 /* two items */
1258 /* printf("Calling find_label_in_current_context with args %s, %s\n",
1259 (char*)((item->u1.list)->u1.str), (char *)item->u1.list->next->u1.str); */
1260 if (!strstr((item->u1.list)->u1.str,"${")
1261 && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ {
1262 struct pval *z = get_contxt(item);
1263 struct pval *x = 0;
1264
1265 if (z)
1266 x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, z);
1267
1268 if (!x) {
1269 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label '%s,%s' exists in the current context, or any of its inclusions!\n",
1270 item->filename, item->startline, item->endline, item->u1.list->u1.str, item->u1.list->next->u1.str );
1271 errs++;
1272 }
1273 else
1274 return;
1275 }
1276 }
1277
1278 /* All 3 items! */
1279 if (item->u1.list->next && item->u1.list->next->next) {
1280 /* all three */
1281 pval *first = item->u1.list;
1282 pval *second = item->u1.list->next;
1283 pval *third = item->u1.list->next->next;
1284
1285 /* printf("Calling find_label_in_current_db with args %s, %s, %s\n",
1286 (char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); */
1287 if (!strstr((item->u1.list)->u1.str,"${")
1288 && !strstr(item->u1.list->next->u1.str,"${")
1289 && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ {
1290 struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
1291 if (!x) {
1292 struct pval *p3;
1293 struct pval *found = 0;
1294 struct pval *that_context = find_context(item->u1.list->u1.str);
1295
1296 /* the target of the goto could be in an included context!! Fancy that!! */
1297 /* look for includes in the current context */
1298 if (that_context) {
1299 for (p3=that_context->u2.statements; p3; p3=p3->next) {
1300 if (p3->type == PV_INCLUDES) {
1301 struct pval *p4;
1302 for (p4=p3->u1.list; p4; p4=p4->next) {
1303 /* for each context pointed to, find it, then find a context/label that matches the
1304 target here! */
1305 char *incl_context = p4->u1.str;
1306 /* find a matching context name */
1307 struct pval *that_other_context = find_context(incl_context);
1308 if (that_other_context) {
1309 struct pval *x3;
1310 x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
1311 if (x3) {
1312 found = x3;
1313 break;
1314 }
1315 }
1316 }
1317 }
1318 }
1319 if (!found) {
1320 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s|%s exists in the context %s or its inclusions!\n",
1321 item->filename, item->startline, item->endline, item->u1.list->next->u1.str, item->u1.list->next->next->u1.str, item->u1.list->u1.str );
1322 errs++;
1323 } else {
1324 struct pval *mac = in_macro(item); /* is this goto inside a macro? */
1325 if( mac ) { /* yes! */
1326 struct pval *targ = in_context(found);
1327 if( mac != targ )
1328 {
1329 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n",
1330 item->filename, item->startline, item->endline);
1331 warns++;
1332 }
1333 }
1334 }
1335 } else {
1336 /* here is where code would go to check for target existence in extensions.conf files */
1337#ifdef STANDALONE
1338 struct pbx_find_info pfiq = {.stacklen = 0 };
1339 extern int localized_pbx_load_module(void);
1340 /* if this is a standalone, we will need to make sure the
1341 localized load of extensions.conf is done */
1342 if (!extensions_dot_conf_loaded) {
1344 extensions_dot_conf_loaded++;
1345 }
1346
1347 pbx_find_extension(NULL, NULL, &pfiq, first->u1.str, second->u1.str, atoi(third->u1.str),
1348 atoi(third->u1.str) ? NULL : third->u1.str, NULL,
1349 atoi(third->u1.str) ? E_MATCH : E_FINDLABEL);
1350
1351 if (pfiq.status != STATUS_SUCCESS) {
1352 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: Couldn't find goto target %s|%s|%s, not even in extensions.conf!\n",
1353 item->filename, item->startline, item->endline, first->u1.str, second->u1.str, third->u1.str);
1354 warns++;
1355 }
1356#else
1357 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: Couldn't find goto target %s|%s|%s in the AEL code!\n",
1358 item->filename, item->startline, item->endline, first->u1.str, second->u1.str, third->u1.str);
1359 warns++;
1360#endif
1361 }
1362 } else {
1363 struct pval *mac = in_macro(item); /* is this goto inside a macro? */
1364 if( mac ) { /* yes! */
1365 struct pval *targ = in_context(x);
1366 if( mac != targ )
1367 {
1368 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n",
1369 item->filename, item->startline, item->endline);
1370 warns++;
1371 }
1372 }
1373 }
1374 }
1375 }
1376}
struct sla_ringing_trunk * first
Definition: app_sla.c:332
@ E_MATCH
Definition: extconf.h:217
@ E_FINDLABEL
Definition: extconf.h:220
#define STATUS_SUCCESS
Definition: extconf.h:248
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 struct pval * find_label_in_current_context(char *exten, char *label, pval *curr_cont)
Definition: pval.c:1879
static pval * get_contxt(pval *p)
Definition: pval.c:4345
static struct pval * in_macro(pval *item)
Definition: pval.c:1077
static struct pval * find_label_in_current_extension(const char *label, pval *curr_ext)
Definition: pval.c:1918
static pval * get_extension_or_contxt(pval *p)
Definition: pval.c:4335
struct pval * find_context(char *name)
Definition: pval.c:1953
static struct pval * in_context(pval *item)
Definition: pval.c:1090
int localized_pbx_load_module(void)
Definition: extconf.c:5644
static struct pval * find_label_in_current_db(const char *context, const char *exten, const char *label)
Definition: pval.c:1929
int stacklen
Definition: extconf.h:237

References ast_log, E_FINDLABEL, E_MATCH, errs, find_context(), find_label_in_current_context(), find_label_in_current_db(), find_label_in_current_extension(), first, get_contxt(), get_extension_or_contxt(), in_context(), in_macro(), item, pval::list, localized_pbx_load_module(), LOG_ERROR, LOG_WARNING, pval::next, NULL, pbx_find_extension(), PV_INCLUDES, pbx_find_info::stacklen, pval::statements, pbx_find_info::status, STATUS_SUCCESS, pval::str, pval::type, pval::u1, pval::u2, and warns.

Referenced by check_pval_item(), and find_pval_goto_item().

◆ check_includes()

static void check_includes ( pval includes)
static

Definition at line 811 of file pval.c.

812{
813 struct pval *p4;
814 for (p4=includes->u1.list; p4; p4=p4->next) {
815 /* for each context pointed to, find it, then find a context/label that matches the
816 target here! */
817 char *incl_context = p4->u1.str;
818 /* find a matching context name */
819 struct pval *that_other_context = find_context(incl_context);
820 if (!that_other_context && strcmp(incl_context, "parkedcalls") != 0) {
821 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The included context '%s' cannot be found.\n\
822 (You may ignore this warning if '%s' exists in extensions.conf, or is created by another module. I cannot check for those.)\n",
823 includes->filename, includes->startline, includes->endline, incl_context, incl_context);
824 warns++;
825 }
826 }
827}

References ast_log, pval::endline, pval::filename, find_context(), pval::list, LOG_WARNING, pval::next, pval::startline, pval::str, pval::u1, and warns.

Referenced by check_pval_item().

◆ check_label()

static void check_label ( pval item)
static

Definition at line 1106 of file pval.c.

1107{
1108 struct pval *curr;
1109 struct pval *x;
1110 int alright = 0;
1111
1112 /* A label outside an extension just plain does not make sense! */
1113
1114 curr = item;
1115
1116 while( curr ) {
1117 if( curr->type == PV_MACRO || curr->type == PV_EXTENSION ) {
1118 alright = 1;
1119 break;
1120 }
1121 curr = curr->dad;
1122 }
1123 if( !alright )
1124 {
1125 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Label %s is not within an extension or macro!\n",
1126 item->filename, item->startline, item->endline, item->u1.str);
1127 errs++;
1128 }
1129
1130
1131 /* basically, ensure that a label is not repeated in a context. Period.
1132 The method: well, for each label, find the first label in the context
1133 with the same name. If it's not the current label, then throw an error. */
1134
1135
1136 /* printf("==== check_label: ====\n"); */
1137 if( !current_extension )
1138 curr = current_context;
1139 else
1140 curr = current_extension;
1141
1142 x = find_first_label_in_current_context((char *)item->u1.str, curr);
1143 /* printf("Hey, check_label found with item = %x, and x is %x, and currcont is %x, label name is %s\n", item,x, current_context, (char *)item->u1.str); */
1144 if( x && x != item )
1145 {
1146 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Duplicate label %s! Previously defined at file %s, line %d.\n",
1147 item->filename, item->startline, item->endline, item->u1.str, x->filename, x->startline);
1148 errs++;
1149 }
1150 /* printf("<<<<< check_label: ====\n"); */
1151}
static pval * current_context
Definition: pval.c:73
static pval * current_extension
Definition: pval.c:74
static struct pval * find_first_label_in_current_context(char *label, pval *curr_cont)
Definition: pval.c:1839

References ast_log, current_context, current_extension, pval::dad, errs, pval::filename, find_first_label_in_current_context(), item, LOG_ERROR, PV_EXTENSION, PV_MACRO, pval::startline, and pval::type.

Referenced by check_pval_item().

◆ check_macro_returns()

static void check_macro_returns ( pval macro)
static

Definition at line 650 of file pval.c.

651{
652 pval *i;
653 if (!macro->u3.macro_statements)
654 {
655 pval *z = calloc(1, sizeof(struct pval));
656 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s is empty! I will insert a return.\n",
657 macro->filename, macro->startline, macro->endline, macro->u1.str);
658
659 z->type = PV_RETURN;
660 z->startline = macro->startline;
661 z->endline = macro->endline;
662 z->startcol = macro->startcol;
663 z->endcol = macro->endcol;
664 z->filename = strdup(macro->filename);
665
666 macro->u3.macro_statements = z;
667 return;
668 }
669 for (i=macro->u3.macro_statements; i; i=i->next) {
670 /* if the last statement in the list is not return, then insert a return there */
671 if (i->next == NULL) {
672 if (i->type != PV_RETURN) {
673 pval *z = calloc(1, sizeof(struct pval));
674 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s does not end with a return; I will insert one.\n",
675 macro->filename, macro->startline, macro->endline, macro->u1.str);
676
677 z->type = PV_RETURN;
678 z->startline = macro->startline;
679 z->endline = macro->endline;
680 z->startcol = macro->startcol;
681 z->endcol = macro->endcol;
682 z->filename = strdup(macro->filename);
683
684 i->next = z;
685 return;
686 }
687 }
688 }
689 return;
690}
#define calloc(a, b)
Definition: astmm.h:155
@ PV_RETURN
Definition: pval.h:27
int startcol
Definition: pval.h:53
int endcol
Definition: pval.h:54

References ast_log, calloc, pval::endcol, pval::endline, pval::filename, LOG_WARNING, pval::macro_statements, pval::next, NULL, PV_RETURN, pval::startcol, pval::startline, pval::str, strdup, pval::type, pval::u1, and pval::u3.

Referenced by check_pval_item().

◆ check_month()

static void check_month ( pval MON)
static

Definition at line 1000 of file pval.c.

1001{
1002 char *mon;
1003 char *c;
1004 /* The following line is coincidence, really! */
1005 int s, e;
1006
1007 mon = ast_strdupa(MON->u1.str);
1008
1009 /* Check for all days */
1010 if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
1011 return ;
1012 /* Get start and ending days */
1013 c = strchr(mon, '-');
1014 if (c) {
1015 *c = '\0';
1016 c++;
1017 }
1018 /* Find the start */
1019 s = 0;
1020 while ((s < 12) && strcasecmp(mon, months[s])) s++;
1021 if (s >= 12) {
1022 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
1023 MON->filename, MON->startline, MON->endline, mon);
1024 warns++;
1025 }
1026 if (c) {
1027 e = 0;
1028 while ((e < 12) && strcasecmp(mon, months[e])) e++;
1029 if (e >= 12) {
1030 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
1031 MON->filename, MON->startline, MON->endline, c);
1032 warns++;
1033 }
1034 } else
1035 e = s;
1036}
static char * months[]
Definition: pval.c:984

References ast_log, ast_strdupa, ast_strlen_zero(), c, pval::endline, pval::filename, LOG_WARNING, months, pval::startline, pval::str, pval::u1, and warns.

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

References check_pval_item(), item, and pval::next.

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
void free()
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 in_abstract_context
Definition: pval.c:79
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_CONTINUE
Definition: pval.h:28
@ PV_BREAK
Definition: pval.h:26
@ PV_APPLICATION_CALL
Definition: pval.h:12
@ 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_RANDOM
Definition: pval.h:31
@ PV_STATEMENTBLOCK
Definition: pval.h:20
void ast_expr_register_extra_error_info(char *errmsg)
Definition: ast_expr2f.c:2463
enum aco_type_t type

References app, pval::arglist, ast_expr(), ast_expr_clear_extra_error_info(), ast_expr_register_extra_error_info(), ast_log, check_abstract_reference(), check_app_args(), check_break(), check_continue(), check_day(), check_dow(), check_expr2_input(), check_goto(), check_includes(), check_label(), check_macro_returns(), check_month(), check_pval(), check_switch_expr(), check_timerange(), current_context, current_extension, E_MATCH, errs, expr_output, find_context(), find_macro(), find_pval_gotos(), free(), in_abstract_context, item, localized_pbx_load_module(), LOG_ERROR, LOG_WARNING, pval::next, NULL, 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::statements, pbx_find_info::status, STATUS_SUCCESS, pval::str, aco_type::type, pval::type, pval::u1, pval::u2, and warns.

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}
struct argapp * next
Definition: pval.h:112
struct test_val * next
const char * name
static struct test_val a

References a, ast_log, ast_strdupa, c, calloc, current_extension, pval::endcol, pval::endline, pval::filename, item, LOG_WARNING, test_val::name, pval::next, argapp::next, test_val::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, pval::u2, and warns.

Referenced by check_pval_item().

◆ check_timerange()

static void check_timerange ( pval p)
static

Definition at line 830 of file pval.c.

831{
832 char *times;
833 char *e;
834 int s1, s2;
835 int e1, e2;
836
837 times = ast_strdupa(p->u1.str);
838
839 /* Star is all times */
840 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
841 return;
842 }
843 /* Otherwise expect a range */
844 e = strchr(times, '-');
845 if (!e) {
846 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) requires a '-' surrounded by two 24-hour times of day!\n",
847 p->filename, p->startline, p->endline, times);
848 warns++;
849 return;
850 }
851 *e = '\0';
852 e++;
853 while (*e && !isdigit(*e))
854 e++;
855 if (!*e) {
856 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n",
857 p->filename, p->startline, p->endline, p->u1.str);
858 warns++;
859 }
860 if (sscanf(times, "%2d:%2d", &s1, &s2) != 2) {
861 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) isn't quite right!\n",
862 p->filename, p->startline, p->endline, times);
863 warns++;
864 }
865 if (sscanf(e, "%2d:%2d", &e1, &e2) != 2) {
866 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) isn't quite right!\n",
867 p->filename, p->startline, p->endline, times);
868 warns++;
869 }
870
871 s1 = s1 * 30 + s2/2;
872 if ((s1 < 0) || (s1 >= 24*30)) {
873 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) is out of range!\n",
874 p->filename, p->startline, p->endline, times);
875 warns++;
876 }
877 e1 = e1 * 30 + e2/2;
878 if ((e1 < 0) || (e1 >= 24*30)) {
879 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) is out of range!\n",
880 p->filename, p->startline, p->endline, e);
881 warns++;
882 }
883 return;
884}

References ast_log, ast_strdupa, ast_strlen_zero(), pval::endline, pval::filename, LOG_WARNING, pval::startline, pval::str, pval::u1, and warns.

Referenced by check_pval_item().

◆ contains_switch()

int contains_switch ( pval item)

Definition at line 3329 of file pval.c.

3330{
3331 pval *i;
3332
3333 for (i=item; i; i=i->next) {
3334 if (find_switch_item(i))
3335 return 1;
3336 }
3337 return 0;
3338}
int find_switch_item(pval *item)
Definition: pval.c:3090

References find_switch_item(), item, and pval::next.

Referenced by find_switch_item(), and gen_prios().

◆ context_used()

static int context_used ( struct ael_extension exten_list,
struct ast_context context 
)
static

Definition at line 4398 of file pval.c.

4399{
4400 struct ael_extension *exten;
4401 /* Check the simple elements first */
4403 return 1;
4404 }
4405 for (exten = exten_list; exten; exten = exten->next_exten) {
4406 if (exten->context == context) {
4407 return 1;
4408 }
4409 }
4410 return 0;
4411}
int ast_context_ignorepats_count(const struct ast_context *con)
Definition: pbx.c:8722
struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *priority)
Definition: ael_main.c:427
int ast_context_switches_count(const struct ast_context *con)
Definition: pbx.c:8634
int ast_context_includes_count(const struct ast_context *con)
Definition: pbx.c:8679

References ast_context_ignorepats_count(), ast_context_includes_count(), ast_context_switches_count(), ast_walk_context_extensions(), voicemailpwcheck::context, ael_extension::context, ael_extension::next_exten, and NULL.

Referenced by ast_compile_ael2().

◆ 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

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.

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

References destroy_pval_item(), item, and pval::next.

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

◆ 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

References ast_log, destroy_pval(), free(), item, LOG_WARNING, NULL, 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, and aco_type::type.

Referenced by destroy_pval().

◆ extension_matches()

static int extension_matches ( pval here,
const char *  exten,
const char *  pattern 
)
static

Definition at line 694 of file pval.c.

695{
696 int err1;
697 regex_t preg;
698
699 /* simple case, they match exactly, the pattern and exten name */
700 if (strcmp(pattern,exten) == 0)
701 return 1;
702
703 if (pattern[0] == '_') {
704 char reg1[2000];
705 const char *p;
706 char *r = reg1;
707
708 if ( strlen(pattern)*5 >= 2000 ) /* safety valve */ {
709 ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n",
710 pattern);
711 return 0;
712 }
713 /* form a regular expression from the pattern, and then match it against exten */
714 *r++ = '^'; /* what if the extension is a pattern ?? */
715 *r++ = '_'; /* what if the extension is a pattern ?? */
716 *r++ = '?';
717 for (p=pattern+1; *p; p++) {
718 switch ( *p ) {
719 case 'X':
720 *r++ = '[';
721 *r++ = '0';
722 *r++ = '-';
723 *r++ = '9';
724 *r++ = 'X';
725 *r++ = ']';
726 break;
727
728 case 'Z':
729 *r++ = '[';
730 *r++ = '1';
731 *r++ = '-';
732 *r++ = '9';
733 *r++ = 'Z';
734 *r++ = ']';
735 break;
736
737 case 'N':
738 *r++ = '[';
739 *r++ = '2';
740 *r++ = '-';
741 *r++ = '9';
742 *r++ = 'N';
743 *r++ = ']';
744 break;
745
746 case '[':
747 while ( *p && *p != ']' ) {
748 *r++ = *p++;
749 }
750 *r++ = ']';
751 if ( *p != ']') {
752 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The extension pattern '%s' is missing a closing bracket \n",
753 here->filename, here->startline, here->endline, pattern);
754 }
755 break;
756
757 case '.':
758 case '!':
759 *r++ = '.';
760 *r++ = '*';
761 break;
762 case '*': /* regex metacharacter */
763 case '+': /* regex metacharacter */
764 *r++ = '\\';
765 /* fall through */
766 default:
767 *r++ = *p;
768 break;
769
770 }
771 }
772 *r++ = '$'; /* what if the extension is a pattern ?? */
773 *r++ = *p++; /* put in the closing null */
774 err1 = regcomp(&preg, reg1, REG_NOSUB|REG_EXTENDED);
775 if ( err1 ) {
776 char errmess[500];
777 regerror(err1,&preg,errmess,sizeof(errmess));
778 regfree(&preg);
779 ast_log(LOG_WARNING, "Regcomp of %s failed, error code %d\n",
780 reg1, err1);
781 return 0;
782 }
783 err1 = regexec(&preg, exten, 0, 0, 0);
784 regfree(&preg);
785
786 if ( err1 ) {
787 /* ast_log(LOG_NOTICE,"*****************************[%d]Extension %s did not match %s(%s)\n",
788 err1,exten, pattern, reg1); */
789 return 0; /* no match */
790 } else {
791 /* ast_log(LOG_NOTICE,"*****************************Extension %s matched %s\n",
792 exten, pattern); */
793 return 1;
794 }
795 }
796
797 return 0;
798}

References ast_log, pval::endline, pval::filename, LOG_ERROR, LOG_WARNING, and pval::startline.

Referenced by match_pval_item().

◆ 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 name[]
Definition: format_mp3.c:68
static const char * match_context
Definition: pval.c:76
struct pval * match_pval(pval *item)
Definition: pval.c:1811
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

References count_labels, current_db, match_context, match_exten, match_label, match_pval(), name, and return_on_context_match.

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().

◆ find_first_label_in_current_context()

struct pval * find_first_label_in_current_context ( char *  label,
pval curr_cont 
)
static

Definition at line 1839 of file pval.c.

1840{
1841 /* printf(" --- Got args %s, %s\n", exten, label); */
1842 struct pval *ret;
1843 struct pval *p3;
1844
1845 count_labels = 0;
1847 match_context = "*";
1848 match_exten = "*";
1849 match_label = label;
1850
1851 ret = match_pval(curr_cont);
1852 if (ret)
1853 return ret;
1854
1855 /* the target of the goto could be in an included context!! Fancy that!! */
1856 /* look for includes in the current context */
1857 for (p3=curr_cont->u2.statements; p3; p3=p3->next) {
1858 if (p3->type == PV_INCLUDES) {
1859 struct pval *p4;
1860 for (p4=p3->u1.list; p4; p4=p4->next) {
1861 /* for each context pointed to, find it, then find a context/label that matches the
1862 target here! */
1863 char *incl_context = p4->u1.str;
1864 /* find a matching context name */
1865 struct pval *that_context = find_context(incl_context);
1866 if (that_context) {
1867 struct pval *x3;
1868 x3 = find_first_label_in_current_context(label, that_context);
1869 if (x3) {
1870 return x3;
1871 }
1872 }
1873 }
1874 }
1875 }
1876 return 0;
1877}

References count_labels, find_context(), find_first_label_in_current_context(), pval::list, match_context, match_exten, match_label, match_pval(), pval::next, PV_INCLUDES, return_on_context_match, pval::statements, pval::str, pval::type, pval::u1, and pval::u2.

Referenced by check_label(), and find_first_label_in_current_context().

◆ find_label_in_current_context()

struct pval * find_label_in_current_context ( char *  exten,
char *  label,
pval curr_cont 
)
static

Definition at line 1879 of file pval.c.

1880{
1881 /* printf(" --- Got args %s, %s\n", exten, label); */
1882 struct pval *ret;
1883 struct pval *p3;
1884
1885 count_labels = 0;
1887 match_context = "*";
1888 match_exten = exten;
1889 match_label = label;
1890 ret = match_pval(curr_cont->u2.statements);
1891 if (ret)
1892 return ret;
1893
1894 /* the target of the goto could be in an included context!! Fancy that!! */
1895 /* look for includes in the current context */
1896 for (p3=curr_cont->u2.statements; p3; p3=p3->next) {
1897 if (p3->type == PV_INCLUDES) {
1898 struct pval *p4;
1899 for (p4=p3->u1.list; p4; p4=p4->next) {
1900 /* for each context pointed to, find it, then find a context/label that matches the
1901 target here! */
1902 char *incl_context = p4->u1.str;
1903 /* find a matching context name */
1904 struct pval *that_context = find_context(incl_context);
1905 if (that_context) {
1906 struct pval *x3;
1907 x3 = find_label_in_current_context(exten, label, that_context);
1908 if (x3) {
1909 return x3;
1910 }
1911 }
1912 }
1913 }
1914 }
1915 return 0;
1916}

References count_labels, find_context(), find_label_in_current_context(), pval::list, match_context, match_exten, match_label, match_pval(), pval::next, PV_INCLUDES, return_on_context_match, pval::statements, pval::str, pval::type, pval::u1, and pval::u2.

Referenced by check_goto(), find_label_in_current_context(), and get_goto_target().

◆ find_label_in_current_db()

static struct pval * find_label_in_current_db ( const char *  context,
const char *  exten,
const char *  label 
)
static

Definition at line 1929 of file pval.c.

1930{
1931 /* printf(" --- Got args %s, %s, %s\n", context, exten, label); */
1932 count_labels = 0;
1934
1936 match_exten = exten;
1937 match_label = label;
1938
1939 return match_pval(current_db);
1940}

References voicemailpwcheck::context, count_labels, current_db, match_context, match_exten, match_label, match_pval(), and return_on_context_match.

Referenced by check_goto(), and get_goto_target().

◆ find_label_in_current_extension()

static struct pval * find_label_in_current_extension ( const char *  label,
pval curr_ext 
)
static

Definition at line 1918 of file pval.c.

1919{
1920 /* printf(" --- Got args %s\n", label); */
1921 count_labels = 0;
1923 match_context = "*";
1924 match_exten = "*";
1925 match_label = label;
1926 return match_pval(curr_ext);
1927}

References count_labels, match_context, match_exten, match_label, match_pval(), and return_on_context_match.

Referenced by check_goto(), and get_goto_target().

◆ find_macro()

struct pval * find_macro ( char *  name)

Definition at line 1943 of file pval.c.

1944{
1946 count_labels = 0;
1948 match_exten = "*"; /* don't really need to set these, shouldn't be reached */
1949 match_label = "*";
1950 return match_pval(current_db);
1951}

References count_labels, current_db, match_context, match_exten, match_label, match_pval(), name, and return_on_context_match.

Referenced by check_pval_item().

◆ find_pval_goto_item()

static void find_pval_goto_item ( pval item,
int  lev 
)
static

Definition at line 1379 of file pval.c.

1380{
1381 struct pval *p4;
1382
1383 if (lev>100) {
1384 ast_log(LOG_ERROR,"find_pval_goto in infinite loop! item_type: %u\n\n", item->type);
1385 return;
1386 }
1387
1388 switch ( item->type ) {
1389 case PV_MACRO:
1390 /* fields: item->u1.str == name of macro
1391 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
1392 item->u2.arglist->u1.str == argument
1393 item->u2.arglist->next == next arg
1394
1395 item->u3.macro_statements == pval list of statements in macro body.
1396 */
1397
1398 /* printf("Descending into macro %s at line %d\n", item->u1.str, item->startline); */
1399 find_pval_gotos(item->u3.macro_statements,lev+1); /* if we're just searching for a context, don't bother descending into them */
1400
1401 break;
1402
1403 case PV_CONTEXT:
1404 /* fields: item->u1.str == name of context
1405 item->u2.statements == pval list of statements in context body
1406 item->u3.abstract == int 1 if an abstract keyword were present
1407 */
1408 break;
1409
1410 case PV_CASE:
1411 /* fields: item->u1.str == value of case
1412 item->u2.statements == pval list of statements under the case
1413 */
1414 /* printf("Descending into Case of %s\n", item->u1.str); */
1415 find_pval_gotos(item->u2.statements,lev+1);
1416 break;
1417
1418 case PV_PATTERN:
1419 /* fields: item->u1.str == value of case
1420 item->u2.statements == pval list of statements under the case
1421 */
1422 /* printf("Descending into Pattern of %s\n", item->u1.str); */
1423 find_pval_gotos(item->u2.statements,lev+1);
1424 break;
1425
1426 case PV_DEFAULT:
1427 /* fields:
1428 item->u2.statements == pval list of statements under the case
1429 */
1430 /* printf("Descending into default\n"); */
1431 find_pval_gotos(item->u2.statements,lev+1);
1432 break;
1433
1434 case PV_CATCH:
1435 /* fields: item->u1.str == name of extension to catch
1436 item->u2.statements == pval list of statements in context body
1437 */
1438 /* printf("Descending into catch of %s\n", item->u1.str); */
1439 find_pval_gotos(item->u2.statements,lev+1);
1440 break;
1441
1442 case PV_STATEMENTBLOCK:
1443 /* fields: item->u1.list == pval list of statements in block, one per entry in the list
1444 */
1445 /* printf("Descending into statement block\n"); */
1446 find_pval_gotos(item->u1.list,lev+1);
1447 break;
1448
1449 case PV_GOTO:
1450 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
1451 item->u1.list->u1.str == where the data on a PV_WORD will always be.
1452 */
1453 check_goto(item); /* THE WHOLE FUNCTION OF THIS ENTIRE ROUTINE!!!! */
1454 break;
1455
1456 case PV_INCLUDES:
1457 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
1458 */
1459 for (p4=item->u1.list; p4; p4=p4->next) {
1460 /* for each context pointed to, find it, then find a context/label that matches the
1461 target here! */
1462 char *incl_context = p4->u1.str;
1463 /* find a matching context name */
1464 struct pval *that_context = find_context(incl_context);
1465 if (that_context && that_context->u2.statements) {
1466 /* printf("Descending into include of '%s' at line %d; that_context=%s, that_context type=%d\n", incl_context, item->startline, that_context->u1.str, that_context->type); */
1467 find_pval_gotos(that_context->u2.statements,lev+1); /* keep working up the includes */
1468 }
1469 }
1470 break;
1471
1472 case PV_FOR:
1473 /* fields: item->u1.for_init == a string containing the initializer
1474 item->u2.for_test == a string containing the loop test
1475 item->u3.for_inc == a string containing the loop increment
1476
1477 item->u4.for_statements == a pval list of statements in the for ()
1478 */
1479 /* printf("Descending into for at line %d\n", item->startline); */
1480 find_pval_gotos(item->u4.for_statements,lev+1);
1481 break;
1482
1483 case PV_WHILE:
1484 /* fields: item->u1.str == the while conditional, as supplied by user
1485
1486 item->u2.statements == a pval list of statements in the while ()
1487 */
1488 /* printf("Descending into while at line %d\n", item->startline); */
1489 find_pval_gotos(item->u2.statements,lev+1);
1490 break;
1491
1492 case PV_RANDOM:
1493 /* fields: item->u1.str == the random number expression, as supplied by user
1494
1495 item->u2.statements == a pval list of statements in the if ()
1496 item->u3.else_statements == a pval list of statements in the else
1497 (could be zero)
1498 fall thru to PV_IF */
1499
1500 case PV_IFTIME:
1501 /* fields: item->u1.list == the time values, 4 of them, as PV_WORD structs in a list
1502
1503 item->u2.statements == a pval list of statements in the if ()
1504 item->u3.else_statements == a pval list of statements in the else
1505 (could be zero)
1506 fall thru to PV_IF*/
1507 case PV_IF:
1508 /* fields: item->u1.str == the if conditional, as supplied by user
1509
1510 item->u2.statements == a pval list of statements in the if ()
1511 item->u3.else_statements == a pval list of statements in the else
1512 (could be zero)
1513 */
1514 /* printf("Descending into random/iftime/if at line %d\n", item->startline); */
1515 find_pval_gotos(item->u2.statements,lev+1);
1516
1517 if (item->u3.else_statements) {
1518 /* printf("Descending into random/iftime/if's ELSE at line %d\n", item->startline); */
1519 find_pval_gotos(item->u3.else_statements,lev+1);
1520 }
1521 break;
1522
1523 case PV_SWITCH:
1524 /* fields: item->u1.str == the switch expression
1525
1526 item->u2.statements == a pval list of statements in the switch,
1527 (will be case statements, most likely!)
1528 */
1529 /* printf("Descending into switch at line %d\n", item->startline); */
1530 find_pval_gotos(item->u3.else_statements,lev+1);
1531 break;
1532
1533 case PV_EXTENSION:
1534 /* fields: item->u1.str == the extension name, label, whatever it's called
1535
1536 item->u2.statements == a pval list of statements in the extension
1537 item->u3.hints == a char * hint argument
1538 item->u4.regexten == an int boolean. non-zero says that regexten was specified
1539 */
1540
1541 /* printf("Descending into extension %s at line %d\n", item->u1.str, item->startline); */
1542 find_pval_gotos(item->u2.statements,lev+1);
1543 break;
1544
1545 default:
1546 break;
1547 }
1548}

References ast_log, check_goto(), find_context(), find_pval_gotos(), item, LOG_ERROR, pval::next, PV_CASE, PV_CATCH, PV_CONTEXT, PV_DEFAULT, PV_EXTENSION, PV_FOR, PV_GOTO, PV_IF, PV_IFTIME, PV_INCLUDES, PV_MACRO, PV_PATTERN, PV_RANDOM, PV_STATEMENTBLOCK, PV_SWITCH, PV_WHILE, pval::statements, pval::str, aco_type::type, pval::u1, and pval::u2.

Referenced by find_pval_gotos().

◆ find_pval_gotos()

static void find_pval_gotos ( pval item,
int  lev 
)
static

Definition at line 1550 of file pval.c.

1551{
1552 pval *i;
1553
1554 for (i=item; i; i=i->next) {
1555 /* printf("About to call pval_goto_item, itemcount=%d, itemtype=%d\n", item_count, i->type); */
1556 find_pval_goto_item(i, lev);
1557 }
1558}
static void find_pval_goto_item(pval *item, int lev)
Definition: pval.c:1379

References find_pval_goto_item(), item, and pval::next.

Referenced by check_pval_item(), and find_pval_goto_item().

◆ find_switch_item()

int find_switch_item ( pval item)

Definition at line 3090 of file pval.c.

3091{
3092 switch ( item->type ) {
3093 case PV_LOCALVARDEC:
3094 /* fields: item->u1.str == string associated with this (word). */
3095 break;
3096
3097 case PV_WORD:
3098 /* fields: item->u1.str == string associated with this (word). */
3099 break;
3100
3101 case PV_MACRO:
3102 /* fields: item->u1.str == name of macro
3103 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
3104 item->u2.arglist->u1.str == argument
3105 item->u2.arglist->next == next arg
3106
3107 item->u3.macro_statements == pval list of statements in macro body.
3108 */
3109 /* had better not see this */
3110 if (contains_switch(item->u3.macro_statements))
3111 return 1;
3112 break;
3113
3114 case PV_CONTEXT:
3115 /* fields: item->u1.str == name of context
3116 item->u2.statements == pval list of statements in context body
3117 item->u3.abstract == int 1 if an abstract keyword were present
3118 */
3119 /* had better not see this */
3120 if (contains_switch(item->u2.statements))
3121 return 1;
3122 break;
3123
3124 case PV_MACRO_CALL:
3125 /* fields: item->u1.str == name of macro to call
3126 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
3127 item->u2.arglist->u1.str == argument
3128 item->u2.arglist->next == next arg
3129 */
3130 break;
3131
3133 /* fields: item->u1.str == name of application to call
3134 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
3135 item->u2.arglist->u1.str == argument
3136 item->u2.arglist->next == next arg
3137 */
3138 break;
3139
3140 case PV_CASE:
3141 /* fields: item->u1.str == value of case
3142 item->u2.statements == pval list of statements under the case
3143 */
3144 /* had better not see this */
3145 if (contains_switch(item->u2.statements))
3146 return 1;
3147 break;
3148
3149 case PV_PATTERN:
3150 /* fields: item->u1.str == value of case
3151 item->u2.statements == pval list of statements under the case
3152 */
3153 /* had better not see this */
3154 if (contains_switch(item->u2.statements))
3155 return 1;
3156 break;
3157
3158 case PV_DEFAULT:
3159 /* fields:
3160 item->u2.statements == pval list of statements under the case
3161 */
3162 /* had better not see this */
3163 if (contains_switch(item->u2.statements))
3164 return 1;
3165 break;
3166
3167 case PV_CATCH:
3168 /* fields: item->u1.str == name of extension to catch
3169 item->u2.statements == pval list of statements in context body
3170 */
3171 /* had better not see this */
3172 if (contains_switch(item->u2.statements))
3173 return 1;
3174 break;
3175
3176 case PV_SWITCHES:
3177 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
3178 */
3179 break;
3180
3181 case PV_ESWITCHES:
3182 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
3183 */
3184 break;
3185
3186 case PV_INCLUDES:
3187 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
3188 item->u2.arglist == pval list of 4 PV_WORD elements for time values
3189 */
3190 break;
3191
3192 case PV_STATEMENTBLOCK:
3193 /* fields: item->u1.list == pval list of statements in block, one per entry in the list
3194 */
3195 if (contains_switch(item->u1.list) )
3196 return 1;
3197 break;
3198
3199 case PV_VARDEC:
3200 /* fields: item->u1.str == variable name
3201 item->u2.val == variable value to assign
3202 */
3203 break;
3204
3205 case PV_GOTO:
3206 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
3207 item->u1.list->u1.str == where the data on a PV_WORD will always be.
3208 */
3209 break;
3210
3211 case PV_LABEL:
3212 /* fields: item->u1.str == label name
3213 */
3214 break;
3215
3216 case PV_FOR:
3217 /* fields: item->u1.for_init == a string containing the initializer
3218 item->u2.for_test == a string containing the loop test
3219 item->u3.for_inc == a string containing the loop increment
3220
3221 item->u4.for_statements == a pval list of statements in the for ()
3222 */
3223 if (contains_switch(item->u4.for_statements))
3224 return 1;
3225 break;
3226
3227 case PV_WHILE:
3228 /* fields: item->u1.str == the while conditional, as supplied by user
3229
3230 item->u2.statements == a pval list of statements in the while ()
3231 */
3232 if (contains_switch(item->u2.statements))
3233 return 1;
3234 break;
3235
3236 case PV_BREAK:
3237 /* fields: none
3238 */
3239 break;
3240
3241 case PV_RETURN:
3242 /* fields: none
3243 */
3244 break;
3245
3246 case PV_CONTINUE:
3247 /* fields: none
3248 */
3249 break;
3250
3251 case PV_IFTIME:
3252 /* fields: item->u1.list == there are 4 linked PV_WORDs here.
3253
3254 item->u2.statements == a pval list of statements in the if ()
3255 item->u3.else_statements == a pval list of statements in the else
3256 (could be zero)
3257 */
3258 if (contains_switch(item->u2.statements))
3259 return 1;
3260 if ( item->u3.else_statements ) {
3261 if (contains_switch(item->u3.else_statements))
3262 return 1;
3263 }
3264 break;
3265
3266 case PV_RANDOM:
3267 /* fields: item->u1.str == the random number expression, as supplied by user
3268
3269 item->u2.statements == a pval list of statements in the if ()
3270 item->u3.else_statements == a pval list of statements in the else
3271 (could be zero)
3272 */
3273 if (contains_switch(item->u2.statements))
3274 return 1;
3275 if ( item->u3.else_statements ) {
3276 if (contains_switch(item->u3.else_statements))
3277 return 1;
3278 }
3279 break;
3280
3281 case PV_IF:
3282 /* fields: item->u1.str == the if conditional, as supplied by user
3283
3284 item->u2.statements == a pval list of statements in the if ()
3285 item->u3.else_statements == a pval list of statements in the else
3286 (could be zero)
3287 */
3288 if (contains_switch(item->u2.statements))
3289 return 1;
3290 if ( item->u3.else_statements ) {
3291 if (contains_switch(item->u3.else_statements))
3292 return 1;
3293 }
3294 break;
3295
3296 case PV_SWITCH:
3297 /* fields: item->u1.str == the switch expression
3298
3299 item->u2.statements == a pval list of statements in the switch,
3300 (will be case statements, most likely!)
3301 */
3302 return 1; /* JACKPOT */
3303 break;
3304
3305 case PV_EXTENSION:
3306 /* fields: item->u1.str == the extension name, label, whatever it's called
3307
3308 item->u2.statements == a pval list of statements in the extension
3309 item->u3.hints == a char * hint argument
3310 item->u4.regexten == an int boolean. non-zero says that regexten was specified
3311 */
3312 if (contains_switch(item->u2.statements))
3313 return 1;
3314 break;
3315
3316 case PV_IGNOREPAT:
3317 /* fields: item->u1.str == the ignorepat data
3318 */
3319 break;
3320
3321 case PV_GLOBALS:
3322 /* fields: item->u1.statements == pval list of statements, usually vardecs
3323 */
3324 break;
3325 }
3326 return 0;
3327}
int contains_switch(pval *item)
Definition: pval.c:3329

References contains_switch(), item, 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, and aco_type::type.

Referenced by contains_switch().

◆ fix_gotos_in_extensions()

static void fix_gotos_in_extensions ( struct ael_extension exten)
static

Definition at line 4355 of file pval.c.

4356{
4357 struct ael_extension *e;
4358 for(e=exten;e;e=e->next_exten) {
4359
4360 struct ael_priority *p;
4361 for(p=e->plist;p;p=p->next) {
4362
4363 if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) {
4364
4365 /* fix the extension of the goto target to the actual extension in the post-compiled dialplan */
4366
4367 pval *target = p->origin->u2.goto_target;
4368 struct ael_extension *z = target->u3.compiled_label;
4369 pval *pv2 = p->origin;
4370 char buf1[500];
4371 char *apparg_save = p->appargs;
4372
4373 p->appargs = 0;
4374 if (!pv2->u1.list->next) /* just one -- it won't hurt to repeat the extension */ {
4375 snprintf(buf1,sizeof(buf1),"%s,%s", z->name, pv2->u1.list->u1.str);
4376 p->appargs = strdup(buf1);
4377
4378 } else if (pv2->u1.list->next && !pv2->u1.list->next->next) /* two */ {
4379 snprintf(buf1,sizeof(buf1),"%s,%s", z->name, pv2->u1.list->next->u1.str);
4380 p->appargs = strdup(buf1);
4381 } else if (pv2->u1.list->next && pv2->u1.list->next->next) {
4382 snprintf(buf1,sizeof(buf1),"%s,%s,%s", pv2->u1.list->u1.str,
4383 z->name,
4384 pv2->u1.list->next->next->u1.str);
4385 p->appargs = strdup(buf1);
4386 }
4387 else
4388 printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n");
4389
4390 if( apparg_save ) {
4391 free(apparg_save);
4392 }
4393 }
4394 }
4395 }
4396}
static struct ast_threadstorage buf1
int goto_target_in_case
Definition: pval.h:82
struct pval * goto_target
Definition: pval.h:72
struct ael_extension * compiled_label
Definition: pval.h:83

References ael_priority::appargs, buf1, pval::compiled_label, free(), pval::goto_target, pval::goto_target_in_case, pval::list, ael_extension::name, ael_priority::next, pval::next, ael_extension::next_exten, ael_priority::origin, ael_extension::plist, PV_GOTO, pval::str, strdup, pval::type, pval::u1, pval::u2, and pval::u3.

Referenced by ast_compile_ael2().

◆ gen_match_to_pattern()

static void gen_match_to_pattern ( char *  pattern,
char *  result 
)
static

Definition at line 3061 of file pval.c.

3062{
3063 /* the result will be a string that will be matched by pattern */
3064 char *p=pattern, *t=result;
3065 while (*p) {
3066 if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
3067 *t++ = '9';
3068 else if (*p == '[') {
3069 char *z = p+1;
3070 while (*z != ']')
3071 z++;
3072 if (*(z+1)== ']')
3073 z++;
3074 *t++=*(p+1); /* use the first char in the set */
3075 p = z;
3076 } else {
3077 *t++ = *p;
3078 }
3079 p++;
3080 }
3081 *t++ = 0; /* cap it off */
3082}
static PGresult * result
Definition: cel_pgsql.c:84

References result.

Referenced by gen_prios().

◆ gen_prios()

static int gen_prios ( struct ael_extension exten,
char *  label,
pval statement,
struct ael_extension mother_exten,
struct ast_context this_context 
)
static

Definition at line 3341 of file pval.c.

3342{
3343 pval *p,*p2,*p3;
3344 struct ael_priority *pr;
3345 struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end;
3346 struct ael_priority *while_test, *while_loop, *while_end;
3347 struct ael_priority *switch_set, *switch_test, *switch_end, *fall_thru, *switch_empty;
3348 struct ael_priority *if_test, *if_end, *if_skip, *if_false;
3349#ifdef OLD_RAND_ACTION
3350 struct ael_priority *rand_test, *rand_end, *rand_skip;
3351#endif
3352 RAII_VAR(char *, buf1, NULL, free);
3353 RAII_VAR(char *, buf2, NULL, free);
3354 RAII_VAR(char *, new_label, NULL, free);
3355 char *strp, *strp2;
3356 int default_exists;
3357 int local_control_statement_count;
3358 int first;
3359 struct ael_priority *loop_break_save;
3360 struct ael_priority *loop_continue_save;
3361 struct ael_extension *switch_case,*switch_null;
3362
3363 if (!(buf1 = malloc(BUF_SIZE))) {
3364 return -1;
3365 }
3366 if (!(buf2 = malloc(BUF_SIZE))) {
3367 return -1;
3368 }
3369 if (!(new_label = malloc(BUF_SIZE))) {
3370 return -1;
3371 }
3372
3373 if ((mother_exten && !mother_exten->checked_switch) || (exten && !exten->checked_switch)) {
3374 if (contains_switch(statement)) { /* only run contains_switch if you haven't checked before */
3375 if (mother_exten) {
3376 if (!mother_exten->has_switch) {
3377 for (first = 1; first >= 0; first--) {
3378 switch_set = new_prio();
3379 switch_set->type = AEL_APPCALL;
3380 switch_set->app = strdup("MSet");
3381 /* Are we likely inside a gosub subroutine? */
3382 if (!strcmp(mother_exten->name, "~~s~~") && first) {
3383 /* If we're not actually within a gosub, this will fail, but the
3384 * second time through, it will get set. If we are within gosub,
3385 * the second time through is redundant, but acceptable. */
3386 switch_set->appargs = strdup("LOCAL(~~EXTEN~~)=${EXTEN}");
3387 } else {
3388 switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
3389 first = 0;
3390 }
3391 linkprio(exten, switch_set, mother_exten);
3392 mother_exten->has_switch = 1;
3393 mother_exten->checked_switch = 1;
3394 if (exten) {
3395 exten->has_switch = 1;
3396 exten->checked_switch = 1;
3397 }
3398 }
3399 }
3400 } else if (exten) {
3401 if (!exten->has_switch) {
3402 for (first = 1; first >= 0; first--) {
3403 switch_set = new_prio();
3404 switch_set->type = AEL_APPCALL;
3405 switch_set->app = strdup("MSet");
3406 /* Are we likely inside a gosub subroutine? */
3407 if (!strcmp(exten->name, "~~s~~")) {
3408 /* If we're not actually within a gosub, this will fail, but the
3409 * second time through, it will get set. If we are within gosub,
3410 * the second time through is redundant, but acceptable. */
3411 switch_set->appargs = strdup("LOCAL(~~EXTEN~~)=${EXTEN}");
3412 } else {
3413 switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
3414 first = 0;
3415 }
3416 linkprio(exten, switch_set, mother_exten);
3417 exten->has_switch = 1;
3418 exten->checked_switch = 1;
3419 if (mother_exten) {
3420 mother_exten->has_switch = 1;
3421 mother_exten->checked_switch = 1;
3422 }
3423 }
3424 }
3425 }
3426 } else {
3427 if (mother_exten) {
3428 mother_exten->checked_switch = 1;
3429 }
3430 if (exten) {
3431 exten->checked_switch = 1;
3432 }
3433 }
3434 }
3435 for (p=statement; p; p=p->next) {
3436 switch (p->type) {
3437 case PV_VARDEC:
3438 pr = new_prio();
3439 pr->type = AEL_APPCALL;
3440 snprintf(buf1, BUF_SIZE, "%s=$[%s]", p->u1.str, p->u2.val);
3441 pr->app = strdup("MSet");
3443 pr->appargs = strdup(buf1);
3444 pr->origin = p;
3445 linkprio(exten, pr, mother_exten);
3446 break;
3447
3448 case PV_LOCALVARDEC:
3449 pr = new_prio();
3450 pr->type = AEL_APPCALL;
3451 snprintf(buf1, BUF_SIZE, "LOCAL(%s)=$[%s]", p->u1.str, p->u2.val);
3452 pr->app = strdup("MSet");
3454 pr->appargs = strdup(buf1);
3455 pr->origin = p;
3456 linkprio(exten, pr, mother_exten);
3457 break;
3458
3459 case PV_GOTO:
3460 pr = new_prio();
3461 pr->type = AEL_APPCALL;
3463 if( p->u2.goto_target ) {
3465 }
3466
3467 if (!p->u1.list->next) /* just one */ {
3468 pr->app = strdup("Goto");
3469 if (!mother_exten)
3470 pr->appargs = strdup(p->u1.list->u1.str);
3471 else { /* for the case of simple within-extension gotos in case/pattern/default statement blocks: */
3472 snprintf(buf1, BUF_SIZE, "%s,%s", mother_exten->name, p->u1.list->u1.str);
3473 pr->appargs = strdup(buf1);
3474 }
3475
3476 } else if (p->u1.list->next && !p->u1.list->next->next) /* two */ {
3477 snprintf(buf1, BUF_SIZE, "%s,%s", p->u1.list->u1.str, p->u1.list->next->u1.str);
3478 pr->app = strdup("Goto");
3479 pr->appargs = strdup(buf1);
3480 } else if (p->u1.list->next && p->u1.list->next->next) {
3481 snprintf(buf1, BUF_SIZE, "%s,%s,%s", p->u1.list->u1.str,
3482 p->u1.list->next->u1.str,
3483 p->u1.list->next->next->u1.str);
3484 pr->app = strdup("Goto");
3485 pr->appargs = strdup(buf1);
3486 }
3487 pr->origin = p;
3488 linkprio(exten, pr, mother_exten);
3489 break;
3490
3491 case PV_LABEL:
3492 pr = new_prio();
3493 pr->type = AEL_LABEL;
3494 pr->origin = p;
3495 p->u3.compiled_label = exten;
3496 linkprio(exten, pr, mother_exten);
3497 break;
3498
3499 case PV_FOR:
3501 loop_break_save = exten->loop_break; /* save them, then restore before leaving */
3502 loop_continue_save = exten->loop_continue;
3503 snprintf(new_label, BUF_SIZE, "for_%s_%d", label, control_statement_count);
3504 for_init = new_prio();
3505 for_inc = new_prio();
3506 for_test = new_prio();
3507 for_loop = new_prio();
3508 for_end = new_prio();
3509 for_init->type = AEL_APPCALL;
3510 for_inc->type = AEL_APPCALL;
3511 for_test->type = AEL_FOR_CONTROL;
3512 for_test->goto_false = for_end;
3513 for_loop->type = AEL_CONTROL1; /* simple goto */
3514 for_end->type = AEL_APPCALL;
3515 for_init->app = strdup("MSet");
3516
3517 strcpy(buf2,p->u1.for_init);
3519 strp = strchr(buf2, '=');
3520 if (strp) {
3521 strp2 = strchr(p->u1.for_init, '=');
3522 *(strp+1) = 0;
3523 strcat(buf2,"$[");
3524 strncat(buf2,strp2+1, BUF_SIZE-strlen(strp2+1)-2);
3525 strcat(buf2,"]");
3526 for_init->appargs = strdup(buf2);
3527 } else {
3528 strp2 = p->u1.for_init;
3529 while (*strp2 && isspace(*strp2))
3530 strp2++;
3531 if (*strp2 == '&') { /* itsa macro call */
3532 char *strp3 = strp2+1;
3533 while (*strp3 && isspace(*strp3))
3534 strp3++;
3535 strcpy(buf2, strp3);
3536 strp3 = strchr(buf2,'(');
3537 if (strp3) {
3538 *strp3 = ',';
3539 }
3540 strp3 = strrchr(buf2, ')');
3541 if (strp3)
3542 *strp3 = 0; /* remove the closing paren */
3543 for_init->appargs = strdup(buf2);
3544 free(for_init->app);
3545 for_init->app = strdup("Gosub");
3546 } else { /* must be a regular app call */
3547 char *strp3;
3548 strcpy(buf2, strp2);
3549 strp3 = strchr(buf2,'(');
3550 if (strp3) {
3551 *strp3 = 0;
3552 free(for_init->app);
3553 for_init->app = strdup(buf2);
3554 for_init->appargs = strdup(strp3+1);
3555 strp3 = strrchr(for_init->appargs, ')');
3556 if (strp3)
3557 *strp3 = 0; /* remove the closing paren */
3558 }
3559 }
3560 }
3561
3562 strcpy(buf2,p->u3.for_inc);
3564 strp = strchr(buf2, '=');
3565 if (strp) { /* there's an = in this part; that means an assignment. set it up */
3566 strp2 = strchr(p->u3.for_inc, '=');
3567 *(strp+1) = 0;
3568 strcat(buf2,"$[");
3569 strncat(buf2,strp2+1, BUF_SIZE-strlen(strp2+1)-2);
3570 strcat(buf2,"]");
3571 for_inc->appargs = strdup(buf2);
3572 for_inc->app = strdup("MSet");
3573 } else {
3574 strp2 = p->u3.for_inc;
3575 while (*strp2 && isspace(*strp2))
3576 strp2++;
3577 if (*strp2 == '&') { /* itsa macro call */
3578 char *strp3 = strp2+1;
3579 while (*strp3 && isspace(*strp3))
3580 strp3++;
3581 strcpy(buf2, strp3);
3582 strp3 = strchr(buf2,'(');
3583 if (strp3) {
3584 *strp3 = ',';
3585 }
3586 strp3 = strrchr(buf2, ')');
3587 if (strp3)
3588 *strp3 = 0; /* remove the closing paren */
3589
3590 for_inc->appargs = strdup(buf2);
3591
3592 for_inc->app = strdup("Gosub");
3593 } else { /* must be a regular app call */
3594 char *strp3;
3595 strcpy(buf2, strp2);
3596 strp3 = strchr(buf2,'(');
3597 if (strp3) {
3598 *strp3 = 0;
3599 for_inc->app = strdup(buf2);
3600 for_inc->appargs = strdup(strp3+1);
3601 strp3 = strrchr(for_inc->appargs, ')');
3602 if (strp3)
3603 *strp3 = 0; /* remove the closing paren */
3604 }
3605 }
3606 }
3607 snprintf(buf1, BUF_SIZE, "$[%s]",p->u2.for_test);
3608 for_test->app = 0;
3609 for_test->appargs = strdup(buf1);
3610 for_loop->goto_true = for_test;
3611 snprintf(buf1, BUF_SIZE, "Finish for_%s_%d", label, control_statement_count);
3612 for_end->app = strdup("NoOp");
3613 for_end->appargs = strdup(buf1);
3614 /* link & load! */
3615 linkprio(exten, for_init, mother_exten);
3616 linkprio(exten, for_test, mother_exten);
3617
3618 /* now, put the body of the for loop here */
3619 exten->loop_break = for_end;
3620 exten->loop_continue = for_inc;
3621
3622 if (gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context)) { /* this will link in all the statements here */
3623 return -1;
3624 }
3625
3626 linkprio(exten, for_inc, mother_exten);
3627 linkprio(exten, for_loop, mother_exten);
3628 linkprio(exten, for_end, mother_exten);
3629
3630
3631 exten->loop_break = loop_break_save;
3632 exten->loop_continue = loop_continue_save;
3633 for_loop->origin = p;
3634 break;
3635
3636 case PV_WHILE:
3638 loop_break_save = exten->loop_break; /* save them, then restore before leaving */
3639 loop_continue_save = exten->loop_continue;
3640 snprintf(new_label, BUF_SIZE, "while_%s_%d", label, control_statement_count);
3641 while_test = new_prio();
3642 while_loop = new_prio();
3643 while_end = new_prio();
3644 while_test->type = AEL_FOR_CONTROL;
3645 while_test->goto_false = while_end;
3646 while_loop->type = AEL_CONTROL1; /* simple goto */
3647 while_end->type = AEL_APPCALL;
3648 snprintf(buf1, BUF_SIZE, "$[%s]",p->u1.str);
3649 while_test->app = 0;
3650 while_test->appargs = strdup(buf1);
3651 while_loop->goto_true = while_test;
3652 snprintf(buf1, BUF_SIZE, "Finish while_%s_%d", label, control_statement_count);
3653 while_end->app = strdup("NoOp");
3654 while_end->appargs = strdup(buf1);
3655
3656 linkprio(exten, while_test, mother_exten);
3657
3658 /* now, put the body of the for loop here */
3659 exten->loop_break = while_end;
3660 exten->loop_continue = while_test;
3661
3662 if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the while body statements here */
3663 return -1;
3664 }
3665
3666 linkprio(exten, while_loop, mother_exten);
3667 linkprio(exten, while_end, mother_exten);
3668
3669
3670 exten->loop_break = loop_break_save;
3671 exten->loop_continue = loop_continue_save;
3672 while_loop->origin = p;
3673 break;
3674
3675 case PV_SWITCH:
3677 local_control_statement_count = control_statement_count;
3678 loop_break_save = exten->loop_break; /* save them, then restore before leaving */
3679 loop_continue_save = exten->loop_continue;
3680 snprintf(new_label, BUF_SIZE, "sw_%s_%d", label, control_statement_count);
3681 switch_test = new_prio();
3682 switch_end = new_prio();
3683 switch_test->type = AEL_APPCALL;
3684 switch_end->type = AEL_APPCALL;
3685 snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", control_statement_count, p->u1.str);
3686 switch_test->app = strdup("Goto");
3687 switch_test->appargs = strdup(buf1);
3688 snprintf(buf1, BUF_SIZE, "Finish switch_%s_%d", label, control_statement_count);
3689 switch_end->app = strdup("NoOp");
3690 switch_end->appargs = strdup(buf1);
3691 switch_end->origin = p;
3692 switch_end->exten = exten;
3693
3694 linkprio(exten, switch_test, mother_exten);
3695 linkprio(exten, switch_end, mother_exten);
3696
3697 exten->loop_break = switch_end;
3698 exten->loop_continue = 0;
3699 default_exists = 0;
3700
3701 for (p2=p->u2.statements; p2; p2=p2->next) {
3702 /* now, for each case/default put the body of the for loop here */
3703 if (p2->type == PV_CASE) {
3704 /* ok, generate a extension and link it in */
3705 switch_case = new_exten();
3706 if (mother_exten && mother_exten->checked_switch) {
3707 switch_case->has_switch = mother_exten->has_switch;
3708 switch_case->checked_switch = mother_exten->checked_switch;
3709 }
3710 if (exten && exten->checked_switch) {
3711 switch_case->has_switch = exten->has_switch;
3712 switch_case->checked_switch = exten->checked_switch;
3713 }
3714 switch_case->context = this_context;
3715 switch_case->is_switch = 1;
3716 /* the break/continue locations are inherited from parent */
3717 switch_case->loop_break = exten->loop_break;
3718 switch_case->loop_continue = exten->loop_continue;
3719
3720 linkexten(exten,switch_case);
3721 snprintf(buf1, BUF_SIZE, "sw_%d_%s", local_control_statement_count, p2->u1.str);
3722 switch_case->name = strdup(buf1);
3723 snprintf(new_label, BUF_SIZE, "sw_%s_%s_%d", label, p2->u1.str, local_control_statement_count);
3724
3725 if (gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context)) { /* this will link in all the case body statements here */
3726 return -1;
3727 }
3728
3729 /* here is where we write code to "fall thru" to the next case... if there is one... */
3730 for (p3=p2->u2.statements; p3; p3=p3->next) {
3731 if (!p3->next)
3732 break;
3733 }
3734 /* p3 now points the last statement... */
3735 if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN) ) {
3736 /* is there a following CASE/PATTERN/DEFAULT? */
3737 if (p2->next && p2->next->type == PV_CASE) {
3738 fall_thru = new_prio();
3739 fall_thru->type = AEL_APPCALL;
3740 fall_thru->app = strdup("Goto");
3741 snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, p2->next->u1.str);
3742 fall_thru->appargs = strdup(buf1);
3743 linkprio(switch_case, fall_thru, mother_exten);
3744 } else if (p2->next && p2->next->type == PV_PATTERN) {
3745 fall_thru = new_prio();
3746 fall_thru->type = AEL_APPCALL;
3747 fall_thru->app = strdup("Goto");
3749 snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, buf2);
3750 fall_thru->appargs = strdup(buf1);
3751 linkprio(switch_case, fall_thru, mother_exten);
3752 } else if (p2->next && p2->next->type == PV_DEFAULT) {
3753 fall_thru = new_prio();
3754 fall_thru->type = AEL_APPCALL;
3755 fall_thru->app = strdup("Goto");
3756 snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
3757 fall_thru->appargs = strdup(buf1);
3758 linkprio(switch_case, fall_thru, mother_exten);
3759 } else if (!p2->next) {
3760 fall_thru = new_prio();
3761 fall_thru->type = AEL_CONTROL1;
3762 fall_thru->goto_true = switch_end;
3763 fall_thru->app = strdup("Goto");
3764 linkprio(switch_case, fall_thru, mother_exten);
3765 }
3766 }
3767 if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
3768 char buf[2000];
3769 struct ael_priority *np2 = new_prio();
3770 np2->type = AEL_APPCALL;
3771 np2->app = strdup("NoOp");
3772 snprintf(buf, BUF_SIZE, "End of Extension %s", switch_case->name);
3773 np2->appargs = strdup(buf);
3774 linkprio(switch_case, np2, mother_exten);
3775 switch_case-> return_target = np2;
3776 }
3777 } else if (p2->type == PV_PATTERN) {
3778 /* ok, generate a extension and link it in */
3779 switch_case = new_exten();
3780 if (mother_exten && mother_exten->checked_switch) {
3781 switch_case->has_switch = mother_exten->has_switch;
3782 switch_case->checked_switch = mother_exten->checked_switch;
3783 }
3784 if (exten && exten->checked_switch) {
3785 switch_case->has_switch = exten->has_switch;
3786 switch_case->checked_switch = exten->checked_switch;
3787 }
3788 switch_case->context = this_context;
3789 switch_case->is_switch = 1;
3790 /* the break/continue locations are inherited from parent */
3791 switch_case->loop_break = exten->loop_break;
3792 switch_case->loop_continue = exten->loop_continue;
3793
3794 linkexten(exten,switch_case);
3795 snprintf(buf1, BUF_SIZE, "_sw_%d_%s", local_control_statement_count, p2->u1.str);
3796 switch_case->name = strdup(buf1);
3797 snprintf(new_label, BUF_SIZE, "sw_%s_%s_%d", label, p2->u1.str, local_control_statement_count);
3798
3799 if (gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context)) { /* this will link in all the while body statements here */
3800 return -1;
3801 }
3802 /* here is where we write code to "fall thru" to the next case... if there is one... */
3803 for (p3=p2->u2.statements; p3; p3=p3->next) {
3804 if (!p3->next)
3805 break;
3806 }
3807 /* p3 now points the last statement... */
3808 if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
3809 /* is there a following CASE/PATTERN/DEFAULT? */
3810 if (p2->next && p2->next->type == PV_CASE) {
3811 fall_thru = new_prio();
3812 fall_thru->type = AEL_APPCALL;
3813 fall_thru->app = strdup("Goto");
3814 snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, p2->next->u1.str);
3815 fall_thru->appargs = strdup(buf1);
3816 linkprio(switch_case, fall_thru, mother_exten);
3817 } else if (p2->next && p2->next->type == PV_PATTERN) {
3818 fall_thru = new_prio();
3819 fall_thru->type = AEL_APPCALL;
3820 fall_thru->app = strdup("Goto");
3822 snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, buf2);
3823 fall_thru->appargs = strdup(buf1);
3824 linkprio(switch_case, fall_thru, mother_exten);
3825 } else if (p2->next && p2->next->type == PV_DEFAULT) {
3826 fall_thru = new_prio();
3827 fall_thru->type = AEL_APPCALL;
3828 fall_thru->app = strdup("Goto");
3829 snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
3830 fall_thru->appargs = strdup(buf1);
3831 linkprio(switch_case, fall_thru, mother_exten);
3832 } else if (!p2->next) {
3833 fall_thru = new_prio();
3834 fall_thru->type = AEL_CONTROL1;
3835 fall_thru->goto_true = switch_end;
3836 fall_thru->app = strdup("Goto");
3837 linkprio(switch_case, fall_thru, mother_exten);
3838 }
3839 }
3840 if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
3841 char buf[2000];
3842 struct ael_priority *np2 = new_prio();
3843 np2->type = AEL_APPCALL;
3844 np2->app = strdup("NoOp");
3845 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
3846 np2->appargs = strdup(buf);
3847 linkprio(switch_case, np2, mother_exten);
3848 switch_case-> return_target = np2;
3849 }
3850 } else if (p2->type == PV_DEFAULT) {
3851 /* ok, generate a extension and link it in */
3852 switch_case = new_exten();
3853 if (mother_exten && mother_exten->checked_switch) {
3854 switch_case->has_switch = mother_exten->has_switch;
3855 switch_case->checked_switch = mother_exten->checked_switch;
3856 }
3857 if (exten && exten->checked_switch) {
3858 switch_case->has_switch = exten->has_switch;
3859 switch_case->checked_switch = exten->checked_switch;
3860 }
3861 switch_case->context = this_context;
3862 switch_case->is_switch = 1;
3863
3864 /* new: the default case intros a pattern with ., which covers ALMOST everything.
3865 but it doesn't cover a NULL pattern. So, we'll define a null extension to match
3866 that goto's the default extension. */
3867
3868 default_exists++;
3869 switch_null = new_exten();
3870 if (mother_exten && mother_exten->checked_switch) {
3871 switch_null->has_switch = mother_exten->has_switch;
3872 switch_null->checked_switch = mother_exten->checked_switch;
3873 }
3874 if (exten && exten->checked_switch) {
3875 switch_null->has_switch = exten->has_switch;
3876 switch_null->checked_switch = exten->checked_switch;
3877 }
3878 switch_null->context = this_context;
3879 switch_null->is_switch = 1;
3880 switch_empty = new_prio();
3881 snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
3882 switch_empty->app = strdup("Goto");
3883 switch_empty->appargs = strdup(buf1);
3884 linkprio(switch_null, switch_empty, mother_exten);
3885 snprintf(buf1, BUF_SIZE, "sw_%d_", local_control_statement_count);
3886 switch_null->name = strdup(buf1);
3887 switch_null->loop_break = exten->loop_break;
3888 switch_null->loop_continue = exten->loop_continue;
3889 linkexten(exten,switch_null);
3890
3891 /* the break/continue locations are inherited from parent */
3892 switch_case->loop_break = exten->loop_break;
3893 switch_case->loop_continue = exten->loop_continue;
3894 linkexten(exten,switch_case);
3895 snprintf(buf1, BUF_SIZE, "_sw_%d_.", local_control_statement_count);
3896 switch_case->name = strdup(buf1);
3897
3898 snprintf(new_label, BUF_SIZE, "sw_%s_default_%d", label, local_control_statement_count);
3899
3900 if (gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context)) { /* this will link in all the default: body statements here */
3901 return -1;
3902 }
3903
3904 /* here is where we write code to "fall thru" to the next case... if there is one... */
3905 for (p3=p2->u2.statements; p3; p3=p3->next) {
3906 if (!p3->next)
3907 break;
3908 }
3909 /* p3 now points the last statement... */
3910 if (!p3 || (p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
3911 /* is there a following CASE/PATTERN/DEFAULT? */
3912 if (p2->next && p2->next->type == PV_CASE) {
3913 fall_thru = new_prio();
3914 fall_thru->type = AEL_APPCALL;
3915 fall_thru->app = strdup("Goto");
3916 snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, p2->next->u1.str);
3917 fall_thru->appargs = strdup(buf1);
3918 linkprio(switch_case, fall_thru, mother_exten);
3919 } else if (p2->next && p2->next->type == PV_PATTERN) {
3920 fall_thru = new_prio();
3921 fall_thru->type = AEL_APPCALL;
3922 fall_thru->app = strdup("Goto");
3924 snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, buf2);
3925 fall_thru->appargs = strdup(buf1);
3926 linkprio(switch_case, fall_thru, mother_exten);
3927 } else if (p2->next && p2->next->type == PV_DEFAULT) {
3928 fall_thru = new_prio();
3929 fall_thru->type = AEL_APPCALL;
3930 fall_thru->app = strdup("Goto");
3931 snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
3932 fall_thru->appargs = strdup(buf1);
3933 linkprio(switch_case, fall_thru, mother_exten);
3934 } else if (!p2->next) {
3935 fall_thru = new_prio();
3936 fall_thru->type = AEL_CONTROL1;
3937 fall_thru->goto_true = switch_end;
3938 fall_thru->app = strdup("Goto");
3939 linkprio(switch_case, fall_thru, mother_exten);
3940 }
3941 }
3942 if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
3943 char buf[2000];
3944 struct ael_priority *np2 = new_prio();
3945 np2->type = AEL_APPCALL;
3946 np2->app = strdup("NoOp");
3947 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
3948 np2->appargs = strdup(buf);
3949 linkprio(switch_case, np2, mother_exten);
3950 switch_case-> return_target = np2;
3951 }
3952 } else {
3953 /* what could it be??? */
3954 }
3955 }
3956
3957 exten->loop_break = loop_break_save;
3958 exten->loop_continue = loop_continue_save;
3959 switch_test->origin = p;
3960 switch_end->origin = p;
3961 break;
3962
3963 case PV_MACRO_CALL:
3964 pr = new_prio();
3965 pr->type = AEL_APPCALL;
3966 snprintf(buf1, BUF_SIZE, "%s,~~s~~,1", p->u1.str);
3967 first = 1;
3968 for (p2 = p->u2.arglist; p2; p2 = p2->next) {
3969 if (first)
3970 {
3971 strcat(buf1,"(");
3972 first = 0;
3973 }
3974 else
3975 strcat(buf1,",");
3976 strcat(buf1,p2->u1.str);
3977 }
3978 if (!first)
3979 strcat(buf1,")");
3980
3981 pr->app = strdup("Gosub");
3982 pr->appargs = strdup(buf1);
3983 pr->origin = p;
3984 linkprio(exten, pr, mother_exten);
3985 break;
3986
3988 pr = new_prio();
3989 pr->type = AEL_APPCALL;
3990 buf1[0] = 0;
3991 for (p2 = p->u2.arglist; p2; p2 = p2->next) {
3992 if (p2 != p->u2.arglist )
3993 strcat(buf1,",");
3994 strcat(buf1,p2->u1.str);
3995 }
3996 pr->app = strdup(p->u1.str);
3997 pr->appargs = strdup(buf1);
3998 pr->origin = p;
3999 linkprio(exten, pr, mother_exten);
4000 break;
4001
4002 case PV_BREAK:
4003 pr = new_prio();
4004 pr->type = AEL_CONTROL1; /* simple goto */
4005 pr->goto_true = exten->loop_break;
4006 pr->origin = p;
4007 linkprio(exten, pr, mother_exten);
4008 break;
4009
4010 case PV_RETURN: /* hmmmm */
4011 pr = new_prio();
4012 pr->type = AEL_RETURN; /* simple Return */
4013 /* exten->return_needed++; */
4014 pr->app = strdup("Return");
4015 pr->appargs = strdup("");
4016 pr->origin = p;
4017 linkprio(exten, pr, mother_exten);
4018 break;
4019
4020 case PV_CONTINUE:
4021 pr = new_prio();
4022 pr->type = AEL_CONTROL1; /* simple goto */
4024 pr->origin = p;
4025 linkprio(exten, pr, mother_exten);
4026 break;
4027
4028 case PV_IFTIME:
4030 snprintf(new_label, BUF_SIZE, "iftime_%s_%d", label, control_statement_count);
4031
4032 if_test = new_prio();
4033 if_test->type = AEL_IFTIME_CONTROL;
4034 snprintf(buf1, BUF_SIZE, "%s,%s,%s,%s",
4035 p->u1.list->u1.str,
4036 p->u1.list->next->u1.str,
4037 p->u1.list->next->next->u1.str,
4038 p->u1.list->next->next->next->u1.str);
4039 if_test->app = 0;
4040 if_test->appargs = strdup(buf1);
4041 if_test->origin = p;
4042
4043 if_end = new_prio();
4044 if_end->type = AEL_APPCALL;
4045 snprintf(buf1, BUF_SIZE, "Finish iftime_%s_%d", label, control_statement_count);
4046 if_end->app = strdup("NoOp");
4047 if_end->appargs = strdup(buf1);
4048
4049 if (p->u3.else_statements) {
4050 if_skip = new_prio();
4051 if_skip->type = AEL_CONTROL1; /* simple goto */
4052 if_skip->goto_true = if_end;
4053 if_skip->origin = p;
4054
4055 } else {
4056 if_skip = 0;
4057
4058 if_test->goto_false = if_end;
4059 }
4060
4061 if_false = new_prio();
4062 if_false->type = AEL_CONTROL1;
4063 if (p->u3.else_statements) {
4064 if_false->goto_true = if_skip; /* +1 */
4065 } else {
4066 if_false->goto_true = if_end;
4067 }
4068
4069 /* link & load! */
4070 linkprio(exten, if_test, mother_exten);
4071 linkprio(exten, if_false, mother_exten);
4072
4073 /* now, put the body of the if here */
4074
4075 if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the statements here */
4076 return -1;
4077 }
4078
4079 if (p->u3.else_statements) {
4080 linkprio(exten, if_skip, mother_exten);
4081 if (gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context)) { /* this will link in all the statements here */
4082 return -1;
4083 }
4084 }
4085
4086 linkprio(exten, if_end, mother_exten);
4087
4088 break;
4089
4090 case PV_RANDOM:
4091 case PV_IF:
4093 snprintf(new_label, BUF_SIZE, "if_%s_%d", label, control_statement_count);
4094
4095 if_test = new_prio();
4096 if_end = new_prio();
4097 if_test->type = AEL_IF_CONTROL;
4098 if_end->type = AEL_APPCALL;
4099 if ( p->type == PV_RANDOM )
4100 snprintf(buf1, BUF_SIZE, "$[${RAND(0,99)} < (%s)]", p->u1.str);
4101 else
4102 snprintf(buf1, BUF_SIZE, "$[%s]", p->u1.str);
4103 if_test->app = 0;
4104 if_test->appargs = strdup(buf1);
4105 snprintf(buf1, BUF_SIZE, "Finish if_%s_%d", label, control_statement_count);
4106 if_end->app = strdup("NoOp");
4107 if_end->appargs = strdup(buf1);
4108 if_test->origin = p;
4109
4110 if (p->u3.else_statements) {
4111 if_skip = new_prio();
4112 if_skip->type = AEL_CONTROL1; /* simple goto */
4113 if_skip->goto_true = if_end;
4114 if_test->goto_false = if_skip;;
4115 } else {
4116 if_skip = 0;
4117 if_test->goto_false = if_end;;
4118 }
4119
4120 /* link & load! */
4121 linkprio(exten, if_test, mother_exten);
4122
4123 /* now, put the body of the if here */
4124
4125 if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the statements here */
4126 return -1;
4127 }
4128
4129 if (p->u3.else_statements) {
4130 linkprio(exten, if_skip, mother_exten);
4131 if (gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context)) { /* this will link in all the statements here */
4132 return -1;
4133 }
4134 }
4135
4136 linkprio(exten, if_end, mother_exten);
4137
4138 break;
4139
4140 case PV_STATEMENTBLOCK:
4141 if (gen_prios(exten, label, p->u1.list, mother_exten, this_context)) { /* recurse into the block */
4142 return -1;
4143 }
4144 break;
4145
4146 case PV_CATCH:
4148 /* generate an extension with name of catch, put all catch stats
4149 into this exten! */
4150 switch_case = new_exten();
4151 if (mother_exten && mother_exten->checked_switch) {
4152 switch_case->has_switch = mother_exten->has_switch;
4153 switch_case->checked_switch = mother_exten->checked_switch;
4154 }
4155 if (exten && exten->checked_switch) {
4156 switch_case->has_switch = exten->has_switch;
4157 switch_case->checked_switch = exten->checked_switch;
4158 }
4159
4160 switch_case->context = this_context;
4161 linkexten(exten,switch_case);
4162 switch_case->name = strdup(p->u1.str);
4163 snprintf(new_label, BUF_SIZE, "catch_%s_%d",p->u1.str, control_statement_count);
4164
4165 if (gen_prios(switch_case, new_label, p->u2.statements, mother_exten,this_context)) { /* this will link in all the catch body statements here */
4166 return -1;
4167 }
4168 if (switch_case->return_needed) { /* returns now generate a Return() app call, no longer a goto to the end of the exten */
4169 char buf[2000];
4170 struct ael_priority *np2 = new_prio();
4171 np2->type = AEL_APPCALL;
4172