Sat Jul 26 06:14:21 2008

Asterisk developer's documentation


pbx_ael.c File Reference

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

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

Include dependency graph for pbx_ael.c:

Go to the source code of this file.

Data Structures

struct  argapp

Defines

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

Functions

void add_extensions (struct ael_extension *exten)
static int ael2_debug_contexts (int fd, int argc, char *argv[])
static int ael2_debug_macros (int fd, int argc, char *argv[])
static int ael2_debug_read (int fd, int argc, char *argv[])
static int ael2_debug_tokens (int fd, int argc, char *argv[])
static int ael2_no_debug (int fd, int argc, char *argv[])
static int ael2_reload (int fd, int argc, char *argv[])
static void ael2_semantic_check (pval *item, int *arg_errs, int *arg_warns, int *arg_notes)
void ast_compile_ael2 (struct ast_context **local_contexts, struct pval *root)
int ast_expr (char *expr, char *buf, int length)
void ast_expr_clear_extra_error_info (void)
void ast_expr_register_extra_error_info (char *errmsg)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Asterisk Extension Language Compiler",.load=load_module,.unload=unload_module,.reload=reload,)
static void attach_exten (struct ael_extension **list, struct ael_extension *newmem)
static void check_abstract_reference (pval *abstract_context)
int check_app_args (pval *appcall, pval *arglist, struct argapp *app)
static int check_break (pval *item)
static void check_context_names (void)
static int check_continue (pval *item)
static void check_day (pval *DAY)
static void check_dow (pval *DOW)
 get_dow: Get day of week
static void check_expr2_input (pval *expr, char *str)
static void check_goto (pval *item)
static void check_includes (pval *includes)
static void check_label (pval *item)
static void check_month (pval *MON)
void check_pval (pval *item, struct argapp *apps, int in_globals)
void check_pval_item (pval *item, struct argapp *apps, int in_globals)
void check_switch_expr (pval *item, struct argapp *apps)
static void check_timerange (pval *p)
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)
static void fix_gotos_in_extensions (struct ael_extension *exten)
static void gen_match_to_pattern (char *pattern, char *result)
static void gen_prios (struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *context)
static pvalget_contxt (pval *p)
static pvalget_extension_or_contxt (pval *p)
static pvalget_goto_target (pval *item)
int is_empty (char *arg)
int is_float (char *arg)
int is_int (char *arg)
static int label_inside_case (pval *label)
static void linkexten (struct ael_extension *exten, struct ael_extension *add)
void linkprio (struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
static int load_module (void)
pvalmatch_pval (pval *item)
static struct pvalmatch_pval_item (pval *item)
ael_extensionnew_exten (void)
ael_prioritynew_prio (void)
static int pbx_load_module (void)
static void print_pval (FILE *fin, pval *item, int depth)
static void print_pval_list (FILE *fin, pval *item, int depth)
static int reload (void)
static void remove_spaces_before_equals (char *str)
void set_priorities (struct ael_extension *exten)
static void substitute_commas (char *str)
void traverse_pval_item_template (pval *item, int depth)
void traverse_pval_template (pval *item, int depth)
static int unload_module (void)

Variables

static int aeldebug = 0
static struct ast_cli_entry cli_ael []
static struct ast_cli_entry cli_ael_no_debug
static char * config = "extensions.ael"
static int control_statement_count = 0
static int count_labels
static pvalcurrent_context = 0
static pvalcurrent_db = 0
static pvalcurrent_extension = 0
static char * days []
static int errs
static char expr_output [2096]
static int in_abstract_context
static int label_count
static pvallast_matched_label
static const char * match_context
static const char * match_exten
static const char * match_label
static char * months []
static int notes
static char * registrar = "pbx_ael"
static int return_on_context_match
static int warns


Detailed Description

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

Definition in file pbx_ael.c.


Define Documentation

#define DEBUG_CONTEXTS   (1 << 3)

Definition at line 58 of file pbx_ael.c.

Referenced by ael2_debug_contexts().

#define DEBUG_MACROS   (1 << 2)

Definition at line 57 of file pbx_ael.c.

Referenced by ael2_debug_macros().

#define DEBUG_READ   (1 << 0)

Definition at line 55 of file pbx_ael.c.

Referenced by ael2_debug_read().

#define DEBUG_TOKENS   (1 << 1)

Definition at line 56 of file pbx_ael.c.

Referenced by ael2_debug_tokens().


Function Documentation

void add_extensions ( struct ael_extension exten  ) 

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

03727 {
03728    struct ael_priority *pr;
03729    char *label=0;
03730    char realext[AST_MAX_EXTENSION];
03731    if (!exten) {
03732       ast_log(LOG_WARNING, "This file is Empty!\n" );
03733       return;
03734    }
03735    do {
03736       struct ael_priority *last = 0;
03737 
03738       memset(realext, '\0', sizeof(realext));
03739       pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
03740       if (exten->hints) {
03741          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, 
03742                           exten->hints, NULL, ast_free, registrar)) {
03743             ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
03744                   exten->name);
03745          }
03746       }
03747       
03748       for (pr=exten->plist; pr; pr=pr->next) {
03749          char app[2000];
03750          char appargs[2000];
03751 
03752          /* before we can add the extension, we need to prep the app/appargs;
03753             the CONTROL types need to be done after the priority numbers are calculated.
03754          */
03755          if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
03756             last = pr;
03757             continue;
03758          }
03759          
03760          if (pr->app)
03761             strcpy(app, pr->app);
03762          else
03763             app[0] = 0;
03764          if (pr->appargs )
03765             strcpy(appargs, pr->appargs);
03766          else
03767             appargs[0] = 0;
03768          switch( pr->type ) {
03769          case AEL_APPCALL:
03770             /* easy case. Everything is all set up */
03771             break;
03772             
03773          case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
03774             /* simple, unconditional goto. */
03775             strcpy(app,"Goto");
03776             if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
03777                snprintf(appargs,sizeof(appargs),"%s|%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
03778             } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
03779                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
03780             } else
03781                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
03782             break;
03783             
03784          case AEL_FOR_CONTROL:  /* WHILE loop test, FOR loop test */
03785             strcpy(app,"GotoIf");
03786             snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
03787             break;
03788             
03789          case AEL_IF_CONTROL:
03790             strcpy(app,"GotoIf");
03791             if (pr->origin->u3.else_statements )
03792                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
03793             else
03794                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
03795             break;
03796 
03797          case AEL_RAND_CONTROL:
03798             strcpy(app,"Random");
03799             snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
03800             break;
03801 
03802          case AEL_IFTIME_CONTROL:
03803             strcpy(app,"GotoIfTime");
03804             snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
03805             break;
03806 
03807          case AEL_RETURN:
03808             strcpy(app,"Goto");
03809             snprintf(appargs,sizeof(appargs), "%d", exten->return_target->priority_num);
03810             break;
03811             
03812          default:
03813             break;
03814          }
03815          if (last && last->type == AEL_LABEL ) {
03816             label = last->origin->u1.str;
03817          }
03818          else
03819             label = 0;
03820          
03821          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, 
03822                           app, strdup(appargs), ast_free, registrar)) {
03823             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, 
03824                   exten->name);
03825          }
03826          last = pr;
03827       }
03828       exten = exten->next_exten;
03829    } while ( exten );
03830 }

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

Definition at line 4187 of file pbx_ael.c.

References DEBUG_CONTEXTS.

04188 {
04189    aeldebug |= DEBUG_CONTEXTS;
04190    return 0;
04191 }

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

Definition at line 4181 of file pbx_ael.c.

References DEBUG_MACROS.

04182 {
04183    aeldebug |= DEBUG_MACROS;
04184    return 0;
04185 }

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

Definition at line 4169 of file pbx_ael.c.

References DEBUG_READ.

04170 {
04171    aeldebug |= DEBUG_READ;
04172    return 0;
04173 }

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

Definition at line 4175 of file pbx_ael.c.

References DEBUG_TOKENS.

04176 {
04177    aeldebug |= DEBUG_TOKENS;
04178    return 0;
04179 }

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

Definition at line 4193 of file pbx_ael.c.

04194 {
04195    aeldebug = 0;
04196    return 0;
04197 }

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

Definition at line 4199 of file pbx_ael.c.

References pbx_load_module().

04200 {
04201    return (pbx_load_module());
04202 }

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

Definition at line 2728 of file pbx_ael.c.

References ast_config_AST_VAR_DIR, check_context_names(), check_pval(), and current_db.

Referenced by pbx_load_module().

02729 {
02730    
02731 #ifdef AAL_ARGCHECK
02732    int argapp_errs =0;
02733    char *rfilename;
02734 #endif
02735    struct argapp *apps=0;
02736 
02737    if (!item)
02738       return; /* don't check an empty tree */
02739 #ifdef AAL_ARGCHECK
02740    rfilename = alloca(10 + strlen(ast_config_AST_VAR_DIR));
02741    sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR);
02742    
02743    apps = argdesc_parse(rfilename, &argapp_errs); /* giveth */
02744 #endif
02745    current_db = item;
02746    errs = warns = notes = 0;
02747 
02748    check_context_names();
02749    check_pval(item, apps, 0);
02750 
02751 #ifdef AAL_ARGCHECK
02752    argdesc_destroy(apps);  /* taketh away */
02753 #endif
02754    current_db = 0;
02755 
02756    *arg_errs = errs;
02757    *arg_warns = warns;
02758    *arg_notes = notes;
02759 }

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

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

03914 {
03915    pval *p,*p2;
03916    struct ast_context *context;
03917    char buf[2000];
03918    struct ael_extension *exten;
03919    struct ael_extension *exten_list = 0;
03920 
03921    for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there
03922                             when we try to eval them */
03923       switch (p->type) {
03924       case PV_GLOBALS:
03925          /* just VARDEC elements */
03926          for (p2=p->u1.list; p2; p2=p2->next) {
03927             char buf2[2000];
03928             snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
03929             pbx_builtin_setvar(NULL, buf2);
03930          }
03931          break;
03932       default:
03933          break;
03934       }
03935    }
03936    
03937    for (p=root; p; p=p->next ) {
03938       pval *lp;
03939       int argc;
03940       
03941       switch (p->type) {
03942       case PV_MACRO:
03943          strcpy(buf,"macro-");
03944          strcat(buf,p->u1.str);
03945          context = ast_context_create(local_contexts, buf, registrar);
03946          
03947          exten = new_exten();
03948          exten->context = context;
03949          exten->name = strdup("s");
03950          argc = 1;
03951          for (lp=p->u2.arglist; lp; lp=lp->next) {
03952             /* for each arg, set up a "Set" command */
03953             struct ael_priority *np2 = new_prio();
03954             np2->type = AEL_APPCALL;
03955             np2->app = strdup("Set");
03956             snprintf(buf,sizeof(buf),"%s=${ARG%d}", lp->u1.str, argc++);
03957             remove_spaces_before_equals(buf);
03958             np2->appargs = strdup(buf);
03959             linkprio(exten, np2, NULL);
03960          }
03961          /* add any includes */
03962          for (p2=p->u3.macro_statements; p2; p2=p2->next) {
03963             pval *p3;
03964             
03965             switch (p2->type) {
03966             case PV_INCLUDES:
03967                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
03968                   if ( p3->u2.arglist ) {
03969                      snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s", 
03970                             p3->u1.str,
03971                             p3->u2.arglist->u1.str,
03972                             p3->u2.arglist->next->u1.str,
03973                             p3->u2.arglist->next->next->u1.str,
03974                             p3->u2.arglist->next->next->next->u1.str);
03975                      ast_context_add_include2(context, buf, registrar);
03976                   } else
03977                      ast_context_add_include2(context, p3->u1.str, registrar);
03978                }
03979                break;
03980             default:
03981                break;
03982             }
03983          }
03984          /* CONTAINS APPCALLS, CATCH, just like extensions... */
03985          gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context );
03986          if (exten->return_needed) {
03987             struct ael_priority *np2 = new_prio();
03988             np2->type = AEL_APPCALL;
03989             np2->app = strdup("NoOp");
03990             snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
03991             np2->appargs = strdup(buf);
03992             linkprio(exten, np2, NULL);
03993             exten-> return_target = np2;
03994          }
03995          
03996          set_priorities(exten);
03997          attach_exten(&exten_list, exten);
03998          break;
03999          
04000       case PV_GLOBALS:
04001          /* already done */
04002          break;
04003          
04004       case PV_CONTEXT:
04005          context = ast_context_find_or_create(local_contexts, p->u1.str, registrar);
04006          
04007          /* contexts contain: ignorepat, includes, switches, eswitches, extensions,  */
04008          for (p2=p->u2.statements; p2; p2=p2->next) {
04009             pval *p3;
04010             char *s3;
04011             
04012             switch (p2->type) {
04013             case PV_EXTENSION:
04014                exten = new_exten();
04015                exten->name = strdup(p2->u1.str);
04016                exten->context = context;
04017                
04018                if( (s3=strchr(exten->name, '/') ) != 0 )
04019                {
04020                   *s3 = 0;
04021                   exten->cidmatch = s3+1;
04022                }
04023                
04024                if ( p2->u3.hints )
04025                   exten->hints = strdup(p2->u3.hints);
04026                exten->regexten = p2->u4.regexten;
04027                gen_prios(exten, p->u1.str, p2->u2.statements, 0, context );
04028                if (exten->return_needed) {
04029                   struct ael_priority *np2 = new_prio();
04030                   np2->type = AEL_APPCALL;
04031                   np2->app = strdup("NoOp");
04032                   snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
04033                   np2->appargs = strdup(buf);
04034                   linkprio(exten, np2, NULL);
04035                   exten-> return_target = np2;
04036                }
04037                /* is the last priority in the extension a label? Then add a trailing no-op */
04038                if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
04039                   struct ael_priority *np2 = new_prio();
04040                   np2->type = AEL_APPCALL;
04041                   np2->app = strdup("NoOp");
04042                   snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
04043                   np2->appargs = strdup(buf);
04044                   linkprio(exten, np2, NULL);
04045                }
04046 
04047                set_priorities(exten);
04048                attach_exten(&exten_list, exten);
04049                break;
04050                
04051             case PV_IGNOREPAT:
04052                ast_context_add_ignorepat2(context, p2->u1.str, registrar);
04053                break;
04054                
04055             case PV_INCLUDES:
04056                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04057                   if ( p3->u2.arglist ) {
04058                      snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s", 
04059                             p3->u1.str,
04060                             p3->u2.arglist->u1.str,
04061                             p3->u2.arglist->next->u1.str,
04062                             p3->u2.arglist->next->next->u1.str,
04063                             p3->u2.arglist->next->next->next->u1.str);
04064                      ast_context_add_include2(context, buf, registrar);
04065                   } else
04066                      ast_context_add_include2(context, p3->u1.str, registrar);
04067                }
04068                break;
04069                
04070             case PV_SWITCHES:
04071                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04072                   char *c = strchr(p3->u1.str, '/');
04073                   if (c) {
04074                      *c = '\0';
04075                      c++;
04076                   } else
04077                      c = "";
04078 
04079                   ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
04080                }
04081                break;
04082 
04083             case PV_ESWITCHES:
04084                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
04085                   char *c = strchr(p3->u1.str, '/');
04086                   if (c) {
04087                      *c = '\0';
04088                      c++;
04089                   } else
04090                      c = "";
04091 
04092                   ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
04093                }
04094                break;
04095             default:
04096                break;
04097             }
04098          }
04099          
04100          break;
04101          
04102       default:
04103          /* huh? what? */
04104          break;
04105          
04106       }
04107    }
04108    /* moved these from being done after a macro or extension were processed,
04109       to after all processing is done, for the sake of fixing gotos to labels inside cases... */
04110    /* I guess this would be considered 2nd pass of compiler now... */
04111    fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */
04112    add_extensions(exten_list);   /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */
04113    destroy_extensions(exten_list);  /* all that remains is an empty husk, discard of it as is proper */
04114    
04115 }

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

Definition at line 2288 of file ast_expr2f.c.

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

Referenced by check_pval_item(), and pbx_substitute_variables_helper_full().

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

void ast_expr_clear_extra_error_info ( void   ) 

void ast_expr_register_extra_error_info ( char *  errmsg  ) 

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

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

Definition at line 3832 of file pbx_ael.c.

References ael_extension::next_exten.

03833 {
03834    /* travel to the end of the list... */
03835    struct ael_extension *lptr;
03836    if( !*list ) {
03837       *list = newmem;
03838       return;
03839    }
03840    lptr = *list;
03841    
03842    while( lptr->next_exten ) {
03843       lptr = lptr->next_exten;
03844    }
03845    /* lptr should now pointing to the last element in the list; it has a null next_exten pointer */
03846    lptr->next_exten = newmem;
03847 }

static void check_abstract_reference ( pval abstract_context  )  [static]

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

02262 {
02263    pval *i,*j;
02264    /* find some context includes that reference this context */
02265    
02266 
02267    /* otherwise, print out a warning */
02268    for (i=current_db; i; i=i->next) {
02269       if (i->type == PV_CONTEXT) {
02270          for (j=i->u2. statements; j; j=j->next) {
02271             if ( j->type == PV_INCLUDES ) {
02272                struct pval *p4;
02273                for (p4=j->u1.list; p4; p4=p4->next) {
02274                   /* for each context pointed to, find it, then find a context/label that matches the
02275                      target here! */
02276                   if ( !strcmp(p4->u1.str, abstract_context->u1.str) )
02277                      return; /* found a match! */
02278                }
02279             }
02280          }
02281       }
02282    }
02283    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",
02284          abstract_context->filename, abstract_context->startline, abstract_context->endline, abstract_context->u1.str);
02285    warns++;
02286 }

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

Definition at line 2062 of file pbx_ael.c.

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

Referenced by check_pval_item().

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

static int check_break ( pval item  )  [static]

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

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

static void check_context_names ( void   )  [static]

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

02243 {
02244    pval *i,*j;
02245    for (i=current_db; i; i=i->next) {
02246       if (i->type == PV_CONTEXT || i->type == PV_MACRO) {
02247          for (j=i->next; j; j=j->next) {
02248             if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) {
02249                if ( !strcmp(i->u1.str, j->u1.str) && !(i->u3.abstract&2) && !(j->u3.abstract&2) )
02250                {
02251                   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",
02252                         i->filename, i->startline, i->endline, i->u1.str,  j->filename, j->startline, j->endline);
02253                   errs++;
02254                }
02255             }
02256          }
02257       }
02258    }
02259 }

static int check_continue ( pval item  )  [static]

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

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

static void check_day ( pval DAY  )  [static]

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

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

static void check_dow ( pval DOW  )  [static]

get_dow: Get day of week

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

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

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

Definition at line 818 of file pbx_ael.c.

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

Referenced by check_pval_item().

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

static void check_goto ( pval item  )  [static]

Definition at line 1190 of file pbx_ael.c.

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

Referenced by check_pval_item(), and find_pval_goto_item().

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

static void check_includes ( pval includes  )  [static]

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

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

static void check_label ( pval item  )  [static]

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

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

static void check_month ( pval MON  )  [static]

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

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

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

Definition at line 2708 of file pbx_ael.c.

References check_pval_item(), and pval::next.

Referenced by ael2_semantic_check(), and check_pval_item().

02709 {
02710    pval *i;
02711 
02712    /* checks to do:
02713       1. Do goto's point to actual labels? 
02714       2. Do macro calls reference a macro?
02715       3. Does the number of macro args match the definition?
02716       4. Is a macro call missing its & at the front?
02717       5. Application calls-- we could check syntax for existing applications,
02718          but I need some some sort of universal description bnf for a general
02719         sort of method for checking arguments, in number, maybe even type, at least. 
02720         Don't want to hand code checks for hundreds of applications.
02721    */
02722    
02723    for (i=item; i; i=i->next) {
02724       check_pval_item(i,apps,in_globals);
02725    }
02726 }

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

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

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

void check_switch_expr ( pval item,
struct argapp apps 
)

Definition at line 2116 of file pbx_ael.c.

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

Referenced by check_pval_item().

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

static void check_timerange ( pval p  )  [static]

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

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

void destroy_extensions ( struct ael_extension exten  ) 

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

02822 {
02823    struct ael_extension *ne, *nen;
02824    for (ne=exten; ne; ne=nen) {
02825       struct ael_priority *pe, *pen;
02826       
02827       if (ne->name)
02828          free(ne->name);
02829       
02830       /* cidmatch fields are allocated with name, and freed when
02831          the name field is freed. Don't do a free for this field,
02832          unless you LIKE to see a crash! */
02833 
02834       if (ne->hints)
02835          free(ne->hints);
02836       
02837       for (pe=ne->plist; pe; pe=pen) {
02838          pen = pe->next;
02839          if (pe->app)
02840             free(pe->app);
02841          pe->app = 0;
02842          if (pe->appargs)
02843             free(pe->appargs);
02844          pe->appargs = 0;
02845          pe->origin = 0;
02846          pe->goto_true = 0;
02847          pe->goto_false = 0;
02848          free(pe);
02849       }
02850       nen = ne->next_exten;
02851       ne->next_exten = 0;
02852       ne->plist =0;
02853       ne->plist_last = 0;
02854       ne->next_exten = 0;
02855       ne->loop_break = 0;
02856       ne->loop_continue = 0;
02857       free(ne);
02858    }
02859 }

void destroy_pval ( pval item  ) 

void destroy_pval_item ( pval item  ) 

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

04270 {
04271    if (item == NULL) {
04272       ast_log(LOG_WARNING, "null item\n");
04273       return;
04274    }
04275 
04276    if (item->filename)
04277       free(item->filename);
04278    
04279    switch (item->type) {
04280    case PV_WORD:
04281       /* fields: item->u1.str == string associated with this (word). */
04282       if (item->u1.str )
04283          free(item->u1.str);
04284       if ( item->u2.arglist )
04285          destroy_pval(item->u2.arglist);
04286       break;
04287       
04288    case PV_MACRO:
04289       /* fields: item->u1.str     == name of macro
04290                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
04291                item->u2.arglist->u1.str  == argument
04292                item->u2.arglist->next   == next arg
04293 
04294                item->u3.macro_statements == pval list of statements in macro body.
04295       */
04296       destroy_pval(item->u2.arglist);
04297       if (item->u1.str )
04298          free(item->u1.str);
04299       destroy_pval(item->u3.macro_statements);
04300       break;
04301          
04302    case PV_CONTEXT:
04303       /* fields: item->u1.str     == name of context
04304                  item->u2.statements == pval list of statements in context body
04305                item->u3.abstract == int 1 if an abstract keyword were present
04306       */
04307       if (item->u1.str)
04308          free(item->u1.str);
04309       destroy_pval(item->u2.statements);
04310       break;
04311          
04312    case PV_MACRO_CALL:
04313       /* fields: item->u1.str     == name of macro to call
04314                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04315                item->u2.arglist->u1.str  == argument
04316                item->u2.arglist->next   == next arg
04317       */
04318       if (item->u1.str)
04319          free(item->u1.str);
04320       destroy_pval(item->u2.arglist);
04321       break;
04322          
04323    case PV_APPLICATION_CALL:
04324       /* fields: item->u1.str     == name of application to call
04325                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04326                item->u2.arglist->u1.str  == argument
04327                item->u2.arglist->next   == next arg
04328       */
04329       if (item->u1.str)
04330          free(item->u1.str);
04331       destroy_pval(item->u2.arglist);
04332       break;
04333          
04334    case PV_CASE:
04335       /* fields: item->u1.str     == value of case
04336                  item->u2.statements == pval list of statements under the case
04337       */
04338       if (item->u1.str)
04339          free(item->u1.str);
04340       destroy_pval(item->u2.statements);
04341       break;
04342          
04343    case PV_PATTERN:
04344       /* fields: item->u1.str     == value of case
04345                  item->u2.statements == pval list of statements under the case
04346       */
04347       if (item->u1.str)
04348          free(item->u1.str);
04349       destroy_pval(item->u2.statements);
04350       break;
04351          
04352    case PV_DEFAULT:
04353       /* fields: 
04354                  item->u2.statements == pval list of statements under the case
04355       */
04356       destroy_pval(item->u2.statements);
04357       break;
04358          
04359    case PV_CATCH:
04360       /* fields: item->u1.str     == name of extension to catch
04361                  item->u2.statements == pval list of statements in context body
04362       */
04363       if (item->u1.str)
04364          free(item->u1.str);
04365       destroy_pval(item->u2.statements);
04366       break;
04367          
04368    case PV_SWITCHES:
04369       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04370       */
04371       destroy_pval(item->u1.list);
04372       break;
04373          
04374    case PV_ESWITCHES:
04375       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04376       */
04377       destroy_pval(item->u1.list);
04378       break;
04379          
04380    case PV_INCLUDES:
04381       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04382                  item->u2.arglist  == pval list of 4 PV_WORD elements for time values
04383       */
04384       destroy_pval(item->u1.list);
04385       break;
04386          
04387    case PV_STATEMENTBLOCK:
04388       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
04389       */
04390       destroy_pval(item->u1.list);
04391       break;
04392          
04393    case PV_VARDEC:
04394       /* fields: item->u1.str     == variable name
04395                  item->u2.val     == variable value to assign
04396       */
04397       if (item->u1.str)
04398          free(item->u1.str);
04399       if (item->u2.val)
04400          free(item->u2.val);
04401       break;
04402          
04403    case PV_GOTO:
04404       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
04405                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
04406       */
04407       
04408       destroy_pval(item->u1.list);
04409       break;
04410          
04411    case PV_LABEL:
04412       /* fields: item->u1.str     == label name
04413       */
04414       if (item->u1.str)
04415          free(item->u1.str);
04416       break;
04417          
04418    case PV_FOR:
04419       /* fields: item->u1.for_init     == a string containing the initalizer
04420                  item->u2.for_test     == a string containing the loop test
04421                  item->u3.for_inc      == a string containing the loop increment
04422 
04423                item->u4.for_statements == a pval list of statements in the for ()
04424       */
04425       if (item->u1.for_init)
04426          free(item->u1.for_init);
04427       if (item->u2.for_test)
04428          free(item->u2.for_test);
04429       if (item->u3.for_inc)
04430          free(item->u3.for_inc);
04431       destroy_pval(item->u4.for_statements);
04432       break;
04433          
04434    case PV_WHILE:
04435       /* fields: item->u1.str        == the while conditional, as supplied by user
04436 
04437                item->u2.statements == a pval list of statements in the while ()
04438       */
04439       if (item->u1.str)
04440          free(item->u1.str);
04441       destroy_pval(item->u2.statements);
04442       break;
04443          
04444    case PV_BREAK:
04445       /* fields: none
04446       */
04447       break;
04448          
04449    case PV_RETURN:
04450       /* fields: none
04451       */
04452       break;
04453          
04454    case PV_CONTINUE:
04455       /* fields: none
04456       */
04457       break;
04458          
04459    case PV_IFTIME:
04460       /* fields: item->u1.list        == the 4 time values, in PV_WORD structs, linked list
04461 
04462                item->u2.statements == a pval list of statements in the if ()
04463                item->u3.else_statements == a pval list of statements in the else
04464                                     (could be zero)
04465       */
04466       destroy_pval(item->u1.list);
04467       destroy_pval(item->u2.statements);
04468       if (item->u3.else_statements) {
04469          destroy_pval(item->u3.else_statements);
04470       }
04471       break;
04472          
04473    case PV_RANDOM:
04474       /* fields: item->u1.str        == the random percentage, as supplied by user
04475 
04476                item->u2.statements == a pval list of statements in the true part ()
04477                item->u3.else_statements == a pval list of statements in the else
04478                                     (could be zero)
04479       fall thru to If */
04480    case PV_IF:
04481       /* fields: item->u1.str        == the if conditional, as supplied by user
04482 
04483                item->u2.statements == a pval list of statements in the if ()
04484                item->u3.else_statements == a pval list of statements in the else
04485                                     (could be zero)
04486       */
04487       if (item->u1.str)
04488          free(item->u1.str);
04489       destroy_pval(item->u2.statements);
04490       if (item->u3.else_statements) {
04491          destroy_pval(item->u3.else_statements);
04492       }
04493       break;
04494          
04495    case PV_SWITCH:
04496       /* fields: item->u1.str        == the switch expression
04497 
04498                item->u2.statements == a pval list of statements in the switch, 
04499                                     (will be case statements, most likely!)
04500       */
04501       if (item->u1.str)
04502          free(item->u1.str);
04503       destroy_pval(item->u2.statements);
04504       break;
04505          
04506    case PV_EXTENSION:
04507       /* fields: item->u1.str        == the extension name, label, whatever it's called
04508 
04509                item->u2.statements == a pval list of statements in the extension
04510                item->u3.hints      == a char * hint argument
04511                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
04512       */
04513       if (item->u1.str)
04514          free(item->u1.str);
04515       if (item->u3.hints)
04516          free(item->u3.hints);
04517       destroy_pval(item->u2.statements);
04518       break;
04519          
04520    case PV_IGNOREPAT:
04521       /* fields: item->u1.str        == the ignorepat data
04522       */
04523       if (item->u1.str)
04524          free(item->u1.str);
04525       break;
04526          
04527    case PV_GLOBALS:
04528       /* fields: item->u1.statements     == pval list of statements, usually vardecs
04529       */
04530       destroy_pval(item->u1.statements);
04531       break;
04532    }
04533    free(item);
04534 }

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

Definition at line 707 of file pbx_ael.c.

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

Referenced by match_pval_item().

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

struct pval * find_context ( char *  name  ) 

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

01886 {
01887    return_on_context_match = 1;
01888    count_labels = 0;
01889    match_context = name;
01890    match_exten = "*";  /* don't really need to set these, shouldn't be reached */
01891    match_label = "*";
01892    return match_pval(current_db);
01893 }

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

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

01765 {
01766    /* printf("  --- Got args %s, %s\n", exten, label); */
01767    struct pval *ret;
01768    struct pval *p3;
01769    struct pval *startpt = ((curr_cont->type==PV_MACRO)?curr_cont->u3.macro_statements: curr_cont->u2.statements);
01770    
01771    count_labels = 0;
01772    return_on_context_match = 0;
01773    match_context = "*";
01774    match_exten = "*";
01775    match_label = label;
01776    
01777    ret =  match_pval(curr_cont);
01778    if (ret)
01779       return ret;
01780                
01781    /* the target of the goto could be in an included context!! Fancy that!! */
01782    /* look for includes in the current context */
01783    for (p3=startpt; p3; p3=p3->next) {
01784       if (p3->type == PV_INCLUDES) {
01785          struct pval *p4;
01786          for (p4=p3->u1.list; p4; p4=p4->next) {
01787             /* for each context pointed to, find it, then find a context/label that matches the
01788                target here! */
01789             char *incl_context = p4->u1.str;
01790             /* find a matching context name */
01791             struct pval *that_context = find_context(incl_context);
01792             if (that_context) {
01793                struct pval *x3;
01794                x3 = find_first_label_in_current_context(label, that_context);
01795                if (x3) {
01796                   return x3;
01797                }
01798             }
01799          }
01800       }
01801    }
01802    return 0;
01803 }

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

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

01806 {
01807    /* printf("  --- Got args %s, %s\n", exten, label); */
01808    struct pval *ret;
01809    struct pval *p3;
01810    struct pval *startpt;
01811    
01812    count_labels = 0;
01813    return_on_context_match = 0;
01814    match_context = "*";
01815    match_exten = exten;
01816    match_label = label;
01817    if (curr_cont->type == PV_MACRO)
01818       startpt = curr_cont->u3.macro_statements;
01819    else
01820       startpt = curr_cont->u2.statements;
01821 
01822    ret =  match_pval(startpt);
01823    if (ret)
01824       return ret;
01825                
01826    /* the target of the goto could be in an included context!! Fancy that!! */
01827    /* look for includes in the current context */
01828    for (p3=startpt; p3; p3=p3->next) {
01829       if (p3->type == PV_INCLUDES) {
01830          struct pval *p4;
01831          for (p4=p3->u1.list; p4; p4=p4->next) {
01832             /* for each context pointed to, find it, then find a context/label that matches the
01833                target here! */
01834             char *incl_context = p4->u1.str;
01835             /* find a matching context name */
01836             struct pval *that_context = find_context(incl_context);
01837             if (that_context) {
01838                struct pval *x3;
01839                x3 = find_label_in_current_context(exten, label, that_context);
01840                if (x3) {
01841                   return x3;
01842                }
01843             }
01844          }
01845       }
01846    }
01847    return 0;
01848 }

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

Definition at line 1861 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_goto(), and get_goto_target().

01862 {
01863    /* printf("  --- Got args %s, %s, %s\n", context, exten, label); */
01864    count_labels = 0;
01865    return_on_context_match = 0;
01866 
01867    match_context = context;
01868    match_exten = exten;
01869    match_label = label;
01870    
01871    return match_pval(current_db);
01872 }

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

Definition at line 1850 of file pbx_ael.c.

References match_pval().

Referenced by check_goto(), and get_goto_target().

01851 {
01852    /* printf("  --- Got args %s\n", label); */
01853    count_labels = 0;
01854    return_on_context_match = 0;
01855    match_context = "*";
01856    match_exten = "*";
01857    match_label = label;
01858    return match_pval(curr_ext);
01859 }

struct pval * find_macro ( char *  name  ) 

Definition at line 1875 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_pval_item().

01876 {
01877    return_on_context_match = 1;
01878    count_labels = 0;
01879    match_context = name;
01880    match_exten = "*";  /* don't really need to set these, shouldn't be reached */
01881    match_label = "*";
01882    return match_pval(current_db);
01883 }

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

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

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

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

Definition at line 1456 of file pbx_ael.c.

References find_pval_goto_item(), and pval::next.

Referenced by check_pval_item(), and find_pval_goto_item().

01457 {
01458    pval *i;
01459 
01460    for (i=item; i; i=i->next) {
01461       
01462       find_pval_goto_item(i, lev);
01463    }
01464 }

static void fix_gotos_in_extensions ( struct ael_extension exten  )  [static]

Definition at line 3869 of file pbx_ael.c.

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

03870 {
03871    struct ael_extension *e;
03872    for(e=exten;e;e=e->next_exten) {
03873 
03874       struct ael_priority *p;
03875       for(p=e->plist;p;p=p->next) {
03876          
03877          if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) {
03878             
03879             /* fix the extension of the goto target to the actual extension in the post-compiled dialplan */
03880 
03881             pval *target = p->origin->u2.goto_target;
03882             struct ael_extension *z = target->u3.compiled_label;
03883             pval *pv2 = p->origin;
03884             char buf1[500];
03885             char *apparg_save = p->appargs;
03886             
03887             p->appargs = 0;
03888             if (!pv2->u1.list->next) /* just one  -- it won't hurt to repeat the extension */ {
03889                snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->u1.str);
03890                p->appargs = strdup(buf1);
03891                
03892             } else if (pv2->u1.list->next && !pv2->u1.list->next->next) /* two */ {
03893                snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->next->u1.str);
03894                p->appargs = strdup(buf1);
03895             } else if (pv2->u1.list->next && pv2->u1.list->next->next) {
03896                snprintf(buf1,sizeof(buf1),"%s|%s|%s", pv2->u1.list->u1.str, 
03897                       z->name,
03898                       pv2->u1.list->next->next->u1.str);
03899                p->appargs = strdup(buf1);
03900             }
03901             else
03902                printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n");
03903             
03904             if( apparg_save ) {
03905                free(apparg_save);
03906             }
03907          }
03908       }
03909    }
03910 }

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

Definition at line 2900 of file pbx_ael.c.

References t.

Referenced by gen_prios().

02901 {
02902    /* the result will be a string that will be matched by pattern */
02903    char *p=pattern, *t=result;
02904    while (*p) {
02905       if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
02906          *t++ = '9';
02907       else if (*p == '[') {
02908          char *z = p+1;
02909          while (*z != ']')
02910             z++;
02911          if (*(z+1)== ']')
02912             z++;
02913          *t++=*(p+1); /* use the first char in the set */
02914          p = z;
02915       } else {
02916          *t++ = *p;
02917       }
02918       p++;
02919    }
02920    *t++ = 0; /* cap it off */
02921 }

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 2923 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, pval::compiled_label, ael_extension::context, control_statement_count, pval::else_statements, ael_priority::exten, exten, pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, free, gen_match_to_pattern(), get_goto_target(), ael_priority::goto_false, pval::goto_target, pval::goto_target_in_case, ael_priority::goto_true, ael_extension::has_switch, ael_extension::is_switch, pval::label_in_case, label_inside_case(), linkexten(), linkprio(), pval::list, ael_extension::loop_break, ael_extension::loop_continue, ael_extension::name, new_exten(), new_prio(), pval::next, ael_priority::origin, PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTINUE, PV_DEFAULT, PV_FOR, PV_GOTO, PV_IF, PV_IFTIME, PV_LABEL, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_VARDEC, PV_WHILE, remove_spaces_before_equals(), ael_extension::return_needed, pval::statements, pval::str, strdup, substitute_commas(), ael_priority::type, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.

02924 {
02925    pval *p,*p2,*p3;
02926    struct ael_priority *pr;
02927    struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end;
02928    struct ael_priority *while_test, *while_loop, *while_end;
02929    struct ael_priority *switch_set, *switch_test, *switch_end, *fall_thru, *switch_empty;
02930    struct ael_priority *if_test, *if_end, *if_skip, *if_false;
02931 #ifdef OLD_RAND_ACTION
02932    struct ael_priority *rand_test, *rand_end, *rand_skip;
02933 #endif
02934    char buf1[2000];
02935    char buf2[2000];
02936    char *strp, *strp2;
02937    char new_label[2000];
02938    int default_exists;
02939    int local_control_statement_count;
02940    struct ael_priority *loop_break_save;
02941    struct ael_priority *loop_continue_save;
02942    struct ael_extension *switch_case,*switch_null;
02943    
02944    for (p=statement; p; p=p->next) {
02945       switch (p->type) {
02946       case PV_VARDEC:
02947          pr = new_prio();
02948          pr->type = AEL_APPCALL;
02949          snprintf(buf1,sizeof(buf1),"%s=$[%s]", p->u1.str, p->u2.val);
02950          pr->app = strdup("Set");
02951          remove_spaces_before_equals(buf1);
02952          pr->appargs = strdup(buf1);
02953          pr->origin = p;
02954          linkprio(exten, pr, mother_exten);
02955          break;
02956 
02957       case PV_GOTO:
02958          pr = new_prio();
02959          pr->type = AEL_APPCALL;
02960          p->u2.goto_target = get_goto_target(p);
02961          if( p->u2.goto_target ) {
02962             p->u3.goto_target_in_case = p->u2.goto_target->u2.label_in_case = label_inside_case(p->u2.goto_target);
02963          }
02964          
02965          if (!p->u1.list->next) /* just one */ {
02966             pr->app = strdup("Goto");
02967             if (!mother_exten)
02968                pr->appargs = strdup(p->u1.list->u1.str);
02969             else {  /* for the case of simple within-extension gotos in case/pattern/default statement blocks: */ 
02970                snprintf(buf1,sizeof(buf1),"%s|%s", mother_exten->name, p->u1.list->u1.str);
02971                pr->appargs = strdup(buf1);
02972             }
02973             
02974          } else if (p->u1.list->next && !p->u1.list->next->next) /* two */ {
02975             snprintf(buf1,sizeof(buf1),"%s|%s", p->u1.list->u1.str, p->u1.list->next->u1.str);
02976             pr->app = strdup("Goto");
02977             pr->appargs = strdup(buf1);
02978          } else if (p->u1.list->next && p->u1.list->next->next) {
02979             snprintf(buf1,sizeof(buf1),"%s|%s|%s", p->u1.list->u1.str, 
02980                   p->u1.list->next->u1.str,
02981                   p->u1.list->next->next->u1.str);
02982             pr->app = strdup("Goto");
02983             pr->appargs = strdup(buf1);
02984          }
02985          pr->origin = p;
02986          linkprio(exten, pr, mother_exten);
02987          break;
02988 
02989       case PV_LABEL:
02990          pr = new_prio();
02991          pr->type = AEL_LABEL;
02992          pr->origin = p;
02993          p->u3.compiled_label = exten;
02994          linkprio(exten, pr, mother_exten);
02995          break;
02996 
02997       case PV_FOR:
02998          control_statement_count++;
02999          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
03000          loop_continue_save = exten->loop_continue;
03001          snprintf(new_label,sizeof(new_label),"for-%s-%d", label, control_statement_count);
03002          for_init = new_prio();
03003          for_inc = new_prio();
03004          for_test = new_prio();
03005          for_loop = new_prio();
03006          for_end = new_prio();
03007          for_init->type = AEL_APPCALL;
03008          for_inc->type = AEL_APPCALL;
03009          for_test->type = AEL_FOR_CONTROL;
03010          for_test->goto_false = for_end;
03011          for_loop->type = AEL_CONTROL1; /* simple goto */
03012          for_end->type = AEL_APPCALL;
03013          for_init->app = strdup("Set");
03014          
03015          strcpy(buf2,p->u1.for_init);
03016          remove_spaces_before_equals(buf2);
03017          strp = strchr(buf2, '=');
03018          if (strp) {
03019             strp2 = strchr(p->u1.for_init, '=');
03020             *(strp+1) = 0;
03021             strcat(buf2,"$[");
03022             strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03023             strcat(buf2,"]");
03024             for_init->appargs = strdup(buf2);
03025             /* for_init->app = strdup("Set"); just set! */
03026          } else {
03027             strp2 = p->u1.for_init;
03028             while (*strp2 && isspace(*strp2))
03029                strp2++;
03030             if (*strp2 == '&') { /* itsa macro call */
03031                char *strp3 = strp2+1;
03032                while (*strp3 && isspace(*strp3))
03033                   strp3++;
03034                strcpy(buf2, strp3);
03035                strp3 = strchr(buf2,'(');
03036                if (strp3) {
03037                   *strp3 = '|';
03038                }
03039                while ((strp3=strchr(buf2,','))) {
03040                   *strp3 = '|';
03041                }
03042                strp3 = strrchr(buf2, ')');
03043                if (strp3)
03044                   *strp3 = 0; /* remove the closing paren */
03045 
03046                for_init->appargs = strdup(buf2);
03047                if (for_init->app)
03048                   free(for_init->app);
03049                for_init->app = strdup("Macro");
03050             } else {  /* must be a regular app call */
03051                char *strp3;
03052                strcpy(buf2, strp2);
03053                strp3 = strchr(buf2,'(');
03054                if (strp3) {
03055                   *strp3 = 0;
03056                   if (for_init->app)
03057                      free(for_init->app);
03058                   for_init->app = strdup(buf2);
03059                   for_init->appargs = strdup(strp3+1);
03060                   strp3 = strrchr(for_init->appargs, ')');
03061                   if (strp3)
03062                      *strp3 = 0; /* remove the closing paren */
03063                }
03064             }
03065          }
03066 
03067          strcpy(buf2,p->u3.for_inc);
03068          remove_spaces_before_equals(buf2);
03069          strp = strchr(buf2, '=');
03070          if (strp) {  /* there's an = in this part; that means an assignment. set it up */
03071             strp2 = strchr(p->u3.for_inc, '=');
03072             *(strp+1) = 0;
03073             strcat(buf2,"$[");
03074             strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03075             strcat(buf2,"]");
03076             for_inc->appargs = strdup(buf2);
03077             for_inc->app = strdup("Set");
03078          } else {
03079             strp2 = p->u3.for_inc;
03080             while (*strp2 && isspace(*strp2))
03081                strp2++;
03082             if (*strp2 == '&') { /* itsa macro call */
03083                char *strp3 = strp2+1;
03084                while (*strp3 && isspace(*strp3))
03085                   strp3++;
03086                strcpy(buf2, strp3);
03087                strp3 = strchr(buf2,'(');
03088                if (strp3) {
03089                   *strp3 = '|';
03090                }
03091                while ((strp3=strchr(buf2,','))) {
03092                   *strp3 = '|';
03093                }
03094                strp3 = strrchr(buf2, ')');
03095                if (strp3)
03096                   *strp3 = 0; /* remove the closing paren */
03097 
03098                for_inc->appargs = strdup(buf2);
03099 
03100                for_inc->app = strdup("Macro");
03101             } else {  /* must be a regular app call */
03102                char *strp3;
03103                strcpy(buf2, strp2);
03104                strp3 = strchr(buf2,'(');
03105                if (strp3) {
03106                   *strp3 = 0;
03107                   for_inc->app = strdup(buf2);
03108                   for_inc->appargs = strdup(strp3+1);
03109                   strp3 = strrchr(for_inc->appargs, ')');
03110                   if (strp3)
03111                      *strp3 = 0; /* remove the closing paren */
03112                }
03113             }
03114          }
03115          snprintf(buf1,sizeof(buf1),"$[%s]",p->u2.for_test);
03116          for_test->app = 0;
03117          for_test->appargs = strdup(buf1);
03118          for_loop->goto_true = for_test;
03119          snprintf(buf1,sizeof(buf1),"Finish for-%s-%d", label, control_statement_count);
03120          for_end->app = strdup("NoOp");
03121          for_end->appargs = strdup(buf1);
03122          /* link & load! */
03123          linkprio(exten, for_init, mother_exten);
03124          linkprio(exten, for_test, mother_exten);
03125          
03126          /* now, put the body of the for loop here */
03127          exten->loop_break = for_end;
03128          exten->loop_continue = for_inc;
03129          
03130          gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context); /* this will link in all the statements here */
03131          
03132          linkprio(exten, for_inc, mother_exten);
03133          linkprio(exten, for_loop, mother_exten);
03134          linkprio(exten, for_end, mother_exten);
03135          
03136          
03137          exten->loop_break = loop_break_save;
03138          exten->loop_continue = loop_continue_save;
03139          for_loop->origin = p;
03140          break;
03141 
03142       case PV_WHILE:
03143          control_statement_count++;
03144          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
03145          loop_continue_save = exten->loop_continue;
03146          snprintf(new_label,sizeof(new_label),"while-%s-%d", label, control_statement_count);
03147          while_test = new_prio();
03148          while_loop = new_prio();
03149          while_end = new_prio();
03150          while_test->type = AEL_FOR_CONTROL;
03151          while_test->goto_false = while_end;
03152          while_loop->type = AEL_CONTROL1; /* simple goto */
03153          while_end->type = AEL_APPCALL;
03154          snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str);
03155          while_test->app = 0;
03156          while_test->appargs = strdup(buf1);
03157          while_loop->goto_true = while_test;
03158          snprintf(buf1,sizeof(buf1),"Finish while-%s-%d", label, control_statement_count);
03159          while_end->app = strdup("NoOp");
03160          while_end->appargs = strdup(buf1);
03161 
03162          linkprio(exten, while_test, mother_exten);
03163          
03164          /* now, put the body of the for loop here */
03165          exten->loop_break = while_end;
03166          exten->loop_continue = while_test;
03167          
03168          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the while body statements here */
03169 
03170          linkprio(exten, while_loop, mother_exten);
03171          linkprio(exten, while_end, mother_exten);
03172          
03173          
03174          exten->loop_break = loop_break_save;
03175          exten->loop_continue = loop_continue_save;
03176          while_loop->origin = p;
03177          break;
03178 
03179       case PV_SWITCH:
03180          control_statement_count++;
03181          local_control_statement_count = control_statement_count;
03182          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
03183          loop_continue_save = exten->loop_continue;
03184          snprintf(new_label,sizeof(new_label),"sw-%s-%d", label, control_statement_count);
03185          if ((mother_exten && !mother_exten->has_switch)) {
03186             switch_set = new_prio();
03187             switch_set->type = AEL_APPCALL;
03188             switch_set->app = strdup("Set");
03189             switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
03190             linkprio(exten, switch_set, mother_exten);
03191             mother_exten->has_switch = 1;
03192          } else if ((exten && !exten->has_switch)) {
03193             switch_set = new_prio();
03194             switch_set->type = AEL_APPCALL;
03195             switch_set->app = strdup("Set");
03196             switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
03197             linkprio(exten, switch_set, exten);
03198             exten->has_switch = 1;
03199          }
03200          switch_test = new_prio();
03201          switch_end = new_prio();
03202          switch_test->type = AEL_APPCALL;
03203          switch_end->type = AEL_APPCALL;
03204          strncpy(buf2,p->u1.str,sizeof(buf2));
03205          buf2[sizeof(buf2)-1] = 0; /* just in case */
03206          substitute_commas(buf2);
03207          snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",control_statement_count, buf2);
03208          switch_test->app = strdup("Goto");
03209          switch_test->appargs = strdup(buf1);
03210          snprintf(buf1,sizeof(buf1),"Finish switch-%s-%d", label, control_statement_count);
03211          switch_end->app = strdup("NoOp");
03212          switch_end->appargs = strdup(buf1);
03213          switch_end->origin = p;
03214          switch_end->exten = exten;
03215 
03216          linkprio(exten, switch_test, mother_exten);
03217          linkprio(exten, switch_end, mother_exten);
03218          
03219          exten->loop_break = switch_end;
03220          exten->loop_continue = 0;
03221          default_exists = 0;
03222          
03223          for (p2=p->u2.statements; p2; p2=p2->next) {
03224             /* now, for each case/default put the body of the for loop here */
03225             if (p2->type == PV_CASE) {
03226                /* ok, generate a extension and link it in */
03227                switch_case = new_exten();
03228                switch_case->context = this_context;
03229                switch_case->is_switch = 1;
03230                /* the break/continue locations are inherited from parent */
03231                switch_case->loop_break = exten->loop_break;
03232                switch_case->loop_continue = exten->loop_continue;
03233                
03234                linkexten(exten,switch_case);
03235                strncpy(buf2,p2->u1.str,sizeof(buf2));
03236                buf2[sizeof(buf2)-1] = 0; /* just in case */
03237                substitute_commas(buf2);
03238                snprintf(buf1,sizeof(buf1),"sw-%d-%s", local_control_statement_count, buf2);
03239                switch_case->name = strdup(buf1);
03240                snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count);
03241                
03242                gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the case body statements here */
03243 
03244                /* here is where we write code to "fall thru" to the next case... if there is one... */
03245                for (p3=p2->u2.statements; p3; p3=p3->next) {
03246                   if (!p3->next)
03247                      break;
03248                }
03249                /* p3 now points the last statement... */
03250                if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN) ) {
03251                   /* is there a following CASE/PATTERN/DEFAULT? */
03252                   if (p2->next && p2->next->type == PV_CASE) {
03253                      fall_thru = new_prio();
03254                      fall_thru->type = AEL_APPCALL;
03255                      fall_thru->app = strdup("Goto");
03256                      strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03257                      buf2[sizeof(buf2)-1] = 0; /* just in case */
03258                      substitute_commas(buf2);
03259                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03260                      fall_thru->appargs = strdup(buf1);
03261                      linkprio(switch_case, fall_thru, mother_exten);
03262                   } else if (p2->next && p2->next->type == PV_PATTERN) {
03263                      fall_thru = new_prio();
03264                      fall_thru->type = AEL_APPCALL;
03265                      fall_thru->app = strdup("Goto");
03266                      gen_match_to_pattern(p2->next->u1.str, buf2);
03267                      substitute_commas(buf2);
03268                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10", local_control_statement_count, buf2);
03269                      fall_thru->appargs = strdup(buf1);
03270                      linkprio(switch_case, fall_thru, mother_exten);
03271                   } else if (p2->next && p2->next->type == PV_DEFAULT) {
03272                      fall_thru = new_prio();
03273                      fall_thru->type = AEL_APPCALL;
03274                      fall_thru->app = strdup("Goto");
03275                      snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03276                      fall_thru->appargs = strdup(buf1);
03277                      linkprio(switch_case, fall_thru, mother_exten);
03278                   } else if (!p2->next) {
03279                      fall_thru = new_prio();
03280                      fall_thru->type = AEL_CONTROL1;
03281                      fall_thru->goto_true = switch_end;
03282                      fall_thru->app = strdup("Goto");
03283                      linkprio(switch_case, fall_thru, mother_exten);
03284                   }
03285                }
03286                if (switch_case->return_needed) {
03287                   char buf[2000];
03288                   struct ael_priority *np2 = new_prio();
03289                   np2->type = AEL_APPCALL;
03290                   np2->app = strdup("NoOp");
03291                   snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03292                   np2->appargs = strdup(buf);
03293                   linkprio(switch_case, np2, mother_exten);
03294                   switch_case-> return_target = np2;
03295                }
03296             } else if (p2->type == PV_PATTERN) {
03297                /* ok, generate a extension and link it in */
03298                switch_case = new_exten();
03299                switch_case->context = this_context;
03300                switch_case->is_switch = 1;
03301                /* the break/continue locations are inherited from parent */
03302                switch_case->loop_break = exten->loop_break;
03303                switch_case->loop_continue = exten->loop_continue;
03304                
03305                linkexten(exten,switch_case);
03306                strncpy(buf2,p2->u1.str,sizeof(buf2));
03307                buf2[sizeof(buf2)-1] = 0; /* just in case */
03308                substitute_commas(buf2);
03309                snprintf(buf1,sizeof(buf1),"_sw-%d-%s", local_control_statement_count, buf2);
03310                switch_case->name = strdup(buf1);
03311                snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count);
03312                
03313                gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the while body statements here */
03314                /* here is where we write code to "fall thru" to the next case... if there is one... */
03315                for (p3=p2->u2.statements; p3; p3=p3->next) {
03316                   if (!p3->next)
03317                      break;
03318                }
03319                /* p3 now points the last statement... */
03320                if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03321                   /* is there a following CASE/PATTERN/DEFAULT? */
03322                   if (p2->next && p2->next->type == PV_CASE) {
03323                      fall_thru = new_prio();
03324                      fall_thru->type = AEL_APPCALL;
03325                      fall_thru->app = strdup("Goto");
03326                      strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03327                      buf2[sizeof(buf2)-1] = 0; /* just in case */
03328                      substitute_commas(buf2);
03329                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03330                      fall_thru->appargs = strdup(buf1);
03331                      linkprio(switch_case, fall_thru, mother_exten);
03332                   } else if (p2->next && p2->next->type == PV_PATTERN) {
03333                      fall_thru = new_prio();
03334                      fall_thru->type = AEL_APPCALL;
03335                      fall_thru->app = strdup("Goto");
03336                      gen_match_to_pattern(p2->next->u1.str, buf2);
03337                      substitute_commas(buf2);
03338                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03339                      fall_thru->appargs = strdup(buf1);
03340                      linkprio(switch_case, fall_thru, mother_exten);
03341                   } else if (p2->next && p2->next->type == PV_DEFAULT) {
03342                      fall_thru = new_prio();
03343                      fall_thru->type = AEL_APPCALL;
03344                      fall_thru->app = strdup("Goto");
03345                      snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03346                      fall_thru->appargs = strdup(buf1);
03347                      linkprio(switch_case, fall_thru, mother_exten);
03348                   } else if (!p2->next) {
03349                      fall_thru = new_prio();
03350                      fall_thru->type = AEL_CONTROL1;
03351                      fall_thru->goto_true = switch_end;
03352                      fall_thru->app = strdup("Goto");
03353                      linkprio(switch_case, fall_thru, mother_exten);
03354                   }
03355                }
03356                if (switch_case->return_needed) {
03357                   char buf[2000];
03358                   struct ael_priority *np2 = new_prio();
03359                   np2->type = AEL_APPCALL;
03360                   np2->app = strdup("NoOp");
03361                   snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03362                   np2->appargs = strdup(buf);
03363                   linkprio(switch_case, np2, mother_exten);
03364                   switch_case-> return_target = np2;
03365                }
03366             } else if (p2->type == PV_DEFAULT) {
03367                /* ok, generate a extension and link it in */
03368                switch_case = new_exten();
03369                switch_case->context = this_context;
03370                switch_case->is_switch = 1;
03371                
03372                /* new: the default case intros a pattern with ., which covers ALMOST everything.
03373                   but it doesn't cover a NULL pattern. So, we'll define a null extension to match
03374                   that goto's the default extension. */
03375 
03376                default_exists++;
03377                switch_null = new_exten();
03378                switch_null->context = this_context;
03379                switch_null->is_switch = 1;
03380                switch_empty = new_prio();
03381                snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03382                switch_empty->app = strdup("Goto");
03383                switch_empty->appargs = strdup(buf1);
03384                linkprio(switch_null, switch_empty, mother_exten);
03385                snprintf(buf1,sizeof(buf1),"sw-%d-", local_control_statement_count);
03386                switch_null->name = strdup(buf1);
03387                switch_null->loop_break = exten->loop_break;
03388                switch_null->loop_continue = exten->loop_continue;
03389                linkexten(exten,switch_null);
03390 
03391                /* the break/continue locations are inherited from parent */
03392                switch_case->loop_break = exten->loop_break;
03393                switch_case->loop_continue = exten->loop_continue;
03394                linkexten(exten,switch_case);
03395                snprintf(buf1,sizeof(buf1),"_sw-%d-.", local_control_statement_count);
03396                switch_case->name = strdup(buf1);
03397                
03398                snprintf(new_label,sizeof(new_label),"sw-%s-default-%d", label, local_control_statement_count);
03399                
03400                gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the default:  body statements here */
03401                
03402                /* here is where we write code to "fall thru" to the next case... if there is one... */
03403                for (p3=p2->u2.statements; p3; p3=p3->next) {
03404                   if (!p3->next)
03405                      break;
03406                }
03407                /* p3 now points the last statement... */
03408                if (!p3 || (p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03409                   /* is there a following CASE/PATTERN/DEFAULT? */
03410                   if (p2->next && p2->next->type == PV_CASE) {
03411                      fall_thru = new_prio();
03412                      fall_thru->type = AEL_APPCALL;
03413                      fall_thru->app = strdup("Goto");
03414                      strncpy(buf2,p2->next->u1.str,sizeof(buf2));
03415                      buf2[sizeof(buf2)-1] = 0; /* just in case */
03416                      substitute_commas(buf2);
03417                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03418                      fall_thru->appargs = strdup(buf1);
03419                      linkprio(switch_case, fall_thru, mother_exten);
03420                   } else if (p2->next && p2->next->type == PV_PATTERN) {
03421                      fall_thru = new_prio();
03422                      fall_thru->type = AEL_APPCALL;
03423                      fall_thru->app = strdup("Goto");
03424                      gen_match_to_pattern(p2->next->u1.str, buf2);
03425                      substitute_commas(buf2);
03426                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03427                      fall_thru->appargs = strdup(buf1);
03428                      linkprio(switch_case, fall_thru, mother_exten);
03429                   } else if (p2->next && p2->next->type == PV_DEFAULT) {
03430                      fall_thru = new_prio();
03431                      fall_thru->type = AEL_APPCALL;
03432                      fall_thru->app = strdup("Goto");
03433                      snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03434                      fall_thru->appargs = strdup(buf1);
03435                      linkprio(switch_case, fall_thru, mother_exten);
03436                   } else if (!p2->next) {
03437                      fall_thru = new_prio();
03438                      fall_thru->type = AEL_CONTROL1;
03439                      fall_thru->goto_true = switch_end;
03440                      fall_thru->app = strdup("Goto");
03441                      linkprio(switch_case, fall_thru, mother_exten);
03442                   }
03443                }
03444                if (switch_case->return_needed) {
03445                   char buf[2000];
03446                   struct ael_priority *np2 = new_prio();
03447                   np2->type = AEL_APPCALL;
03448                   np2->app = strdup("NoOp");
03449                   snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03450                   np2->appargs = strdup(buf);
03451                   linkprio(switch_case, np2, mother_exten);
03452                   switch_case-> return_target = np2;
03453                }
03454             } else {
03455                /* what could it be??? */
03456             }
03457          }
03458          
03459          exten->loop_break = loop_break_save;
03460          exten->loop_continue = loop_continue_save;
03461          switch_test->origin = p;
03462          switch_end->origin = p;
03463          break;
03464 
03465       case PV_MACRO_CALL:
03466          pr = new_prio();
03467          pr->type = AEL_APPCALL;
03468          snprintf(buf1,sizeof(buf1),"%s", p->u1.str);
03469          for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03470             strcat(buf1,"|");
03471             strcat(buf1,p2->u1.str);
03472          }
03473          pr->app = strdup("Macro");
03474          pr->appargs = strdup(buf1);
03475          pr->origin = p;
03476          linkprio(exten, pr, mother_exten);
03477          break;
03478 
03479       case PV_APPLICATION_CALL:
03480          pr = new_prio();
03481          pr->type = AEL_APPCALL;
03482          buf1[0] = 0;
03483          for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03484             if (p2 != p->u2.arglist )
03485                strcat(buf1,"|");
03486             substitute_commas(p2->u1.str);
03487             strcat(buf1,p2->u1.str);
03488          }
03489          pr->app = strdup(p->u1.str);
03490          pr->appargs = strdup(buf1);
03491          pr->origin = p;
03492          linkprio(exten, pr, mother_exten);
03493          break;
03494 
03495       case PV_BREAK:
03496          pr = new_prio();
03497          pr->type = AEL_CONTROL1; /* simple goto */
03498          pr->goto_true = exten->loop_break;
03499          pr->origin = p;
03500          linkprio(exten, pr, mother_exten);
03501          break;
03502 
03503       case PV_RETURN: /* hmmmm */
03504          pr = new_prio();
03505          pr->type = AEL_RETURN; /* simple goto */
03506          exten->return_needed++;
03507          pr->app = strdup("Goto");
03508          pr->appargs = strdup("");
03509          pr->origin = p;
03510          linkprio(exten, pr, mother_exten);
03511          break;
03512 
03513       case PV_CONTINUE:
03514          pr = new_prio();
03515          pr->type = AEL_CONTROL1; /* simple goto */
03516          pr->goto_true = exten->loop_continue;
03517          pr->origin = p;
03518          linkprio(exten, pr, mother_exten);
03519          break;
03520 
03521 #ifdef OLD_RAND_ACTION
03522       case PV_RANDOM:
03523          control_statement_count++;
03524          snprintf(new_label,sizeof(new_label),"rand-%s-%d", label, control_statement_count);
03525          rand_test = new_prio();
03526          rand_test->type = AEL_RAND_CONTROL;
03527          snprintf(buf1,sizeof(buf1),"$[%s]",
03528                 p->u1.str );
03529          rand_test->app = 0;
03530          rand_test->appargs = strdup(buf1);
03531          rand_test->origin = p;
03532          
03533          rand_end = new_prio();
03534          rand_end->type = AEL_APPCALL;
03535          snprintf(buf1,sizeof(buf1),"Finish rand-%s-%d", label, control_statement_count);
03536          rand_end->app = strdup("NoOp");
03537          rand_end->appargs = strdup(buf1);
03538          
03539          rand_skip = new_prio();
03540          rand_skip->type = AEL_CONTROL1; /* simple goto */
03541          rand_skip->goto_true = rand_end;
03542          rand_skip->origin  = p;
03543 
03544          rand_test->goto_true = rand_skip; /* +1, really */
03545 
03546          linkprio(exten, rand_test, mother_exten);
03547          
03548          if (p->u3.else_statements) {
03549             gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the else statements here */
03550          }
03551          
03552          linkprio(exten, rand_skip, mother_exten);
03553          
03554          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the "true" statements here */
03555 
03556          linkprio(exten, rand_end, mother_exten);
03557          
03558          break;
03559 #endif         
03560 
03561       case PV_IFTIME:
03562          control_statement_count++;
03563          snprintf(new_label,sizeof(new_label),"iftime-%s-%d", label, control_statement_count);
03564          
03565          if_test = new_prio();
03566          if_test->type = AEL_IFTIME_CONTROL;
03567          snprintf(buf1,sizeof(buf1),"%s|%s|%s|%s",
03568                 p->u1.list->u1.str, 
03569                 p->u1.list->next->u1.str, 
03570                 p->u1.list->next->next->u1.str, 
03571                 p->u1.list->next->next->next->u1.str);
03572          if_test->app = 0;
03573          if_test->appargs = strdup(buf1);
03574          if_test->origin = p;
03575 
03576          if_end = new_prio();
03577          if_end->type = AEL_APPCALL;
03578          snprintf(buf1,sizeof(buf1),"Finish iftime-%s-%d", label, control_statement_count);
03579          if_end->app = strdup("NoOp");
03580          if_end->appargs = strdup(buf1);
03581 
03582          if (p->u3.else_statements) {
03583             if_skip = new_prio();
03584             if_skip->type = AEL_CONTROL1; /* simple goto */
03585             if_skip->goto_true = if_end;
03586             if_skip->origin  = p;
03587 
03588          } else {
03589             if_skip = 0;
03590 
03591             if_test->goto_false = if_end;
03592          }
03593 
03594          if_false = new_prio();
03595          if_false->type = AEL_CONTROL1;
03596          if (p->u3.else_statements) {
03597             if_false->goto_true = if_skip; /* +1 */
03598          } else {
03599             if_false->goto_true = if_end;
03600          }
03601          
03602          /* link & load! */
03603          linkprio(exten, if_test, mother_exten);
03604          linkprio(exten, if_false, mother_exten);
03605          
03606          /* now, put the body of the if here */
03607          
03608          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the statements here */
03609          
03610          if (p->u3.else_statements) {
03611             linkprio(exten, if_skip, mother_exten);
03612             gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the statements here */
03613 
03614          }
03615          
03616          linkprio(exten, if_end, mother_exten);
03617          
03618          break;
03619 
03620       case PV_RANDOM:
03621       case PV_IF:
03622          control_statement_count++;
03623          snprintf(new_label,sizeof(new_label),"if-%s-%d", label, control_statement_count);
03624          
03625          if_test = new_prio();
03626          if_end = new_prio();
03627          if_test->type = AEL_IF_CONTROL;
03628          if_end->type = AEL_APPCALL;
03629          if ( p->type == PV_RANDOM )
03630             snprintf(buf1,sizeof(buf1),"$[${RAND(0,99)} < (%s)]",p->u1.str);
03631          else
03632             snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str);
03633          if_test->app = 0;
03634          if_test->appargs = strdup(buf1);
03635          snprintf(buf1,sizeof(buf1),"Finish if-%s-%d", label, control_statement_count);
03636          if_end->app = strdup("NoOp");
03637          if_end->appargs = strdup(buf1);
03638          if_test->origin = p;
03639          
03640          if (p->u3.else_statements) {
03641             if_skip = new_prio();
03642             if_skip->type = AEL_CONTROL1; /* simple goto */
03643             if_skip->goto_true = if_end;
03644             if_test->goto_false = if_skip;;
03645          } else {
03646             if_skip = 0;
03647             if_test->goto_false = if_end;;
03648          }
03649          
03650          /* link & load! */
03651          linkprio(exten, if_test, mother_exten);
03652          
03653          /* now, put the body of the if here */
03654          
03655          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the statements here */
03656          
03657          if (p->u3.else_statements) {
03658             linkprio(exten, if_skip, mother_exten);
03659             gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the statements here */
03660 
03661          }
03662          
03663          linkprio(exten, if_end, mother_exten);
03664          
03665          break;
03666 
03667       case PV_STATEMENTBLOCK:
03668          gen_prios(exten, label, p->u1.list, mother_exten, this_context ); /* recurse into the block */
03669          break;
03670 
03671       case PV_CATCH:
03672          control_statement_count++;
03673          /* generate an extension with name of catch, put all catch stats
03674             into this exten! */
03675          switch_case = new_exten();
03676          switch_case->context = this_context;
03677          linkexten(exten,switch_case);
03678          switch_case->name = strdup(p->u1.str);
03679          snprintf(new_label,sizeof(new_label),"catch-%s-%d",p->u1.str, control_statement_count);
03680          
03681          gen_prios(switch_case, new_label, p->u2.statements,mother_exten,this_context); /* this will link in all the catch body statements here */
03682          if (switch_case->return_needed) {
03683             char buf[2000];
03684             struct ael_priority *np2 = new_prio();
03685             np2->type = AEL_APPCALL;
03686             np2->app = strdup("NoOp");
03687             snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03688             np2->appargs = strdup(buf);
03689             linkprio(switch_case, np2, mother_exten);
03690             switch_case-> return_target = np2;
03691          }
03692 
03693          break;
03694       default:
03695          break;
03696       }
03697    }
03698 }

static pval * get_contxt ( pval p  )  [static]

Definition at line 3859 of file pbx_ael.c.

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

Referenced by check_goto(), and get_goto_target().

03860 {
03861    while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
03862       
03863       p = p->dad;
03864    }
03865    
03866    return p;
03867 }

static pval * get_extension_or_contxt ( pval p  )  [static]

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

03850 {
03851    while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
03852       
03853       p = p->dad;
03854    }
03855    
03856    return p;
03857 }

static pval * get_goto_target ( pval item  )  [static]

Definition at line 1122 of file pbx_ael.c.

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

Referenced by gen_prios().

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

int is_empty ( char *  arg  ) 

Definition at line 1913 of file pbx_ael.c.

01914 {
01915    if (!arg)
01916       return 1;
01917    if (*arg == 0)
01918       return 1;
01919    while (*arg) {
01920       if (*arg != ' ' && *arg != '\t')
01921          return 0;
01922       arg++;
01923    }
01924    return 1;
01925 }

int is_float ( char *  arg  ) 

Definition at line 1895 of file pbx_ael.c.

References s.

01896 {
01897    char *s;
01898    for (s=arg; *s; s++) {
01899       if (*s != '.' && (*s < '0' || *s > '9'))
01900          return 0;
01901    }
01902    return 1;
01903 }

int is_int ( char *  arg  ) 

Definition at line 1904 of file pbx_ael.c.

References s.

01905 {
01906    char *s;
01907    for (s=arg; *s; s++) {
01908       if (*s < '0' || *s > '9')
01909          return 0;
01910    }
01911    return 1;
01912 }

static int label_inside_case ( pval label  )  [static]

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

02862 {
02863    pval *p = label;
02864    
02865    while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
02866       if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN ) {
02867          return 1;
02868       }
02869 
02870       p = p->dad;
02871    }
02872    return 0;
02873 }

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

Definition at line 2875 of file pbx_ael.c.

References exten, and ael_extension::next_exten.

Referenced by gen_prios().

02876 {
02877    add->next_exten = exten->next_exten; /* this will reverse the order. Big deal. */
02878    exten->next_exten = add;
02879 }

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

Definition at line 2779 of file pbx_ael.c.

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

Referenced by gen_prios().

02780 {
02781    char *p1, *p2;
02782    
02783    if (!exten->plist) {
02784       exten->plist = prio;
02785       exten->plist_last = prio;
02786    } else {
02787       exten->plist_last->next = prio;
02788       exten->plist_last = prio;
02789    }
02790    if( !prio->exten )
02791       prio->exten = exten; /* don't override the switch value */
02792    /* The following code will cause all priorities within an extension 
02793       to have ${EXTEN} or ${EXTEN: replaced with ~~EXTEN~~, which is
02794       set just before the first switch in an exten. The switches
02795       will muck up the original ${EXTEN} value, so we save it away
02796       and the user accesses this copy instead. */
02797    if (prio->appargs && ((mother_exten && mother_exten->has_switch) || exten->has_switch) ) {
02798       while ((p1 = strstr(prio->appargs, "${EXTEN}"))) {
02799          p2 = malloc(strlen(prio->appargs)+5);
02800          *p1 = 0;
02801          strcpy(p2, prio->appargs);
02802          strcat(p2, "${~~EXTEN~~}");
02803          if (*(p1+8))
02804             strcat(p2, p1+8);
02805          free(prio->appargs);
02806          prio->appargs = p2;
02807       }
02808       while ((p1 = strstr(prio->appargs, "${EXTEN:"))) {
02809          p2 = malloc(strlen(prio->appargs)+5);
02810          *p1 = 0;
02811          strcpy(p2, prio->appargs);
02812          strcat(p2, "${~~EXTEN~~:");
02813          if (*(p1+8))
02814             strcat(p2, p1+8);
02815          free(prio->appargs);
02816          prio->appargs = p2;
02817       }
02818    }
02819 }

static int load_module ( void   )  [static]

Definition at line 4237 of file pbx_ael.c.

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

04238 {
04239    ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04240    return (pbx_load_module());
04241 }

struct pval * match_pval ( pval item  ) 

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

01737 {
01738    pval *i;
01739 
01740    for (i=item; i; i=i->next) {
01741       pval *x;
01742       /* printf("   -- match pval: item %d\n", i->type); */
01743       
01744       if ((x = match_pval_item(i))) {
01745          /* printf("match_pval: returning x=%x\n", (int)x); */
01746          return x; /* cut the search short */
01747       }
01748    }
01749    return 0;
01750 }

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

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

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

struct ael_extension * new_exten ( void   ) 

Definition at line 2773 of file pbx_ael.c.

References calloc.

Referenced by gen_prios().

02774 {
02775    struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
02776    return x;
02777 }

struct ael_priority * new_prio ( void   ) 

Definition at line 2767 of file pbx_ael.c.

References calloc.

Referenced by gen_prios().

02768 {
02769    struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
02770    return x;
02771 }

static int pbx_load_module ( void   )  [static]

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

04125 {
04126    int errs=0, sem_err=0, sem_warn=0, sem_note=0;
04127    char *rfilename;
04128    struct ast_context *local_contexts=NULL, *con;
04129    struct pval *parse_tree;
04130 
04131    ast_log(LOG_NOTICE, "Starting AEL load process.\n");
04132    if (config[0] == '/')
04133       rfilename = (char *)config;
04134    else {
04135       rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
04136       sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
04137    }
04138    ast_log(LOG_NOTICE, "AEL load process: calculated config file name '%s'.\n", rfilename);
04139 
04140    if (access(rfilename,R_OK) != 0) {
04141       ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
04142       return AST_MODULE_LOAD_DECLINE;
04143    }
04144    
04145    parse_tree = ael2_parse(rfilename, &errs);
04146    ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
04147    ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
04148    if (errs == 0 && sem_err == 0) {
04149       ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
04150       ast_compile_ael2(&local_contexts, parse_tree);
04151       ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
04152       
04153       ast_merge_contexts_and_delete(&local_contexts, registrar);
04154       ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
04155       for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
04156          ast_context_verify_includes(con);
04157       ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
04158    } else {
04159       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);
04160       destroy_pval(parse_tree); /* free up the memory */
04161       return AST_MODULE_LOAD_DECLINE;
04162    }
04163    destroy_pval(parse_tree); /* free up the memory */
04164    
04165    return AST_MODULE_LOAD_SUCCESS;
04166 }

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

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

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

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

Definition at line 428 of file pbx_ael.c.

References pval::next, and print_pval().

00429 {
00430    pval *i;
00431    
00432    for (i=item; i; i=i->next) {
00433       print_pval(fin, i, depth);
00434    }
00435 }

static int reload ( void   )  [static]

Definition at line 4243 of file pbx_ael.c.

References pbx_load_module().

04244 {
04245    return pbx_load_module();
04246 }

static void remove_spaces_before_equals ( char *  str  )  [static]

Definition at line 2881 of file pbx_ael.c.

Referenced by gen_prios().

02882 {
02883    char *p;
02884    while( str && *str && *str != '=' )
02885    {
02886       if( *str == ' ' || *str == '\n' || *str == '\r' || *str == '\t' )
02887       {
02888          p = str;
02889          while( *p )
02890          {
02891             *p = *(p+1);
02892             p++;
02893          }
02894       }
02895       else
02896          str++;
02897    }
02898 }

void set_priorities ( struct ael_extension exten  ) 

Definition at line 3700 of file pbx_ael.c.

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

03701 {
03702    int i;
03703    struct ael_priority *pr;
03704    do {
03705       if (exten->is_switch)
03706          i = 10;
03707       else if (exten->regexten)
03708          i=2;
03709       else
03710          i=1;
03711       
03712       for (pr=exten->plist; pr; pr=pr->next) {
03713          pr->priority_num = i;
03714          
03715          if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
03716                                       but we want them to point to the right
03717                                       priority, which would be the next line
03718                                       after the label; */
03719             i++;
03720       }
03721       
03722       exten = exten->next_exten;
03723    } while ( exten );
03724 }

static void substitute_commas ( char *  str  )  [static]

Definition at line 151 of file pbx_ael.c.

Referenced by gen_prios().

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

void traverse_pval_item_template ( pval item,
int  depth 
)

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

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

void traverse_pval_template ( pval item,
int  depth 
)

Definition at line 690 of file pbx_ael.c.

References pval::next, and traverse_pval_item_template().

00692 {
00693    pval *i;
00694    
00695    for (i=item; i; i=i->next) {
00696       traverse_pval_item_template(i, depth);
00697    }
00698 }

static int unload_module ( void   )  [static]

Definition at line 4230 of file pbx_ael.c.

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

04231 {
04232    ast_context_destroy(NULL, registrar);
04233    ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04234    return 0;
04235 }


Variable Documentation

int aeldebug = 0 [static]

Definition at line 4118 of file pbx_ael.c.

struct ast_cli_entry cli_ael[] [static]

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

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

Definition at line 60 of file pbx_ael.c.

int control_statement_count = 0 [static]

Definition at line 2765 of file pbx_ael.c.

Referenced by gen_prios().

int count_labels [static]

Definition at line 120 of file pbx_ael.c.

pval* current_context = 0 [static]

Definition at line 113 of file pbx_ael.c.

Referenced by check_label(), and check_pval_item().

pval* current_db = 0 [static]

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

Referenced by check_label(), and check_pval_item().

char* days[] [static]

Definition at line 903 of file pbx_ael.c.

int errs [static]

Definition at line 64 of file pbx_ael.c.

char expr_output[2096] [static]

Definition at line 51 of file pbx_ael.c.

int in_abstract_context [static]

Definition at line 119 of file pbx_ael.c.

int label_count [static]

Definition at line 121 of file pbx_ael.c.

pval* last_matched_label [static]

Definition at line 123 of file pbx_ael.c.

Referenced by match_pval_item().

const char* match_context [static]

Definition at line 116 of file pbx_ael.c.

const char* match_exten [static]

Definition at line 117 of file pbx_ael.c.

const char* match_label [static]

Definition at line 118 of file pbx_ael.c.

char* months[] [static]

Definition at line 1001 of file pbx_ael.c.

int notes [static]

Definition at line 65 of file pbx_ael.c.

char* registrar = "pbx_ael" [static]

Definition at line 61 of file pbx_ael.c.

Referenced by ast_autoanswer_login(), autoanswer_reregister_extensions(), do_autoanswer_thread(), park_add_hints(), pbx_load_module(), and pbx_load_users().

int return_on_context_match [static]

Definition at line 122 of file pbx_ael.c.

int warns [static]

Definition at line 64 of file pbx_ael.c.


Generated on Sat Jul 26 06:14:22 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1