Thu Feb 5 16:26:20 2009

Asterisk developer's documentation


pbx_ael.c File Reference

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

#include "asterisk.h"
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <regex.h>
#include <sys/stat.h>
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/callerid.h"
#include "asterisk/ael_structs.h"

Go to the source code of this file.

Data Structures

struct  argapp

Defines

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

Functions

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)
void ast_compile_ael2 (struct ast_context **local_contexts, struct pval *root)
int ast_expr (char *expr, char *buf, int length)
void ast_expr_clear_extra_error_info (void)
void ast_expr_register_extra_error_info (char *errmsg)
static void attach_exten (struct ael_extension **list, struct ael_extension *newmem)
static void check_abstract_reference (pval *abstract_context)
int check_app_args (pval *appcall, pval *arglist, struct argapp *app)
static int check_break (pval *item)
static void check_context_names (void)
static int check_continue (pval *item)
static void check_day (pval *DAY)
static void check_dow (pval *DOW)
 get_dow: Get day of week
static void check_expr2_input (pval *expr, char *str)
static void check_goto (pval *item)
static void check_includes (pval *includes)
static void check_label (pval *item)
static void check_month (pval *MON)
void check_pval (pval *item, struct argapp *apps, int in_globals)
void check_pval_item (pval *item, struct argapp *apps, int in_globals)
void check_switch_expr (pval *item, struct argapp *apps)
static void check_timerange (pval *p)
int contains_switch (pval *item)
void destroy_extensions (struct ael_extension *exten)
void destroy_pval (pval *item)
void destroy_pval_item (pval *item)
static int extension_matches (pval *here, const char *exten, const char *pattern)
pvalfind_context (char *name)
static struct pvalfind_first_label_in_current_context (char *label, pval *curr_cont)
static struct pvalfind_label_in_current_context (char *exten, char *label, pval *curr_cont)
static struct pvalfind_label_in_current_db (const char *context, const char *exten, const char *label)
static struct pvalfind_label_in_current_extension (const char *label, pval *curr_ext)
pvalfind_macro (char *name)
static void find_pval_goto_item (pval *item, int lev)
static void find_pval_gotos (pval *item, int lev)
int find_switch_item (pval *item)
static void fix_gotos_in_extensions (struct ael_extension *exten)
static void gen_match_to_pattern (char *pattern, char *result)
static void gen_prios (struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *context)
static pvalget_contxt (pval *p)
static pvalget_extension_or_contxt (pval *p)
static pvalget_goto_target (pval *item)
int is_empty (char *arg)
int is_float (char *arg)
int is_int (char *arg)
static int label_inside_case (pval *label)
static void linkexten (struct ael_extension *exten, struct ael_extension *add)
void linkprio (struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
static int load_module (void)
pvalmatch_pval (pval *item)
static struct pvalmatch_pval_item (pval *item)
ael_extensionnew_exten (void)
ael_prioritynew_prio (void)
static int pbx_load_module (void)
static void print_pval (FILE *fin, pval *item, int depth)
static void print_pval_list (FILE *fin, pval *item, int depth)
static int reload (void)
static void remove_spaces_before_equals (char *str)
void set_priorities (struct ael_extension *exten)
static void substitute_commas (char *str)
void traverse_pval_item_template (pval *item, int depth)
void traverse_pval_template (pval *item, int depth)
static int unload_module (void)

Variables

static 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 = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, .reload = reload, }
static int aeldebug = 0
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 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 4649 of file pbx_ael.c.

04657 {

static void __unreg_module ( void   )  [static]

Definition at line 4649 of file pbx_ael.c.

04657 {

void add_extensions ( struct ael_extension exten  ) 

Definition at line 4113 of file pbx_ael.c.

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

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

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

Definition at line 4574 of file pbx_ael.c.

References DEBUG_CONTEXTS.

04575 {
04576    aeldebug |= DEBUG_CONTEXTS;
04577    return 0;
04578 }

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

Definition at line 4568 of file pbx_ael.c.

References DEBUG_MACROS.

04569 {
04570    aeldebug |= DEBUG_MACROS;
04571    return 0;
04572 }

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

Definition at line 4556 of file pbx_ael.c.

References DEBUG_READ.

04557 {
04558    aeldebug |= DEBUG_READ;
04559    return 0;
04560 }

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

Definition at line 4562 of file pbx_ael.c.

References DEBUG_TOKENS.

04563 {
04564    aeldebug |= DEBUG_TOKENS;
04565    return 0;
04566 }

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

Definition at line 4580 of file pbx_ael.c.

04581 {
04582    aeldebug = 0;
04583    return 0;
04584 }

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

Definition at line 4586 of file pbx_ael.c.

References pbx_load_module().

04587 {
04588    return (pbx_load_module());
04589 }

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

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

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

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

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

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

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

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

03160 {
03161    struct parse_io io;
03162    int return_value = 0;
03163    
03164    memset(&io, 0, sizeof(io));
03165    io.string = expr;  /* to pass to the error routine */
03166    
03167    ast_yylex_init(&io.scanner);
03168    
03169    ast_yy_scan_string(expr, io.scanner);
03170    
03171    ast_yyparse ((void *) &io);
03172 
03173    ast_yylex_destroy(io.scanner);
03174 
03175    if (!io.val) {
03176       if (length > 1) {
03177          strcpy(buf, "0");
03178          return_value = 1;
03179       }
03180    } else {
03181       if (io.val->type == AST_EXPR_integer) {
03182          int res_length;
03183 
03184          res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i);
03185          return_value = (res_length <= length) ? res_length : length;
03186       } else {
03187 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
03188          strncpy(buf, io.val->u.s, length - 1);
03189 #else /* !STANDALONE && !LOW_MEMORY */
03190          ast_copy_string(buf, io.val->u.s, length);
03191 #endif /* STANDALONE || LOW_MEMORY */
03192          return_value = strlen(buf);
03193          free(io.val->u.s);
03194       }
03195       free(io.val);
03196    }
03197    return return_value;
03198 }

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 4219 of file pbx_ael.c.

References ael_extension::next_exten.

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

static void check_abstract_reference ( pval abstract_context  )  [static]

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

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

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

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

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

static int check_break ( pval item  )  [static]

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

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

static void check_context_names ( void   )  [static]

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

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

static int check_continue ( pval item  )  [static]

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

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

static void check_day ( pval DAY  )  [static]

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

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

static void check_dow ( pval DOW  )  [static]

get_dow: Get day of week

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

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

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

Definition at line 824 of file pbx_ael.c.

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

Referenced by check_pval_item().

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

static void check_goto ( pval item  )  [static]

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

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

static void check_includes ( pval includes  )  [static]

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

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

static void check_label ( pval item  )  [static]

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

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

static void check_month ( pval MON  )  [static]

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

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

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

Definition at line 2727 of file pbx_ael.c.

References check_pval_item(), and pval::next.

Referenced by ael2_semantic_check(), and check_pval_item().

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

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

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

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

void check_switch_expr ( pval item,
struct argapp apps 
)

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

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

static void check_timerange ( pval p  )  [static]

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

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

int contains_switch ( pval item  ) 

Definition at line 3227 of file pbx_ael.c.

References find_switch_item(), and pval::next.

Referenced by find_switch_item(), and gen_prios().

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

void destroy_extensions ( struct ael_extension exten  ) 

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

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

void destroy_pval ( pval item  ) 

void destroy_pval_item ( pval item  ) 

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

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

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

Definition at line 712 of file pbx_ael.c.

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

Referenced by match_pval_item().

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

struct pval * find_context ( char *  name  ) 

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

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

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

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

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

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

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

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

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

Definition at line 1880 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_goto(), and get_goto_target().

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

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

Definition at line 1869 of file pbx_ael.c.

References match_pval().

Referenced by check_goto(), and get_goto_target().

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

struct pval * find_macro ( char *  name  ) 

Definition at line 1894 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_pval_item().

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

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

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

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

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

Definition at line 1475 of file pbx_ael.c.

References find_pval_goto_item(), and pval::next.

Referenced by check_pval_item(), and find_pval_goto_item().

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

int find_switch_item ( pval item  ) 

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

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

static void fix_gotos_in_extensions ( struct ael_extension exten  )  [static]

Definition at line 4256 of file pbx_ael.c.

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

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

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

Definition at line 2963 of file pbx_ael.c.

References t.

Referenced by gen_prios().

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

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

Definition at line 3239 of file pbx_ael.c.

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

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

static pval * get_contxt ( pval p  )  [static]

Definition at line 4246 of file pbx_ael.c.

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

Referenced by check_goto(), and get_goto_target().

04247 {
04248    while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
04249       
04250       p = p->dad;
04251    }
04252    
04253    return p;
04254 }

static pval * get_extension_or_contxt ( pval p  )  [static]

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

04237 {
04238    while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
04239       
04240       p = p->dad;
04241    }
04242    
04243    return p;
04244 }

static pval * get_goto_target ( pval item  )  [static]

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

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

int is_empty ( char *  arg  ) 

Definition at line 1932 of file pbx_ael.c.

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

int is_float ( char *  arg  ) 

Definition at line 1914 of file pbx_ael.c.

References s.

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

int is_int ( char *  arg  ) 

Definition at line 1923 of file pbx_ael.c.

References s.

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

static int label_inside_case ( pval label  )  [static]

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

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

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

Definition at line 2938 of file pbx_ael.c.

References exten, and ael_extension::next_exten.

Referenced by gen_prios().

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

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

Definition at line 2842 of file pbx_ael.c.

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

Referenced by gen_prios().

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

static int load_module ( void   )  [static]

Definition at line 4624 of file pbx_ael.c.

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

04625 {
04626    ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04627    return (pbx_load_module());
04628 }

struct pval * match_pval ( pval item  ) 

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

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

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

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

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

struct ael_extension * new_exten ( void   ) 

Definition at line 2836 of file pbx_ael.c.

References calloc.

Referenced by gen_prios().

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

struct ael_priority * new_prio ( void   ) 

Definition at line 2830 of file pbx_ael.c.

References calloc.

Referenced by gen_prios().

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

static int pbx_load_module ( void   )  [static]

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

04512 {
04513    int errs=0, sem_err=0, sem_warn=0, sem_note=0;
04514    char *rfilename;
04515    struct ast_context *local_contexts=NULL, *con;
04516    struct pval *parse_tree;
04517 
04518    ast_log(LOG_NOTICE, "Starting AEL load process.\n");
04519    if (config[0] == '/')
04520       rfilename = (char *)config;
04521    else {
04522       rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
04523       sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
04524    }
04525    ast_log(LOG_NOTICE, "AEL load process: calculated config file name '%s'.\n", rfilename);
04526 
04527    if (access(rfilename,R_OK) != 0) {
04528       ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
04529       return AST_MODULE_LOAD_DECLINE;
04530    }
04531    
04532    parse_tree = ael2_parse(rfilename, &errs);
04533    ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
04534    ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
04535    if (errs == 0 && sem_err == 0) {
04536       ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
04537       ast_compile_ael2(&local_contexts, parse_tree);
04538       ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
04539       
04540       ast_merge_contexts_and_delete(&local_contexts, registrar);
04541       ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
04542       for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
04543          ast_context_verify_includes(con);
04544       ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
04545    } else {
04546       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);
04547       destroy_pval(parse_tree); /* free up the memory */
04548       return AST_MODULE_LOAD_DECLINE;
04549    }
04550    destroy_pval(parse_tree); /* free up the memory */
04551    
04552    return AST_MODULE_LOAD_SUCCESS;
04553 }

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

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

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

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

Definition at line 433 of file pbx_ael.c.

References pval::next, and print_pval().

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

static int reload ( void   )  [static]

Definition at line 4630 of file pbx_ael.c.

References pbx_load_module().

04631 {
04632    return pbx_load_module();
04633 }

static void remove_spaces_before_equals ( char *  str  )  [static]

Definition at line 2944 of file pbx_ael.c.

Referenced by gen_prios().

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

void set_priorities ( struct ael_extension exten  ) 

Definition at line 4087 of file pbx_ael.c.

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

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

static void substitute_commas ( char *  str  )  [static]

Definition at line 156 of file pbx_ael.c.

Referenced by gen_prios().

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

void traverse_pval_item_template ( pval item,
int  depth 
)

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

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

void traverse_pval_template ( pval item,
int  depth 
)

Definition at line 695 of file pbx_ael.c.

References pval::next, and traverse_pval_item_template().

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

static int unload_module ( void   )  [static]

Definition at line 4617 of file pbx_ael.c.

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

04618 {
04619    ast_context_destroy(NULL, registrar);
04620    ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04621    return 0;
04622 }


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 = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 4649 of file pbx_ael.c.

int aeldebug = 0 [static]

Definition at line 4505 of file pbx_ael.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 4649 of file pbx_ael.c.

struct ast_cli_entry cli_ael[] [static]

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

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

Definition at line 65 of file pbx_ael.c.

int control_statement_count = 0 [static]

Definition at line 2828 of file pbx_ael.c.

Referenced by gen_prios().

int count_labels [static]

Definition at line 125 of file pbx_ael.c.

pval* current_context = 0 [static]

Definition at line 118 of file pbx_ael.c.

Referenced by check_label(), and check_pval_item().

pval* current_db = 0 [static]

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

Referenced by check_label(), and check_pval_item().

char* days[] [static]

Definition at line 909 of file pbx_ael.c.

int errs [static]

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

int label_count [static]

Definition at line 126 of file pbx_ael.c.

pval* last_matched_label [static]

Definition at line 128 of file pbx_ael.c.

Referenced by match_pval_item().

const char* match_context [static]

Definition at line 121 of file pbx_ael.c.

const char* match_exten [static]

Definition at line 122 of file pbx_ael.c.

const char* match_label [static]

Definition at line 123 of file pbx_ael.c.

char* months[] [static]

Definition at line 1007 of file pbx_ael.c.

int notes [static]

Definition at line 70 of file pbx_ael.c.

char* registrar = "pbx_ael" [static]

Definition at line 66 of file pbx_ael.c.

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

int return_on_context_match [static]

Definition at line 127 of file pbx_ael.c.

int warns [static]

Definition at line 69 of file pbx_ael.c.


Generated on Thu Feb 5 16:26:20 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7