Mon Nov 24 15:34:46 2008

Asterisk developer's documentation


pbx_ael.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/callerid.h"
#include "asterisk/ael_structs.h"

Go to the source code of this file.

Data Structures

struct  argapp

Defines

#define AST_MAX_FILENAME_LEN   256
#define DEBUG_CONTEXTS   (1 << 3)
#define DEBUG_MACROS   (1 << 2)
#define DEBUG_READ   (1 << 0)
#define DEBUG_TOKENS   (1 << 1)

Functions

void add_extensions (struct ael_extension *exten)
static int ael2_debug_contexts (int fd, int argc, char *argv[])
static int ael2_debug_macros (int fd, int argc, char *argv[])
static int ael2_debug_read (int fd, int argc, char *argv[])
static int ael2_debug_tokens (int fd, int argc, char *argv[])
static int ael2_no_debug (int fd, int argc, char *argv[])
static int ael2_reload (int fd, int argc, char *argv[])
static void ael2_semantic_check (pval *item, int *arg_errs, int *arg_warns, int *arg_notes)
void ast_compile_ael2 (struct ast_context **local_contexts, struct pval *root)
int ast_expr (char *expr, char *buf, int length)
void ast_expr_clear_extra_error_info (void)
void ast_expr_register_extra_error_info (char *errmsg)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Asterisk Extension Language Compiler",.load=load_module,.unload=unload_module,.reload=reload,)
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
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_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)
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)
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)
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 void gen_prios (struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *context)
static pvalget_contxt (pval *p)
static pvalget_extension_or_contxt (pval *p)
static pvalget_goto_target (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)
static int load_module (void)
pvalmatch_pval (pval *item)
static struct pvalmatch_pval_item (pval *item)
ael_extensionnew_exten (void)
ael_prioritynew_prio (void)
static int pbx_load_module (void)
static void print_pval (FILE *fin, pval *item, int depth)
static void print_pval_list (FILE *fin, pval *item, int depth)
static int reload (void)
static void remove_spaces_before_equals (char *str)
void set_priorities (struct ael_extension *exten)
static void substitute_commas (char *str)
void traverse_pval_item_template (pval *item, int depth)
void traverse_pval_template (pval *item, int depth)
static int unload_module (void)

Variables

static int aeldebug = 0
static struct ast_cli_entry cli_ael []
static struct ast_cli_entry cli_ael_no_debug
static char * config = "extensions.ael"
static int control_statement_count = 0
static int count_labels
static pvalcurrent_context = 0
static pvalcurrent_db = 0
static pvalcurrent_extension = 0
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 pbx_ael.c.


Define Documentation

#define AST_MAX_FILENAME_LEN   256

Definition at line 61 of file pbx_ael.c.

#define DEBUG_CONTEXTS   (1 << 3)

Definition at line 59 of file pbx_ael.c.

Referenced by ael2_debug_contexts().

#define DEBUG_MACROS   (1 << 2)

Definition at line 58 of file pbx_ael.c.

Referenced by ael2_debug_macros().

#define DEBUG_READ   (1 << 0)

Definition at line 56 of file pbx_ael.c.

Referenced by ael2_debug_read().

#define DEBUG_TOKENS   (1 << 1)

Definition at line 57 of file pbx_ael.c.

Referenced by ael2_debug_tokens().


Function Documentation

void add_extensions ( struct ael_extension exten  ) 

Definition at line 4110 of file pbx_ael.c.

References AEL_APPCALL, AEL_CONTROL1, AEL_FOR_CONTROL, AEL_IF_CONTROL, AEL_IFTIME_CONTROL, AEL_LABEL, AEL_RAND_CONTROL, AEL_RETURN, ael_priority::app, app, ael_priority::appargs, ast_add_extension2(), ast_free, ast_log(), AST_MAX_EXTENSION, pval::else_statements, ael_priority::exten, exten, ael_priority::goto_false, ael_priority::goto_true, last, LOG_WARNING, ael_extension::name, ael_priority::next, ael_priority::origin, pbx_substitute_variables_helper(), PRIORITY_HINT, ael_priority::priority_num, PV_IFTIME, PV_SWITCH, strdup, pval::type, ael_priority::type, and pval::u3.

04111 {
04112    struct ael_priority *pr;
04113    char *label=0;
04114    char realext[AST_MAX_EXTENSION];
04115    if (!exten) {
04116       ast_log(LOG_WARNING, "This file is Empty!\n" );
04117       return;
04118    }
04119    do {
04120       struct ael_priority *last = 0;
04121 
04122       memset(realext, '\0', sizeof(realext));
04123       pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
04124       if (exten->hints) {
04125          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, 
04126                           exten->hints, NULL, ast_free, registrar)) {
04127             ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
04128                   exten->name);
04129          }
04130       }
04131       
04132       for (pr=exten->plist; pr; pr=pr->next) {
04133          char app[2000];
04134          char appargs[2000];
04135 
04136          /* before we can add the extension, we need to prep the app/appargs;
04137             the CONTROL types need to be done after the priority numbers are calculated.
04138          */
04139          if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
04140             last = pr;
04141             continue;
04142          }
04143          
04144          if (pr->app)
04145             strcpy(app, pr->app);
04146          else
04147             app[0] = 0;
04148          if (pr->appargs )
04149             strcpy(appargs, pr->appargs);
04150          else
04151             appargs[0] = 0;
04152          switch( pr->type ) {
04153          case AEL_APPCALL:
04154             /* easy case. Everything is all set up */
04155             break;
04156             
04157          case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
04158             /* simple, unconditional goto. */
04159             strcpy(app,"Goto");
04160             if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
04161                snprintf(appargs,sizeof(appargs),"%s|%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
04162             } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
04163                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
04164             } else
04165                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
04166             break;
04167             
04168          case AEL_FOR_CONTROL:  /* WHILE loop test, FOR loop test */
04169             strcpy(app,"GotoIf");
04170             snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04171             break;
04172             
04173          case AEL_IF_CONTROL:
04174             strcpy(app,"GotoIf");
04175             if (pr->origin->u3.else_statements )
04176                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
04177             else
04178                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04179             break;
04180 
04181          case AEL_RAND_CONTROL:
04182             strcpy(app,"Random");
04183             snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
04184             break;
04185 
04186          case AEL_IFTIME_CONTROL:
04187             strcpy(app,"GotoIfTime");
04188             snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
04189             break;
04190 
04191          case AEL_RETURN:
04192             strcpy(app,"Goto");
04193             snprintf(appargs,sizeof(appargs), "%d", exten->return_target->priority_num);
04194             break;
04195             
04196          default:
04197             break;
04198          }
04199          if (last && last->type == AEL_LABEL ) {
04200             label = last->origin->u1.str;
04201          }
04202          else
04203             label = 0;
04204          
04205          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, 
04206                           app, strdup(appargs), ast_free, registrar)) {
04207             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, 
04208                   exten->name);
04209          }
04210          last = pr;
04211       }
04212       exten = exten->next_exten;
04213    } while ( exten );
04214 }

static int ael2_debug_contexts ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 4571 of file pbx_ael.c.

References DEBUG_CONTEXTS.

04572 {
04573    aeldebug |= DEBUG_CONTEXTS;
04574    return 0;
04575 }

static int ael2_debug_macros ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 4565 of file pbx_ael.c.

References DEBUG_MACROS.

04566 {
04567    aeldebug |= DEBUG_MACROS;
04568    return 0;
04569 }

static int ael2_debug_read ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 4553 of file pbx_ael.c.

References DEBUG_READ.

04554 {
04555    aeldebug |= DEBUG_READ;
04556    return 0;
04557 }

static int ael2_debug_tokens ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 4559 of file pbx_ael.c.

References DEBUG_TOKENS.

04560 {
04561    aeldebug |= DEBUG_TOKENS;
04562    return 0;
04563 }

static int ael2_no_debug ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 4577 of file pbx_ael.c.

04578 {
04579    aeldebug = 0;
04580    return 0;
04581 }

static int ael2_reload ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 4583 of file pbx_ael.c.

References pbx_load_module().

04584 {
04585    return (pbx_load_module());
04586 }

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

Definition at line 2744 of file pbx_ael.c.

References app, argdesc_destroy(), argdesc_parse(), ast_config_AST_VAR_DIR, ast_log(), AST_MAX_FILENAME_LEN, check_context_names(), check_pval(), current_db, LOG_ERROR, LOG_NOTICE, and LOG_WARNING.

Referenced by pbx_load_module().

02745 {
02746    
02747 #ifdef AAL_ARGCHECK
02748    int argapp_errs =0;
02749    char *rfilename, *rdirname, *xappsfilename;
02750    DIR *dir = NULL;
02751    struct dirent *de;
02752 #endif
02753    struct argapp *apps=0, *xapps=0, *app;
02754 
02755    if (!item)
02756       return; /* don't check an empty tree */
02757 #ifdef AAL_ARGCHECK
02758    rfilename = alloca(10 + strlen(ast_config_AST_VAR_DIR));
02759    sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR);
02760    
02761    apps = argdesc_parse(rfilename, &argapp_errs); /* giveth */
02762 
02763    if (argapp_errs == 0) {
02764       ast_log(LOG_NOTICE, "AEL load process: parsed default apps desc file '%s'.\n", rfilename);
02765    } else {
02766       ast_log(LOG_ERROR, "AEL load process: %d errors found parsing apps file '%s'.\n", argapp_errs, rfilename);  
02767    }
02768 
02769    // Open applist.d/ for extra applists
02770    rdirname = alloca(16 + strlen(ast_config_AST_VAR_DIR));
02771    sprintf(rdirname, "%s/applist.d", ast_config_AST_VAR_DIR);
02772    dir = opendir(rdirname);
02773    if (!dir) {
02774       ast_log(LOG_WARNING, "Unable to open ael2 extra apps dir. %s is not a valid directory\n", rdirname);
02775    } else {
02776       // Reset errors count
02777       argapp_errs = 0;
02778       // Load apps from each file named *.apps into AST_VAR_DIR/applist.d/
02779       xappsfilename = alloca(AST_MAX_FILENAME_LEN + strlen(rdirname));
02780       while ((de = readdir(dir))) {
02781          xappsfilename[0] = 0;
02782          if ((strlen(de->d_name) > 4) && !strcasecmp(de->d_name + strlen(de->d_name) - 5, ".apps")) {
02783             sprintf(xappsfilename, "%s/%s", rdirname, de->d_name);
02784             xapps = argdesc_parse(xappsfilename, &argapp_errs);
02785             // If xapps list is not empty prepend it to apps
02786             if(xapps != NULL) {
02787                if (argapp_errs == 0) {
02788                   ast_log(LOG_NOTICE, "AEL load process: parsed extra apps desc file '%s'.\n", xappsfilename);
02789                } else {
02790                   ast_log(LOG_ERROR, "AEL load process: %d errors found parsing extra apps file '%s'.\n", argapp_errs, xappsfilename);
02791                }
02792                app=xapps;
02793                while (app->next != NULL) {
02794                   app=app->next;
02795                }
02796                app->next = apps;
02797                apps = xapps;
02798             } else {
02799                ast_log(LOG_WARNING, "AEL load process: no apps desc found into file '%s'.\n", xappsfilename);
02800             }
02801          }
02802       }
02803    }
02804 #endif
02805    current_db = item;
02806    errs = warns = notes = 0;
02807 
02808    check_context_names();
02809    check_pval(item, apps, 0);
02810 
02811 #ifdef AAL_ARGCHECK
02812    argdesc_destroy(apps);  /* taketh away */
02813 #endif
02814    current_db = 0;
02815 
02816    *arg_errs = errs;
02817    *arg_warns = warns;
02818    *arg_notes = notes;
02819 }

void ast_compile_ael2 ( struct ast_context **  local_contexts,
struct pval root 
)

Definition at line 4297 of file pbx_ael.c.

References context, exten, pval::list, pval::next, pbx_builtin_setvar(), PV_GLOBALS, pval::str, pval::type, pval::u1, pval::u2, and pval::val.

Referenced by pbx_load_module().

04298 {
04299    pval *p,*p2;
04300    struct ast_context *context;
04301    char buf[2000];
04302    struct ael_extension *exten;
04303    struct ael_extension *exten_list = 0;
04304 
04305    for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there
04306                             when we try to eval them */
04307       switch (p->type) {
04308       case PV_GLOBALS:
04309          /* just VARDEC elements */
04310          for (p2=p->u1.list; p2; p2=p2->next) {
04311             char buf2[2000];
04312             snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
04313             pbx_builtin_setvar(NULL, buf2);
04314          }
04315          break;
04316       default:
04317          break;
04318       }
04319    }
04320    
04321    for (p=root; p; p=p->next ) {
04322       pval *lp;
04323       int argc;
04324       
04325       switch (p->type) {
04326       case PV_MACRO:
04327          strcpy(buf,"macro-");
04328          strcat(buf,p->u1.str);
04329          context = ast_context_create(local_contexts, buf, registrar);
04330          
04331          exten = new_exten();
04332          exten->context = context;
04333          exten->name = strdup("s");
04334          argc = 1;
04335          for (lp=p->u2.arglist; lp; lp=lp->next) {
04336             /* for each arg, set up a "Set" command */
04337             struct ael_priority *np2 = new_prio();
04338             np2->type = AEL_APPCALL;
04339             np2->app = strdup("Set");
04340             snprintf(buf,sizeof(buf),"%s=${ARG%d}", lp->u1.str, argc++);
04341             remove_spaces_before_equals(buf);
04342             np2->appargs = strdup(buf);
04343             linkprio(exten, np2, NULL);
04344          }
04345          /* add any includes */
04346          for (p2=p->u3.macro_statements; p2; p2=p2->next) {
04347             pval *p3;
04348             
04349             switch (p2->type) {
04350             case PV_INCLUDES:
04351                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04352                   if ( p3->u2.arglist ) {
04353                      snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s", 
04354                             p3->u1.str,
04355                             p3->u2.arglist->u1.str,
04356                             p3->u2.arglist->next->u1.str,
04357                             p3->u2.arglist->next->next->u1.str,
04358                             p3->u2.arglist->next->next->next->u1.str);
04359                      ast_context_add_include2(context, buf, registrar);
04360                   } else
04361                      ast_context_add_include2(context, p3->u1.str, registrar);
04362                }
04363                break;
04364             default:
04365                break;
04366             }
04367          }
04368          /* CONTAINS APPCALLS, CATCH, just like extensions... */
04369          gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context );
04370          if (exten->return_needed) {
04371             struct ael_priority *np2 = new_prio();
04372             np2->type = AEL_APPCALL;
04373             np2->app = strdup("NoOp");
04374             snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
04375             np2->appargs = strdup(buf);
04376             linkprio(exten, np2, NULL);
04377             exten-> return_target = np2;
04378          }
04379          
04380          set_priorities(exten);
04381          attach_exten(&exten_list, exten);
04382          break;
04383          
04384       case PV_GLOBALS:
04385          /* already done */
04386          break;
04387          
04388       case PV_CONTEXT:
04389          context = ast_context_find_or_create(local_contexts, p->u1.str, registrar);
04390          
04391          /* contexts contain: ignorepat, includes, switches, eswitches, extensions,  */
04392          for (p2=p->u2.statements; p2; p2=p2->next) {
04393             pval *p3;
04394             char *s3;
04395             
04396             switch (p2->type) {
04397             case PV_EXTENSION:
04398                exten = new_exten();
04399                exten->name = strdup(p2->u1.str);
04400                exten->context = context;
04401                
04402                if( (s3=strchr(exten->name, '/') ) != 0 )
04403                {
04404                   *s3 = 0;
04405                   exten->cidmatch = s3+1;
04406                }
04407                
04408                if ( p2->u3.hints )
04409                   exten->hints = strdup(p2->u3.hints);
04410                exten->regexten = p2->u4.regexten;
04411                gen_prios(exten, p->u1.str, p2->u2.statements, 0, context );
04412                if (exten->return_needed) {
04413                   struct ael_priority *np2 = new_prio();
04414                   np2->type = AEL_APPCALL;
04415                   np2->app = strdup("NoOp");
04416                   snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
04417                   np2->appargs = strdup(buf);
04418                   linkprio(exten, np2, NULL);
04419                   exten-> return_target = np2;
04420                }
04421                /* is the last priority in the extension a label? Then add a trailing no-op */
04422                if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
04423                   struct ael_priority *np2 = new_prio();
04424                   np2->type = AEL_APPCALL;
04425                   np2->app = strdup("NoOp");
04426                   snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
04427                   np2->appargs = strdup(buf);
04428                   linkprio(exten, np2, NULL);
04429                }
04430 
04431                set_priorities(exten);
04432                attach_exten(&exten_list, exten);
04433                break;
04434                
04435             case PV_IGNOREPAT:
04436                ast_context_add_ignorepat2(context, p2->u1.str, registrar);
04437                break;
04438                
04439             case PV_INCLUDES:
04440                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04441                   if ( p3->u2.arglist ) {
04442                      snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s", 
04443                             p3->u1.str,
04444                             p3->u2.arglist->u1.str,
04445                             p3->u2.arglist->next->u1.str,
04446                             p3->u2.arglist->next->next->u1.str,
04447                             p3->u2.arglist->next->next->next->u1.str);
04448                      ast_context_add_include2(context, buf, registrar);
04449                   } else
04450                      ast_context_add_include2(context, p3->u1.str, registrar);
04451                }
04452                break;
04453                
04454             case PV_SWITCHES:
04455                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04456                   char *c = strchr(p3->u1.str, '/');
04457                   if (c) {
04458                      *c = '\0';
04459                      c++;
04460                   } else
04461                      c = "";
04462 
04463                   ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
04464                }
04465                break;
04466 
04467             case PV_ESWITCHES:
04468                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04469                   char *c = strchr(p3->u1.str, '/');
04470                   if (c) {
04471                      *c = '\0';
04472                      c++;
04473                   } else
04474                      c = "";
04475 
04476                   ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
04477                }
04478                break;
04479             default:
04480                break;
04481             }
04482          }
04483          
04484          break;
04485          
04486       default:
04487          /* huh? what? */
04488          break;
04489          
04490       }
04491    }
04492    /* moved these from being done after a macro or extension were processed,
04493       to after all processing is done, for the sake of fixing gotos to labels inside cases... */
04494    /* I guess this would be considered 2nd pass of compiler now... */
04495    fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */
04496    add_extensions(exten_list);   /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */
04497    destroy_extensions(exten_list);  /* all that remains is an empty husk, discard of it as is proper */
04498    
04499 }

int ast_expr ( char *  expr,
char *  buf,
int  length 
)

Definition at line 2288 of file ast_expr2f.c.

References AST_EXPR_integer, ast_yy_scan_string(), ast_yylex_destroy(), ast_yylex_init(), ast_yyparse(), free, and io.

Referenced by check_pval_item(), and pbx_substitute_variables_helper_full().

02289 {
02290    struct parse_io io;
02291    int return_value = 0;
02292    
02293    memset(&io, 0, sizeof(io));
02294    io.string = expr;  /* to pass to the error routine */
02295    
02296    ast_yylex_init(&io.scanner);
02297    
02298    ast_yy_scan_string(expr, io.scanner);
02299    
02300    ast_yyparse ((void *) &io);
02301 
02302    ast_yylex_destroy(io.scanner);
02303 
02304    if (!io.val) {
02305       if (length > 1) {
02306          strcpy(buf, "0");
02307          return_value = 1;
02308       }
02309    } else {
02310       if (io.val->type == AST_EXPR_integer) {
02311          int res_length;
02312 
02313          res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i);
02314          return_value = (res_length <= length) ? res_length : length;
02315       } else {
02316 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
02317          strncpy(buf, io.val->u.s, length - 1);
02318 #else /* !STANDALONE && !LOW_MEMORY */
02319          ast_copy_string(buf, io.val->u.s, length);
02320 #endif /* STANDALONE || LOW_MEMORY */
02321          return_value = strlen(buf);
02322          free(io.val->u.s);
02323       }
02324       free(io.val);
02325    }
02326    return return_value;
02327 }

void ast_expr_clear_extra_error_info ( void   ) 

void ast_expr_register_extra_error_info ( char *  errmsg  ) 

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT  ,
"Asterisk Extension Language Compiler"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

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

Definition at line 4216 of file pbx_ael.c.

References ael_extension::next_exten.

04217 {
04218    /* travel to the end of the list... */
04219    struct ael_extension *lptr;
04220    if( !*list ) {
04221       *list = newmem;
04222       return;
04223    }
04224    lptr = *list;
04225    
04226    while( lptr->next_exten ) {
04227       lptr = lptr->next_exten;
04228    }
04229    /* lptr should now pointing to the last element in the list; it has a null next_exten pointer */
04230    lptr->next_exten = newmem;
04231 }

static void check_abstract_reference ( pval abstract_context  )  [static]

Definition at line 2277 of file pbx_ael.c.

References current_db, pval::list, pval::next, PV_CONTEXT, PV_INCLUDES, pval::str, pval::type, pval::u1, and pval::u2.

Referenced by check_pval_item().

02278 {
02279    pval *i,*j;
02280    /* find some context includes that reference this context */
02281    
02282 
02283    /* otherwise, print out a warning */
02284    for (i=current_db; i; i=i->next) {
02285       if (i->type == PV_CONTEXT) {
02286          for (j=i->u2. statements; j; j=j->next) {
02287             if ( j->type == PV_INCLUDES ) {
02288                struct pval *p4;
02289                for (p4=j->u1.list; p4; p4=p4->next) {
02290                   /* for each context pointed to, find it, then find a context/label that matches the
02291                      target here! */
02292                   if ( !strcmp(p4->u1.str, abstract_context->u1.str) )
02293                      return; /* found a match! */
02294                }
02295             }
02296          }
02297       }
02298    }
02299    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",
02300          abstract_context->filename, abstract_context->startline, abstract_context->endline, abstract_context->u1.str);
02301    warns++;
02302 }

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

Definition at line 2078 of file pbx_ael.c.

References app, ARGD_OPTIONSET, ARGD_REQUIRED, ARGD_VARARG, ast_log(), argdesc::dtype, pval::endline, pval::filename, LOG_WARNING, argdesc::name, argdesc::next, pval::next, pval::startline, pval::str, argdesc::type, and pval::u1.

Referenced by check_pval_item().

02079 {
02080 #ifdef AAL_ARGCHECK
02081    struct argdesc *ad = app->args;
02082    pval *pa;
02083    int z;
02084    
02085    for (pa = arglist; pa; pa=pa->next) {
02086       if (!ad) {
02087          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
02088                arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
02089          warns++;
02090          return 1;
02091       } else {
02092          /* find the first entry in the ad list that will match */
02093          do {
02094             if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */
02095                break;
02096             
02097             z= option_matches( ad, pa, app);
02098             if (!z) {
02099                if ( !arglist )
02100                   arglist=appcall;
02101                
02102                if (ad->type == ARGD_REQUIRED) {
02103                   ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02104                         arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02105                   warns++;
02106                   return 1;
02107                }
02108             } else if (z && ad->dtype == ARGD_OPTIONSET) {
02109                option_matches_j( ad, pa, app);
02110             }
02111             ad = ad->next;
02112          } while (ad && !z);
02113       }
02114    }
02115    /* any app nodes left, that are not optional? */
02116    for ( ; ad; ad=ad->next) {
02117       if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
02118          if ( !arglist ) 
02119             arglist=appcall;
02120          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02121                arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02122          warns++;
02123          return 1;
02124       }
02125    }
02126    return 0;
02127 #else
02128    return 0;
02129 #endif
02130 }

static int check_break ( pval item  )  [static]

Definition at line 1058 of file pbx_ael.c.

References ast_log(), pval::dad, pval::endline, pval::filename, LOG_ERROR, PV_CASE, PV_CONTEXT, PV_DEFAULT, PV_FOR, PV_MACRO, PV_PATTERN, PV_WHILE, pval::startline, and pval::type.

Referenced by check_pval_item().

01059 {
01060    pval *p = item;
01061    
01062    while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
01063       /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make
01064          no sense */
01065       if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN 
01066          || p->type == PV_WHILE || p->type == PV_FOR   ) {
01067          return 1;
01068       }
01069       p = p->dad;
01070    }
01071    ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'break' not in switch, for, or while statement!\n",
01072          item->filename, item->startline, item->endline);
01073    errs++;
01074    
01075    return 0;
01076 }

static void check_context_names ( void   )  [static]

Definition at line 2258 of file pbx_ael.c.

References pval::abstract, ast_log(), current_db, pval::endline, pval::filename, LOG_ERROR, pval::next, PV_CONTEXT, PV_MACRO, pval::startline, pval::str, pval::type, pval::u1, and pval::u3.

Referenced by ael2_semantic_check().

02259 {
02260    pval *i,*j;
02261    for (i=current_db; i; i=i->next) {
02262       if (i->type == PV_CONTEXT || i->type == PV_MACRO) {
02263          for (j=i->next; j; j=j->next) {
02264             if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) {
02265                if ( !strcmp(i->u1.str, j->u1.str) && !(i->u3.abstract&2) && !(j->u3.abstract&2) )
02266                {
02267                   ast_log(LOG_ERROR,"Error: file %s, line %d-%d: The context name (%s) is also declared in file %s, line %d-%d! (and neither is marked 'extend')\n",
02268                         i->filename, i->startline, i->endline, i->u1.str,  j->filename, j->startline, j->endline);
02269                   errs++;
02270                }
02271             }
02272          }
02273       }
02274    }
02275 }

static int check_continue ( pval item  )  [static]

Definition at line 1078 of file pbx_ael.c.

References ast_log(), pval::dad, pval::endline, pval::filename, LOG_ERROR, PV_CONTEXT, PV_FOR, PV_MACRO, PV_WHILE, pval::startline, and pval::type.

Referenced by check_pval_item().

01079 {
01080    pval *p = item;
01081    
01082    while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
01083       /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make
01084          no sense */
01085       if( p->type == PV_WHILE || p->type == PV_FOR   ) {
01086          return 1;
01087       }
01088       p = p->dad;
01089    }
01090    ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'continue' not in 'for' or 'while' statement!\n",
01091          item->filename, item->startline, item->endline);
01092    errs++;
01093    
01094    return 0;
01095 }

static void check_day ( pval DAY  )  [static]

Definition at line 957 of file pbx_ael.c.

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

Referenced by check_pval_item().

00958 {
00959    char *day;
00960    char *c;
00961    /* The following line is coincidence, really! */
00962    int s, e;
00963 
00964    day = ast_strdupa(DAY->u1.str);
00965 
00966    /* Check for all days */
00967    if (ast_strlen_zero(day) || !strcmp(day, "*")) {
00968       return;
00969    }
00970    /* Get start and ending days */
00971    c = strchr(day, '-');
00972    if (c) {
00973       *c = '\0';
00974       c++;
00975    }
00976    /* Find the start */
00977    if (sscanf(day, "%d", &s) != 1) {
00978       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number!\n",
00979             DAY->filename, DAY->startline, DAY->endline, day);
00980       warns++;
00981    }
00982    else if ((s < 1) || (s > 31)) {
00983       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",
00984             DAY->filename, DAY->startline, DAY->endline, day);
00985       warns++;
00986    }
00987    s--;
00988    if (c) {
00989       if (sscanf(c, "%d", &e) != 1) {
00990          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number!\n",
00991                DAY->filename, DAY->startline, DAY->endline, c);
00992          warns++;
00993       }
00994       else if ((e < 1) || (e > 31)) {
00995          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",
00996                DAY->filename, DAY->startline, DAY->endline, day);
00997          warns++;
00998       }
00999       e--;
01000    } else
01001       e = s;
01002 }

static void check_dow ( pval DOW  )  [static]

get_dow: Get day of week

Definition at line 918 of file pbx_ael.c.

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

Referenced by check_pval_item().

00919 {
00920    char *dow;
00921    char *c;
00922    /* The following line is coincidence, really! */
00923    int s, e;
00924    
00925    dow = ast_strdupa(DOW->u1.str);
00926 
00927    /* Check for all days */
00928    if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
00929       return;
00930    /* Get start and ending days */
00931    c = strchr(dow, '-');
00932    if (c) {
00933       *c = '\0';
00934       c++;
00935    } else
00936       c = NULL;
00937    /* Find the start */
00938    s = 0;
00939    while ((s < 7) && strcasecmp(dow, days[s])) s++;
00940    if (s >= 7) {
00941       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",
00942             DOW->filename, DOW->startline, DOW->endline, dow);
00943       warns++;
00944    }
00945    if (c) {
00946       e = 0;
00947       while ((e < 7) && strcasecmp(c, days[e])) e++;
00948       if (e >= 7) {
00949          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",
00950                DOW->filename, DOW->startline, DOW->endline, c);
00951          warns++;
00952       }
00953    } else
00954       e = s;
00955 }

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

Definition at line 821 of file pbx_ael.c.

References ast_log(), pval::endline, pval::filename, LOG_WARNING, and pval::startline.

Referenced by check_pval_item().

00822 {
00823    int spaces = strspn(str,"\t \n");
00824    if ( !strncmp(str+spaces,"$[",2) ) {
00825       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The expression '%s' is redundantly wrapped in '$[ ]'. \n",
00826             expr->filename, expr->startline, expr->endline, str);
00827       warns++;
00828    }
00829 }

static void check_goto ( pval item  )  [static]

Definition at line 1193 of file pbx_ael.c.

References ast_log(), pval::endline, pval::filename, find_context(), find_label_in_current_context(), find_label_in_current_db(), find_label_in_current_extension(), get_contxt(), get_extension_or_contxt(), pval::list, LOG_ERROR, LOG_WARNING, pval::next, PV_INCLUDES, pval::startline, pval::statements, pval::str, pval::type, pval::u1, and pval::u2.

Referenced by check_pval_item(), and find_pval_goto_item().

01194 {
01195    /* check for the target of the goto-- does it exist? */
01196    if ( !(item->u1.list)->next && !(item->u1.list)->u1.str ) {
01197       ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto:  empty label reference found!\n",
01198             item->filename, item->startline, item->endline);
01199       errs++;
01200    }
01201    
01202    /* just one item-- the label should be in the current extension */
01203    
01204    if (item->u1.list && !item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) {
01205       struct pval *z = get_extension_or_contxt(item);
01206       struct pval *x = 0;
01207       if (z)
01208          x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), z); /* if in macro, use current context instead */
01209       /* printf("Called find_label_in_current_extension with arg %s; current_extension is %x: %d\n",
01210          (char*)((item->u1.list)->u1.str), current_extension?current_extension:current_context, current_extension?current_extension->type:current_context->type); */
01211       if (!x) {
01212          ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto:  no label %s exists in the current extension!\n",
01213                item->filename, item->startline, item->endline, item->u1.list->u1.str);
01214          errs++;
01215       }
01216       else
01217          return;
01218    }
01219    
01220    /* TWO items */
01221    if (item->u1.list->next && !item->u1.list->next->next) {
01222       /* two items */
01223       /* printf("Calling find_label_in_current_context with args %s, %s\n",
01224          (char*)((item->u1.list)->u1.str), (char *)item->u1.list->next->u1.str); */
01225       if (!strstr((item->u1.list)->u1.str,"${") 
01226          && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ {
01227          struct pval *z = get_contxt(item);
01228          struct pval *x = 0;
01229          
01230          if (z)
01231             x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, z);
01232 
01233          if (!x) {
01234             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",
01235                   item->filename, item->startline, item->endline, item->u1.list->u1.str, item->u1.list->next->u1.str );
01236             errs++;
01237          }
01238          else
01239             return;
01240       }
01241    }
01242    
01243    /* All 3 items! */
01244    if (item->u1.list->next && item->u1.list->next->next) {
01245       /* all three */
01246       pval *first = item->u1.list;
01247       pval *second = item->u1.list->next;
01248       pval *third = item->u1.list->next->next;
01249       
01250       /* printf("Calling find_label_in_current_db with args %s, %s, %s\n",
01251          (char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); */
01252       if (!strstr((item->u1.list)->u1.str,"${") 
01253          && !strstr(item->u1.list->next->u1.str,"${")
01254          && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ {
01255          struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
01256          if (!x) {
01257             struct pval *p3;
01258             struct pval *found = 0;
01259             struct pval *that_context = find_context(item->u1.list->u1.str);
01260             
01261             /* the target of the goto could be in an included context!! Fancy that!! */
01262             /* look for includes in the current context */
01263             if (that_context) {
01264                for (p3=that_context->u2.statements; p3; p3=p3->next) {
01265                   if (p3->type == PV_INCLUDES) {
01266                      struct pval *p4;
01267                      for (p4=p3->u1.list; p4; p4=p4->next) {
01268                         /* for each context pointed to, find it, then find a context/label that matches the
01269                            target here! */
01270                         char *incl_context = p4->u1.str;
01271                         /* find a matching context name */
01272                         struct pval *that_other_context = find_context(incl_context);
01273                         if (that_other_context) {
01274                            struct pval *x3;
01275                            x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
01276                            if (x3) {
01277                               found = x3;
01278                               break;
01279                            }
01280                         }
01281                      }
01282                   }
01283                }
01284                if (!found) {
01285                   ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto:  no label %s|%s exists in the context %s or its inclusions!\n",
01286                         item->filename, item->startline, item->endline, item->u1.list->next->u1.str, item->u1.list->next->next->u1.str, item->u1.list->u1.str );
01287                   errs++;
01288                }
01289             } else {
01290                /* here is where code would go to check for target existence in extensions.conf files */
01291                ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto:  no context %s could be found that matches the goto target!\n",
01292                      item->filename, item->startline, item->endline, item->u1.list->u1.str);
01293                warns++; /* this is just a warning, because this context could be in extensions.conf or somewhere */
01294             }
01295          }
01296       }
01297    }
01298 }

static void check_includes ( pval includes  )  [static]

Definition at line 831 of file pbx_ael.c.

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

Referenced by check_pval_item().

00832 {
00833    struct pval *p4;
00834    for (p4=includes->u1.list; p4; p4=p4->next) {
00835       /* for each context pointed to, find it, then find a context/label that matches the
00836          target here! */
00837       char *incl_context = p4->u1.str;
00838       /* find a matching context name */
00839       struct pval *that_other_context = find_context(incl_context);
00840       if (!that_other_context && strcmp(incl_context, "parkedcalls") != 0) {
00841          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The included context '%s' cannot be found.\n\
00842  (You may ignore this warning if '%s' exists in extensions.conf, or is created by another module. I cannot check for those.)\n",
00843                includes->filename, includes->startline, includes->endline, incl_context, incl_context);
00844          warns++;
00845       }
00846    }
00847 }

static void check_label ( pval item  )  [static]

Definition at line 1100 of file pbx_ael.c.

References ast_log(), current_context, current_extension, pval::endline, pval::filename, find_first_label_in_current_context(), LOG_ERROR, pval::startline, pval::str, and pval::u1.

Referenced by check_pval_item().

01101 {
01102    /* basically, ensure that a label is not repeated in a context. Period.
01103       The method:  well, for each label, find the first label in the context
01104       with the same name. If it's not the current label, then throw an error. */
01105    struct pval *curr;
01106    struct pval *x;
01107    
01108    /* printf("==== check_label:   ====\n"); */
01109    if( !current_extension )
01110       curr = current_context;
01111    else
01112       curr = current_extension;
01113    
01114    x = find_first_label_in_current_context((char *)item->u1.str, curr);
01115    /* 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); */
01116    if( x && x != item )
01117    {
01118       ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Duplicate label %s! Previously defined at file %s, line %d.\n",
01119             item->filename, item->startline, item->endline, item->u1.str, x->filename, x->startline);
01120       errs++;
01121    }
01122    /* printf("<<<<< check_label:   ====\n"); */
01123 }

static void check_month ( pval MON  )  [static]

Definition at line 1020 of file pbx_ael.c.

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

Referenced by check_pval_item().

01021 {
01022    char *mon;
01023    char *c;
01024    /* The following line is coincidence, really! */
01025    int s, e;
01026 
01027    mon = ast_strdupa(MON->u1.str);
01028 
01029    /* Check for all days */
01030    if (ast_strlen_zero(mon) || !strcmp(mon, "*")) 
01031       return ;
01032    /* Get start and ending days */
01033    c = strchr(mon, '-');
01034    if (c) {
01035       *c = '\0';
01036       c++;
01037    }
01038    /* Find the start */
01039    s = 0;
01040    while ((s < 12) && strcasecmp(mon, months[s])) s++;
01041    if (s >= 12) {
01042       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
01043             MON->filename, MON->startline, MON->endline, mon);
01044       warns++;
01045    }
01046    if (c) {
01047       e = 0;
01048       while ((e < 12) && strcasecmp(mon, months[e])) e++;
01049       if (e >= 12) {
01050          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
01051                MON->filename, MON->startline, MON->endline, c);
01052          warns++;
01053       }
01054    } else
01055       e = s;
01056 }

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

Definition at line 2724 of file pbx_ael.c.

References check_pval_item(), and pval::next.

Referenced by ael2_semantic_check(), and check_pval_item().

02725 {
02726    pval *i;
02727 
02728    /* checks to do:
02729       1. Do goto's point to actual labels? 
02730       2. Do macro calls reference a macro?
02731       3. Does the number of macro args match the definition?
02732       4. Is a macro call missing its & at the front?
02733       5. Application calls-- we could check syntax for existing applications,
02734          but I need some some sort of universal description bnf for a general
02735         sort of method for checking arguments, in number, maybe even type, at least. 
02736         Don't want to hand code checks for hundreds of applications.
02737    */
02738    
02739    for (i=item; i; i=i->next) {
02740       check_pval_item(i,apps,in_globals);
02741    }
02742 }

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

Definition at line 2305 of file pbx_ael.c.

References pval::abstract, app, pval::arglist, ast_expr(), ast_expr_clear_extra_error_info(), ast_expr_register_extra_error_info(), ast_log(), check_abstract_reference(), check_app_args(), check_break(), check_continue(), check_day(), check_dow(), check_expr2_input(), check_goto(), check_includes(), check_label(), check_month(), check_pval(), check_switch_expr(), check_timerange(), current_context, current_extension, pval::else_statements, pval::endcol, pval::endline, pval::filename, find_context(), find_macro(), find_pval_gotos(), pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, pval::list, LOG_ERROR, LOG_WARNING, pval::macro_statements, pval::next, 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_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pval::startcol, pval::startline, pval::statements, pval::str, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.

Referenced by check_pval().

02306 {
02307    pval *lp;
02308 #ifdef AAL_ARGCHECK
02309    struct argapp *app, *found;
02310 #endif
02311    struct pval *macro_def;
02312    struct pval *app_def;
02313    
02314    char errmsg[4096];
02315    char *strp;
02316    
02317    switch (item->type) {
02318    case PV_WORD:
02319       /* fields: item->u1.str == string associated with this (word).
02320                  item->u2.arglist  == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */
02321       break;
02322       
02323    case PV_MACRO:
02324       /* fields: item->u1.str     == name of macro
02325                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
02326                item->u2.arglist->u1.str  == argument
02327                item->u2.arglist->next   == next arg
02328 
02329                item->u3.macro_statements == pval list of statements in macro body.
02330       */
02331       in_abstract_context = 0;
02332       current_context = item;
02333       current_extension = 0;
02334       for (lp=item->u2.arglist; lp; lp=lp->next) {
02335       
02336       }
02337       check_pval(item->u3.macro_statements, apps,in_globals);
02338       break;
02339          
02340    case PV_CONTEXT:
02341       /* fields: item->u1.str     == name of context
02342                  item->u2.statements == pval list of statements in context body
02343                item->u3.abstract == int 1 if an abstract keyword were present
02344       */
02345       current_context = item;
02346       current_extension = 0;
02347       if ( item->u3.abstract ) {
02348          in_abstract_context = 1;
02349          check_abstract_reference(item);
02350       } else
02351          in_abstract_context = 0;
02352       check_pval(item->u2.statements, apps,in_globals);
02353       break;
02354          
02355    case PV_MACRO_CALL:
02356       /* fields: item->u1.str     == name of macro to call
02357                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
02358                item->u2.arglist->u1.str  == argument
02359                item->u2.arglist->next   == next arg
02360       */
02361       macro_def = find_macro(item->u1.str);
02362       if (!macro_def) {
02363          /* here is a good place to check to see if the definition is in extensions.conf! */
02364          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s ! Hopefully it is present in extensions.conf! \n",
02365                item->filename, item->startline, item->endline, item->u1.str);
02366          warns++;
02367       } else if (macro_def->type != PV_MACRO) {
02368          ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n",
02369                item->filename, item->startline, item->endline, item->u1.str);
02370          errs++;
02371       } else {
02372          /* macro_def is a MACRO, so do the args match in number? */
02373          int hereargs = 0;
02374          int thereargs = 0;
02375          
02376          for (lp=item->u2.arglist; lp; lp=lp->next) {
02377             hereargs++;
02378          }
02379          for (lp=macro_def->u2.arglist; lp; lp=lp->next) {
02380             thereargs++;
02381          }
02382          if (hereargs != thereargs ) {
02383             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",
02384                   item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs);
02385             errs++;
02386          }
02387       }
02388       break;
02389          
02390    case PV_APPLICATION_CALL:
02391       /* fields: item->u1.str     == name of application to call
02392                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
02393                item->u2.arglist->u1.str  == argument
02394                item->u2.arglist->next   == next arg
02395       */
02396       /* Need to check to see if the application is available! */
02397       app_def = find_context(item->u1.str);
02398       if (app_def && app_def->type == PV_MACRO) {
02399          ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n",
02400                item->filename, item->startline, item->endline, item->u1.str);
02401          errs++;
02402       }
02403       if (strcasecmp(item->u1.str,"GotoIf") == 0
02404          || strcasecmp(item->u1.str,"GotoIfTime") == 0
02405          || strcasecmp(item->u1.str,"while") == 0
02406          || strcasecmp(item->u1.str,"endwhile") == 0
02407          || strcasecmp(item->u1.str,"random") == 0
02408          || strcasecmp(item->u1.str,"execIf") == 0 ) {
02409          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s needs to be re-written using AEL if, while, goto, etc. keywords instead!\n",
02410                item->filename, item->startline, item->endline, item->u1.str);
02411          warns++;
02412       }
02413 #ifdef AAL_ARGCHECK
02414       found = 0;
02415       for (app=apps; app; app=app->next) {
02416          if (strcasecmp(app->name, item->u1.str) == 0) {
02417             found =app;
02418             break;
02419          }
02420       }
02421       if (!found) {
02422          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n",
02423                item->filename, item->startline, item->endline, item->u1.str);
02424          warns++;
02425       } else
02426          check_app_args(item, item->u2.arglist, app);
02427 #endif
02428       break;
02429       
02430    case PV_CASE:
02431       /* fields: item->u1.str     == value of case
02432                  item->u2.statements == pval list of statements under the case
02433       */
02434       /* Make sure sequence of statements under case is terminated with  goto, return, or break */
02435       /* find the last statement */
02436       check_pval(item->u2.statements, apps,in_globals);
02437       break;
02438          
02439    case PV_PATTERN:
02440       /* fields: item->u1.str     == value of case
02441                  item->u2.statements == pval list of statements under the case
02442       */
02443       /* Make sure sequence of statements under case is terminated with  goto, return, or break */
02444       /* find the last statement */
02445       
02446       check_pval(item->u2.statements, apps,in_globals);
02447       break;
02448          
02449    case PV_DEFAULT:
02450       /* fields: 
02451                  item->u2.statements == pval list of statements under the case
02452       */
02453 
02454       check_pval(item->u2.statements, apps,in_globals);
02455       break;
02456          
02457    case PV_CATCH:
02458       /* fields: item->u1.str     == name of extension to catch
02459                  item->u2.statements == pval list of statements in context body
02460       */
02461       check_pval(item->u2.statements, apps,in_globals);
02462       break;
02463          
02464    case PV_SWITCHES:
02465       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
02466       */
02467       check_pval(item->u1.list, apps,in_globals);
02468       break;
02469          
02470    case PV_ESWITCHES:
02471       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
02472       */
02473       check_pval(item->u1.list, apps,in_globals);
02474       break;
02475          
02476    case PV_INCLUDES:
02477       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
02478       */
02479       check_pval(item->u1.list, apps,in_globals);
02480       check_includes(item);
02481       for (lp=item->u1.list; lp; lp=lp->next){
02482          char *incl_context = lp->u1.str;
02483          struct pval *that_context = find_context(incl_context);
02484 
02485          if ( lp->u2.arglist ) {
02486             check_timerange(lp->u2.arglist);
02487             check_dow(lp->u2.arglist->next);
02488             check_day(lp->u2.arglist->next->next);
02489             check_month(lp->u2.arglist->next->next->next);
02490          }
02491          
02492          if (that_context) {
02493             find_pval_gotos(that_context->u2.statements,0);
02494             
02495          }
02496       }
02497       break;
02498          
02499    case PV_STATEMENTBLOCK:
02500       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
02501       */
02502       check_pval(item->u1.list, apps,in_globals);
02503       break;
02504          
02505    case PV_VARDEC:
02506       /* fields: item->u1.str     == variable name
02507                  item->u2.val     == variable value to assign
02508       */
02509       /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
02510       if( !in_globals ) { /* don't check stuff inside the globals context; no wrapping in $[ ] there... */
02511          snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", config, item->startline, item->startcol, item->endcol, item->u2.val);
02512          ast_expr_register_extra_error_info(errmsg);
02513          ast_expr(item->u2.val, expr_output, sizeof(expr_output));
02514          ast_expr_clear_extra_error_info();
02515          if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
02516             ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02517                   item->filename, item->startline, item->endline, item->u2.val);
02518             warns++;
02519          }
02520          check_expr2_input(item,item->u2.val);
02521       }
02522       break;
02523          
02524    case PV_GOTO:
02525       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
02526                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
02527       */
02528       /* don't check goto's in abstract contexts */
02529       if ( in_abstract_context )
02530          break;
02531       
02532       check_goto(item);
02533       break;
02534          
02535    case PV_LABEL:
02536       /* fields: item->u1.str     == label name
02537       */
02538       if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) {
02539          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n",
02540                item->filename, item->startline, item->endline, item->u1.str);
02541          warns++;
02542       }
02543 
02544       check_label(item);
02545       break;
02546          
02547    case PV_FOR:
02548       /* fields: item->u1.for_init     == a string containing the initalizer
02549                  item->u2.for_test     == a string containing the loop test
02550                  item->u3.for_inc      == a string containing the loop increment
02551 
02552                item->u4.for_statements == a pval list of statements in the for ()
02553       */
02554       snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, for test expr '%s':", config, item->startline, item->startcol, item->endcol, item->u2.for_test);
02555       ast_expr_register_extra_error_info(errmsg);
02556 
02557       strp = strchr(item->u1.for_init, '=');
02558       if (strp) {
02559          ast_expr(strp+1, expr_output, sizeof(expr_output));
02560       }
02561       ast_expr(item->u2.for_test, expr_output, sizeof(expr_output));
02562       strp = strchr(item->u3.for_inc, '=');
02563       if (strp) {
02564          ast_expr(strp+1, expr_output, sizeof(expr_output));
02565       }
02566       if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) {
02567          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02568                item->filename, item->startline, item->endline, item->u2.for_test);
02569          warns++;
02570       }
02571       if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) {
02572          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02573                item->filename, item->startline, item->endline, item->u3.for_inc);
02574          warns++;
02575       }
02576       check_expr2_input(item,item->u2.for_test);
02577       check_expr2_input(item,item->u3.for_inc);
02578       
02579       ast_expr_clear_extra_error_info();
02580       check_pval(item->u4.for_statements, apps,in_globals);
02581       break;
02582          
02583    case PV_WHILE:
02584       /* fields: item->u1.str        == the while conditional, as supplied by user
02585 
02586                item->u2.statements == a pval list of statements in the while ()
02587       */
02588       snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, while expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02589       ast_expr_register_extra_error_info(errmsg);
02590       ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02591       ast_expr_clear_extra_error_info();
02592       if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02593          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
02594                item->filename, item->startline, item->endline, item->u1.str);
02595          warns++;
02596       }
02597       check_expr2_input(item,item->u1.str);
02598       check_pval(item->u2.statements, apps,in_globals);
02599       break;
02600          
02601    case PV_BREAK:
02602       /* fields: none
02603       */
02604       check_break(item);
02605       break;
02606          
02607    case PV_RETURN:
02608       /* fields: none
02609       */
02610       break;
02611          
02612    case PV_CONTINUE:
02613       /* fields: none
02614       */
02615       check_continue(item);
02616       break;
02617          
02618    case PV_RANDOM:
02619       /* fields: item->u1.str        == the random number expression, as supplied by user
02620 
02621                item->u2.statements == a pval list of statements in the if ()
02622                item->u3.else_statements == a pval list of statements in the else
02623                                     (could be zero)
02624       */
02625       snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, random expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02626       ast_expr_register_extra_error_info(errmsg);
02627       ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02628       ast_expr_clear_extra_error_info();
02629       if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02630          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n",
02631                item->filename, item->startline, item->endline, item->u1.str);
02632          warns++;
02633       }
02634       check_expr2_input(item,item->u1.str);
02635       check_pval(item->u2.statements, apps,in_globals);
02636       if (item->u3.else_statements) {
02637          check_pval(item->u3.else_statements, apps,in_globals);
02638       }
02639       break;
02640 
02641    case PV_IFTIME:
02642       /* fields: item->u1.list        == the if time values, 4 of them, each in PV_WORD, linked list 
02643 
02644                item->u2.statements == a pval list of statements in the if ()
02645                item->u3.else_statements == a pval list of statements in the else
02646                                     (could be zero)
02647       */
02648       if ( item->u2.arglist ) {
02649          check_timerange(item->u1.list);
02650          check_dow(item->u1.list->next);
02651          check_day(item->u1.list->next->next);
02652          check_month(item->u1.list->next->next->next);
02653       }
02654 
02655       check_pval(item->u2.statements, apps,in_globals);
02656       if (item->u3.else_statements) {
02657          check_pval(item->u3.else_statements, apps,in_globals);
02658       }
02659       break;
02660          
02661    case PV_IF:
02662       /* fields: item->u1.str        == the if conditional, as supplied by user
02663 
02664                item->u2.statements == a pval list of statements in the if ()
02665                item->u3.else_statements == a pval list of statements in the else
02666                                     (could be zero)
02667       */
02668       snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, if expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str);
02669       ast_expr_register_extra_error_info(errmsg);
02670       ast_expr(item->u1.str, expr_output, sizeof(expr_output));
02671       ast_expr_clear_extra_error_info();
02672       if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
02673          ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n",
02674                item->filename, item->startline, item->endline, item->u1.str);
02675          warns++;
02676       }
02677       check_expr2_input(item,item->u1.str);
02678       check_pval(item->u2.statements, apps,in_globals);
02679       if (item->u3.else_statements) {
02680          check_pval(item->u3.else_statements, apps,in_globals);
02681       }
02682       break;
02683          
02684    case PV_SWITCH:
02685       /* fields: item->u1.str        == the switch expression
02686 
02687                item->u2.statements == a pval list of statements in the switch, 
02688                                     (will be case statements, most likely!)
02689       */
02690       /* we can check the switch expression, see if it matches any of the app variables...
02691            if it does, then, are all the possible cases accounted for? */
02692       check_switch_expr(item, apps);
02693       check_pval(item->u2.statements, apps,in_globals);
02694       break;
02695          
02696    case PV_EXTENSION:
02697       /* fields: item->u1.str        == the extension name, label, whatever it's called
02698 
02699                item->u2.statements == a pval list of statements in the extension
02700                item->u3.hints      == a char * hint argument
02701                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
02702       */
02703       current_extension = item ;
02704       
02705       check_pval(item->u2.statements, apps,in_globals);
02706       break;
02707          
02708    case PV_IGNOREPAT:
02709       /* fields: item->u1.str        == the ignorepat data
02710       */
02711       break;
02712          
02713    case PV_GLOBALS:
02714       /* fields: item->u1.statements     == pval list of statements, usually vardecs
02715       */
02716       in_abstract_context = 0;
02717       check_pval(item->u1.statements, apps, 1);
02718       break;
02719    default:
02720       break;
02721    }
02722 }

void check_switch_expr ( pval item,
struct argapp apps 
)

Definition at line 2132 of file pbx_ael.c.

References ast_strdupa, appsetvar::name, appsetvar::next, argapp::next, argapp::setvars, pval::str, t, and pval::u1.

Referenced by check_pval_item().

02133 {
02134 #ifdef AAL_ARGCHECK
02135    /* get and clean the variable name */
02136    char *buff1, *p;
02137    struct argapp *a,*a2;
02138    struct appsetvar *v,*v2;
02139    struct argchoice *c;
02140    pval *t;
02141    
02142    p = item->u1.str;
02143    while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) )
02144       p++;
02145    
02146    buff1 = ast_strdupa(p);
02147 
02148    while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t'))
02149       buff1[strlen(buff1)-1] = 0;
02150    /* buff1 now contains the variable name */
02151    v = 0;
02152    for (a=apps; a; a=a->next) {
02153       for (v=a->setvars;v;v=v->next) {
02154          if (strcmp(v->name,buff1) == 0) {
02155             break;
02156          }
02157       }
02158       if ( v )
02159          break;
02160    }
02161    if (v && v->vals) {
02162       /* we have a match, to a variable that has a set of determined values */
02163       int def= 0;
02164       int pat = 0;
02165       int f1 = 0;
02166       
02167       /* first of all, does this switch have a default case ? */
02168       for (t=item->u2.statements; t; t=t->next) {
02169          if (t->type == PV_DEFAULT) {
02170             def =1;
02171             break;
02172          }
02173          if (t->type == PV_PATTERN) {
02174             pat++;
02175          }
02176       }
02177       if (def || pat) /* nothing to check. All cases accounted for! */
02178          return;
02179       for (c=v->vals; c; c=c->next) {
02180          f1 = 0;
02181          for (t=item->u2.statements; t; t=t->next) {
02182             if (t->type == PV_CASE || t->type == PV_PATTERN) {
02183                if (!strcmp(t->u1.str,c->name)) {
02184                   f1 = 1;
02185                   break;
02186                }
02187             }
02188          }
02189          if (!f1) {
02190             ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n",
02191                   item->filename, item->startline, item->endline, item->u1.str, c->name);
02192             warns++;
02193          }
02194       }
02195       /* next, is there an app call in the current exten, that would set this var? */
02196       f1 = 0;
02197       t = current_extension->u2.statements;
02198       if ( t && t->type == PV_STATEMENTBLOCK )
02199          t = t->u1.statements;
02200       for (; t && t != item; t=t->next) {
02201          if (t->type == PV_APPLICATION_CALL) {
02202             /* find the application that matches the u1.str */
02203             for (a2=apps; a2; a2=a2->next) {
02204                if (strcasecmp(a2->name, t->u1.str)==0) {
02205                   for (v2=a2->setvars; v2; v2=v2->next) {
02206                      if (strcmp(v2->name, buff1) == 0) {
02207                         /* found an app that sets the var */
02208                         f1 = 1;
02209                         break;
02210                      }
02211                   }
02212                }
02213                if (f1)
02214                   break;
02215             }
02216          }
02217          if (f1)
02218             break;
02219       }
02220             
02221       /* see if it sets the var */
02222       if (!f1) {
02223          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",
02224                item->filename, item->startline, item->endline, item->u1.str);
02225          warns++;
02226       }
02227    }
02228 #else
02229    pval *t,*tl=0,*p2;
02230    int def= 0;
02231    
02232    /* first of all, does this switch have a default case ? */
02233    for (t=item->u2.statements; t; t=t->next) {
02234       if (t->type == PV_DEFAULT) {
02235          def =1;
02236          break;
02237       }
02238       tl = t;
02239    }
02240    if (def) /* nothing to check. All cases accounted for! */
02241       return;
02242    /* if no default, warn and insert a default case at the end */
02243    p2 = tl->next = calloc(1, sizeof(struct pval));
02244    
02245    p2->type = PV_DEFAULT;
02246    p2->startline = tl->startline;
02247    p2->endline = tl->endline;
02248    p2->startcol = tl->startcol;
02249    p2->endcol = tl->endcol;
02250    p2->filename = strdup(tl->filename);
02251    ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n",
02252          p2->filename, p2->startline, p2->endline);
02253    warns++;
02254 
02255 #endif
02256 }

static void check_timerange ( pval p  )  [static]

Definition at line 850 of file pbx_ael.c.

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

Referenced by check_pval_item().

00851 {
00852    char *times;
00853    char *e;
00854    int s1, s2;
00855    int e1, e2;
00856 
00857    times = ast_strdupa(p->u1.str);
00858 
00859    /* Star is all times */
00860    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
00861       return;
00862    }
00863    /* Otherwise expect a range */
00864    e = strchr(times, '-');
00865    if (!e) {
00866       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",
00867             p->filename, p->startline, p->endline, times);
00868       warns++;
00869       return;
00870    }
00871    *e = '\0';
00872    e++;
00873    while (*e && !isdigit(*e)) 
00874       e++;
00875    if (!*e) {
00876       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n",
00877             p->filename, p->startline, p->endline, p->u1.str);
00878       warns++;
00879    }
00880    if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
00881       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) isn't quite right!\n",
00882             p->filename, p->startline, p->endline, times);
00883       warns++;
00884    }
00885    if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
00886       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) isn't quite right!\n",
00887             p->filename, p->startline, p->endline, times);
00888       warns++;
00889    }
00890 
00891    s1 = s1 * 30 + s2/2;
00892    if ((s1 < 0) || (s1 >= 24*30)) {
00893       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) is out of range!\n",
00894             p->filename, p->startline, p->endline, times);
00895       warns++;
00896    }
00897    e1 = e1 * 30 + e2/2;
00898    if ((e1 < 0) || (e1 >= 24*30)) {
00899       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) is out of range!\n",
00900             p->filename, p->startline, p->endline, e);
00901       warns++;
00902    }
00903    return;
00904 }

int contains_switch ( pval item  ) 

Definition at line 3224 of file pbx_ael.c.

References find_switch_item(), and pval::next.

Referenced by find_switch_item(), and gen_prios().

03225 {
03226    pval *i;
03227    
03228    for (i=item; i; i=i->next) {
03229       if (find_switch_item(i))
03230          return 1;
03231    }
03232    return 0;
03233 }

void destroy_extensions ( struct ael_extension exten  ) 

Definition at line 2881 of file pbx_ael.c.

References ael_priority::app, ael_priority::appargs, exten, free, ael_priority::goto_false, ael_priority::goto_true, ael_extension::hints, ael_extension::loop_break, ael_extension::loop_continue, ael_extension::name, ael_priority::next, ael_extension::next_exten, ael_priority::origin, ael_extension::plist, and ael_extension::plist_last.

02882 {
02883    struct ael_extension *ne, *nen;
02884    for (ne=exten; ne; ne=nen) {
02885       struct ael_priority *pe, *pen;
02886       
02887       if (ne->name)
02888          free(ne->name);
02889       
02890       /* cidmatch fields are allocated with name, and freed when
02891          the name field is freed. Don't do a free for this field,
02892          unless you LIKE to see a crash! */
02893 
02894       if (ne->hints)
02895          free(ne->hints);
02896       
02897       for (pe=ne->plist; pe; pe=pen) {
02898          pen = pe->next;
02899          if (pe->app)
02900             free(pe->app);
02901          pe->app = 0;
02902          if (pe->appargs)
02903             free(pe->appargs);
02904          pe->appargs = 0;
02905          pe->origin = 0;
02906          pe->goto_true = 0;
02907          pe->goto_false = 0;
02908          free(pe);
02909       }
02910       nen = ne->next_exten;
02911       ne->next_exten = 0;
02912       ne->plist =0;
02913       ne->plist_last = 0;
02914       ne->next_exten = 0;
02915       ne->loop_break = 0;
02916       ne->loop_continue = 0;
02917       free(ne);
02918    }
02919 }

void destroy_pval ( pval item  ) 

void destroy_pval_item ( pval item  ) 

Definition at line 4653 of file pbx_ael.c.

References pval::arglist, ast_log(), destroy_pval(), pval::else_statements, pval::filename, pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, free, pval::hints, pval::list, LOG_WARNING, pval::macro_statements, PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTEXT, PV_CONTINUE, PV_DEFAULT, PV_ESWITCHES, PV_EXTENSION, PV_FOR, PV_GLOBALS, PV_GOTO, PV_IF, PV_IFTIME, PV_IGNOREPAT, PV_INCLUDES, PV_LABEL, PV_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pval::statements, pval::str, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.

Referenced by destroy_pval().

04654 {
04655    if (item == NULL) {
04656       ast_log(LOG_WARNING, "null item\n");
04657       return;
04658    }
04659 
04660    if (item->filename)
04661       free(item->filename);
04662    
04663    switch (item->type) {
04664    case PV_WORD:
04665       /* fields: item->u1.str == string associated with this (word). */
04666       if (item->u1.str )
04667          free(item->u1.str);
04668       if ( item->u2.arglist )
04669          destroy_pval(item->u2.arglist);
04670       break;
04671       
04672    case PV_MACRO:
04673       /* fields: item->u1.str     == name of macro
04674                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
04675                item->u2.arglist->u1.str  == argument
04676                item->u2.arglist->next   == next arg
04677 
04678                item->u3.macro_statements == pval list of statements in macro body.
04679       */
04680       destroy_pval(item->u2.arglist);
04681       if (item->u1.str )
04682          free(item->u1.str);
04683       destroy_pval(item->u3.macro_statements);
04684       break;
04685          
04686    case PV_CONTEXT:
04687       /* fields: item->u1.str     == name of context
04688                  item->u2.statements == pval list of statements in context body
04689                item->u3.abstract == int 1 if an abstract keyword were present
04690       */
04691       if (item->u1.str)
04692          free(item->u1.str);
04693       destroy_pval(item->u2.statements);
04694       break;
04695          
04696    case PV_MACRO_CALL:
04697       /* fields: item->u1.str     == name of macro to call
04698                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04699                item->u2.arglist->u1.str  == argument
04700                item->u2.arglist->next   == next arg
04701       */
04702       if (item->u1.str)
04703          free(item->u1.str);
04704       destroy_pval(item->u2.arglist);
04705       break;
04706          
04707    case PV_APPLICATION_CALL:
04708       /* fields: item->u1.str     == name of application to call
04709                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04710                item->u2.arglist->u1.str  == argument
04711                item->u2.arglist->next   == next arg
04712       */
04713       if (item->u1.str)
04714          free(item->u1.str);
04715       destroy_pval(item->u2.arglist);
04716       break;
04717          
04718    case PV_CASE:
04719       /* fields: item->u1.str     == value of case
04720                  item->u2.statements == pval list of statements under the case
04721       */
04722       if (item->u1.str)
04723          free(item->u1.str);
04724       destroy_pval(item->u2.statements);
04725       break;
04726          
04727    case PV_PATTERN:
04728       /* fields: item->u1.str     == value of case
04729                  item->u2.statements == pval list of statements under the case
04730       */
04731       if (item->u1.str)
04732          free(item->u1.str);
04733       destroy_pval(item->u2.statements);
04734       break;
04735          
04736    case PV_DEFAULT:
04737       /* fields: 
04738                  item->u2.statements == pval list of statements under the case
04739       */
04740       destroy_pval(item->u2.statements);
04741       break;
04742          
04743    case PV_CATCH:
04744       /* fields: item->u1.str     == name of extension to catch
04745                  item->u2.statements == pval list of statements in context body
04746       */
04747       if (item->u1.str)
04748          free(item->u1.str);
04749       destroy_pval(item->u2.statements);
04750       break;
04751          
04752    case PV_SWITCHES:
04753       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04754       */
04755       destroy_pval(item->u1.list);
04756       break;
04757          
04758    case PV_ESWITCHES:
04759       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04760       */
04761       destroy_pval(item->u1.list);
04762       break;
04763          
04764    case PV_INCLUDES:
04765       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04766                  item->u2.arglist  == pval list of 4 PV_WORD elements for time values
04767       */
04768       destroy_pval(item->u1.list);
04769       break;
04770          
04771    case PV_STATEMENTBLOCK:
04772       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
04773       */
04774       destroy_pval(item->u1.list);
04775       break;
04776          
04777    case PV_VARDEC:
04778       /* fields: item->u1.str     == variable name
04779                  item->u2.val     == variable value to assign
04780       */
04781       if (item->u1.str)
04782          free(item->u1.str);
04783       if (item->u2.val)
04784          free(item->u2.val);
04785       break;
04786          
04787    case PV_GOTO:
04788       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
04789                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
04790       */
04791       
04792       destroy_pval(item->u1.list);
04793       break;
04794          
04795    case PV_LABEL:
04796       /* fields: item->u1.str     == label name
04797       */
04798       if (item->u1.str)
04799          free(item->u1.str);
04800       break;
04801          
04802    case PV_FOR:
04803       /* fields: item->u1.for_init     == a string containing the initalizer
04804                  item->u2.for_test     == a string containing the loop test
04805                  item->u3.for_inc      == a string containing the loop increment
04806 
04807                item->u4.for_statements == a pval list of statements in the for ()
04808       */
04809       if (item->u1.for_init)
04810          free(item->u1.for_init);
04811       if (item->u2.for_test)
04812          free(item->u2.for_test);
04813       if (item->u3.for_inc)
04814          free(item->u3.for_inc);
04815       destroy_pval(item->u4.for_statements);
04816       break;
04817          
04818    case PV_WHILE:
04819       /* fields: item->u1.str        == the while conditional, as supplied by user
04820 
04821                item->u2.statements == a pval list of statements in the while ()
04822       */
04823       if (item->u1.str)
04824          free(item->u1.str);
04825       destroy_pval(item->u2.statements);
04826       break;
04827          
04828    case PV_BREAK:
04829       /* fields: none
04830       */
04831       break;
04832          
04833    case PV_RETURN:
04834       /* fields: none
04835       */
04836       break;
04837          
04838    case PV_CONTINUE:
04839       /* fields: none
04840       */
04841       break;
04842          
04843    case PV_IFTIME:
04844       /* fields: item->u1.list        == the 4 time values, in PV_WORD structs, linked list
04845 
04846                item->u2.statements == a pval list of statements in the if ()
04847                item->u3.else_statements == a pval list of statements in the else
04848                                     (could be zero)
04849       */
04850       destroy_pval(item->u1.list);
04851       destroy_pval(item->u2.statements);
04852       if (item->u3.else_statements) {
04853          destroy_pval(item->u3.else_statements);
04854       }
04855       break;
04856          
04857    case PV_RANDOM:
04858       /* fields: item->u1.str        == the random percentage, as supplied by user
04859 
04860                item->u2.statements == a pval list of statements in the true part ()
04861                item->u3.else_statements == a pval list of statements in the else
04862                                     (could be zero)
04863       fall thru to If */
04864    case PV_IF:
04865       /* fields: item->u1.str        == the if conditional, as supplied by user
04866 
04867                item->u2.statements == a pval list of statements in the if ()
04868                item->u3.else_statements == a pval list of statements in the else
04869                                     (could be zero)
04870       */
04871       if (item->u1.str)
04872          free(item->u1.str);
04873       destroy_pval(item->u2.statements);
04874       if (item->u3.else_statements) {
04875          destroy_pval(item->u3.else_statements);
04876       }
04877       break;
04878          
04879    case PV_SWITCH:
04880       /* fields: item->u1.str        == the switch expression
04881 
04882                item->u2.statements == a pval list of statements in the switch, 
04883                                     (will be case statements, most likely!)
04884       */
04885       if (item->u1.str)
04886          free(item->u1.str);
04887       destroy_pval(item->u2.statements);
04888       break;
04889          
04890    case PV_EXTENSION:
04891       /* fields: item->u1.str        == the extension name, label, whatever it's called
04892 
04893                item->u2.statements == a pval list of statements in the extension
04894                item->u3.hints      == a char * hint argument
04895                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
04896       */
04897       if (item->u1.str)
04898          free(item->u1.str);
04899       if (item->u3.hints)
04900          free(item->u3.hints);
04901       destroy_pval(item->u2.statements);
04902       break;
04903          
04904    case PV_IGNOREPAT:
04905       /* fields: item->u1.str        == the ignorepat data
04906       */
04907       if (item->u1.str)
04908          free(item->u1.str);
04909       break;
04910          
04911    case PV_GLOBALS:
04912       /* fields: item->u1.statements     == pval list of statements, usually vardecs
04913       */
04914       destroy_pval(item->u1.statements);
04915       break;
04916    }
04917    free(item);
04918 }

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

Definition at line 710 of file pbx_ael.c.

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

Referenced by match_pval_item().

00711 {
00712    int err1;
00713    regex_t preg;
00714    
00715    /* simple case, they match exactly, the pattern and exten name */
00716    if( !strcmp(pattern,exten) == 0 )
00717       return 1;
00718    
00719    if ( pattern[0] == '_' ) {
00720       char reg1[2000];
00721       const char *p;
00722       char *r = reg1;
00723       
00724       if ( strlen(pattern)*5 >= 2000 ) /* safety valve */ {
00725          ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n",
00726                pattern);
00727          return 0;
00728       }
00729       /* form a regular expression from the pattern, and then match it against exten */
00730       *r++ = '^'; /* what if the extension is a pattern ?? */
00731       *r++ = '_'; /* what if the extension is a pattern ?? */
00732       *r++ = '?';
00733       for (p=pattern+1; *p; p++) {
00734          switch ( *p ) {
00735          case 'X':
00736             *r++ = '[';
00737             *r++ = '0';
00738             *r++ = '-';
00739             *r++ = '9';
00740             *r++ = 'X';
00741             *r++ = ']';
00742             break;
00743             
00744          case 'Z':
00745             *r++ = '[';
00746             *r++ = '1';
00747             *r++ = '-';
00748             *r++ = '9';
00749             *r++ = 'Z';
00750             *r++ = ']';
00751             break;
00752             
00753          case 'N':
00754             *r++ = '[';
00755             *r++ = '2';
00756             *r++ = '-';
00757             *r++ = '9';
00758             *r++ = 'N';
00759             *r++ = ']';
00760             break;
00761             
00762          case '[':
00763             while ( *p && *p != ']' ) {
00764                *r++ = *p++;
00765             }
00766             if ( *p != ']') {
00767                ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The extension pattern '%s' is missing a closing bracket \n",
00768                      here->filename, here->startline, here->endline, pattern);
00769             }
00770             break;
00771             
00772          case '.':
00773          case '!':
00774             *r++ = '.';
00775             *r++ = '*';
00776             break;
00777          case '*':
00778             *r++ = '\\';
00779             *r++ = '*';
00780             break;
00781          default:
00782             *r++ = *p;
00783             break;
00784             
00785          }
00786       }
00787       *r++ = '$'; /* what if the extension is a pattern ?? */
00788       *r++ = *p++; /* put in the closing null */
00789       err1 = regcomp(&preg, reg1, REG_NOSUB|REG_EXTENDED);
00790       if ( err1 ) {
00791          char errmess[500];
00792          regerror(err1,&preg,errmess,sizeof(errmess));
00793          regfree(&preg);
00794          ast_log(LOG_WARNING, "Regcomp of %s failed, error code %d\n",
00795                reg1, err1);
00796          return 0;
00797       }
00798       err1 = regexec(&preg, exten, 0, 0, 0);
00799       regfree(&preg);
00800       
00801       if ( err1 ) {
00802          /* ast_log(LOG_NOTICE,"*****************************[%d]Extension %s did not match %s(%s)\n",
00803             err1,exten, pattern, reg1); */
00804          return 0; /* no match */
00805       } else {
00806          /* ast_log(LOG_NOTICE,"*****************************Extension %s matched %s\n",
00807             exten, pattern); */
00808          return 1;
00809       }
00810       
00811       
00812    } else {
00813       if ( strcmp(exten,pattern) == 0 ) {
00814          return 1;
00815       } else
00816          return 0;
00817    }
00818 }

struct pval * find_context ( char *  name  ) 

Definition at line 1901 of file pbx_ael.c.

References current_db, and match_pval().

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

01902 {
01903    return_on_context_match = 1;
01904    count_labels = 0;
01905    match_context = name;
01906    match_exten = "*";  /* don't really need to set these, shouldn't be reached */
01907    match_label = "*";
01908    return match_pval(current_db);
01909 }

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

Definition at line 1780 of file pbx_ael.c.

References find_context(), pval::list, pval::macro_statements, match_pval(), pval::next, PV_INCLUDES, PV_MACRO, pval::statements, pval::str, pval::type, pval::u1, pval::u2, and pval::u3.

Referenced by check_label().

01781 {
01782    /* printf("  --- Got args %s, %s\n", exten, label); */
01783    struct pval *ret;
01784    struct pval *p3;
01785    struct pval *startpt = ((curr_cont->type==PV_MACRO)?curr_cont->u3.macro_statements: curr_cont->u2.statements);
01786    
01787    count_labels = 0;
01788    return_on_context_match = 0;
01789    match_context = "*";
01790    match_exten = "*";
01791    match_label = label;
01792    
01793    ret =  match_pval(curr_cont);
01794    if (ret)
01795       return ret;
01796                
01797    /* the target of the goto could be in an included context!! Fancy that!! */
01798    /* look for includes in the current context */
01799    for (p3=startpt; p3; p3=p3->next) {
01800       if (p3->type == PV_INCLUDES) {
01801          struct pval *p4;
01802          for (p4=p3->u1.list; p4; p4=p4->next) {
01803             /* for each context pointed to, find it, then find a context/label that matches the
01804                target here! */
01805             char *incl_context = p4->u1.str;
01806             /* find a matching context name */
01807             struct pval *that_context = find_context(incl_context);
01808             if (that_context) {
01809                struct pval *x3;
01810                x3 = find_first_label_in_current_context(label, that_context);
01811                if (x3) {
01812                   return x3;
01813                }
01814             }
01815          }
01816       }
01817    }
01818    return 0;
01819 }

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

Definition at line 1821 of file pbx_ael.c.

References find_context(), pval::list, pval::macro_statements, match_pval(), pval::next, PV_INCLUDES, PV_MACRO, pval::statements, pval::str, pval::type, pval::u1, pval::u2, and pval::u3.

Referenced by check_goto(), and get_goto_target().

01822 {
01823    /* printf("  --- Got args %s, %s\n", exten, label); */
01824    struct pval *ret;
01825    struct pval *p3;
01826    struct pval *startpt;
01827    
01828    count_labels = 0;
01829    return_on_context_match = 0;
01830    match_context = "*";
01831    match_exten = exten;
01832    match_label = label;
01833    if (curr_cont->type == PV_MACRO)
01834       startpt = curr_cont->u3.macro_statements;
01835    else
01836       startpt = curr_cont->u2.statements;
01837 
01838    ret =  match_pval(startpt);
01839    if (ret)
01840       return ret;
01841                
01842    /* the target of the goto could be in an included context!! Fancy that!! */
01843    /* look for includes in the current context */
01844    for (p3=startpt; p3; p3=p3->next) {
01845       if (p3->type == PV_INCLUDES) {
01846          struct pval *p4;
01847          for (p4=p3->u1.list; p4; p4=p4->next) {
01848             /* for each context pointed to, find it, then find a context/label that matches the
01849                target here! */
01850             char *incl_context = p4->u1.str;
01851             /* find a matching context name */
01852             struct pval *that_context = find_context(incl_context);
01853             if (that_context) {
01854                struct pval *x3;
01855                x3 = find_label_in_current_context(exten, label, that_context);
01856                if (x3) {
01857                   return x3;
01858                }
01859             }
01860          }
01861       }
01862    }
01863    return 0;
01864 }

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

Definition at line 1877 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_goto(), and get_goto_target().

01878 {
01879    /* printf("  --- Got args %s, %s, %s\n", context, exten, label); */
01880    count_labels = 0;
01881    return_on_context_match = 0;
01882 
01883    match_context = context;
01884    match_exten = exten;
01885    match_label = label;
01886    
01887    return match_pval(current_db);
01888 }

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

Definition at line 1866 of file pbx_ael.c.

References match_pval().

Referenced by check_goto(), and get_goto_target().

01867 {
01868    /* printf("  --- Got args %s\n", label); */
01869    count_labels = 0;
01870    return_on_context_match = 0;
01871    match_context = "*";
01872    match_exten = "*";
01873    match_label = label;
01874    return match_pval(curr_ext);
01875 }

struct pval * find_macro ( char *  name  ) 

Definition at line 1891 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_pval_item().

01892 {
01893    return_on_context_match = 1;
01894    count_labels = 0;
01895    match_context = name;
01896    match_exten = "*";  /* don't really need to set these, shouldn't be reached */
01897    match_label = "*";
01898    return match_pval(current_db);
01899 }

static void find_pval_goto_item ( pval item,
int  lev 
) [static]

Definition at line 1301 of file pbx_ael.c.

References ast_log(), check_goto(), pval::else_statements, find_context(), find_pval_gotos(), pval::for_statements, pval::list, LOG_ERROR, pval::macro_statements, 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, pval::type, pval::u1, pval::u2, pval::u3, and pval::u4.

Referenced by find_pval_gotos().

01302 {
01303    struct pval *p4;
01304    
01305    if (lev>100) {
01306       ast_log(LOG_ERROR,"find_pval_goto in infinite loop! item_type: %d\n\n", item->type);
01307       return;
01308    }
01309    
01310    switch ( item->type ) {
01311    case PV_MACRO:
01312       /* fields: item->u1.str     == name of macro
01313                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
01314                item->u2.arglist->u1.str  == argument
01315                item->u2.arglist->next   == next arg
01316 
01317                item->u3.macro_statements == pval list of statements in macro body.
01318       */
01319          
01320       /* printf("Descending into macro %s at line %d\n", item->u1.str, item->startline); */
01321       find_pval_gotos(item->u3.macro_statements,lev+1); /* if we're just searching for a context, don't bother descending into them */
01322       
01323       break;
01324          
01325    case PV_CONTEXT:
01326       /* fields: item->u1.str     == name of context
01327                  item->u2.statements == pval list of statements in context body
01328                item->u3.abstract == int 1 if an abstract keyword were present
01329       */
01330       break;
01331 
01332    case PV_CASE:
01333       /* fields: item->u1.str     == value of case
01334                  item->u2.statements == pval list of statements under the case
01335       */
01336       /* printf("Descending into Case of %s\n", item->u1.str); */
01337       find_pval_gotos(item->u2.statements,lev+1);
01338       break;
01339          
01340    case PV_PATTERN:
01341       /* fields: item->u1.str     == value of case
01342                  item->u2.statements == pval list of statements under the case
01343       */
01344       /* printf("Descending into Pattern of %s\n", item->u1.str); */
01345       find_pval_gotos(item->u2.statements,lev+1);
01346       break;
01347          
01348    case PV_DEFAULT:
01349       /* fields: 
01350                  item->u2.statements == pval list of statements under the case
01351       */
01352       /* printf("Descending into default\n"); */
01353       find_pval_gotos(item->u2.statements,lev+1);
01354       break;
01355          
01356    case PV_CATCH:
01357       /* fields: item->u1.str     == name of extension to catch
01358                  item->u2.statements == pval list of statements in context body
01359       */
01360       /* printf("Descending into catch of %s\n", item->u1.str); */
01361       find_pval_gotos(item->u2.statements,lev+1);
01362       break;
01363          
01364    case PV_STATEMENTBLOCK:
01365       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
01366       */
01367       /* printf("Descending into statement block\n"); */
01368       find_pval_gotos(item->u1.list,lev+1);
01369       break;
01370          
01371    case PV_GOTO:
01372       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
01373                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
01374       */
01375       check_goto(item);  /* THE WHOLE FUNCTION OF THIS ENTIRE ROUTINE!!!! */
01376       break;
01377          
01378    case PV_INCLUDES:
01379       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
01380       */
01381       for (p4=item->u1.list; p4; p4=p4->next) {
01382          /* for each context pointed to, find it, then find a context/label that matches the
01383             target here! */
01384          char *incl_context = p4->u1.str;
01385          /* find a matching context name */
01386          struct pval *that_context = find_context(incl_context);
01387          if (that_context && that_context->u2.statements) {
01388             /* 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); */
01389             find_pval_gotos(that_context->u2.statements,lev+1); /* keep working up the includes */
01390          }
01391       }
01392       break;
01393       
01394    case PV_FOR:
01395       /* fields: item->u1.for_init     == a string containing the initalizer
01396                  item->u2.for_test     == a string containing the loop test
01397                  item->u3.for_inc      == a string containing the loop increment
01398 
01399                item->u4.for_statements == a pval list of statements in the for ()
01400       */
01401       /* printf("Descending into for at line %d\n", item->startline); */
01402       find_pval_gotos(item->u4.for_statements,lev+1);
01403       break;
01404          
01405    case PV_WHILE:
01406       /* fields: item->u1.str        == the while conditional, as supplied by user
01407 
01408                item->u2.statements == a pval list of statements in the while ()
01409       */
01410       /* printf("Descending into while at line %d\n", item->startline); */
01411       find_pval_gotos(item->u2.statements,lev+1);
01412       break;
01413          
01414    case PV_RANDOM:
01415       /* fields: item->u1.str        == the random number expression, as supplied by user
01416 
01417                item->u2.statements == a pval list of statements in the if ()
01418                item->u3.else_statements == a pval list of statements in the else
01419                                     (could be zero)
01420        fall thru to PV_IF */
01421       
01422    case PV_IFTIME:
01423       /* fields: item->u1.list        == the time values, 4 of them, as PV_WORD structs in a list
01424 
01425                item->u2.statements == a pval list of statements in the if ()
01426                item->u3.else_statements == a pval list of statements in the else
01427                                     (could be zero)
01428       fall thru to PV_IF*/
01429    case PV_IF:
01430       /* fields: item->u1.str        == the if conditional, as supplied by user
01431 
01432                item->u2.statements == a pval list of statements in the if ()
01433                item->u3.else_statements == a pval list of statements in the else
01434                                     (could be zero)
01435       */
01436       /* printf("Descending into random/iftime/if at line %d\n", item->startline); */
01437       find_pval_gotos(item->u2.statements,lev+1);
01438 
01439       if (item->u3.else_statements) {
01440          /* printf("Descending into random/iftime/if's ELSE at line %d\n", item->startline); */
01441          find_pval_gotos(item->u3.else_statements,lev+1);
01442       }
01443       break;
01444          
01445    case PV_SWITCH:
01446       /* fields: item->u1.str        == the switch expression
01447 
01448                item->u2.statements == a pval list of statements in the switch, 
01449                                     (will be case statements, most likely!)
01450       */
01451       /* printf("Descending into switch at line %d\n", item->startline); */
01452       find_pval_gotos(item->u3.else_statements,lev+1);
01453       break;
01454          
01455    case PV_EXTENSION:
01456       /* fields: item->u1.str        == the extension name, label, whatever it's called
01457 
01458                item->u2.statements == a pval list of statements in the extension
01459                item->u3.hints      == a char * hint argument
01460                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
01461       */
01462 
01463       /* printf("Descending into extension %s at line %d\n", item->u1.str, item->startline); */
01464       find_pval_gotos(item->u2.statements,lev+1);
01465       break;
01466 
01467    default:
01468       break;
01469    }
01470 }

static void find_pval_gotos ( pval item,
int  lev 
) [static]

Definition at line 1472 of file pbx_ael.c.

References find_pval_goto_item(), and pval::next.

Referenced by check_pval_item(), and find_pval_goto_item().

01473 {
01474    pval *i;
01475    
01476    for (i=item; i; i=i->next) {
01477       /* printf("About to call pval_goto_item, itemcount=%d, itemtype=%d\n", item_count, i->type); */
01478       find_pval_goto_item(i, lev);
01479    }
01480 }

int find_switch_item ( pval item  ) 

Definition at line 2989 of file pbx_ael.c.

References contains_switch(), pval::else_statements, pval::for_statements, pval::list, pval::macro_statements, PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTEXT, PV_CONTINUE, PV_DEFAULT, PV_ESWITCHES, PV_EXTENSION, PV_FOR, PV_GLOBALS, PV_GOTO, PV_IF, PV_IFTIME, PV_IGNOREPAT, PV_INCLUDES, PV_LABEL, PV_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pval::statements, pval::type, pval::u1, pval::u2, pval::u3, and pval::u4.

Referenced by contains_switch().

02990 {
02991    switch ( item->type ) {
02992    case PV_WORD:
02993       /* fields: item->u1.str == string associated with this (word). */
02994       break;
02995       
02996    case PV_MACRO:
02997       /* fields: item->u1.str     == name of macro
02998                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
02999                item->u2.arglist->u1.str  == argument
03000                item->u2.arglist->next   == next arg
03001 
03002                item->u3.macro_statements == pval list of statements in macro body.
03003       */
03004       /* had better not see this */
03005       if (contains_switch(item->u3.macro_statements))
03006          return 1;
03007       break;
03008          
03009    case PV_CONTEXT:
03010       /* fields: item->u1.str     == name of context
03011                  item->u2.statements == pval list of statements in context body
03012                item->u3.abstract == int 1 if an abstract keyword were present
03013       */
03014       /* had better not see this */
03015       if (contains_switch(item->u2.statements))
03016          return 1;
03017       break;
03018          
03019    case PV_MACRO_CALL:
03020       /* fields: item->u1.str     == name of macro to call
03021                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
03022                item->u2.arglist->u1.str  == argument
03023                item->u2.arglist->next   == next arg
03024       */
03025       break;
03026          
03027    case PV_APPLICATION_CALL:
03028       /* fields: item->u1.str     == name of application to call
03029                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
03030                item->u2.arglist->u1.str  == argument
03031                item->u2.arglist->next   == next arg
03032       */
03033       break;
03034          
03035    case PV_CASE:
03036       /* fields: item->u1.str     == value of case
03037                  item->u2.statements == pval list of statements under the case
03038       */
03039       /* had better not see this */
03040       if (contains_switch(item->u2.statements))
03041          return 1;
03042       break;
03043          
03044    case PV_PATTERN:
03045       /* fields: item->u1.str     == value of case
03046                  item->u2.statements == pval list of statements under the case
03047       */
03048       /* had better not see this */
03049       if (contains_switch(item->u2.statements))
03050          return 1;
03051       break;
03052          
03053    case PV_DEFAULT:
03054       /* fields: 
03055                  item->u2.statements == pval list of statements under the case
03056       */
03057       /* had better not see this */
03058       if (contains_switch(item->u2.statements))
03059          return 1;
03060       break;
03061          
03062    case PV_CATCH:
03063       /* fields: item->u1.str     == name of extension to catch
03064                  item->u2.statements == pval list of statements in context body
03065       */
03066       /* had better not see this */
03067       if (contains_switch(item->u2.statements))
03068          return 1;
03069       break;
03070          
03071    case PV_SWITCHES:
03072       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
03073       */
03074       break;
03075          
03076    case PV_ESWITCHES:
03077       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
03078       */
03079       break;
03080          
03081    case PV_INCLUDES:
03082       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
03083                  item->u2.arglist  == pval list of 4 PV_WORD elements for time values
03084       */
03085       break;
03086          
03087    case PV_STATEMENTBLOCK:
03088       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
03089       */
03090       if (contains_switch(item->u1.list) )
03091          return 1;
03092       break;
03093          
03094    case PV_VARDEC:
03095       /* fields: item->u1.str     == variable name
03096                  item->u2.val     == variable value to assign
03097       */
03098       break;
03099          
03100    case PV_GOTO:
03101       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
03102                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
03103       */
03104       break;
03105          
03106    case PV_LABEL:
03107       /* fields: item->u1.str     == label name
03108       */
03109       break;
03110          
03111    case PV_FOR:
03112       /* fields: item->u1.for_init     == a string containing the initalizer
03113                  item->u2.for_test     == a string containing the loop test
03114                  item->u3.for_inc      == a string containing the loop increment
03115 
03116                item->u4.for_statements == a pval list of statements in the for ()
03117       */
03118       if (contains_switch(item->u4.for_statements))
03119          return 1;
03120       break;
03121          
03122    case PV_WHILE:
03123       /* fields: item->u1.str        == the while conditional, as supplied by user
03124 
03125                item->u2.statements == a pval list of statements in the while ()
03126       */
03127       if (contains_switch(item->u2.statements))
03128          return 1;
03129       break;
03130          
03131    case PV_BREAK:
03132       /* fields: none
03133       */
03134       break;
03135          
03136    case PV_RETURN:
03137       /* fields: none
03138       */
03139       break;
03140          
03141    case PV_CONTINUE:
03142       /* fields: none
03143       */
03144       break;
03145          
03146    case PV_IFTIME:
03147       /* fields: item->u1.list        == there are 4 linked PV_WORDs here.
03148 
03149                item->u2.statements == a pval list of statements in the if ()
03150                item->u3.else_statements == a pval list of statements in the else
03151                                     (could be zero)
03152       */
03153       if (contains_switch(item->u2.statements))
03154          return 1;
03155       if ( item->u3.else_statements ) {
03156          if (contains_switch(item->u3.else_statements))
03157             return 1;
03158       }
03159       break;
03160          
03161    case PV_RANDOM:
03162       /* fields: item->u1.str        == the random number expression, as supplied by user
03163 
03164                item->u2.statements == a pval list of statements in the if ()
03165                item->u3.else_statements == a pval list of statements in the else
03166                                     (could be zero)
03167       */
03168       if (contains_switch(item->u2.statements))
03169          return 1;
03170       if ( item->u3.else_statements ) {
03171          if (contains_switch(item->u3.else_statements))
03172             return 1;
03173       }
03174       break;
03175          
03176    case PV_IF:
03177       /* fields: item->u1.str        == the if conditional, as supplied by user
03178 
03179                item->u2.statements == a pval list of statements in the if ()
03180                item->u3.else_statements == a pval list of statements in the else
03181                                     (could be zero)
03182       */
03183       if (contains_switch(item->u2.statements))
03184          return 1;
03185       if ( item->u3.else_statements ) {
03186          if (contains_switch(item->u3.else_statements))
03187             return 1;
03188       }
03189       break;
03190          
03191    case PV_SWITCH:
03192       /* fields: item->u1.str        == the switch expression
03193 
03194                item->u2.statements == a pval list of statements in the switch, 
03195                                     (will be case statements, most likely!)
03196       */
03197       return 1; /* JACKPOT */
03198       break;
03199          
03200    case PV_EXTENSION:
03201       /* fields: item->u1.str        == the extension name, label, whatever it's called
03202 
03203                item->u2.statements == a pval list of statements in the extension
03204                item->u3.hints      == a char * hint argument
03205                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
03206       */
03207       if (contains_switch(item->u2.statements))
03208          return 1;
03209       break;
03210          
03211    case PV_IGNOREPAT:
03212       /* fields: item->u1.str        == the ignorepat data
03213       */
03214       break;
03215          
03216    case PV_GLOBALS:
03217       /* fields: item->u1.statements     == pval list of statements, usually vardecs
03218       */
03219       break;
03220    }
03221    return 0;
03222 }

static void fix_gotos_in_extensions ( struct ael_extension exten  )  [static]

Definition at line 4253 of file pbx_ael.c.

References exten, ael_priority::next, ael_extension::next_exten, ael_extension::plist, PV_GOTO, and strdup.

04254 {
04255    struct ael_extension *e;
04256    for(e=exten;e;e=e->next_exten) {
04257 
04258       struct ael_priority *p;
04259       for(p=e->plist;p;p=p->next) {
04260          
04261          if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) {
04262             
04263             /* fix the extension of the goto target to the actual extension in the post-compiled dialplan */
04264 
04265             pval *target = p->origin->u2.goto_target;
04266             struct ael_extension *z = target->u3.compiled_label;
04267             pval *pv2 = p->origin;
04268             char buf1[500];
04269             char *apparg_save = p->appargs;
04270             
04271             p->appargs = 0;
04272             if (!pv2->u1.list->next) /* just one  -- it won't hurt to repeat the extension */ {
04273                snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->u1.str);
04274                p->appargs = strdup(buf1);
04275                
04276             } else if (pv2->u1.list->next && !pv2->u1.list->next->next) /* two */ {
04277                snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->next->u1.str);
04278                p->appargs = strdup(buf1);
04279             } else if (pv2->u1.list->next && pv2->u1.list->next->next) {
04280                snprintf(buf1,sizeof(buf1),"%s|%s|%s", pv2->u1.list->u1.str, 
04281                       z->name,
04282                       pv2->u1.list->next->next->u1.str);
04283                p->appargs = strdup(buf1);
04284             }
04285             else
04286                printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n");
04287             
04288             if( apparg_save ) {
04289                free(apparg_save);
04290             }
04291          }
04292       }
04293    }
04294 }

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

Definition at line 2960 of file pbx_ael.c.

References t.

Referenced by gen_prios().

02961 {
02962    /* the result will be a string that will be matched by pattern */
02963    char *p=pattern, *t=result;
02964    while (*p) {
02965       if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
02966          *t++ = '9';
02967       else if (*p == '[') {
02968          char *z = p+1;
02969          while (*z != ']')
02970             z++;
02971          if (*(z+1)== ']')
02972             z++;
02973          *t++=*(p+1); /* use the first char in the set */
02974          p = z;
02975       } else {
02976          *t++ = *p;
02977       }
02978       p++;
02979    }
02980    *t++ = 0; /* cap it off */
02981 }

static void gen_prios ( struct ael_extension exten,
char *  label,
pval statement,
struct ael_extension mother_exten,
struct ast_context context 
) [static]

Definition at line 3236 of file pbx_ael.c.

References AEL_APPCALL, AEL_CONTROL1, AEL_FOR_CONTROL, AEL_IF_CONTROL, AEL_IFTIME_CONTROL, AEL_LABEL, AEL_RAND_CONTROL, AEL_RETURN, ael_priority::app, ael_priority::appargs, pval::arglist, ael_extension::checked_switch, pval::compiled_label, contains_switch(), ael_extension::context, control_statement_count, pval::else_statements, ael_priority::exten, exten, pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, free, gen_match_to_pattern(), get_goto_target(), ael_priority::goto_false, pval::goto_target, pval::goto_target_in_case, ael_priority::goto_true, ael_extension::has_switch, ael_extension::is_switch, pval::label_in_case, label_inside_case(), linkexten(), linkprio(), pval::list, ael_extension::loop_break, ael_extension::loop_continue, ael_extension::name, new_exten(), new_prio(), pval::next, ael_priority::origin, PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTINUE, PV_DEFAULT, PV_FOR, PV_GOTO, PV_IF, PV_IFTIME, PV_LABEL, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_VARDEC, PV_WHILE, remove_spaces_before_equals(), ael_extension::return_needed, pval::statements, pval::str, strdup, substitute_commas(), pval::type, ael_priority::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.

03237 {
03238    pval *p,*p2,*p3;
03239    struct ael_priority *pr;
03240    struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end;
03241    struct ael_priority *while_test, *while_loop, *while_end;
03242    struct ael_priority *switch_set, *switch_test, *switch_end, *fall_thru, *switch_empty;
03243    struct ael_priority *if_test, *if_end, *if_skip, *if_false;
03244 #ifdef OLD_RAND_ACTION
03245    struct ael_priority *rand_test, *rand_end, *rand_skip;
03246 #endif
03247    char buf1[2000];
03248    char buf2[2000];
03249    char *strp, *strp2;
03250    char new_label[2000];
03251    int default_exists;
03252    int local_control_statement_count;
03253    struct ael_priority *loop_break_save;
03254    struct ael_priority *loop_continue_save;
03255    struct ael_extension *switch_case,*switch_null;
03256    
03257    if ((mother_exten && !mother_exten->checked_switch) || (exten && !exten->checked_switch)) {
03258       if (contains_switch(statement)) { /* only run contains_switch if you haven't checked before */
03259          if (mother_exten) {
03260             if (!mother_exten->has_switch) {
03261                switch_set = new_prio();
03262                switch_set->type = AEL_APPCALL;
03263                switch_set->app = strdup("Set");
03264                switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
03265                linkprio(exten, switch_set, mother_exten);
03266                mother_exten->has_switch = 1;
03267                mother_exten->checked_switch = 1;
03268                if (exten) {
03269                   exten->has_switch = 1;
03270                   exten->checked_switch = 1;
03271                }
03272             }
03273          } else if (exten) {
03274             if (!exten->has_switch) {
03275                switch_set = new_prio();
03276                switch_set->type = AEL_APPCALL;
03277                switch_set->app = strdup("Set");
03278                switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
03279                linkprio(exten, switch_set, mother_exten);
03280                exten->has_switch = 1;
03281                exten->checked_switch = 1;
03282                if (mother_exten) {
03283                   mother_exten->has_switch = 1;
03284                   mother_exten->checked_switch = 1;
03285                }
03286             }
03287          }
03288       } else {
03289          if (mother_exten) {
03290             mother_exten->checked_switch = 1;
03291          }
03292          if (exten) {
03293             exten->checked_switch = 1;
03294          }
03295       }
03296    }
03297    for (p=statement; p; p=p->next) {
03298       switch (p->type) {
03299       case PV_VARDEC:
03300          pr = new_prio();
03301          pr->type = AEL_APPCALL;
03302          snprintf(buf1,sizeof(buf1),"%s=$[%s]", p->u1.str, p->u2.val);
03303          pr->app = strdup("Set");
03304          remove_spaces_before_equals(buf1);
03305          pr->appargs = strdup(buf1);
03306          pr->origin = p;
03307          linkprio(exten, pr, mother_exten);
03308          break;
03309          
03310       case PV_GOTO:
03311          pr = new_prio();
03312          pr->type = AEL_APPCALL;
03313          p->u2.goto_target = get_goto_target(p);
03314          if( p->u2.goto_target ) {
03315             p->u3.goto_target_in_case = p->u2.goto_target->u2.label_in_case = label_inside_case(p->u2.goto_target);
03316          }
03317          
03318          if (!p->u1.list->next) /* just one */ {
03319             pr->app = strdup("Goto");
03320             if (!mother_exten)
03321                pr->appargs = strdup(p->u1.list->u1.str);
03322             else {  /* for the case of simple within-extension gotos in case/pattern/default statement blocks: */ 
03323                snprintf(buf1,sizeof(buf1),"%s|%s", mother_exten->name, p->u1.list->u1.str);
03324                pr->appargs = strdup(buf1);
03325             }
03326             
03327          } else if (p->u1.list->next && !p->u1.list->next->next) /* two */ {
03328             snprintf(buf1,sizeof(buf1),"%s|%s", p->u1.list->u1.str, p->u1.list->next->u1.str);
03329             pr->app = strdup("Goto");
03330             pr->appargs = strdup(buf1);
03331          } else if (p->u1.list->next && p->u1.list->next->next) {
03332             snprintf(buf1,sizeof(buf1),"%s|%s|%s", p->u1.list->u1.str, 
03333                   p->u1.list->next->u1.str,
03334                   p->u1.list->next->next->u1.str);
03335             pr->app = strdup("Goto");
03336             pr->appargs = strdup(buf1);
03337          }
03338          pr->origin = p;
03339          linkprio(exten, pr, mother_exten);
03340          break;
03341 
03342       case PV_LABEL:
03343          pr = new_prio();
03344          pr->type = AEL_LABEL;
03345          pr->origin = p;
03346          p->u3.compiled_label = exten;
03347          linkprio(exten, pr, mother_exten);
03348          break;
03349 
03350       case PV_FOR:
03351          control_statement_count++;
03352          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
03353          loop_continue_save = exten->loop_continue;
03354          snprintf(new_label,sizeof(new_label),"for-%s-%d", label, control_statement_count);
03355          for_init = new_prio();
03356          for_inc = new_prio();
03357          for_test = new_prio();
03358          for_loop = new_prio();
03359          for_end = new_prio();
03360          for_init->type = AEL_APPCALL;
03361          for_inc->type = AEL_APPCALL;
03362          for_test->type = AEL_FOR_CONTROL;
03363          for_test->goto_false = for_end;
03364          for_loop->type = AEL_CONTROL1; /* simple goto */
03365          for_end->type = AEL_APPCALL;
03366          for_init->app = strdup("Set");
03367          
03368          strcpy(buf2,p->u1.for_init);
03369          remove_spaces_before_equals(buf2);
03370          strp = strchr(buf2, '=');
03371          if (strp) {
03372             strp2 = strchr(p->u1.for_init, '=');
03373             *(strp+1) = 0;
03374             strcat(buf2,"$[");
03375             strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03376             strcat(buf2,"]");
03377             for_init->appargs = strdup(buf2);
03378             /* for_init->app = strdup("Set"); just set! */
03379          } else {
03380             strp2 = p->u1.for_init;
03381             while (*strp2 && isspace(*strp2))
03382                strp2++;
03383             if (*strp2 == '&') { /* itsa macro call */
03384                char *strp3 = strp2+1;
03385                while (*strp3 && isspace(*strp3))
03386                   strp3++;
03387                strcpy(buf2, strp3);
03388                strp3 = strchr(buf2,'(');
03389                if (strp3) {
03390                   *strp3 = '|';
03391                }
03392                while ((strp3=strchr(buf2,','))) {
03393                   *strp3 = '|';
03394                }
03395                strp3 = strrchr(buf2, ')');
03396                if (strp3)
03397                   *strp3 = 0; /* remove the closing paren */
03398 
03399                for_init->appargs = strdup(buf2);
03400                if (for_init->app)
03401                   free(for_init->app);
03402                for_init->app = strdup("Macro");
03403             } else {  /* must be a regular app call */
03404                char *strp3;
03405                strcpy(buf2, strp2);
03406                strp3 = strchr(buf2,'(');
03407                if (strp3) {
03408                   *strp3 = 0;
03409                   if (for_init->app)
03410                      free(for_init->app);
03411                   for_init->app = strdup(buf2);
03412                   for_init->appargs = strdup(strp3+1);
03413                   strp3 = strrchr(for_init->appargs, ')');
03414                   if (strp3)
03415                      *strp3 = 0; /* remove the closing paren */
03416                }
03417             }
03418          }
03419 
03420          strcpy(buf2,p->u3.for_inc);
03421          remove_spaces_before_equals(buf2);
03422          strp = strchr(buf2, '=');
03423          if (strp) {  /* there's an = in this part; that means an assignment. set it up */
03424             strp2 = strchr(p->u3.for_inc, '=');
03425             *(strp+1) = 0;
03426             strcat(buf2,"$[");
03427             strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03428             strcat(buf2,"]");
03429             for_inc->appargs = strdup(buf2);
03430             for_inc->app = strdup("Set");
03431          } else {
03432             strp2 = p->u3.for_inc;
03433             while (*strp2 && isspace(*strp2))
03434                strp2++;
03435             if (*strp2 == '&') { /* itsa macro call */
03436                char *strp3 = strp2+1;
03437                while (*strp3 && isspace(*strp3))
03438                   strp3++;
03439                strcpy(buf2, strp3);
03440                strp3 = strchr(buf2,'(');
03441                if (strp3) {
03442                   *strp3 = '|';
03443                }
03444                while ((strp3=strchr(buf2,','))) {
03445                   *strp3 = '|';
03446                }
03447                strp3 = strrchr(buf2, ')');
03448                if (strp3)
03449                   *strp3 = 0; /* remove the closing paren */
03450 
03451                for_inc->appargs = strdup(buf2);
03452 
03453                for_inc->app = strdup("Macro");
03454             } else {  /* must be a regular app call */
03455                char *strp3;
03456                strcpy(buf2, strp2);
03457                strp3 = strchr(buf2,'(');
03458                if (strp3) {
03459                   *strp3 = 0;
03460                   for_inc->app = strdup(buf2);
03461                   for_inc->appargs = strdup(strp3+1);
03462                   strp3 = strrchr(for_inc->appargs, ')');
03463                   if (strp3)
03464                      *strp3 = 0; /* remove the closing paren */
03465                }
03466             }
03467          }
03468          snprintf(buf1,sizeof(buf1),"$[%s]",p->u2.for_test);
03469          for_test->app = 0;
03470          for_test->appargs = strdup(buf1);
03471          for_loop->goto_true = for_test;
03472          snprintf(buf1,sizeof(buf1),"Finish for-%s-%d", label, control_statement_count);
03473          for_end->app = strdup("NoOp");
03474          for_end->appargs = strdup(buf1);
03475          /* link & load! */
03476          linkprio(exten, for_init, mother_exten);
03477          linkprio(exten, for_test, mother_exten);
03478          
03479          /* now, put the body of the for loop here */
03480          exten->loop_break = for_end;
03481          exten->loop_continue = for_inc;
03482          
03483          gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context); /* this will link in all the statements here */
03484          
03485          linkprio(exten, for_inc, mother_exten);
03486          linkprio(exten, for_loop, mother_exten);
03487          linkprio(exten, for_end, mother_exten);
03488          
03489          
03490          exten->loop_break = loop_break_save;
03491          exten->loop_continue = loop_continue_save;
03492          for_loop->origin = p;
03493          break;
03494 
03495       case PV_WHILE:
03496          control_statement_count++;
03497          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
03498          loop_continue_save = exten->loop_continue;
03499          snprintf(new_label,sizeof(new_label),"while-%s-%d", label, control_statement_count);
03500          while_test = new_prio();
03501          while_loop = new_prio();
03502          while_end = new_prio();
03503          while_test->type = AEL_FOR_CONTROL;
03504          while_test->goto_false = while_end;
03505          while_loop->type = AEL_CONTROL1; /* simple goto */
03506          while_end->type = AEL_APPCALL;
03507          snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str);
03508          while_test->app = 0;
03509          while_test->appargs = strdup(buf1);
03510          while_loop->goto_true = while_test;
03511          snprintf(buf1,sizeof(buf1),"Finish while-%s-%d", label, control_statement_count);
03512          while_end->app = strdup("NoOp");
03513          while_end->appargs = strdup(buf1);
03514 
03515          linkprio(exten, while_test, mother_exten);
03516          
03517          /* now, put the body of the for loop here */
03518          exten->loop_break = while_end;
03519          exten->loop_continue = while_test;
03520          
03521          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the while body statements here */
03522 
03523          linkprio(exten, while_loop, mother_exten);
03524          linkprio(exten, while_end, mother_exten);
03525          
03526          
03527          exten->loop_break = loop_break_save;
03528          exten->loop_continue = loop_continue_save;
03529          while_loop->origin = p;
03530          break;
03531 
03532       case PV_SWITCH:
03533          control_statement_count++;
03534          local_control_statement_count = control_statement_count;
03535          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
03536          loop_continue_save = exten->loop_continue;
03537          snprintf(new_label,sizeof(new_label),"sw-%s-%d", label, control_statement_count);
03538          switch_test = new_prio();
03539          switch_end = new_prio();
03540          switch_test->type = AEL_APPCALL;
03541          switch_end->type = AEL_APPCALL;
03542          strncpy(buf2,p->u1.str,sizeof(buf2));
03543          buf2[sizeof(buf2)-1] = 0; /* just in case */
03544          substitute_commas(buf2);
03545          snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",control_statement_count, buf2);
03546          switch_test->app = strdup("Goto");
03547          switch_test->appargs = strdup(buf1);
03548          snprintf(buf1,sizeof(buf1),"Finish switch-%s-%d", label, control_statement_count);
03549          switch_end->app = strdup("NoOp");
03550          switch_end->appargs = strdup(buf1);
03551          switch_end->origin = p;
03552          switch_end->exten = exten;
03553 
03554          linkprio(exten, switch_test, mother_exten);
03555          linkprio(exten, switch_end, mother_exten);
03556          
03557          exten->loop_break = switch_end;
03558          exten->loop_continue = 0;
03559          default_exists = 0;
03560          
03561          for (p2=p->u2.statements; p2; p2=p2->next) {
03562             /* now, for each case/default put the body of the for loop here */
03563             if (p2->type == PV_CASE) {
03564                /* ok, generate a extension and link it in */
03565                switch_case = new_exten();
03566                if (mother_exten && mother_exten->checked_switch) {
03567                   switch_case->has_switch = mother_exten->has_switch;
03568                   switch_case->checked_switch = mother_exten->checked_switch;
03569                }
03570                if (exten && exten->checked_switch) {
03571                   switch_case->has_switch = exten->has_switch;
03572                   switch_case->checked_switch = exten->checked_switch;
03573                }
03574                switch_case->context = this_context;
03575                switch_case->is_switch = 1;
03576                /* the break/continue locations are inherited from parent */
03577                switch_case->loop_break = exten->loop_break;
03578                switch_case->loop_continue = exten->loop_continue;
03579                
03580                linkexten(exten,switch_case);
03581                strncpy(buf2,p2->u1.str,sizeof(buf2));
03582                buf2[sizeof(buf2)-1] = 0; /* just in case */
03583                substitute_commas(buf2);
03584                snprintf(buf1,sizeof(buf1),"sw-%d-%s", local_control_statement_count, buf2);
03585                switch_case->name = strdup(buf1);
03586                snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count);
03587                
03588                gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the case body statements here */
03589 
03590                /* here is where we write code to "fall thru" to the next case... if there is one... */
03591                for (p3=p2->u2.statements; p3; p3=p3->next) {
03592                   if (!p3->next)
03593                      break;
03594                }
03595                /* p3 now points the last statement... */
03596                if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN) ) {
03597                   /* is there a following CASE/PATTERN/DEFAULT? */
03598                   if (p2->next && p2->next->type == PV_CASE) {
03599                      fall_thru = new_prio();
03600                      fall_thru->type = AEL_APPCALL;
03601                      fall_thru->app = strdup("Goto");
03602                      strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03603                      buf2[sizeof(buf2)-1] = 0; /* just in case */
03604                      substitute_commas(buf2);
03605                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03606                      fall_thru->appargs = strdup(buf1);
03607                      linkprio(switch_case, fall_thru, mother_exten);
03608                   } else if (p2->next && p2->next->type == PV_PATTERN) {
03609                      fall_thru = new_prio();
03610                      fall_thru->type = AEL_APPCALL;
03611                      fall_thru->app = strdup("Goto");
03612                      gen_match_to_pattern(p2->next->u1.str, buf2);
03613                      substitute_commas(buf2);
03614                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10", local_control_statement_count, buf2);
03615                      fall_thru->appargs = strdup(buf1);
03616                      linkprio(switch_case, fall_thru, mother_exten);
03617                   } else if (p2->next && p2->next->type == PV_DEFAULT) {
03618                      fall_thru = new_prio();
03619                      fall_thru->type = AEL_APPCALL;
03620                      fall_thru->app = strdup("Goto");
03621                      snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03622                      fall_thru->appargs = strdup(buf1);
03623                      linkprio(switch_case, fall_thru, mother_exten);
03624                   } else if (!p2->next) {
03625                      fall_thru = new_prio();
03626                      fall_thru->type = AEL_CONTROL1;
03627                      fall_thru->goto_true = switch_end;
03628                      fall_thru->app = strdup("Goto");
03629                      linkprio(switch_case, fall_thru, mother_exten);
03630                   }
03631                }
03632                if (switch_case->return_needed) {
03633                   char buf[2000];
03634                   struct ael_priority *np2 = new_prio();
03635                   np2->type = AEL_APPCALL;
03636                   np2->app = strdup("NoOp");
03637                   snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03638                   np2->appargs = strdup(buf);
03639                   linkprio(switch_case, np2, mother_exten);
03640                   switch_case-> return_target = np2;
03641                }
03642             } else if (p2->type == PV_PATTERN) {
03643                /* ok, generate a extension and link it in */
03644                switch_case = new_exten();
03645                if (mother_exten && mother_exten->checked_switch) {
03646                   switch_case->has_switch = mother_exten->has_switch;
03647                   switch_case->checked_switch = mother_exten->checked_switch;
03648                }
03649                if (exten && exten->checked_switch) {
03650                   switch_case->has_switch = exten->has_switch;
03651                   switch_case->checked_switch = exten->checked_switch;
03652                }
03653                switch_case->context = this_context;
03654                switch_case->is_switch = 1;
03655                /* the break/continue locations are inherited from parent */
03656                switch_case->loop_break = exten->loop_break;
03657                switch_case->loop_continue = exten->loop_continue;
03658                
03659                linkexten(exten,switch_case);
03660                strncpy(buf2,p2->u1.str,sizeof(buf2));
03661                buf2[sizeof(buf2)-1] = 0; /* just in case */
03662                substitute_commas(buf2);
03663                snprintf(buf1,sizeof(buf1),"_sw-%d-%s", local_control_statement_count, buf2);
03664                switch_case->name = strdup(buf1);
03665                snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count);
03666                
03667                gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the while body statements here */
03668                /* here is where we write code to "fall thru" to the next case... if there is one... */
03669                for (p3=p2->u2.statements; p3; p3=p3->next) {
03670                   if (!p3->next)
03671                      break;
03672                }
03673                /* p3 now points the last statement... */
03674                if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03675                   /* is there a following CASE/PATTERN/DEFAULT? */
03676                   if (p2->next && p2->next->type == PV_CASE) {
03677                      fall_thru = new_prio();
03678                      fall_thru->type = AEL_APPCALL;
03679                      fall_thru->app = strdup("Goto");
03680                      strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03681                      buf2[sizeof(buf2)-1] = 0; /* just in case */
03682                      substitute_commas(buf2);
03683                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03684                      fall_thru->appargs = strdup(buf1);
03685                      linkprio(switch_case, fall_thru, mother_exten);
03686                   } else if (p2->next && p2->next->type == PV_PATTERN) {
03687                      fall_thru = new_prio();
03688                      fall_thru->type = AEL_APPCALL;
03689                      fall_thru->app = strdup("Goto");
03690                      gen_match_to_pattern(p2->next->u1.str, buf2);
03691                      substitute_commas(buf2);
03692                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03693                      fall_thru->appargs = strdup(buf1);
03694                      linkprio(switch_case, fall_thru, mother_exten);
03695                   } else if (p2->next && p2->next->type == PV_DEFAULT) {
03696                      fall_thru = new_prio();
03697                      fall_thru->type = AEL_APPCALL;
03698                      fall_thru->app = strdup("Goto");
03699                      snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03700                      fall_thru->appargs = strdup(buf1);
03701                      linkprio(switch_case, fall_thru, mother_exten);
03702                   } else if (!p2->next) {
03703                      fall_thru = new_prio();
03704                      fall_thru->type = AEL_CONTROL1;
03705                      fall_thru->goto_true = switch_end;
03706                      fall_thru->app = strdup("Goto");
03707                      linkprio(switch_case, fall_thru, mother_exten);
03708                   }
03709                }
03710                if (switch_case->return_needed) {
03711                   char buf[2000];
03712                   struct ael_priority *np2 = new_prio();
03713                   np2->type = AEL_APPCALL;
03714                   np2->app = strdup("NoOp");
03715                   snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03716                   np2->appargs = strdup(buf);
03717                   linkprio(switch_case, np2, mother_exten);
03718                   switch_case-> return_target = np2;
03719                }
03720             } else if (p2->type == PV_DEFAULT) {
03721                /* ok, generate a extension and link it in */
03722                switch_case = new_exten();
03723                if (mother_exten && mother_exten->checked_switch) {
03724                   switch_case->has_switch = mother_exten->has_switch;
03725                   switch_case->checked_switch = mother_exten->checked_switch;
03726                }
03727                if (exten && exten->checked_switch) {
03728                   switch_case->has_switch = exten->has_switch;
03729                   switch_case->checked_switch = exten->checked_switch;
03730                }
03731                switch_case->context = this_context;
03732                switch_case->is_switch = 1;
03733                
03734                /* new: the default case intros a pattern with ., which covers ALMOST everything.
03735                   but it doesn't cover a NULL pattern. So, we'll define a null extension to match
03736                   that goto's the default extension. */
03737 
03738                default_exists++;
03739                switch_null = new_exten();
03740                if (mother_exten && mother_exten->checked_switch) {
03741                   switch_null->has_switch = mother_exten->has_switch;
03742                   switch_null->checked_switch = mother_exten->checked_switch;
03743                }
03744                if (exten && exten->checked_switch) {
03745                   switch_null->has_switch = exten->has_switch;
03746                   switch_null->checked_switch = exten->checked_switch;
03747                }
03748                switch_null->context = this_context;
03749                switch_null->is_switch = 1;
03750                switch_empty = new_prio();
03751                snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03752                switch_empty->app = strdup("Goto");
03753                switch_empty->appargs = strdup(buf1);
03754                linkprio(switch_null, switch_empty, mother_exten);
03755                snprintf(buf1,sizeof(buf1),"sw-%d-", local_control_statement_count);
03756                switch_null->name = strdup(buf1);
03757                switch_null->loop_break = exten->loop_break;
03758                switch_null->loop_continue = exten->loop_continue;
03759                linkexten(exten,switch_null);
03760 
03761                /* the break/continue locations are inherited from parent */
03762                switch_case->loop_break = exten->loop_break;
03763                switch_case->loop_continue = exten->loop_continue;
03764                linkexten(exten,switch_case);
03765                snprintf(buf1,sizeof(buf1),"_sw-%d-.", local_control_statement_count);
03766                switch_case->name = strdup(buf1);
03767                
03768                snprintf(new_label,sizeof(new_label),"sw-%s-default-%d", label, local_control_statement_count);
03769                
03770                gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the default:  body statements here */
03771                
03772                /* here is where we write code to "fall thru" to the next case... if there is one... */
03773                for (p3=p2->u2.statements; p3; p3=p3->next) {
03774                   if (!p3->next)
03775                      break;
03776                }
03777                /* p3 now points the last statement... */
03778                if (!p3 || (p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03779                   /* is there a following CASE/PATTERN/DEFAULT? */
03780                   if (p2->next && p2->next->type == PV_CASE) {
03781                      fall_thru = new_prio();
03782                      fall_thru->type = AEL_APPCALL;
03783                      fall_thru->app = strdup("Goto");
03784                      strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03785                      buf2[sizeof(buf2)-1] = 0; /* just in case */
03786                      substitute_commas(buf2);
03787                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03788                      fall_thru->appargs = strdup(buf1);
03789                      linkprio(switch_case, fall_thru, mother_exten);
03790                   } else if (p2->next && p2->next->type == PV_PATTERN) {
03791                      fall_thru = new_prio();
03792                      fall_thru->type = AEL_APPCALL;
03793                      fall_thru->app = strdup("Goto");
03794                      gen_match_to_pattern(p2->next->u1.str, buf2);
03795                      substitute_commas(buf2);
03796                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03797                      fall_thru->appargs = strdup(buf1);
03798                      linkprio(switch_case, fall_thru, mother_exten);
03799                   } else if (p2->next && p2->next->type == PV_DEFAULT) {
03800                      fall_thru = new_prio();
03801                      fall_thru->type = AEL_APPCALL;
03802                      fall_thru->app = strdup("Goto");
03803                      snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03804                      fall_thru->appargs = strdup(buf1);
03805                      linkprio(switch_case, fall_thru, mother_exten);
03806                   } else if (!p2->next) {
03807                      fall_thru = new_prio();
03808                      fall_thru->type = AEL_CONTROL1;
03809                      fall_thru->goto_true = switch_end;
03810                      fall_thru->app = strdup("Goto");
03811                      linkprio(switch_case, fall_thru, mother_exten);
03812                   }
03813                }
03814                if (switch_case->return_needed) {
03815                   char buf[2000];
03816                   struct ael_priority *np2 = new_prio();
03817                   np2->type = AEL_APPCALL;
03818                   np2->app = strdup("NoOp");
03819                   snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03820                   np2->appargs = strdup(buf);
03821                   linkprio(switch_case, np2, mother_exten);
03822                   switch_case-> return_target = np2;
03823                }
03824             } else {
03825                /* what could it be??? */
03826             }
03827          }
03828          
03829          exten->loop_break = loop_break_save;
03830          exten->loop_continue = loop_continue_save;
03831          switch_test->origin = p;
03832          switch_end->origin = p;
03833          break;
03834 
03835       case PV_MACRO_CALL:
03836          pr = new_prio();
03837          pr->type = AEL_APPCALL;
03838          snprintf(buf1,sizeof(buf1),"%s", p->u1.str);
03839          for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03840             strcat(buf1,"|");
03841             strcat(buf1,p2->u1.str);
03842          }
03843          pr->app = strdup("Macro");
03844          pr->appargs = strdup(buf1);
03845          pr->origin = p;
03846          linkprio(exten, pr, mother_exten);
03847          break;
03848 
03849       case PV_APPLICATION_CALL:
03850          pr = new_prio();
03851          pr->type = AEL_APPCALL;
03852          buf1[0] = 0;
03853          for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03854             if (p2 != p->u2.arglist )
03855                strcat(buf1,"|");
03856             substitute_commas(p2->u1.str);
03857             strcat(buf1,p2->u1.str);
03858          }
03859          pr->app = strdup(p->u1.str);
03860          pr->appargs = strdup(buf1);
03861          pr->origin = p;
03862          linkprio(exten, pr, mother_exten);
03863          break;
03864 
03865       case PV_BREAK:
03866          pr = new_prio();
03867          pr->type = AEL_CONTROL1; /* simple goto */
03868          pr->goto_true = exten->loop_break;
03869          pr->origin = p;
03870          linkprio(exten, pr, mother_exten);
03871          break;
03872 
03873       case PV_RETURN: /* hmmmm */
03874          pr = new_prio();
03875          pr->type = AEL_RETURN; /* simple goto */
03876          exten->return_needed++;
03877          pr->app = strdup("Goto");
03878          pr->appargs = strdup("");
03879          pr->origin = p;
03880          linkprio(exten, pr, mother_exten);
03881          break;
03882 
03883       case PV_CONTINUE:
03884          pr = new_prio();
03885          pr->type = AEL_CONTROL1; /* simple goto */
03886          pr->goto_true = exten->loop_continue;
03887          pr->origin = p;
03888          linkprio(exten, pr, mother_exten);
03889          break;
03890 
03891 #ifdef OLD_RAND_ACTION
03892       case PV_RANDOM:
03893          control_statement_count++;
03894          snprintf(new_label,sizeof(new_label),"rand-%s-%d", label, control_statement_count);
03895          rand_test = new_prio();
03896          rand_test->type = AEL_RAND_CONTROL;
03897          snprintf(buf1,sizeof(buf1),"$[%s]",
03898                 p->u1.str );
03899          rand_test->app = 0;
03900          rand_test->appargs = strdup(buf1);
03901          rand_test->origin = p;
03902          
03903          rand_end = new_prio();
03904          rand_end->type = AEL_APPCALL;
03905          snprintf(buf1,sizeof(buf1),"Finish rand-%s-%d", label, control_statement_count);
03906          rand_end->app = strdup("NoOp");
03907          rand_end->appargs = strdup(buf1);
03908          
03909          rand_skip = new_prio();
03910          rand_skip->type = AEL_CONTROL1; /* simple goto */
03911          rand_skip->goto_true = rand_end;
03912          rand_skip->origin  = p;
03913 
03914          rand_test->goto_true = rand_skip; /* +1, really */
03915 
03916          linkprio(exten, rand_test, mother_exten);
03917          
03918          if (p->u3.else_statements) {
03919             gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the else statements here */
03920          }
03921          
03922          linkprio(exten, rand_skip, mother_exten);
03923          
03924          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the "true" statements here */
03925 
03926          linkprio(exten, rand_end, mother_exten);
03927          
03928          break;
03929 #endif         
03930 
03931       case PV_IFTIME:
03932          control_statement_count++;
03933          snprintf(new_label,sizeof(new_label),"iftime-%s-%d", label, control_statement_count);
03934          
03935          if_test = new_prio();
03936          if_test->type = AEL_IFTIME_CONTROL;
03937          snprintf(buf1,sizeof(buf1),"%s|%s|%s|%s",
03938                 p->u1.list->u1.str, 
03939                 p->u1.list->next->u1.str, 
03940                 p->u1.list->next->next->u1.str, 
03941                 p->u1.list->next->next->next->u1.str);
03942          if_test->app = 0;
03943          if_test->appargs = strdup(buf1);
03944          if_test->origin = p;
03945 
03946          if_end = new_prio();
03947          if_end->type = AEL_APPCALL;
03948          snprintf(buf1,sizeof(buf1),"Finish iftime-%s-%d", label, control_statement_count);
03949          if_end->app = strdup("NoOp");
03950          if_end->appargs = strdup(buf1);
03951 
03952          if (p->u3.else_statements) {
03953             if_skip = new_prio();
03954             if_skip->type = AEL_CONTROL1; /* simple goto */
03955             if_skip->goto_true = if_end;
03956             if_skip->origin  = p;
03957 
03958          } else {
03959             if_skip = 0;
03960 
03961             if_test->goto_false = if_end;
03962          }
03963 
03964          if_false = new_prio();
03965          if_false->type = AEL_CONTROL1;
03966          if (p->u3.else_statements) {
03967             if_false->goto_true = if_skip; /* +1 */
03968          } else {
03969             if_false->goto_true = if_end;
03970          }
03971          
03972          /* link & load! */
03973          linkprio(exten, if_test, mother_exten);
03974          linkprio(exten, if_false, mother_exten);
03975          
03976          /* now, put the body of the if here */
03977          
03978          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the statements here */
03979          
03980          if (p->u3.else_statements) {
03981             linkprio(exten, if_skip, mother_exten);
03982             gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the statements here */
03983 
03984          }
03985          
03986          linkprio(exten, if_end, mother_exten);
03987          
03988          break;
03989 
03990       case PV_RANDOM:
03991       case PV_IF:
03992          control_statement_count++;
03993          snprintf(new_label,sizeof(new_label),"if-%s-%d", label, control_statement_count);
03994          
03995          if_test = new_prio();
03996          if_end = new_prio();
03997          if_test->type = AEL_IF_CONTROL;
03998          if_end->type = AEL_APPCALL;
03999          if ( p->type == PV_RANDOM )
04000             snprintf(buf1,sizeof(buf1),"$[${RAND(0|99)} < (%s)]",p->u1.str);
04001          else {
04002             char buf[8000];
04003             strcpy(buf,p->u1.str);
04004             substitute_commas(buf);
04005             snprintf(buf1,sizeof(buf1),"$[%s]",buf);
04006          }
04007          
04008          if_test->app = 0;
04009          if_test->appargs = strdup(buf1);
04010          snprintf(buf1,sizeof(buf1),"Finish if-%s-%d", label, control_statement_count);
04011          if_end->app = strdup("NoOp");
04012          if_end->appargs = strdup(buf1);
04013          if_test->origin = p;
04014          
04015          if (p->u3.else_statements) {
04016             if_skip = new_prio();
04017             if_skip->type = AEL_CONTROL1; /* simple goto */
04018             if_skip->goto_true = if_end;
04019             if_test->goto_false = if_skip;;
04020          } else {
04021             if_skip = 0;
04022             if_test->goto_false = if_end;;
04023          }
04024          
04025          /* link & load! */
04026          linkprio(exten, if_test, mother_exten);
04027          
04028          /* now, put the body of the if here */
04029          
04030          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the statements here */
04031          
04032          if (p->u3.else_statements) {
04033             linkprio(exten, if_skip, mother_exten);
04034             gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the statements here */
04035 
04036          }
04037          
04038          linkprio(exten, if_end, mother_exten);
04039          
04040          break;
04041 
04042       case PV_STATEMENTBLOCK:
04043          gen_prios(exten, label, p->u1.list, mother_exten, this_context ); /* recurse into the block */
04044          break;
04045 
04046       case PV_CATCH:
04047          control_statement_count++;
04048          /* generate an extension with name of catch, put all catch stats
04049             into this exten! */
04050          switch_case = new_exten();
04051          if (mother_exten && mother_exten->checked_switch) {
04052             switch_case->has_switch = mother_exten->has_switch;
04053             switch_case->checked_switch = mother_exten->checked_switch;
04054          }
04055          if (exten && exten->checked_switch) {
04056             switch_case->has_switch = exten->has_switch;
04057             switch_case->checked_switch = exten->checked_switch;
04058          }
04059          
04060          switch_case->context = this_context;
04061          linkexten(exten,switch_case);
04062          switch_case->name = strdup(p->u1.str);
04063          snprintf(new_label,sizeof(new_label),"catch-%s-%d",p->u1.str, control_statement_count);
04064          
04065          gen_prios(switch_case, new_label, p->u2.statements,mother_exten,this_context); /* this will link in all the catch body statements here */
04066          if (switch_case->return_needed) {
04067             char buf[2000];
04068             struct ael_priority *np2 = new_prio();
04069             np2->type = AEL_APPCALL;
04070             np2->app = strdup("NoOp");
04071             snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
04072             np2->appargs = strdup(buf);
04073             linkprio(switch_case, np2, mother_exten);
04074             switch_case-> return_target = np2;
04075          }
04076 
04077          break;
04078       default:
04079          break;
04080       }
04081    }
04082 }

static pval * get_contxt ( pval p  )  [static]

Definition at line 4243 of file pbx_ael.c.

References pval::dad, PV_CONTEXT, PV_MACRO, and pval::type.

Referenced by check_goto(), and get_goto_target().

04244 {
04245    while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
04246       
04247       p = p->dad;
04248    }
04249    
04250    return p;
04251 }

static pval * get_extension_or_contxt ( pval p  )  [static]

Definition at line 4233 of file pbx_ael.c.

References pval::dad, PV_CONTEXT, PV_EXTENSION, PV_MACRO, and pval::type.

Referenced by check_goto(), and get_goto_target().

04234 {
04235    while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
04236       
04237       p = p->dad;
04238    }
04239    
04240    return p;
04241 }

static pval * get_goto_target ( pval item  )  [static]

Definition at line 1125 of file pbx_ael.c.

References find_context(), find_label_in_current_context(), find_label_in_current_db(), find_label_in_current_extension(), get_contxt(), get_extension_or_contxt(), pval::list, pval::next, PV_INCLUDES, pval::statements, pval::str, pval::type, pval::u1, and pval::u2.

Referenced by gen_prios().

01126 {
01127    /* just one item-- the label should be in the current extension */
01128    pval *curr_ext = get_extension_or_contxt(item); /* containing exten, or macro */
01129    pval *curr_cont;
01130    
01131    if (item->u1.list && !item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) {
01132       struct pval *x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), curr_ext);
01133          return x;
01134    }
01135 
01136    curr_cont = get_contxt(item);
01137 
01138    /* TWO items */
01139    if (item->u1.list->next && !item->u1.list->next->next) {
01140       if (!strstr((item->u1.list)->u1.str,"${") 
01141          && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ {
01142          struct pval *x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, curr_cont);
01143             return x;
01144       }
01145    }
01146    
01147    /* All 3 items! */
01148    if (item->u1.list->next && item->u1.list->next->next) {
01149       /* all three */
01150       pval *first = item->u1.list;
01151       pval *second = item->u1.list->next;
01152       pval *third = item->u1.list->next->next;
01153       
01154       if (!strstr((item->u1.list)->u1.str,"${") 
01155          && !strstr(item->u1.list->next->u1.str,"${")
01156          && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ {
01157          struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
01158          if (!x) {
01159 
01160             struct pval *p3;
01161             struct pval *that_context = find_context(item->u1.list->u1.str);
01162             
01163             /* the target of the goto could be in an included context!! Fancy that!! */
01164             /* look for includes in the current context */
01165             if (that_context) {
01166                for (p3=that_context->u2.statements; p3; p3=p3->next) {
01167                   if (p3->type == PV_INCLUDES) {
01168                      struct pval *p4;
01169                      for (p4=p3->u1.list; p4; p4=p4->next) {
01170                         /* for each context pointed to, find it, then find a context/label that matches the
01171                            target here! */
01172                         char *incl_context = p4->u1.str;
01173                         /* find a matching context name */
01174                         struct pval *that_other_context = find_context(incl_context);
01175                         if (that_other_context) {
01176                            struct pval *x3;
01177                            x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
01178                            if (x3) {
01179                               return x3;
01180                            }
01181                         }
01182                      }
01183                   }
01184                }
01185             }
01186          }
01187          return x;
01188       }
01189    }
01190    return 0;
01191 }

int is_empty ( char *  arg  ) 

Definition at line 1929 of file pbx_ael.c.

01930 {
01931    if (!arg)
01932       return 1;
01933    if (*arg == 0)
01934       return 1;
01935    while (*arg) {
01936       if (*arg != ' ' && *arg != '\t')
01937          return 0;
01938       arg++;
01939    }
01940    return 1;
01941 }

int is_float ( char *  arg  ) 

Definition at line 1911 of file pbx_ael.c.

References s.

01912 {
01913    char *s;
01914    for (s=arg; *s; s++) {
01915       if (*s != '.' && (*s < '0' || *s > '9'))
01916          return 0;
01917    }
01918    return 1;
01919 }

int is_int ( char *  arg  ) 

Definition at line 1920 of file pbx_ael.c.

References s.

01921 {
01922    char *s;
01923    for (s=arg; *s; s++) {
01924       if (*s < '0' || *s > '9')
01925          return 0;
01926    }
01927    return 1;
01928 }

static int label_inside_case ( pval label  )  [static]

Definition at line 2921 of file pbx_ael.c.

References pval::dad, PV_CASE, PV_CONTEXT, PV_DEFAULT, PV_MACRO, PV_PATTERN, and pval::type.

Referenced by gen_prios().

02922 {
02923    pval *p = label;
02924    
02925    while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
02926       if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN ) {
02927          return 1;
02928       }
02929 
02930       p = p->dad;
02931    }
02932    return 0;
02933 }

static void linkexten ( struct ael_extension exten,
struct ael_extension add 
) [static]

Definition at line 2935 of file pbx_ael.c.

References exten, and ael_extension::next_exten.

Referenced by gen_prios().

02936 {
02937    add->next_exten = exten->next_exten; /* this will reverse the order. Big deal. */
02938    exten->next_exten = add;
02939 }

void linkprio ( struct ael_extension exten,
struct ael_priority prio,
struct ael_extension mother_exten 
)

Definition at line 2839 of file pbx_ael.c.

References ael_priority::appargs, ael_priority::exten, exten, free, ael_extension::has_switch, and malloc.

Referenced by gen_prios().

02840 {
02841    char *p1, *p2;
02842    
02843    if (!exten->plist) {
02844       exten->plist = prio;
02845       exten->plist_last = prio;
02846    } else {
02847       exten->plist_last->next = prio;
02848       exten->plist_last = prio;
02849    }
02850    if( !prio->exten )
02851       prio->exten = exten; /* don't override the switch value */
02852    /* The following code will cause all priorities within an extension 
02853       to have ${EXTEN} or ${EXTEN: replaced with ~~EXTEN~~, which is
02854       set just before the first switch in an exten. The switches
02855       will muck up the original ${EXTEN} value, so we save it away
02856       and the user accesses this copy instead. */
02857    if (prio->appargs && ((mother_exten && mother_exten->has_switch) || exten->has_switch) ) {
02858       while ((p1 = strstr(prio->appargs, "${EXTEN}"))) {
02859          p2 = malloc(strlen(prio->appargs)+5);
02860          *p1 = 0;
02861          strcpy(p2, prio->appargs);
02862          strcat(p2, "${~~EXTEN~~}");
02863          if (*(p1+8))
02864             strcat(p2, p1+8);
02865          free(prio->appargs);
02866          prio->appargs = p2;
02867       }
02868       while ((p1 = strstr(prio->appargs, "${EXTEN:"))) {
02869          p2 = malloc(strlen(prio->appargs)+5);
02870          *p1 = 0;
02871          strcpy(p2, prio->appargs);
02872          strcat(p2, "${~~EXTEN~~:");
02873          if (*(p1+8))
02874             strcat(p2, p1+8);
02875          free(prio->appargs);
02876          prio->appargs = p2;
02877       }
02878    }
02879 }

static int load_module ( void   )  [static]

Definition at line 4621 of file pbx_ael.c.

References ast_cli_register_multiple(), cli_ael, and pbx_load_module().

04622 {
04623    ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04624    return (pbx_load_module());
04625 }

struct pval * match_pval ( pval item  ) 

Definition at line 1752 of file pbx_ael.c.

References match_pval_item(), and pval::next.

Referenced by find_context(), find_first_label_in_current_context(), find_label_in_current_context(), find_label_in_current_db(), find_label_in_current_extension(), find_macro(), and match_pval_item().

01753 {
01754    pval *i;
01755 
01756    for (i=item; i; i=i->next) {
01757       pval *x;
01758       /* printf("   -- match pval: item %d\n", i->type); */
01759       
01760       if ((x = match_pval_item(i))) {
01761          /* printf("match_pval: returning x=%x\n", (int)x); */
01762          return x; /* cut the search short */
01763       }
01764    }
01765    return 0;
01766 }

static struct pval* match_pval_item ( pval item  )  [static]

Definition at line 1485 of file pbx_ael.c.

References pval::else_statements, extension_matches(), pval::for_statements, last_matched_label, pval::list, pval::macro_statements, match_pval(), pval::next, PV_CASE, PV_CATCH, PV_CONTEXT, PV_DEFAULT, PV_EXTENSION, PV_FOR, PV_IF, PV_IFTIME, PV_LABEL, PV_MACRO, PV_PATTERN, PV_RANDOM, PV_STATEMENTBLOCK, PV_SWITCH, PV_WHILE, pval::statements, pval::str, pval::type, pval::u1, pval::u2, pval::u3, and pval::u4.

Referenced by match_pval().

01486 {
01487    pval *x;
01488    
01489    switch ( item->type ) {
01490    case PV_MACRO:
01491       /* fields: item->u1.str     == name of macro
01492                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
01493                item->u2.arglist->u1.str  == argument
01494                item->u2.arglist->next   == next arg
01495 
01496                item->u3.macro_statements == pval list of statements in macro body.
01497       */
01498       /* printf("    matching in MACRO %s, match_context=%s; retoncontmtch=%d; \n", item->u1.str, match_context, return_on_context_match); */
01499       if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
01500          
01501          /* printf("MACRO: match context is: %s\n", match_context); */
01502          
01503          if (return_on_context_match && !strcmp(item->u1.str, match_context)) /* if we're just searching for a context, don't bother descending into them */ {
01504             /* printf("Returning on matching macro %s\n", match_context); */
01505             return item;
01506          }
01507          
01508          
01509          if (!return_on_context_match) {
01510             /* printf("Descending into matching macro %s/%s\n", match_context, item->u1.str); */
01511             if ((x=match_pval(item->u3.macro_statements)))  {
01512                /* printf("Responded with pval match %x\n", x); */
01513                return x;
01514             }
01515          }
01516       } else {
01517          /* printf("Skipping context/macro %s\n", item->u1.str); */
01518       }
01519       
01520       break;
01521          
01522    case PV_CONTEXT:
01523       /* fields: item->u1.str     == name of context
01524                  item->u2.statements == pval list of statements in context body
01525                item->u3.abstract == int 1 if an abstract keyword were present
01526       */
01527       /* printf("    matching in CONTEXT\n"); */
01528       if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
01529          if (return_on_context_match && !strcmp(item->u1.str, match_context)) {
01530             /* printf("Returning on matching context %s\n", match_context); */
01531             /* printf("non-CONTEXT: Responded with pval match %x\n", x); */
01532             return item;
01533          }
01534          
01535          if (!return_on_context_match ) {
01536             /* printf("Descending into matching context %s\n", match_context); */
01537             if ((x=match_pval(item->u2.statements))) /* if we're just searching for a context, don't bother descending into them */ {
01538                /* printf("CONTEXT: Responded with pval match %x\n", x); */
01539                return x;
01540             }
01541          }
01542       } else {
01543          /* printf("Skipping context/macro %s\n", item->u1.str); */
01544       }
01545       break;
01546 
01547    case PV_CASE:
01548       /* fields: item->u1.str     == value of case
01549                  item->u2.statements == pval list of statements under the case
01550       */
01551       /* printf("    matching in CASE\n"); */
01552       if ((x=match_pval(item->u2.statements))) {
01553          /* printf("CASE: Responded with pval match %x\n", x); */
01554          return x;
01555       }
01556       break;
01557          
01558    case PV_PATTERN:
01559       /* fields: item->u1.str     == value of case
01560                  item->u2.statements == pval list of statements under the case
01561       */
01562       /* printf("    matching in PATTERN\n"); */
01563       if ((x=match_pval(item->u2.statements))) {
01564          /* printf("PATTERN: Responded with pval match %x\n", x); */
01565          return x;
01566       }
01567       break;
01568          
01569    case PV_DEFAULT:
01570       /* fields: 
01571                  item->u2.statements == pval list of statements under the case
01572       */
01573       /* printf("    matching in DEFAULT\n"); */
01574       if ((x=match_pval(item->u2.statements))) {
01575          /* printf("DEFAULT: Responded with pval match %x\n", x); */
01576          return x;
01577       }
01578       break;
01579          
01580    case PV_CATCH:
01581       /* fields: item->u1.str     == name of extension to catch
01582                  item->u2.statements == pval list of statements in context body
01583       */
01584       /* printf("    matching in CATCH\n"); */
01585       if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) {
01586          /* printf("Descending into matching catch %s => %s\n", match_exten, item->u1.str); */
01587          if (strcmp(match_label,"1") == 0) {
01588             if (item->u2.statements) {
01589                struct pval *p5 = item->u2.statements;
01590                while (p5 && p5->type == PV_LABEL)  /* find the first non-label statement in this context. If it exists, there's a "1" */
01591                   p5 = p5->next;
01592                if (p5)
01593                   return p5;
01594                else
01595                   return 0;
01596             }
01597             else
01598                return 0;
01599          }
01600 
01601          if ((x=match_pval(item->u2.statements))) {
01602             /* printf("CATCH: Responded with pval match %x\n", (unsigned int)x); */
01603             return x;
01604          }
01605       } else {
01606          /* printf("Skipping catch %s\n", item->u1.str); */
01607       }
01608       break;
01609          
01610    case PV_STATEMENTBLOCK:
01611       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
01612       */
01613       /* printf("    matching in STATEMENTBLOCK\n"); */
01614       if ((x=match_pval(item->u1.list))) {
01615          /* printf("STATEMENTBLOCK: Responded with pval match %x\n", x); */
01616          return x;
01617       }
01618       break;
01619          
01620    case PV_LABEL:
01621       /* fields: item->u1.str     == label name
01622       */
01623       /* printf("PV_LABEL %s (cont=%s, exten=%s\n", 
01624          item->u1.str, current_context->u1.str, (current_extension?current_extension->u1.str:"<macro>"));*/
01625       
01626       if (count_labels) {
01627          if (!strcmp(match_label, item->u1.str)) {
01628             label_count++;
01629             last_matched_label = item;
01630          }
01631          
01632       } else {
01633          if (!strcmp(match_label, item->u1.str)) {
01634             /* printf("LABEL: Responded with pval match %x\n", x); */
01635             return item;
01636          }
01637       }
01638       break;
01639          
01640    case PV_FOR:
01641       /* fields: item->u1.for_init     == a string containing the initalizer
01642                  item->u2.for_test     == a string containing the loop test
01643                  item->u3.for_inc      == a string containing the loop increment
01644 
01645                item->u4.for_statements == a pval list of statements in the for ()
01646       */
01647       /* printf("    matching in FOR\n"); */
01648       if ((x=match_pval(item->u4.for_statements))) {
01649          /* printf("FOR: Responded with pval match %x\n", x);*/
01650          return x;
01651       }
01652       break;
01653          
01654    case PV_WHILE:
01655       /* fields: item->u1.str        == the while conditional, as supplied by user
01656 
01657                item->u2.statements == a pval list of statements in the while ()
01658       */
01659       /* printf("    matching in WHILE\n"); */
01660       if ((x=match_pval(item->u2.statements))) {
01661          /* printf("WHILE: Responded with pval match %x\n", x); */
01662          return x;
01663       }
01664       break;
01665          
01666    case PV_RANDOM:
01667       /* fields: item->u1.str        == the random number expression, as supplied by user
01668 
01669                item->u2.statements == a pval list of statements in the if ()
01670                item->u3.else_statements == a pval list of statements in the else
01671                                     (could be zero)
01672        fall thru to PV_IF */
01673       
01674    case PV_IFTIME:
01675       /* fields: item->u1.list        == the time values, 4 of them, as PV_WORD structs in a list
01676 
01677                item->u2.statements == a pval list of statements in the if ()
01678                item->u3.else_statements == a pval list of statements in the else
01679                                     (could be zero)
01680       fall thru to PV_IF*/
01681    case PV_IF:
01682       /* fields: item->u1.str        == the if conditional, as supplied by user
01683 
01684                item->u2.statements == a pval list of statements in the if ()
01685                item->u3.else_statements == a pval list of statements in the else
01686                                     (could be zero)
01687       */
01688       /* printf("    matching in IF/IFTIME/RANDOM\n"); */
01689       if ((x=match_pval(item->u2.statements))) {
01690          return x;
01691       }
01692       if (item->u3.else_statements) {
01693          if ((x=match_pval(item->u3.else_statements))) {
01694             /* printf("IF/IFTIME/RANDOM: Responded with pval match %x\n", x); */
01695             return x;
01696          }
01697       }
01698       break;
01699          
01700    case PV_SWITCH:
01701       /* fields: item->u1.str        == the switch expression
01702 
01703                item->u2.statements == a pval list of statements in the switch, 
01704                                     (will be case statements, most likely!)
01705       */
01706       /* printf("    matching in SWITCH\n"); */
01707       if ((x=match_pval(item->u2.statements))) {
01708          /* printf("SWITCH: Responded with pval match %x\n", x); */
01709          return x;
01710       }
01711       break;
01712          
01713    case PV_EXTENSION:
01714       /* fields: item->u1.str        == the extension name, label, whatever it's called
01715 
01716                item->u2.statements == a pval list of statements in the extension
01717                item->u3.hints      == a char * hint argument
01718                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
01719       */
01720       /* printf("    matching in EXTENSION\n"); */
01721       if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) {
01722          /* printf("Descending into matching exten %s => %s\n", match_exten, item->u1.str); */
01723          if (strcmp(match_label,"1") == 0) {
01724             if (item->u2.statements) {
01725                struct pval *p5 = item->u2.statements;
01726                while (p5 && p5->type == PV_LABEL)  /* find the first non-label statement in this context. If it exists, there's a "1" */
01727                   p5 = p5->next;
01728                if (p5)
01729                   return p5;
01730                else
01731                   return 0;
01732             }
01733             else
01734                return 0;
01735          }
01736 
01737          if ((x=match_pval(item->u2.statements))) {
01738             /* printf("EXTENSION: Responded with pval match %x\n", x); */
01739             return x;
01740          }
01741       } else {
01742          /* printf("Skipping exten %s\n", item->u1.str); */
01743       }
01744       break;
01745    default:
01746       /* printf("    matching in default = %d\n", item->type); */
01747       break;
01748    }
01749    return 0;
01750 }

struct ael_extension * new_exten ( void   ) 

Definition at line 2833 of file pbx_ael.c.

References calloc.

Referenced by gen_prios().

02834 {
02835    struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
02836    return x;
02837 }

struct ael_priority * new_prio ( void   ) 

Definition at line 2827 of file pbx_ael.c.

References calloc.

Referenced by gen_prios().

02828 {
02829    struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
02830    return x;
02831 }

static int pbx_load_module ( void   )  [static]

Definition at line 4508 of file pbx_ael.c.

References ael2_parse(), ael2_semantic_check(), ast_compile_ael2(), ast_config_AST_CONFIG_DIR, ast_context_verify_includes(), ast_log(), ast_merge_contexts_and_delete(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_walk_contexts(), destroy_pval(), local_contexts, LOG_ERROR, and LOG_NOTICE.

Referenced by ael2_reload(), handle_reload_extensions(), load_module(), and reload().

04509 {
04510    int errs=0, sem_err=0, sem_warn=0, sem_note=0;
04511    char *rfilename;
04512    struct ast_context *local_contexts=NULL, *con;
04513    struct pval *parse_tree;
04514 
04515    ast_log(LOG_NOTICE, "Starting AEL load process.\n");
04516    if (config[0] == '/')
04517       rfilename = (char *)config;
04518    else {
04519       rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
04520       sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
04521    }
04522    ast_log(LOG_NOTICE, "AEL load process: calculated config file name '%s'.\n", rfilename);
04523 
04524    if (access(rfilename,R_OK) != 0) {
04525       ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
04526       return AST_MODULE_LOAD_DECLINE;
04527    }
04528    
04529    parse_tree = ael2_parse(rfilename, &errs);
04530    ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
04531    ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
04532    if (errs == 0 && sem_err == 0) {
04533       ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
04534       ast_compile_ael2(&local_contexts, parse_tree);
04535       ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
04536       
04537       ast_merge_contexts_and_delete(&local_contexts, registrar);
04538       ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
04539       for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
04540          ast_context_verify_includes(con);
04541       ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
04542    } else {
04543       ast_log(LOG_ERROR, "Sorry, but %d syntax errors and %d semantic errors were detected. It doesn't make sense to compile.\n", errs, sem_err);
04544       destroy_pval(parse_tree); /* free up the memory */
04545       return AST_MODULE_LOAD_DECLINE;
04546    }
04547    destroy_pval(parse_tree); /* free up the memory */
04548    
04549    return AST_MODULE_LOAD_SUCCESS;
04550 }

static void print_pval ( FILE *  fin,
pval item,
int  depth 
) [static]

Definition at line 177 of file pbx_ael.c.

References pval::arglist, pval::next, PV_MACRO, PV_WORD, pval::str, pval::type, pval::u1, and pval::u2.

Referenced by print_pval_list().

00178 {
00179    int i;
00180    pval *lp;
00181    
00182    for (i=0; i<depth; i++) {
00183       fprintf(fin, "\t"); /* depth == indentation */
00184    }
00185    
00186    switch ( item->type ) {
00187    case PV_WORD:
00188       fprintf(fin,"%s;\n", item->u1.str); /* usually, words are encapsulated in something else */
00189       break;
00190       
00191    case PV_MACRO:
00192       fprintf(fin,"macro %s(", item->u1.str);
00193       for (lp=item->u2.arglist; lp; lp=lp->next) {
00194          if (lp != item->u2.arglist )
00195             fprintf(fin,", ");
00196          fprintf(fin,"%s", lp->u1.str);
00197       }
00198       fprintf(fin,") {\n");
00199       print_pval_list(fin,item->u3.macro_statements,depth+1);
00200       for (i=0; i<depth; i++) {
00201          fprintf(fin,"\t"); /* depth == indentation */
00202       }
00203       fprintf(fin,"};\n\n");
00204       break;
00205          
00206    case PV_CONTEXT:
00207       if ( item->u3.abstract )
00208          fprintf(fin,"abstract context %s {\n", item->u1.str);
00209       else
00210          fprintf(fin,"context %s {\n", item->u1.str);
00211       print_pval_list(fin,item->u2.statements,depth+1);
00212       for (i=0; i<depth; i++) {
00213          fprintf(fin,"\t"); /* depth == indentation */
00214       }
00215       fprintf(fin,"};\n\n");
00216       break;
00217          
00218    case PV_MACRO_CALL:
00219       fprintf(fin,"&%s(", item->u1.str);
00220       for (lp=item->u2.arglist; lp; lp=lp->next) {
00221          if ( lp != item->u2.arglist )
00222             fprintf(fin,", ");
00223          fprintf(fin,"%s", lp->u1.str);
00224       }
00225       fprintf(fin,");\n");
00226       break;
00227          
00228    case PV_APPLICATION_CALL:
00229       fprintf(fin,"%s(", item->u1.str);
00230       for (lp=item->u2.arglist; lp; lp=lp->next) {
00231          if ( lp != item->u2.arglist )
00232             fprintf(fin,",");
00233          fprintf(fin,"%s", lp->u1.str);
00234       }
00235       fprintf(fin,");\n");
00236       break;
00237          
00238    case PV_CASE:
00239       fprintf(fin,"case %s:\n", item->u1.str);
00240       print_pval_list(fin,item->u2.statements, depth+1);
00241       break;
00242          
00243    case PV_PATTERN:
00244       fprintf(fin,"pattern %s:\n", item->u1.str);
00245       print_pval_list(fin,item->u2.statements, depth+1);
00246       break;
00247          
00248    case PV_DEFAULT:
00249       fprintf(fin,"default:\n");
00250       print_pval_list(fin,item->u2.statements, depth+1);
00251       break;
00252          
00253    case PV_CATCH:
00254       fprintf(fin,"catch %s {\n", item->u1.str);
00255       print_pval_list(fin,item->u2.statements, depth+1);
00256       for (i=0; i<depth; i++) {
00257          fprintf(fin,"\t"); /* depth == indentation */
00258       }
00259       fprintf(fin,"};\n");
00260       break;
00261          
00262    case PV_SWITCHES:
00263       fprintf(fin,"switches {\n");
00264       print_pval_list(fin,item->u1.list,depth+1);
00265       for (i=0; i<depth; i++) {
00266          fprintf(fin,"\t"); /* depth == indentation */
00267       }
00268       fprintf(fin,"};\n");
00269       break;
00270          
00271    case PV_ESWITCHES:
00272       fprintf(fin,"eswitches {\n");
00273       print_pval_list(fin,item->u1.list,depth+1);
00274       for (i=0; i<depth; i++) {
00275          fprintf(fin,"\t"); /* depth == indentation */
00276       }
00277       fprintf(fin,"};\n");
00278       break;
00279          
00280    case PV_INCLUDES:
00281       fprintf(fin,"includes {\n");
00282       for (lp=item->u1.list; lp; lp=lp->next) {
00283          for (i=0; i<depth+1; i++) {
00284             fprintf(fin,"\t"); /* depth == indentation */
00285          }
00286          fprintf(fin,"%s", lp->u1.str); /* usually, words are encapsulated in something else */
00287          if ( lp->u2.arglist )
00288             fprintf(fin,"|%s|%s|%s|%s", 
00289                   lp->u2.arglist->u1.str,
00290                   lp->u2.arglist->next->u1.str,
00291                   lp->u2.arglist->next->next->u1.str,
00292                   lp->u2.arglist->next->next->next->u1.str
00293                );
00294          fprintf(fin,";\n"); /* usually, words are encapsulated in something else */
00295       }
00296       
00297       print_pval_list(fin,item->u1.list,depth+1);
00298       for (i=0; i<depth; i++) {
00299          fprintf(fin,"\t"); /* depth == indentation */
00300       }
00301       fprintf(fin,"};\n");
00302       break;
00303          
00304    case PV_STATEMENTBLOCK:
00305       fprintf(fin,"{\n");
00306       print_pval_list(fin,item->u1.list, depth+1);
00307       for (i=0; i<depth; i++) {
00308          fprintf(fin,"\t"); /* depth == indentation */
00309       }
00310       fprintf(fin,"};\n");
00311       break;
00312          
00313    case PV_VARDEC:
00314       fprintf(fin,"%s=%s;\n", item->u1.str, item->u2.val);
00315       break;
00316          
00317    case PV_GOTO:
00318       fprintf(fin,"goto %s", item->u1.list->u1.str);
00319       if ( item->u1.list->next )
00320          fprintf(fin,"|%s", item->u1.list->next->u1.str);
00321       if ( item->u1.list->next && item->u1.list->next->next )
00322          fprintf(fin,"|%s", item->u1.list->next->next->u1.str);
00323       fprintf(fin,"\n");
00324       break;
00325          
00326    case PV_LABEL:
00327       fprintf(fin,"%s:\n", item->u1.str);
00328       break;
00329          
00330    case PV_FOR:
00331       fprintf(fin,"for (%s; %s; %s)\n", item->u1.for_init, item->u2.for_test, item->u3.for_inc);
00332       print_pval_list(fin,item->u4.for_statements,depth+1);
00333       break;
00334          
00335    case PV_WHILE:
00336       fprintf(fin,"while (%s)\n", item->u1.str);
00337       print_pval_list(fin,item->u2.statements,depth+1);
00338       break;
00339          
00340    case PV_BREAK:
00341       fprintf(fin,"break;\n");
00342       break;
00343          
00344    case PV_RETURN:
00345       fprintf(fin,"return;\n");
00346       break;
00347          
00348    case PV_CONTINUE:
00349       fprintf(fin,"continue;\n");
00350       break;
00351          
00352    case PV_RANDOM:
00353    case PV_IFTIME:
00354    case PV_IF:
00355       if ( item->type == PV_IFTIME ) {
00356          
00357          fprintf(fin,"ifTime ( %s|%s|%s|%s )\n", 
00358                item->u1.list->u1.str, 
00359                item->u1.list->next->u1.str, 
00360                item->u1.list->next->next->u1.str, 
00361                item->u1.list->next->next->next->u1.str
00362                );
00363       } else if ( item->type == PV_RANDOM ) {
00364          fprintf(fin,"random ( %s )\n", item->u1.str );
00365       } else
00366          fprintf(fin,"if ( %s )\n", item->u1.str);
00367       if ( item->u2.statements && item->u2.statements->next ) {
00368          for (i=0; i<depth; i++) {
00369             fprintf(fin,"\t"); /* depth == indentation */
00370          }
00371          fprintf(fin,"{\n");
00372          print_pval_list(fin,item->u2.statements,depth+1);
00373          for (i=0; i<depth; i++) {
00374             fprintf(fin,"\t"); /* depth == indentation */
00375          }
00376          if ( item->u3.else_statements )
00377             fprintf(fin,"}\n");
00378          else
00379             fprintf(fin,"};\n");
00380       } else if (item->u2.statements ) {
00381          print_pval_list(fin,item->u2.statements,depth+1);
00382       } else {
00383          if (item->u3.else_statements )
00384             fprintf(fin, " {} ");
00385          else
00386             fprintf(fin, " {}; ");
00387       }
00388       if ( item->u3.else_statements ) {
00389          for (i=0; i<depth; i++) {
00390             fprintf(fin,"\t"); /* depth == indentation */
00391          }
00392          fprintf(fin,"else\n");
00393          print_pval_list(fin,item->u3.else_statements, depth);
00394       }
00395       break;
00396          
00397    case PV_SWITCH:
00398       fprintf(fin,"switch( %s ) {\n", item->u1.str);
00399       print_pval_list(fin,item->u2.statements,depth+1);
00400       for (i=0; i<depth; i++) {
00401          fprintf(fin,"\t"); /* depth == indentation */
00402       }
00403       fprintf(fin,"}\n");
00404       break;
00405          
00406    case PV_EXTENSION:
00407       if ( item->u4.regexten )
00408          fprintf(fin, "regexten ");
00409       if ( item->u3.hints )
00410          fprintf(fin,"hints(%s) ", item->u3.hints);
00411       
00412       fprintf(fin,"%s => \n", item->u1.str);
00413       print_pval_list(fin,item->u2.statements,depth+1);
00414       break;
00415          
00416    case PV_IGNOREPAT:
00417       fprintf(fin,"ignorepat => %s\n", item->u1.str);
00418       break;
00419          
00420    case PV_GLOBALS:
00421       fprintf(fin,"globals {\n");
00422       print_pval_list(fin,item->u1.statements,depth+1);
00423       for (i=0; i<depth; i++) {
00424          fprintf(fin,"\t"); /* depth == indentation */
00425       }
00426       fprintf(fin,"}\n");
00427       break;
00428    }
00429 }

static void print_pval_list ( FILE *  fin,
pval item,
int  depth 
) [static]

Definition at line 431 of file pbx_ael.c.

References pval::next, and print_pval().

00432 {
00433    pval *i;
00434    
00435    for (i=item; i; i=i->next) {
00436       print_pval(fin, i, depth);
00437    }
00438 }

static int reload ( void   )  [static]

Definition at line 4627 of file pbx_ael.c.

References pbx_load_module().

04628 {
04629    return pbx_load_module();
04630 }

static void remove_spaces_before_equals ( char *  str  )  [static]

Definition at line 2941 of file pbx_ael.c.

Referenced by gen_prios().

02942 {
02943    char *p;
02944    while( str && *str && *str != '=' )
02945    {
02946       if( *str == ' ' || *str == '\n' || *str == '\r' || *str == '\t' )
02947       {
02948          p = str;
02949          while( *p )
02950          {
02951             *p = *(p+1);
02952             p++;
02953          }
02954       }
02955       else
02956          str++;
02957    }
02958 }

void set_priorities ( struct ael_extension exten  ) 

Definition at line 4084 of file pbx_ael.c.

References exten, ael_priority::next, ael_priority::origin, ael_priority::priority_num, PV_LABEL, and pval::type.

04085 {
04086    int i;
04087    struct ael_priority *pr;
04088    do {
04089       if (exten->is_switch)
04090          i = 10;
04091       else if (exten->regexten)
04092          i=2;
04093       else
04094          i=1;
04095       
04096       for (pr=exten->plist; pr; pr=pr->next) {
04097          pr->priority_num = i;
04098          
04099          if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
04100                                       but we want them to point to the right
04101                                       priority, which would be the next line
04102                                       after the label; */
04103             i++;
04104       }
04105       
04106       exten = exten->next_exten;
04107    } while ( exten );
04108 }

static void substitute_commas ( char *  str  )  [static]

Definition at line 154 of file pbx_ael.c.

Referenced by gen_prios().

00155 {
00156    char *p = str;
00157    
00158    while (p && *p)
00159    {
00160       if (*p == ',' && ((p != str && *(p-1) != '\\')
00161             || p == str))
00162          *p = '|';
00163       if (*p == '\\' && *(p+1) == ',') { /* learning experience: the '\,' is turned into just ',' by pbx_config; So we need to do the same */
00164          char *q = p;
00165          while (*q) {  /* move the ',' and everything after it up 1 char */
00166             *q = *(q+1);
00167             q++;
00168          }
00169       }
00170       p++;
00171    }
00172 }

void traverse_pval_item_template ( pval item,
int  depth 
)

Definition at line 460 of file pbx_ael.c.

References pval::arglist, pval::else_statements, pval::for_statements, pval::list, pval::macro_statements, pval::next, 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_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pval::statements, pval::type, pval::u1, pval::u2, pval::u3, and pval::u4.

Referenced by traverse_pval_template().

00462 {
00463    pval *lp;
00464    
00465    switch ( item->type ) {
00466    case PV_WORD:
00467       /* fields: item->u1.str == string associated with this (word). */
00468       break;
00469       
00470    case PV_MACRO:
00471       /* fields: item->u1.str     == name of macro
00472                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
00473                item->u2.arglist->u1.str  == argument
00474                item->u2.arglist->next   == next arg
00475 
00476                item->u3.macro_statements == pval list of statements in macro body.
00477       */
00478       for (lp=item->u2.arglist; lp; lp=lp->next) {
00479       
00480       }
00481       traverse_pval_item_template(item->u3.macro_statements,depth+1);
00482       break;
00483          
00484    case PV_CONTEXT:
00485       /* fields: item->u1.str     == name of context
00486                  item->u2.statements == pval list of statements in context body
00487                item->u3.abstract == int 1 if an abstract keyword were present
00488       */
00489       traverse_pval_item_template(item->u2.statements,depth+1);
00490       break;
00491          
00492    case PV_MACRO_CALL:
00493       /* fields: item->u1.str     == name of macro to call
00494                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
00495                item->u2.arglist->u1.str  == argument
00496                item->u2.arglist->next   == next arg
00497       */
00498       for (lp=item->u2.arglist; lp; lp=lp->next) {
00499       }
00500       break;
00501          
00502    case PV_APPLICATION_CALL:
00503       /* fields: item->u1.str     == name of application to call
00504                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
00505                item->u2.arglist->u1.str  == argument
00506                item->u2.arglist->next   == next arg
00507       */
00508       for (lp=item->u2.arglist; lp; lp=lp->next) {
00509       }
00510       break;
00511          
00512    case PV_CASE:
00513       /* fields: item->u1.str     == value of case
00514                  item->u2.statements == pval list of statements under the case
00515       */
00516       traverse_pval_item_template(item->u2.statements,depth+1);
00517       break;
00518          
00519    case PV_PATTERN:
00520       /* fields: item->u1.str     == value of case
00521                  item->u2.statements == pval list of statements under the case
00522       */
00523       traverse_pval_item_template(item->u2.statements,depth+1);
00524       break;
00525          
00526    case PV_DEFAULT:
00527       /* fields: 
00528                  item->u2.statements == pval list of statements under the case
00529       */
00530       traverse_pval_item_template(item->u2.statements,depth+1);
00531       break;
00532          
00533    case PV_CATCH:
00534       /* fields: item->u1.str     == name of extension to catch
00535                  item->u2.statements == pval list of statements in context body
00536       */
00537       traverse_pval_item_template(item->u2.statements,depth+1);
00538       break;
00539          
00540    case PV_SWITCHES:
00541       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
00542       */
00543       traverse_pval_item_template(item->u1.list,depth+1);
00544       break;
00545          
00546    case PV_ESWITCHES:
00547       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
00548       */
00549       traverse_pval_item_template(item->u1.list,depth+1);
00550       break;
00551          
00552    case PV_INCLUDES:
00553       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
00554                  item->u2.arglist  == pval list of 4 PV_WORD elements for time values
00555       */
00556       traverse_pval_item_template(item->u1.list,depth+1);
00557       traverse_pval_item_template(item->u2.arglist,depth+1);
00558       break;
00559          
00560    case PV_STATEMENTBLOCK:
00561       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
00562       */
00563       traverse_pval_item_template(item->u1.list,depth+1);
00564       break;
00565          
00566    case PV_VARDEC:
00567       /* fields: item->u1.str     == variable name
00568                  item->u2.val     == variable value to assign
00569       */
00570       break;
00571          
00572    case PV_GOTO:
00573       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
00574                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
00575       */
00576       
00577       if ( item->u1.list->next )
00578          ;
00579       if ( item->u1.list->next && item->u1.list->next->next )
00580          ;
00581       
00582       break;
00583          
00584    case PV_LABEL:
00585       /* fields: item->u1.str     == label name
00586       */
00587       break;
00588          
00589    case PV_FOR:
00590       /* fields: item->u1.for_init     == a string containing the initalizer
00591                  item->u2.for_test     == a string containing the loop test
00592                  item->u3.for_inc      == a string containing the loop increment
00593 
00594                item->u4.for_statements == a pval list of statements in the for ()
00595       */
00596       traverse_pval_item_template(item->u4.for_statements,depth+1);
00597       break;
00598          
00599    case PV_WHILE:
00600       /* fields: item->u1.str        == the while conditional, as supplied by user
00601 
00602                item->u2.statements == a pval list of statements in the while ()
00603       */
00604       traverse_pval_item_template(item->u2.statements,depth+1);
00605       break;
00606          
00607    case PV_BREAK:
00608       /* fields: none
00609       */
00610       break;
00611          
00612    case PV_RETURN:
00613       /* fields: none
00614       */
00615       break;
00616          
00617    case PV_CONTINUE:
00618       /* fields: none
00619       */
00620       break;
00621          
00622    case PV_IFTIME:
00623       /* fields: item->u1.list        == there are 4 linked PV_WORDs here.
00624 
00625                item->u2.statements == a pval list of statements in the if ()
00626                item->u3.else_statements == a pval list of statements in the else
00627                                     (could be zero)
00628       */
00629       traverse_pval_item_template(item->u2.statements,depth+1);
00630       if ( item->u3.else_statements ) {
00631          traverse_pval_item_template(item->u3.else_statements,depth+1);
00632       }
00633       break;
00634          
00635    case PV_RANDOM:
00636       /* fields: item->u1.str        == the random number expression, as supplied by user
00637 
00638                item->u2.statements == a pval list of statements in the if ()
00639                item->u3.else_statements == a pval list of statements in the else
00640                                     (could be zero)
00641       */
00642       traverse_pval_item_template(item->u2.statements,depth+1);
00643       if ( item->u3.else_statements ) {
00644          traverse_pval_item_template(item->u3.else_statements,depth+1);
00645       }
00646       break;
00647          
00648    case PV_IF:
00649       /* fields: item->u1.str        == the if conditional, as supplied by user
00650 
00651                item->u2.statements == a pval list of statements in the if ()
00652                item->u3.else_statements == a pval list of statements in the else
00653                                     (could be zero)
00654       */
00655       traverse_pval_item_template(item->u2.statements,depth+1);
00656       if ( item->u3.else_statements ) {
00657          traverse_pval_item_template(item->u3.else_statements,depth+1);
00658       }
00659       break;
00660          
00661    case PV_SWITCH:
00662       /* fields: item->u1.str        == the switch expression
00663 
00664                item->u2.statements == a pval list of statements in the switch, 
00665                                     (will be case statements, most likely!)
00666       */
00667       traverse_pval_item_template(item->u2.statements,depth+1);
00668       break;
00669          
00670    case PV_EXTENSION:
00671       /* fields: item->u1.str        == the extension name, label, whatever it's called
00672 
00673                item->u2.statements == a pval list of statements in the extension
00674                item->u3.hints      == a char * hint argument
00675                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
00676       */
00677       traverse_pval_item_template(item->u2.statements,depth+1);
00678       break;
00679          
00680    case PV_IGNOREPAT:
00681       /* fields: item->u1.str        == the ignorepat data
00682       */
00683       break;
00684          
00685    case PV_GLOBALS:
00686       /* fields: item->u1.statements     == pval list of statements, usually vardecs
00687       */
00688       traverse_pval_item_template(item->u1.statements,depth+1);
00689       break;
00690    }
00691 }

void traverse_pval_template ( pval item,
int  depth 
)

Definition at line 693 of file pbx_ael.c.

References pval::next, and traverse_pval_item_template().

00695 {
00696    pval *i;
00697    
00698    for (i=item; i; i=i->next) {
00699       traverse_pval_item_template(i, depth);
00700    }
00701 }

static int unload_module ( void   )  [static]

Definition at line 4614 of file pbx_ael.c.

References ast_cli_unregister_multiple(), ast_context_destroy(), and cli_ael.

04615 {
04616    ast_context_destroy(NULL, registrar);
04617    ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04618    return 0;
04619 }


Variable Documentation

int aeldebug = 0 [static]

Definition at line 4502 of file pbx_ael.c.

struct ast_cli_entry cli_ael[] [static]

Definition at line 4593 of file pbx_ael.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_ael_no_debug [static]

Initial value:

 {
   { "ael", "no", "debug", NULL },
   ael2_no_debug, NULL,
   NULL }

Definition at line 4588 of file pbx_ael.c.

char* config = "extensions.ael" [static]

Definition at line 63 of file pbx_ael.c.

int control_statement_count = 0 [static]

Definition at line 2825 of file pbx_ael.c.

Referenced by gen_prios().

int count_labels [static]

Definition at line 123 of file pbx_ael.c.

pval* current_context = 0 [static]

Definition at line 116 of file pbx_ael.c.

Referenced by check_label(), and check_pval_item().

pval* current_db = 0 [static]

Definition at line 115 of file pbx_ael.c.

Referenced by ael2_semantic_check(), check_abstract_reference(), check_context_names(), find_context(), find_label_in_current_db(), and find_macro().

pval* current_extension = 0 [static]

Definition at line 117 of file pbx_ael.c.

Referenced by check_label(), and check_pval_item().

char* days[] [static]

Definition at line 906 of file pbx_ael.c.

int errs [static]

Definition at line 67 of file pbx_ael.c.

char expr_output[2096] [static]

Definition at line 52 of file pbx_ael.c.

int in_abstract_context [static]

Definition at line 122 of file pbx_ael.c.

int label_count [static]

Definition at line 124 of file pbx_ael.c.

pval* last_matched_label [static]

Definition at line 126 of file pbx_ael.c.

Referenced by match_pval_item().

const char* match_context [static]

Definition at line 119 of file pbx_ael.c.

const char* match_exten [static]

Definition at line 120 of file pbx_ael.c.

const char* match_label [static]

Definition at line 121 of file pbx_ael.c.

char* months[] [static]

Definition at line 1004 of file pbx_ael.c.

int notes [static]

Definition at line 68 of file pbx_ael.c.

char* registrar = "pbx_ael" [static]

Definition at line 64 of file pbx_ael.c.

Referenced by park_add_hints(), pbx_load_module(), and pbx_load_users().

int return_on_context_match [static]

Definition at line 125 of file pbx_ael.c.

int warns [static]

Definition at line 67 of file pbx_ael.c.


Generated on Mon Nov 24 15:34:47 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7