Sat Aug 6 00:40:01 2011

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 BUF_SIZE   2000
#define DEBUG_CONTEXTS   (1 << 3)
#define DEBUG_MACROS   (1 << 2)
#define DEBUG_READ   (1 << 0)
#define DEBUG_TOKENS   (1 << 1)

Functions

static void __reg_module (void)
static void __unreg_module (void)
void add_extensions (struct ael_extension *exten)
static int 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)
static int aelsub_exec (struct ast_channel *chan, void *vdata)
int 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)
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 int 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 struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Asterisk Extension Language Compiler" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, }
static int aeldebug = 0
static char * aelsub = "AELSub"
static char * aelsub_descrip
static char * aelsub_synopsis = "Launch subroutine built with AEL"
static const struct ast_module_infoast_module_info = &__mod_info
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 65 of file pbx_ael.c.

#define BUF_SIZE   2000

Definition at line 63 of file pbx_ael.c.

#define DEBUG_CONTEXTS   (1 << 3)

Definition at line 61 of file pbx_ael.c.

Referenced by ael2_debug_contexts().

#define DEBUG_MACROS   (1 << 2)

Definition at line 60 of file pbx_ael.c.

Referenced by ael2_debug_macros().

#define DEBUG_READ   (1 << 0)

Definition at line 58 of file pbx_ael.c.

Referenced by ael2_debug_read().

#define DEBUG_TOKENS   (1 << 1)

Definition at line 59 of file pbx_ael.c.

Referenced by ael2_debug_tokens().


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 4728 of file pbx_ael.c.

04736 {

static void __unreg_module ( void   )  [static]

Definition at line 4728 of file pbx_ael.c.

04736 {

void add_extensions ( struct ael_extension exten  ) 

Definition at line 4153 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_ptr, 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.

04154 {
04155    struct ael_priority *pr;
04156    char *label=0;
04157    char realext[AST_MAX_EXTENSION];
04158    if (!exten) {
04159       ast_log(LOG_WARNING, "This file is Empty!\n" );
04160       return;
04161    }
04162    do {
04163       struct ael_priority *last = 0;
04164 
04165       memset(realext, '\0', sizeof(realext));
04166       pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
04167       if (exten->hints) {
04168          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, 
04169                           exten->hints, NULL, ast_free_ptr, registrar)) {
04170             ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
04171                   exten->name);
04172          }
04173       }
04174       
04175       for (pr=exten->plist; pr; pr=pr->next) {
04176          char app[2000];
04177          char appargs[2000];
04178 
04179          /* before we can add the extension, we need to prep the app/appargs;
04180             the CONTROL types need to be done after the priority numbers are calculated.
04181          */
04182          if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
04183             last = pr;
04184             continue;
04185          }
04186          
04187          if (pr->app)
04188             strcpy(app, pr->app);
04189          else
04190             app[0] = 0;
04191          if (pr->appargs )
04192             strcpy(appargs, pr->appargs);
04193          else
04194             appargs[0] = 0;
04195          switch( pr->type ) {
04196          case AEL_APPCALL:
04197             /* easy case. Everything is all set up */
04198             break;
04199             
04200          case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
04201             /* simple, unconditional goto. */
04202             strcpy(app,"Goto");
04203             if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
04204                snprintf(appargs,sizeof(appargs),"%s|%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
04205             } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
04206                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
04207             } else
04208                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
04209             break;
04210             
04211          case AEL_FOR_CONTROL:  /* WHILE loop test, FOR loop test */
04212             strcpy(app,"GotoIf");
04213             snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04214             break;
04215             
04216          case AEL_IF_CONTROL:
04217             strcpy(app,"GotoIf");
04218             if (pr->origin->u3.else_statements )
04219                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
04220             else
04221                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
04222             break;
04223 
04224          case AEL_RAND_CONTROL:
04225             strcpy(app,"Random");
04226             snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
04227             break;
04228 
04229          case AEL_IFTIME_CONTROL:
04230             strcpy(app,"GotoIfTime");
04231             snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
04232             break;
04233 
04234          case AEL_RETURN:
04235             strcpy(app,"Goto");
04236             snprintf(appargs,sizeof(appargs), "%d", exten->return_target->priority_num);
04237             break;
04238             
04239          default:
04240             break;
04241          }
04242          if (last && last->type == AEL_LABEL ) {
04243             label = last->origin->u1.str;
04244          }
04245          else
04246             label = 0;
04247          
04248          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, 
04249                           app, strdup(appargs), ast_free_ptr, registrar)) {
04250             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, 
04251                   exten->name);
04252          }
04253          last = pr;
04254       }
04255       exten = exten->next_exten;
04256    } while ( exten );
04257 }

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

Definition at line 4647 of file pbx_ael.c.

References DEBUG_CONTEXTS.

04648 {
04649    aeldebug |= DEBUG_CONTEXTS;
04650    return 0;
04651 }

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

Definition at line 4641 of file pbx_ael.c.

References DEBUG_MACROS.

04642 {
04643    aeldebug |= DEBUG_MACROS;
04644    return 0;
04645 }

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

Definition at line 4629 of file pbx_ael.c.

References DEBUG_READ.

04630 {
04631    aeldebug |= DEBUG_READ;
04632    return 0;
04633 }

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

Definition at line 4635 of file pbx_ael.c.

References DEBUG_TOKENS.

04636 {
04637    aeldebug |= DEBUG_TOKENS;
04638    return 0;
04639 }

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

Definition at line 4653 of file pbx_ael.c.

04654 {
04655    aeldebug = 0;
04656    return 0;
04657 }

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

Definition at line 4659 of file pbx_ael.c.

References pbx_load_module().

04660 {
04661    return (pbx_load_module());
04662 }

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

Definition at line 2749 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().

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

static int aelsub_exec ( struct ast_channel chan,
void *  vdata 
) [static]

Definition at line 4562 of file pbx_ael.c.

References ast_strdupa, pbx_exec(), and pbx_findapp().

Referenced by load_module().

04563 {
04564    char *data = ast_strdupa(vdata);
04565    struct ast_app *macro = pbx_findapp("Macro");
04566    if (macro) {
04567       if (strncmp(data, "macro-", 6) == 0) {
04568          data += 6;
04569       }
04570       return pbx_exec(chan, macro, data);
04571    }
04572    return -1;
04573 }

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

Definition at line 4340 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().

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

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

Definition at line 2352 of file ast_expr2f.c.

References ast_copy_string(), 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().

02353 {
02354    struct parse_io io;
02355    int return_value = 0;
02356    
02357    memset(&io, 0, sizeof(io));
02358    io.string = expr;  /* to pass to the error routine */
02359    
02360    ast_yylex_init(&io.scanner);
02361    
02362    ast_yy_scan_string(expr, io.scanner);
02363    
02364    ast_yyparse ((void *) &io);
02365 
02366    ast_yylex_destroy(io.scanner);
02367 
02368    if (!io.val) {
02369       if (length > 1) {
02370          strcpy(buf, "0");
02371          return_value = 1;
02372       }
02373    } else {
02374       if (io.val->type == AST_EXPR_integer) {
02375          int res_length;
02376 
02377          res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i);
02378          return_value = (res_length <= length) ? res_length : length;
02379       } else {
02380 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
02381          strncpy(buf, io.val->u.s, length - 1);
02382 #else /* !STANDALONE && !LOW_MEMORY */
02383          ast_copy_string(buf, io.val->u.s, length);
02384 #endif /* STANDALONE || LOW_MEMORY */
02385          return_value = strlen(buf);
02386          free(io.val->u.s);
02387       }
02388       free(io.val);
02389    }
02390    return return_value;
02391 }

void ast_expr_clear_extra_error_info ( void   ) 

void ast_expr_register_extra_error_info ( char *  errmsg  ) 

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

Definition at line 4259 of file pbx_ael.c.

References ael_extension::next_exten.

04260 {
04261    /* travel to the end of the list... */
04262    struct ael_extension *lptr;
04263    if( !*list ) {
04264       *list = newmem;
04265       return;
04266    }
04267    lptr = *list;
04268    
04269    while( lptr->next_exten ) {
04270       lptr = lptr->next_exten;
04271    }
04272    /* lptr should now pointing to the last element in the list; it has a null next_exten pointer */
04273    lptr->next_exten = newmem;
04274 }

static void check_abstract_reference ( pval abstract_context  )  [static]

Definition at line 2282 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().

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

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

Definition at line 2083 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().

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

static int check_break ( pval item  )  [static]

Definition at line 1063 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().

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

static void check_context_names ( void   )  [static]

Definition at line 2263 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().

02264 {
02265    pval *i,*j;
02266    for (i=current_db; i; i=i->next) {
02267       if (i->type == PV_CONTEXT || i->type == PV_MACRO) {
02268          for (j=i->next; j; j=j->next) {
02269             if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) {
02270                if ( !strcmp(i->u1.str, j->u1.str) && !(i->u3.abstract&2) && !(j->u3.abstract&2) )
02271                {
02272                   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",
02273                         i->filename, i->startline, i->endline, i->u1.str,  j->filename, j->startline, j->endline);
02274                   errs++;
02275                }
02276             }
02277          }
02278       }
02279    }
02280 }

static int check_continue ( pval item  )  [static]

Definition at line 1083 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().

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

static void check_day ( pval DAY  )  [static]

Definition at line 962 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().

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

static void check_dow ( pval DOW  )  [static]

get_dow: Get day of week

Definition at line 923 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().

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

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

Definition at line 826 of file pbx_ael.c.

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

Referenced by check_pval_item().

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

static void check_goto ( pval item  )  [static]

Definition at line 1198 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(), first, 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().

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

static void check_includes ( pval includes  )  [static]

Definition at line 836 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().

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

static void check_label ( pval item  )  [static]

Definition at line 1105 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().

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

static void check_month ( pval MON  )  [static]

Definition at line 1025 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().

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

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

Definition at line 2729 of file pbx_ael.c.

References check_pval_item(), and pval::next.

Referenced by ael2_semantic_check(), and check_pval_item().

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

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

Definition at line 2310 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().

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

void check_switch_expr ( pval item,
struct argapp apps 
)

Definition at line 2137 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().

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

static void check_timerange ( pval p  )  [static]

Definition at line 855 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().

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

int contains_switch ( pval item  ) 

Definition at line 3229 of file pbx_ael.c.

References find_switch_item(), and pval::next.

Referenced by find_switch_item(), and gen_prios().

03230 {
03231    pval *i;
03232    
03233    for (i=item; i; i=i->next) {
03234       if (find_switch_item(i))
03235          return 1;
03236    }
03237    return 0;
03238 }

void destroy_extensions ( struct ael_extension exten  ) 

Definition at line 2886 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.

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

void destroy_pval ( pval item  ) 

void destroy_pval_item ( pval item  ) 

Definition at line 4735 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().

04736 {
04737    if (item == NULL) {
04738       ast_log(LOG_WARNING, "null item\n");
04739       return;
04740    }
04741 
04742    if (item->filename)
04743       free(item->filename);
04744    
04745    switch (item->type) {
04746    case PV_WORD:
04747       /* fields: item->u1.str == string associated with this (word). */
04748       if (item->u1.str )
04749          free(item->u1.str);
04750       if ( item->u2.arglist )
04751          destroy_pval(item->u2.arglist);
04752       break;
04753       
04754    case PV_MACRO:
04755       /* fields: item->u1.str     == name of macro
04756                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
04757                item->u2.arglist->u1.str  == argument
04758                item->u2.arglist->next   == next arg
04759 
04760                item->u3.macro_statements == pval list of statements in macro body.
04761       */
04762       destroy_pval(item->u2.arglist);
04763       if (item->u1.str )
04764          free(item->u1.str);
04765       destroy_pval(item->u3.macro_statements);
04766       break;
04767          
04768    case PV_CONTEXT:
04769       /* fields: item->u1.str     == name of context
04770                  item->u2.statements == pval list of statements in context body
04771                item->u3.abstract == int 1 if an abstract keyword were present
04772       */
04773       if (item->u1.str)
04774          free(item->u1.str);
04775       destroy_pval(item->u2.statements);
04776       break;
04777          
04778    case PV_MACRO_CALL:
04779       /* fields: item->u1.str     == name of macro to call
04780                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04781                item->u2.arglist->u1.str  == argument
04782                item->u2.arglist->next   == next arg
04783       */
04784       if (item->u1.str)
04785          free(item->u1.str);
04786       destroy_pval(item->u2.arglist);
04787       break;
04788          
04789    case PV_APPLICATION_CALL:
04790       /* fields: item->u1.str     == name of application to call
04791                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04792                item->u2.arglist->u1.str  == argument
04793                item->u2.arglist->next   == next arg
04794       */
04795       if (item->u1.str)
04796          free(item->u1.str);
04797       destroy_pval(item->u2.arglist);
04798       break;
04799          
04800    case PV_CASE:
04801       /* fields: item->u1.str     == value of case
04802                  item->u2.statements == pval list of statements under the case
04803       */
04804       if (item->u1.str)
04805          free(item->u1.str);
04806       destroy_pval(item->u2.statements);
04807       break;
04808          
04809    case PV_PATTERN:
04810       /* fields: item->u1.str     == value of case
04811                  item->u2.statements == pval list of statements under the case
04812       */
04813       if (item->u1.str)
04814          free(item->u1.str);
04815       destroy_pval(item->u2.statements);
04816       break;
04817          
04818    case PV_DEFAULT:
04819       /* fields: 
04820                  item->u2.statements == pval list of statements under the case
04821       */
04822       destroy_pval(item->u2.statements);
04823       break;
04824          
04825    case PV_CATCH:
04826       /* fields: item->u1.str     == name of extension to catch
04827                  item->u2.statements == pval list of statements in context body
04828       */
04829       if (item->u1.str)
04830          free(item->u1.str);
04831       destroy_pval(item->u2.statements);
04832       break;
04833          
04834    case PV_SWITCHES:
04835       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04836       */
04837       destroy_pval(item->u1.list);
04838       break;
04839          
04840    case PV_ESWITCHES:
04841       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04842       */
04843       destroy_pval(item->u1.list);
04844       break;
04845          
04846    case PV_INCLUDES:
04847       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04848                  item->u2.arglist  == pval list of 4 PV_WORD elements for time values
04849       */
04850       destroy_pval(item->u1.list);
04851       break;
04852          
04853    case PV_STATEMENTBLOCK:
04854       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
04855       */
04856       destroy_pval(item->u1.list);
04857       break;
04858          
04859    case PV_VARDEC:
04860       /* fields: item->u1.str     == variable name
04861                  item->u2.val     == variable value to assign
04862       */
04863       if (item->u1.str)
04864          free(item->u1.str);
04865       if (item->u2.val)
04866          free(item->u2.val);
04867       break;
04868          
04869    case PV_GOTO:
04870       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
04871                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
04872       */
04873       
04874       destroy_pval(item->u1.list);
04875       break;
04876          
04877    case PV_LABEL:
04878       /* fields: item->u1.str     == label name
04879       */
04880       if (item->u1.str)
04881          free(item->u1.str);
04882       break;
04883          
04884    case PV_FOR:
04885       /* fields: item->u1.for_init     == a string containing the initalizer
04886                  item->u2.for_test     == a string containing the loop test
04887                  item->u3.for_inc      == a string containing the loop increment
04888 
04889                item->u4.for_statements == a pval list of statements in the for ()
04890       */
04891       if (item->u1.for_init)
04892          free(item->u1.for_init);
04893       if (item->u2.for_test)
04894          free(item->u2.for_test);
04895       if (item->u3.for_inc)
04896          free(item->u3.for_inc);
04897       destroy_pval(item->u4.for_statements);
04898       break;
04899          
04900    case PV_WHILE:
04901       /* fields: item->u1.str        == the while conditional, as supplied by user
04902 
04903                item->u2.statements == a pval list of statements in the while ()
04904       */
04905       if (item->u1.str)
04906          free(item->u1.str);
04907       destroy_pval(item->u2.statements);
04908       break;
04909          
04910    case PV_BREAK:
04911       /* fields: none
04912       */
04913       break;
04914          
04915    case PV_RETURN:
04916       /* fields: none
04917       */
04918       break;
04919          
04920    case PV_CONTINUE:
04921       /* fields: none
04922       */
04923       break;
04924          
04925    case PV_IFTIME:
04926       /* fields: item->u1.list        == the 4 time values, in PV_WORD structs, linked list
04927 
04928                item->u2.statements == a pval list of statements in the if ()
04929                item->u3.else_statements == a pval list of statements in the else
04930                                     (could be zero)
04931       */
04932       destroy_pval(item->u1.list);
04933       destroy_pval(item->u2.statements);
04934       if (item->u3.else_statements) {
04935          destroy_pval(item->u3.else_statements);
04936       }
04937       break;
04938          
04939    case PV_RANDOM:
04940       /* fields: item->u1.str        == the random percentage, as supplied by user
04941 
04942                item->u2.statements == a pval list of statements in the true part ()
04943                item->u3.else_statements == a pval list of statements in the else
04944                                     (could be zero)
04945       fall thru to If */
04946    case PV_IF:
04947       /* fields: item->u1.str        == the if conditional, as supplied by user
04948 
04949                item->u2.statements == a pval list of statements in the if ()
04950                item->u3.else_statements == a pval list of statements in the else
04951                                     (could be zero)
04952       */
04953       if (item->u1.str)
04954          free(item->u1.str);
04955       destroy_pval(item->u2.statements);
04956       if (item->u3.else_statements) {
04957          destroy_pval(item->u3.else_statements);
04958       }
04959       break;
04960          
04961    case PV_SWITCH:
04962       /* fields: item->u1.str        == the switch expression
04963 
04964                item->u2.statements == a pval list of statements in the switch, 
04965                                     (will be case statements, most likely!)
04966       */
04967       if (item->u1.str)
04968          free(item->u1.str);
04969       destroy_pval(item->u2.statements);
04970       break;
04971          
04972    case PV_EXTENSION:
04973       /* fields: item->u1.str        == the extension name, label, whatever it's called
04974 
04975                item->u2.statements == a pval list of statements in the extension
04976                item->u3.hints      == a char * hint argument
04977                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
04978       */
04979       if (item->u1.str)
04980          free(item->u1.str);
04981       if (item->u3.hints)
04982          free(item->u3.hints);
04983       destroy_pval(item->u2.statements);
04984       break;
04985          
04986    case PV_IGNOREPAT:
04987       /* fields: item->u1.str        == the ignorepat data
04988       */
04989       if (item->u1.str)
04990          free(item->u1.str);
04991       break;
04992          
04993    case PV_GLOBALS:
04994       /* fields: item->u1.statements     == pval list of statements, usually vardecs
04995       */
04996       destroy_pval(item->u1.statements);
04997       break;
04998    }
04999    free(item);
05000 }

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

Definition at line 714 of file pbx_ael.c.

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

Referenced by match_pval_item().

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

struct pval * find_context ( char *  name  ) 

Definition at line 1906 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().

01907 {
01908    return_on_context_match = 1;
01909    count_labels = 0;
01910    match_context = name;
01911    match_exten = "*";  /* don't really need to set these, shouldn't be reached */
01912    match_label = "*";
01913    return match_pval(current_db);
01914 }

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

Definition at line 1785 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().

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

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

Definition at line 1826 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().

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

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

Definition at line 1882 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_goto(), and get_goto_target().

01883 {
01884    /* printf("  --- Got args %s, %s, %s\n", context, exten, label); */
01885    count_labels = 0;
01886    return_on_context_match = 0;
01887 
01888    match_context = context;
01889    match_exten = exten;
01890    match_label = label;
01891    
01892    return match_pval(current_db);
01893 }

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

Definition at line 1871 of file pbx_ael.c.

References match_pval().

Referenced by check_goto(), and get_goto_target().

01872 {
01873    /* printf("  --- Got args %s\n", label); */
01874    count_labels = 0;
01875    return_on_context_match = 0;
01876    match_context = "*";
01877    match_exten = "*";
01878    match_label = label;
01879    return match_pval(curr_ext);
01880 }

struct pval * find_macro ( char *  name  ) 

Definition at line 1896 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_pval_item().

01897 {
01898    return_on_context_match = 1;
01899    count_labels = 0;
01900    match_context = name;
01901    match_exten = "*";  /* don't really need to set these, shouldn't be reached */
01902    match_label = "*";
01903    return match_pval(current_db);
01904 }

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

Definition at line 1306 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().

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

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

Definition at line 1477 of file pbx_ael.c.

References find_pval_goto_item(), and pval::next.

Referenced by check_pval_item(), and find_pval_goto_item().

01478 {
01479    pval *i;
01480    
01481    for (i=item; i; i=i->next) {
01482       /* printf("About to call pval_goto_item, itemcount=%d, itemtype=%d\n", item_count, i->type); */
01483       find_pval_goto_item(i, lev);
01484    }
01485 }

int find_switch_item ( pval item  ) 

Definition at line 2994 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().

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

static void fix_gotos_in_extensions ( struct ael_extension exten  )  [static]

Definition at line 4296 of file pbx_ael.c.

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

04297 {
04298    struct ael_extension *e;
04299    for(e=exten;e;e=e->next_exten) {
04300 
04301       struct ael_priority *p;
04302       for(p=e->plist;p;p=p->next) {
04303          
04304          if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) {
04305             
04306             /* fix the extension of the goto target to the actual extension in the post-compiled dialplan */
04307 
04308             pval *target = p->origin->u2.goto_target;
04309             struct ael_extension *z = target->u3.compiled_label;
04310             pval *pv2 = p->origin;
04311             char buf1[500];
04312             char *apparg_save = p->appargs;
04313             
04314             p->appargs = 0;
04315             if (!pv2->u1.list->next) /* just one  -- it won't hurt to repeat the extension */ {
04316                snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->u1.str);
04317                p->appargs = strdup(buf1);
04318                
04319             } else if (pv2->u1.list->next && !pv2->u1.list->next->next) /* two */ {
04320                snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->next->u1.str);
04321                p->appargs = strdup(buf1);
04322             } else if (pv2->u1.list->next && pv2->u1.list->next->next) {
04323                snprintf(buf1,sizeof(buf1),"%s|%s|%s", pv2->u1.list->u1.str, 
04324                       z->name,
04325                       pv2->u1.list->next->next->u1.str);
04326                p->appargs = strdup(buf1);
04327             }
04328             else
04329                printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n");
04330             
04331             if( apparg_save ) {
04332                free(apparg_save);
04333             }
04334          }
04335       }
04336    }
04337 }

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

Definition at line 2965 of file pbx_ael.c.

References t.

Referenced by gen_prios().

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

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

Definition at line 3241 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, BUF_SIZE, 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, label_inside_case(), linkexten(), linkprio(), pval::list, ael_extension::loop_break, ael_extension::loop_continue, malloc, 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.

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

static pval * get_contxt ( pval p  )  [static]

Definition at line 4286 of file pbx_ael.c.

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

Referenced by check_goto(), and get_goto_target().

04287 {
04288    while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
04289       
04290       p = p->dad;
04291    }
04292    
04293    return p;
04294 }

static pval * get_extension_or_contxt ( pval p  )  [static]

Definition at line 4276 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().

04277 {
04278    while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
04279       
04280       p = p->dad;
04281    }
04282    
04283    return p;
04284 }

static pval * get_goto_target ( pval item  )  [static]

Definition at line 1130 of file pbx_ael.c.

References find_context(), find_label_in_current_context(), find_label_in_current_db(), find_label_in_current_extension(), first, 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().

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

int is_empty ( char *  arg  ) 

Definition at line 1934 of file pbx_ael.c.

01935 {
01936    if (!arg)
01937       return 1;
01938    if (*arg == 0)
01939       return 1;
01940    while (*arg) {
01941       if (*arg != ' ' && *arg != '\t')
01942          return 0;
01943       arg++;
01944    }
01945    return 1;
01946 }

int is_float ( char *  arg  ) 

Definition at line 1916 of file pbx_ael.c.

References s.

01917 {
01918    char *s;
01919    for (s=arg; *s; s++) {
01920       if (*s != '.' && (*s < '0' || *s > '9'))
01921          return 0;
01922    }
01923    return 1;
01924 }

int is_int ( char *  arg  ) 

Definition at line 1925 of file pbx_ael.c.

References s.

01926 {
01927    char *s;
01928    for (s=arg; *s; s++) {
01929       if (*s < '0' || *s > '9')
01930          return 0;
01931    }
01932    return 1;
01933 }

static int label_inside_case ( pval label  )  [static]

Definition at line 2926 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().

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

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

Definition at line 2940 of file pbx_ael.c.

References exten, and ael_extension::next_exten.

Referenced by gen_prios().

02941 {
02942    add->next_exten = exten->next_exten; /* this will reverse the order. Big deal. */
02943    exten->next_exten = add;
02944 }

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

Definition at line 2844 of file pbx_ael.c.

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

Referenced by gen_prios().

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

static int load_module ( void   )  [static]

Definition at line 4700 of file pbx_ael.c.

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

04701 {
04702    ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04703 #ifndef STANDALONE_AEL
04704    ast_register_application(aelsub, aelsub_exec, aelsub_synopsis, aelsub_descrip);
04705 #endif
04706    return (pbx_load_module());
04707 }

struct pval * match_pval ( pval item  ) 

Definition at line 1757 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().

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

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

Definition at line 1490 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().

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

struct ael_extension * new_exten ( void   ) 

Definition at line 2838 of file pbx_ael.c.

References calloc.

Referenced by gen_prios().

02839 {
02840    struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
02841    return x;
02842 }

struct ael_priority * new_prio ( void   ) 

Definition at line 2832 of file pbx_ael.c.

References calloc.

Referenced by gen_prios().

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

static int pbx_load_module ( void   )  [static]

Definition at line 4580 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().

04581 {
04582    int errs=0, sem_err=0, sem_warn=0, sem_note=0;
04583    char *rfilename;
04584    struct ast_context *local_contexts=NULL, *con;
04585    struct pval *parse_tree;
04586 
04587    ast_log(LOG_NOTICE, "Starting AEL load process.\n");
04588    if (config[0] == '/')
04589       rfilename = (char *)config;
04590    else {
04591       rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
04592       sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
04593    }
04594    ast_log(LOG_NOTICE, "AEL load process: calculated config file name '%s'.\n", rfilename);
04595 
04596    if (access(rfilename,R_OK) != 0) {
04597       ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
04598       return AST_MODULE_LOAD_DECLINE;
04599    }
04600    
04601    parse_tree = ael2_parse(rfilename, &errs);
04602    ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
04603    ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
04604    if (errs == 0 && sem_err == 0) {
04605       ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
04606       if (ast_compile_ael2(&local_contexts, parse_tree)) {
04607          ast_log(LOG_ERROR, "AEL compile failure! Aborting\n");
04608          destroy_pval(parse_tree); /* free up the memory */
04609          return AST_MODULE_LOAD_DECLINE;
04610       }
04611       ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
04612       
04613       ast_merge_contexts_and_delete(&local_contexts, registrar);
04614       ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
04615       for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
04616          ast_context_verify_includes(con);
04617       ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
04618    } else {
04619       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);
04620       destroy_pval(parse_tree); /* free up the memory */
04621       return AST_MODULE_LOAD_DECLINE;
04622    }
04623    destroy_pval(parse_tree); /* free up the memory */
04624    
04625    return AST_MODULE_LOAD_SUCCESS;
04626 }

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

Definition at line 181 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().

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

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

Definition at line 435 of file pbx_ael.c.

References pval::next, and print_pval().

00436 {
00437    pval *i;
00438    
00439    for (i=item; i; i=i->next) {
00440       print_pval(fin, i, depth);
00441    }
00442 }

static int reload ( void   )  [static]

Definition at line 4709 of file pbx_ael.c.

References pbx_load_module().

04710 {
04711    return pbx_load_module();
04712 }

static void remove_spaces_before_equals ( char *  str  )  [static]

Definition at line 2946 of file pbx_ael.c.

Referenced by gen_prios().

02947 {
02948    char *p;
02949    while( str && *str && *str != '=' )
02950    {
02951       if( *str == ' ' || *str == '\n' || *str == '\r' || *str == '\t' )
02952       {
02953          p = str;
02954          while( *p )
02955          {
02956             *p = *(p+1);
02957             p++;
02958          }
02959       }
02960       else
02961          str++;
02962    }
02963 }

void set_priorities ( struct ael_extension exten  ) 

Definition at line 4127 of file pbx_ael.c.

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

04128 {
04129    int i;
04130    struct ael_priority *pr;
04131    do {
04132       if (exten->is_switch)
04133          i = 10;
04134       else if (exten->regexten)
04135          i=2;
04136       else
04137          i=1;
04138       
04139       for (pr=exten->plist; pr; pr=pr->next) {
04140          pr->priority_num = i;
04141          
04142          if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
04143                                       but we want them to point to the right
04144                                       priority, which would be the next line
04145                                       after the label; */
04146             i++;
04147       }
04148       
04149       exten = exten->next_exten;
04150    } while ( exten );
04151 }

static void substitute_commas ( char *  str  )  [static]

Definition at line 158 of file pbx_ael.c.

Referenced by gen_prios().

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

void traverse_pval_item_template ( pval item,
int  depth 
)

Definition at line 464 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().

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

void traverse_pval_template ( pval item,
int  depth 
)

Definition at line 697 of file pbx_ael.c.

References pval::next, and traverse_pval_item_template().

00699 {
00700    pval *i;
00701    
00702    for (i=item; i; i=i->next) {
00703       traverse_pval_item_template(i, depth);
00704    }
00705 }

static int unload_module ( void   )  [static]

Definition at line 4690 of file pbx_ael.c.

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

04691 {
04692    ast_context_destroy(NULL, registrar);
04693    ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04694 #ifndef STANDALONE_AEL
04695    ast_unregister_application(aelsub);
04696 #endif
04697    return 0;
04698 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Asterisk Extension Language Compiler" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 4728 of file pbx_ael.c.

int aeldebug = 0 [static]

Definition at line 4550 of file pbx_ael.c.

char* aelsub = "AELSub" [static]

Definition at line 4553 of file pbx_ael.c.

char* aelsub_descrip [static]

Definition at line 4555 of file pbx_ael.c.

char* aelsub_synopsis = "Launch subroutine built with AEL" [static]

Definition at line 4554 of file pbx_ael.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 4728 of file pbx_ael.c.

struct ast_cli_entry cli_ael[] [static]

Definition at line 4669 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 4664 of file pbx_ael.c.

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

Definition at line 67 of file pbx_ael.c.

int control_statement_count = 0 [static]

Definition at line 2830 of file pbx_ael.c.

Referenced by gen_prios().

int count_labels [static]

Definition at line 127 of file pbx_ael.c.

pval* current_context = 0 [static]

Definition at line 120 of file pbx_ael.c.

Referenced by check_label(), and check_pval_item().

pval* current_db = 0 [static]

Definition at line 119 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 121 of file pbx_ael.c.

Referenced by check_label(), and check_pval_item().

char* days[] [static]

Definition at line 911 of file pbx_ael.c.

int errs [static]

Definition at line 71 of file pbx_ael.c.

char expr_output[2096] [static]

Definition at line 54 of file pbx_ael.c.

int in_abstract_context [static]

Definition at line 126 of file pbx_ael.c.

int label_count [static]

Definition at line 128 of file pbx_ael.c.

pval* last_matched_label [static]

Definition at line 130 of file pbx_ael.c.

Referenced by match_pval_item().

const char* match_context [static]

Definition at line 123 of file pbx_ael.c.

const char* match_exten [static]

Definition at line 124 of file pbx_ael.c.

const char* match_label [static]

Definition at line 125 of file pbx_ael.c.

char* months[] [static]

Definition at line 1009 of file pbx_ael.c.

int notes [static]

Definition at line 72 of file pbx_ael.c.

char* registrar = "pbx_ael" [static]

Definition at line 68 of file pbx_ael.c.

Referenced by pbx_load_module(), and pbx_load_users().

int return_on_context_match [static]

Definition at line 129 of file pbx_ael.c.

int warns [static]

Definition at line 71 of file pbx_ael.c.


Generated on Sat Aug 6 00:40:01 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7