Fri Aug 24 02:27:07 2007

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)
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
static pvalcurrent_db
static pvalcurrent_extension
static char * days []
static int errs
static char expr_output [2096]
static int in_abstract_context
static int label_count
static pvallast_matched_label
static const char * match_context
static const char * match_exten
static const char * match_label
static char * months []
static int notes
static char * registrar = "pbx_ael"
static int return_on_context_match
static int warns


Detailed Description

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

Definition in file 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 3567 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.

03568 {
03569    struct ael_priority *pr;
03570    char *label=0;
03571    char realext[AST_MAX_EXTENSION];
03572    if (!exten) {
03573       ast_log(LOG_WARNING, "This file is Empty!\n" );
03574       return;
03575    }
03576    do {
03577       struct ael_priority *last = 0;
03578 
03579       memset(realext, '\0', sizeof(realext));
03580       pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
03581       if (exten->hints) {
03582          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, 
03583                           exten->hints, NULL, ast_free, registrar)) {
03584             ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
03585                   exten->name);
03586          }
03587       }
03588       
03589       for (pr=exten->plist; pr; pr=pr->next) {
03590          char app[2000];
03591          char appargs[2000];
03592 
03593          /* before we can add the extension, we need to prep the app/appargs;
03594             the CONTROL types need to be done after the priority numbers are calculated.
03595          */
03596          if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
03597             last = pr;
03598             continue;
03599          }
03600          
03601          if (pr->app)
03602             strcpy(app, pr->app);
03603          else
03604             app[0] = 0;
03605          if (pr->appargs )
03606             strcpy(appargs, pr->appargs);
03607          else
03608             appargs[0] = 0;
03609          switch( pr->type ) {
03610          case AEL_APPCALL:
03611             /* easy case. Everything is all set up */
03612             break;
03613             
03614          case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
03615             /* simple, unconditional goto. */
03616             strcpy(app,"Goto");
03617             if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
03618                snprintf(appargs,sizeof(appargs),"%s|%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
03619             } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
03620                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
03621             } else
03622                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
03623             break;
03624             
03625          case AEL_FOR_CONTROL:  /* WHILE loop test, FOR loop test */
03626             strcpy(app,"GotoIf");
03627             snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
03628             break;
03629             
03630          case AEL_IF_CONTROL:
03631             strcpy(app,"GotoIf");
03632             if (pr->origin->u3.else_statements )
03633                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
03634             else
03635                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
03636             break;
03637 
03638          case AEL_RAND_CONTROL:
03639             strcpy(app,"Random");
03640             snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
03641             break;
03642 
03643          case AEL_IFTIME_CONTROL:
03644             strcpy(app,"GotoIfTime");
03645             snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
03646             break;
03647 
03648          case AEL_RETURN:
03649             strcpy(app,"Goto");
03650             snprintf(appargs,sizeof(appargs), "%d", exten->return_target->priority_num);
03651             break;
03652             
03653          default:
03654             break;
03655          }
03656          if (last && last->type == AEL_LABEL ) {
03657             label = last->origin->u1.str;
03658          }
03659          else
03660             label = 0;
03661          
03662          if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, 
03663                           app, strdup(appargs), ast_free, registrar)) {
03664             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, 
03665                   exten->name);
03666          }
03667          last = pr;
03668       }
03669       exten = exten->next_exten;
03670    } while ( exten );
03671 }

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

Definition at line 4034 of file pbx_ael.c.

References DEBUG_CONTEXTS.

04035 {
04036    aeldebug |= DEBUG_CONTEXTS;
04037    return 0;
04038 }

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

Definition at line 4028 of file pbx_ael.c.

References DEBUG_MACROS.

04029 {
04030    aeldebug |= DEBUG_MACROS;
04031    return 0;
04032 }

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

Definition at line 4016 of file pbx_ael.c.

References DEBUG_READ.

04017 {
04018    aeldebug |= DEBUG_READ;
04019    return 0;
04020 }

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

Definition at line 4022 of file pbx_ael.c.

References DEBUG_TOKENS.

04023 {
04024    aeldebug |= DEBUG_TOKENS;
04025    return 0;
04026 }

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

Definition at line 4040 of file pbx_ael.c.

04041 {
04042    aeldebug = 0;
04043    return 0;
04044 }

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

Definition at line 4046 of file pbx_ael.c.

References pbx_load_module().

04047 {
04048    return (pbx_load_module());
04049 }

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

Definition at line 2727 of file pbx_ael.c.

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

Referenced by pbx_load_module().

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

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

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

03755 {
03756    pval *p,*p2;
03757    struct ast_context *context;
03758    char buf[2000];
03759    struct ael_extension *exten;
03760    struct ael_extension *exten_list = 0;
03761 
03762    for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there
03763                             when we try to eval them */
03764       switch (p->type) {
03765       case PV_GLOBALS:
03766          /* just VARDEC elements */
03767          for (p2=p->u1.list; p2; p2=p2->next) {
03768             char buf2[2000];
03769             snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
03770             pbx_builtin_setvar(NULL, buf2);
03771          }
03772          break;
03773       default:
03774          break;
03775       }
03776    }
03777    
03778    for (p=root; p; p=p->next ) {
03779       pval *lp;
03780       int argc;
03781       
03782       switch (p->type) {
03783       case PV_MACRO:
03784          strcpy(buf,"macro-");
03785          strcat(buf,p->u1.str);
03786          context = ast_context_create(local_contexts, buf, registrar);
03787          
03788          exten = new_exten();
03789          exten->context = context;
03790          exten->name = strdup("s");
03791          argc = 1;
03792          for (lp=p->u2.arglist; lp; lp=lp->next) {
03793             /* for each arg, set up a "Set" command */
03794             struct ael_priority *np2 = new_prio();
03795             np2->type = AEL_APPCALL;
03796             np2->app = strdup("Set");
03797             snprintf(buf,sizeof(buf),"%s=${ARG%d}", lp->u1.str, argc++);
03798             remove_spaces_before_equals(buf);
03799             np2->appargs = strdup(buf);
03800             linkprio(exten, np2);
03801          }
03802          /* add any includes */
03803          for (p2=p->u3.macro_statements; p2; p2=p2->next) {
03804             pval *p3;
03805             
03806             switch (p2->type) {
03807             case PV_INCLUDES:
03808                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
03809                   if ( p3->u2.arglist ) {
03810                      snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s", 
03811                             p3->u1.str,
03812                             p3->u2.arglist->u1.str,
03813                             p3->u2.arglist->next->u1.str,
03814                             p3->u2.arglist->next->next->u1.str,
03815                             p3->u2.arglist->next->next->next->u1.str);
03816                      ast_context_add_include2(context, buf, registrar);
03817                   } else
03818                      ast_context_add_include2(context, p3->u1.str, registrar);
03819                }
03820                break;
03821             default:
03822                break;
03823             }
03824          }
03825          /* CONTAINS APPCALLS, CATCH, just like extensions... */
03826          gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context );
03827          if (exten->return_needed) {
03828             struct ael_priority *np2 = new_prio();
03829             np2->type = AEL_APPCALL;
03830             np2->app = strdup("NoOp");
03831             snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
03832             np2->appargs = strdup(buf);
03833             linkprio(exten, np2);
03834             exten-> return_target = np2;
03835          }
03836          
03837          set_priorities(exten);
03838          attach_exten(&exten_list, exten);
03839          break;
03840          
03841       case PV_GLOBALS:
03842          /* already done */
03843          break;
03844          
03845       case PV_CONTEXT:
03846          context = ast_context_create(local_contexts, p->u1.str, registrar);
03847          
03848          /* contexts contain: ignorepat, includes, switches, eswitches, extensions,  */
03849          for (p2=p->u2.statements; p2; p2=p2->next) {
03850             pval *p3;
03851             char *s3;
03852             
03853             switch (p2->type) {
03854             case PV_EXTENSION:
03855                exten = new_exten();
03856                exten->name = strdup(p2->u1.str);
03857                exten->context = context;
03858                
03859                if( (s3=strchr(exten->name, '/') ) != 0 )
03860                {
03861                   *s3 = 0;
03862                   exten->cidmatch = s3+1;
03863                }
03864                
03865                if ( p2->u3.hints )
03866                   exten->hints = strdup(p2->u3.hints);
03867                exten->regexten = p2->u4.regexten;
03868                gen_prios(exten, p->u1.str, p2->u2.statements, 0, context );
03869                if (exten->return_needed) {
03870                   struct ael_priority *np2 = new_prio();
03871                   np2->type = AEL_APPCALL;
03872                   np2->app = strdup("NoOp");
03873                   snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
03874                   np2->appargs = strdup(buf);
03875                   linkprio(exten, np2);
03876                   exten-> return_target = np2;
03877                }
03878                /* is the last priority in the extension a label? Then add a trailing no-op */
03879                if( !exten->plist_last )
03880                {
03881                   ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Empty Extension!\n",
03882                         p2->filename, p2->startline, p2->endline);
03883                }
03884                
03885                if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
03886                   struct ael_priority *np2 = new_prio();
03887                   np2->type = AEL_APPCALL;
03888                   np2->app = strdup("NoOp");
03889                   snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
03890                   np2->appargs = strdup(buf);
03891                   linkprio(exten, np2);
03892                }
03893 
03894                set_priorities(exten);
03895                attach_exten(&exten_list, exten);
03896                break;
03897                
03898             case PV_IGNOREPAT:
03899                ast_context_add_ignorepat2(context, p2->u1.str, registrar);
03900                break;
03901                
03902             case PV_INCLUDES:
03903                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
03904                   if ( p3->u2.arglist ) {
03905                      snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s", 
03906                             p3->u1.str,
03907                             p3->u2.arglist->u1.str,
03908                             p3->u2.arglist->next->u1.str,
03909                             p3->u2.arglist->next->next->u1.str,
03910                             p3->u2.arglist->next->next->next->u1.str);
03911                      ast_context_add_include2(context, buf, registrar);
03912                   } else
03913                      ast_context_add_include2(context, p3->u1.str, registrar);
03914                }
03915                break;
03916                
03917             case PV_SWITCHES:
03918                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
03919                   char *c = strchr(p3->u1.str, '/');
03920                   if (c) {
03921                      *c = '\0';
03922                      c++;
03923                   } else
03924                      c = "";
03925 
03926                   ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
03927                }
03928                break;
03929 
03930             case PV_ESWITCHES:
03931                for (p3 = p2->u1.list; p3 ;p3=p3->next) {
03932                   char *c = strchr(p3->u1.str, '/');
03933                   if (c) {
03934                      *c = '\0';
03935                      c++;
03936                   } else
03937                      c = "";
03938 
03939                   ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
03940                }
03941                break;
03942             default:
03943                break;
03944             }
03945          }
03946          
03947          break;
03948          
03949       default:
03950          /* huh? what? */
03951          break;
03952          
03953       }
03954    }
03955    /* moved these from being done after a macro or extension were processed,
03956       to after all processing is done, for the sake of fixing gotos to labels inside cases... */
03957    /* I guess this would be considered 2nd pass of compiler now... */
03958    fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */
03959    add_extensions(exten_list);   /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */
03960    destroy_extensions(exten_list);  /* all that remains is an empty husk, discard of it as is proper */
03961    
03962 }

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

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

03123 {
03124    struct parse_io io;
03125    int return_value = 0;
03126    
03127    memset(&io, 0, sizeof(io));
03128    io.string = expr;  /* to pass to the error routine */
03129    
03130    ast_yylex_init(&io.scanner);
03131    
03132    ast_yy_scan_string(expr, io.scanner);
03133    
03134    ast_yyparse ((void *) &io);
03135 
03136    ast_yylex_destroy(io.scanner);
03137 
03138    if (!io.val) {
03139       if (length > 1) {
03140          strcpy(buf, "0");
03141          return_value = 1;
03142       }
03143    } else {
03144       if (io.val->type == AST_EXPR_integer) {
03145          int res_length;
03146 
03147          res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i);
03148          return_value = (res_length <= length) ? res_length : length;
03149       } else {
03150 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL)
03151          strncpy(buf, io.val->u.s, length - 1);
03152 #else /* !STANDALONE && !LOW_MEMORY */
03153          ast_copy_string(buf, io.val->u.s, length);
03154 #endif /* STANDALONE || LOW_MEMORY */
03155          return_value = strlen(buf);
03156          free(io.val->u.s);
03157       }
03158       free(io.val);
03159    }
03160    return return_value;
03161 }

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

References ael_extension::next_exten.

03674 {
03675    /* travel to the end of the list... */
03676    struct ael_extension *lptr;
03677    if( !*list ) {
03678       *list = newmem;
03679       return;
03680    }
03681    lptr = *list;
03682    
03683    while( lptr->next_exten ) {
03684       lptr = lptr->next_exten;
03685    }
03686    /* lptr should now pointing to the last element in the list; it has a null next_exten pointer */
03687    lptr->next_exten = newmem;
03688 }

static void check_abstract_reference ( pval abstract_context  )  [static]

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

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

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

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

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

static int check_break ( pval item  )  [static]

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

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

static void check_context_names ( void   )  [static]

Definition at line 2241 of file pbx_ael.c.

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

Referenced by ael2_semantic_check().

02242 {
02243    pval *i,*j;
02244    for (i=current_db; i; i=i->next) {
02245       if (i->type == PV_CONTEXT || i->type == PV_MACRO) {
02246          for (j=i->next; j; j=j->next) {
02247             if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) {
02248                if ( !strcmp(i->u1.str, j->u1.str) )
02249                {
02250                   ast_log(LOG_ERROR,"Error: file %s, line %d-%d: The context name (%s) is also declared in file %s, line %d-%d!\n",
02251                         i->filename, i->startline, i->endline, i->u1.str,  j->filename, j->startline, j->endline);
02252                   errs++;
02253                }
02254             }
02255          }
02256       }
02257    }
02258 }

static int check_continue ( pval item  )  [static]

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

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

static void check_day ( pval DAY  )  [static]

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

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

static void check_dow ( pval DOW  )  [static]

get_dow: Get day of week

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

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

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

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

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                includes->filename, includes->startline, includes->endline, incl_context);
00840          warns++;
00841       }
00842    }
00843 }

static void check_label ( pval item  )  [static]

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

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

static void check_month ( pval MON  )  [static]

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

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

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

Definition at line 2707 of file pbx_ael.c.

References check_pval_item(), and pval::next.

Referenced by ael2_semantic_check(), and check_pval_item().

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

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

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

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

void check_switch_expr ( pval item,
struct argapp apps 
)

Definition at line 2115 of file pbx_ael.c.

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

Referenced by check_pval_item().

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

static void check_timerange ( pval p  )  [static]

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

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

void destroy_extensions ( struct ael_extension exten  ) 

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

02790 {
02791    struct ael_extension *ne, *nen;
02792    for (ne=exten; ne; ne=nen) {
02793       struct ael_priority *pe, *pen;
02794       
02795       if (ne->name)
02796          free(ne->name);
02797       
02798       /* cidmatch fields are allocated with name, and freed when
02799          the name field is freed. Don't do a free for this field,
02800          unless you LIKE to see a crash! */
02801 
02802       if (ne->hints)
02803          free(ne->hints);
02804       
02805       for (pe=ne->plist; pe; pe=pen) {
02806          pen = pe->next;
02807          if (pe->app)
02808             free(pe->app);
02809          pe->app = 0;
02810          if (pe->appargs)
02811             free(pe->appargs);
02812          pe->appargs = 0;
02813          pe->origin = 0;
02814          pe->goto_true = 0;
02815          pe->goto_false = 0;
02816          free(pe);
02817       }
02818       nen = ne->next_exten;
02819       ne->next_exten = 0;
02820       ne->plist =0;
02821       ne->plist_last = 0;
02822       ne->next_exten = 0;
02823       ne->loop_break = 0;
02824       ne->loop_continue = 0;
02825       free(ne);
02826    }
02827 }

void destroy_pval ( pval item  ) 

void destroy_pval_item ( pval item  ) 

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

04117 {
04118    if (item == NULL) {
04119       ast_log(LOG_WARNING, "null item\n");
04120       return;
04121    }
04122 
04123    if (item->filename)
04124       free(item->filename);
04125    
04126    switch (item->type) {
04127    case PV_WORD:
04128       /* fields: item->u1.str == string associated with this (word). */
04129       if (item->u1.str )
04130          free(item->u1.str);
04131       if ( item->u2.arglist )
04132          destroy_pval(item->u2.arglist);
04133       break;
04134       
04135    case PV_MACRO:
04136       /* fields: item->u1.str     == name of macro
04137                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
04138                item->u2.arglist->u1.str  == argument
04139                item->u2.arglist->next   == next arg
04140 
04141                item->u3.macro_statements == pval list of statements in macro body.
04142       */
04143       destroy_pval(item->u2.arglist);
04144       if (item->u1.str )
04145          free(item->u1.str);
04146       destroy_pval(item->u3.macro_statements);
04147       break;
04148          
04149    case PV_CONTEXT:
04150       /* fields: item->u1.str     == name of context
04151                  item->u2.statements == pval list of statements in context body
04152                item->u3.abstract == int 1 if an abstract keyword were present
04153       */
04154       if (item->u1.str)
04155          free(item->u1.str);
04156       destroy_pval(item->u2.statements);
04157       break;
04158          
04159    case PV_MACRO_CALL:
04160       /* fields: item->u1.str     == name of macro to call
04161                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04162                item->u2.arglist->u1.str  == argument
04163                item->u2.arglist->next   == next arg
04164       */
04165       if (item->u1.str)
04166          free(item->u1.str);
04167       destroy_pval(item->u2.arglist);
04168       break;
04169          
04170    case PV_APPLICATION_CALL:
04171       /* fields: item->u1.str     == name of application to call
04172                  item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
04173                item->u2.arglist->u1.str  == argument
04174                item->u2.arglist->next   == next arg
04175       */
04176       if (item->u1.str)
04177          free(item->u1.str);
04178       destroy_pval(item->u2.arglist);
04179       break;
04180          
04181    case PV_CASE:
04182       /* fields: item->u1.str     == value of case
04183                  item->u2.statements == pval list of statements under the case
04184       */
04185       if (item->u1.str)
04186          free(item->u1.str);
04187       destroy_pval(item->u2.statements);
04188       break;
04189          
04190    case PV_PATTERN:
04191       /* fields: item->u1.str     == value of case
04192                  item->u2.statements == pval list of statements under the case
04193       */
04194       if (item->u1.str)
04195          free(item->u1.str);
04196       destroy_pval(item->u2.statements);
04197       break;
04198          
04199    case PV_DEFAULT:
04200       /* fields: 
04201                  item->u2.statements == pval list of statements under the case
04202       */
04203       destroy_pval(item->u2.statements);
04204       break;
04205          
04206    case PV_CATCH:
04207       /* fields: item->u1.str     == name of extension to catch
04208                  item->u2.statements == pval list of statements in context body
04209       */
04210       if (item->u1.str)
04211          free(item->u1.str);
04212       destroy_pval(item->u2.statements);
04213       break;
04214          
04215    case PV_SWITCHES:
04216       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04217       */
04218       destroy_pval(item->u1.list);
04219       break;
04220          
04221    case PV_ESWITCHES:
04222       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04223       */
04224       destroy_pval(item->u1.list);
04225       break;
04226          
04227    case PV_INCLUDES:
04228       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
04229                  item->u2.arglist  == pval list of 4 PV_WORD elements for time values
04230       */
04231       destroy_pval(item->u1.list);
04232       break;
04233          
04234    case PV_STATEMENTBLOCK:
04235       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
04236       */
04237       destroy_pval(item->u1.list);
04238       break;
04239          
04240    case PV_VARDEC:
04241       /* fields: item->u1.str     == variable name
04242                  item->u2.val     == variable value to assign
04243       */
04244       if (item->u1.str)
04245          free(item->u1.str);
04246       if (item->u2.val)
04247          free(item->u2.val);
04248       break;
04249          
04250    case PV_GOTO:
04251       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
04252                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
04253       */
04254       
04255       destroy_pval(item->u1.list);
04256       break;
04257          
04258    case PV_LABEL:
04259       /* fields: item->u1.str     == label name
04260       */
04261       if (item->u1.str)
04262          free(item->u1.str);
04263       break;
04264          
04265    case PV_FOR:
04266       /* fields: item->u1.for_init     == a string containing the initalizer
04267                  item->u2.for_test     == a string containing the loop test
04268                  item->u3.for_inc      == a string containing the loop increment
04269 
04270                item->u4.for_statements == a pval list of statements in the for ()
04271       */
04272       if (item->u1.for_init)
04273          free(item->u1.for_init);
04274       if (item->u2.for_test)
04275          free(item->u2.for_test);
04276       if (item->u3.for_inc)
04277          free(item->u3.for_inc);
04278       destroy_pval(item->u4.for_statements);
04279       break;
04280          
04281    case PV_WHILE:
04282       /* fields: item->u1.str        == the while conditional, as supplied by user
04283 
04284                item->u2.statements == a pval list of statements in the while ()
04285       */
04286       if (item->u1.str)
04287          free(item->u1.str);
04288       destroy_pval(item->u2.statements);
04289       break;
04290          
04291    case PV_BREAK:
04292       /* fields: none
04293       */
04294       break;
04295          
04296    case PV_RETURN:
04297       /* fields: none
04298       */
04299       break;
04300          
04301    case PV_CONTINUE:
04302       /* fields: none
04303       */
04304       break;
04305          
04306    case PV_IFTIME:
04307       /* fields: item->u1.list        == the 4 time values, in PV_WORD structs, linked list
04308 
04309                item->u2.statements == a pval list of statements in the if ()
04310                item->u3.else_statements == a pval list of statements in the else
04311                                     (could be zero)
04312       */
04313       destroy_pval(item->u1.list);
04314       destroy_pval(item->u2.statements);
04315       if (item->u3.else_statements) {
04316          destroy_pval(item->u3.else_statements);
04317       }
04318       break;
04319          
04320    case PV_RANDOM:
04321       /* fields: item->u1.str        == the random percentage, as supplied by user
04322 
04323                item->u2.statements == a pval list of statements in the true part ()
04324                item->u3.else_statements == a pval list of statements in the else
04325                                     (could be zero)
04326       fall thru to If */
04327    case PV_IF:
04328       /* fields: item->u1.str        == the if conditional, as supplied by user
04329 
04330                item->u2.statements == a pval list of statements in the if ()
04331                item->u3.else_statements == a pval list of statements in the else
04332                                     (could be zero)
04333       */
04334       if (item->u1.str)
04335          free(item->u1.str);
04336       destroy_pval(item->u2.statements);
04337       if (item->u3.else_statements) {
04338          destroy_pval(item->u3.else_statements);
04339       }
04340       break;
04341          
04342    case PV_SWITCH:
04343       /* fields: item->u1.str        == the switch expression
04344 
04345                item->u2.statements == a pval list of statements in the switch, 
04346                                     (will be case statements, most likely!)
04347       */
04348       if (item->u1.str)
04349          free(item->u1.str);
04350       destroy_pval(item->u2.statements);
04351       break;
04352          
04353    case PV_EXTENSION:
04354       /* fields: item->u1.str        == the extension name, label, whatever it's called
04355 
04356                item->u2.statements == a pval list of statements in the extension
04357                item->u3.hints      == a char * hint argument
04358                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
04359       */
04360       if (item->u1.str)
04361          free(item->u1.str);
04362       if (item->u3.hints)
04363          free(item->u3.hints);
04364       destroy_pval(item->u2.statements);
04365       break;
04366          
04367    case PV_IGNOREPAT:
04368       /* fields: item->u1.str        == the ignorepat data
04369       */
04370       if (item->u1.str)
04371          free(item->u1.str);
04372       break;
04373          
04374    case PV_GLOBALS:
04375       /* fields: item->u1.statements     == pval list of statements, usually vardecs
04376       */
04377       destroy_pval(item->u1.statements);
04378       break;
04379    }
04380    free(item);
04381 }

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

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

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

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

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

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

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

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

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

Definition at line 1860 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_goto(), and get_goto_target().

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

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

Definition at line 1849 of file pbx_ael.c.

References match_pval().

Referenced by check_goto(), and get_goto_target().

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

struct pval * find_macro ( char *  name  ) 

Definition at line 1874 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_pval_item().

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

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

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

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

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

Definition at line 1455 of file pbx_ael.c.

References find_pval_goto_item(), and pval::next.

Referenced by check_pval_item(), and find_pval_goto_item().

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

static void fix_gotos_in_extensions ( struct ael_extension exten  )  [static]

Definition at line 3710 of file pbx_ael.c.

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

03711 {
03712    struct ael_extension *e;
03713    for(e=exten;e;e=e->next_exten) {
03714 
03715       struct ael_priority *p;
03716       for(p=e->plist;p;p=p->next) {
03717          
03718          if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) {
03719             
03720             /* fix the extension of the goto target to the actual extension in the post-compiled dialplan */
03721 
03722             pval *target = p->origin->u2.goto_target;
03723             struct ael_extension *z = target->u3.compiled_label;
03724             pval *pv2 = p->origin;
03725             char buf1[500];
03726             char *apparg_save = p->appargs;
03727             
03728             p->appargs = 0;
03729             if (!pv2->u1.list->next) /* just one  -- it won't hurt to repeat the extension */ {
03730                snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->u1.str);
03731                p->appargs = strdup(buf1);
03732                
03733             } else if (pv2->u1.list->next && !pv2->u1.list->next->next) /* two */ {
03734                snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->next->u1.str);
03735                p->appargs = strdup(buf1);
03736             } else if (pv2->u1.list->next && pv2->u1.list->next->next) {
03737                snprintf(buf1,sizeof(buf1),"%s|%s|%s", pv2->u1.list->u1.str, 
03738                       z->name,
03739                       pv2->u1.list->next->next->u1.str);
03740                p->appargs = strdup(buf1);
03741             }
03742             else
03743                printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n");
03744             
03745             if( apparg_save ) {
03746                free(apparg_save);
03747             }
03748          }
03749       }
03750    }
03751 }

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

Definition at line 2868 of file pbx_ael.c.

References t.

Referenced by gen_prios().

02869 {
02870    /* the result will be a string that will be matched by pattern */
02871    char *p=pattern, *t=result;
02872    while (*p) {
02873       if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
02874          *t++ = '9';
02875       else if (*p == '[') {
02876          char *z = p+1;
02877          while (*z != ']')
02878             z++;
02879          if (*(z+1)== ']')
02880             z++;
02881          *t++=*(p+1); /* use the first char in the set */
02882          p = z;
02883       } else {
02884          *t++ = *p;
02885       }
02886       p++;
02887    }
02888    *t++ = 0; /* cap it off */
02889 }

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 2891 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, 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::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.

02892 {
02893    pval *p,*p2,*p3;
02894    struct ael_priority *pr;
02895    struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end;
02896    struct ael_priority *while_test, *while_loop, *while_end;
02897    struct ael_priority *switch_test, *switch_end, *fall_thru;
02898    struct ael_priority *if_test, *if_end, *if_skip, *if_false;
02899 #ifdef OLD_RAND_ACTION
02900    struct ael_priority *rand_test, *rand_end, *rand_skip;
02901 #endif
02902    char buf1[2000];
02903    char buf2[2000];
02904    char *strp, *strp2;
02905    char new_label[2000];
02906    int default_exists;
02907    int local_control_statement_count;
02908    struct ael_priority *loop_break_save;
02909    struct ael_priority *loop_continue_save;
02910    struct ael_extension *switch_case;
02911    
02912    for (p=statement; p; p=p->next) {
02913       switch (p->type) {
02914       case PV_VARDEC:
02915          pr = new_prio();
02916          pr->type = AEL_APPCALL;
02917          snprintf(buf1,sizeof(buf1),"%s=$[%s]", p->u1.str, p->u2.val);
02918          pr->app = strdup("Set");
02919          remove_spaces_before_equals(buf1);
02920          pr->appargs = strdup(buf1);
02921          pr->origin = p;
02922          linkprio(exten, pr);
02923          break;
02924 
02925       case PV_GOTO:
02926          pr = new_prio();
02927          pr->type = AEL_APPCALL;
02928          p->u2.goto_target = get_goto_target(p);
02929          if( p->u2.goto_target ) {
02930             p->u3.goto_target_in_case = p->u2.goto_target->u2.label_in_case = label_inside_case(p->u2.goto_target);
02931          }
02932          
02933          if (!p->u1.list->next) /* just one */ {
02934             pr->app = strdup("Goto");
02935             if (!mother_exten)
02936                pr->appargs = strdup(p->u1.list->u1.str);
02937             else {  /* for the case of simple within-extension gotos in case/pattern/default statement blocks: */ 
02938                snprintf(buf1,sizeof(buf1),"%s|%s", mother_exten->name, p->u1.list->u1.str);
02939                pr->appargs = strdup(buf1);
02940             }
02941             
02942          } else if (p->u1.list->next && !p->u1.list->next->next) /* two */ {
02943             snprintf(buf1,sizeof(buf1),"%s|%s", p->u1.list->u1.str, p->u1.list->next->u1.str);
02944             pr->app = strdup("Goto");
02945             pr->appargs = strdup(buf1);
02946          } else if (p->u1.list->next && p->u1.list->next->next) {
02947             snprintf(buf1,sizeof(buf1),"%s|%s|%s", p->u1.list->u1.str, 
02948                   p->u1.list->next->u1.str,
02949                   p->u1.list->next->next->u1.str);
02950             pr->app = strdup("Goto");
02951             pr->appargs = strdup(buf1);
02952          }
02953          pr->origin = p;
02954          linkprio(exten, pr);
02955          break;
02956 
02957       case PV_LABEL:
02958          pr = new_prio();
02959          pr->type = AEL_LABEL;
02960          pr->origin = p;
02961          p->u3.compiled_label = exten;
02962          linkprio(exten, pr);
02963          break;
02964 
02965       case PV_FOR:
02966          control_statement_count++;
02967          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
02968          loop_continue_save = exten->loop_continue;
02969          snprintf(new_label,sizeof(new_label),"for-%s-%d", label, control_statement_count);
02970          for_init = new_prio();
02971          for_inc = new_prio();
02972          for_test = new_prio();
02973          for_loop = new_prio();
02974          for_end = new_prio();
02975          for_init->type = AEL_APPCALL;
02976          for_inc->type = AEL_APPCALL;
02977          for_test->type = AEL_FOR_CONTROL;
02978          for_test->goto_false = for_end;
02979          for_loop->type = AEL_CONTROL1; /* simple goto */
02980          for_end->type = AEL_APPCALL;
02981          for_init->app = strdup("Set");
02982          
02983          strcpy(buf2,p->u1.for_init);
02984          remove_spaces_before_equals(buf2);
02985          strp = strchr(buf2, '=');
02986          strp2 = strchr(p->u1.for_init, '=');
02987          if (strp) {
02988             *(strp+1) = 0;
02989             strcat(buf2,"$[");
02990             strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
02991             strcat(buf2,"]");
02992             for_init->appargs = strdup(buf2);
02993          } else
02994             for_init->appargs = strdup(p->u1.for_init);
02995 
02996          for_inc->app = strdup("Set");
02997 
02998          strcpy(buf2,p->u3.for_inc);
02999          remove_spaces_before_equals(buf2);
03000          strp = strchr(buf2, '=');
03001          strp2 = strchr(p->u3.for_inc, '=');
03002          if (strp) {
03003             *(strp+1) = 0;
03004             strcat(buf2,"$[");
03005             strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03006             strcat(buf2,"]");
03007             for_inc->appargs = strdup(buf2);
03008          } else
03009             for_inc->appargs = strdup(p->u3.for_inc);
03010          snprintf(buf1,sizeof(buf1),"$[%s]",p->u2.for_test);
03011          for_test->app = 0;
03012          for_test->appargs = strdup(buf1);
03013          for_loop->goto_true = for_test;
03014          snprintf(buf1,sizeof(buf1),"Finish for-%s-%d", label, control_statement_count);
03015          for_end->app = strdup("NoOp");
03016          for_end->appargs = strdup(buf1);
03017          /* link & load! */
03018          linkprio(exten, for_init);
03019          linkprio(exten, for_test);
03020          
03021          /* now, put the body of the for loop here */
03022          exten->loop_break = for_end;
03023          exten->loop_continue = for_inc;
03024          
03025          gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context); /* this will link in all the statements here */
03026          
03027          linkprio(exten, for_inc);
03028          linkprio(exten, for_loop);
03029          linkprio(exten, for_end);
03030          
03031          
03032          exten->loop_break = loop_break_save;
03033          exten->loop_continue = loop_continue_save;
03034          for_loop->origin = p;
03035          break;
03036 
03037       case PV_WHILE:
03038          control_statement_count++;
03039          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
03040          loop_continue_save = exten->loop_continue;
03041          snprintf(new_label,sizeof(new_label),"while-%s-%d", label, control_statement_count);
03042          while_test = new_prio();
03043          while_loop = new_prio();
03044          while_end = new_prio();
03045          while_test->type = AEL_FOR_CONTROL;
03046          while_test->goto_false = while_end;
03047          while_loop->type = AEL_CONTROL1; /* simple goto */
03048          while_end->type = AEL_APPCALL;
03049          snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str);
03050          while_test->app = 0;
03051          while_test->appargs = strdup(buf1);
03052          while_loop->goto_true = while_test;
03053          snprintf(buf1,sizeof(buf1),"Finish while-%s-%d", label, control_statement_count);
03054          while_end->app = strdup("NoOp");
03055          while_end->appargs = strdup(buf1);
03056 
03057          linkprio(exten, while_test);
03058          
03059          /* now, put the body of the for loop here */
03060          exten->loop_break = while_end;
03061          exten->loop_continue = while_test;
03062          
03063          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the while body statements here */
03064 
03065          linkprio(exten, while_loop);
03066          linkprio(exten, while_end);
03067          
03068          
03069          exten->loop_break = loop_break_save;
03070          exten->loop_continue = loop_continue_save;
03071          while_loop->origin = p;
03072          break;
03073 
03074       case PV_SWITCH:
03075          control_statement_count++;
03076          local_control_statement_count = control_statement_count;
03077          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
03078          loop_continue_save = exten->loop_continue;
03079          snprintf(new_label,sizeof(new_label),"sw-%s-%d", label, control_statement_count);
03080 
03081          switch_test = new_prio();
03082          switch_end = new_prio();
03083          switch_test->type = AEL_APPCALL;
03084          switch_end->type = AEL_APPCALL;
03085          snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",control_statement_count, p->u1.str);
03086          switch_test->app = strdup("Goto");
03087          switch_test->appargs = strdup(buf1);
03088          snprintf(buf1,sizeof(buf1),"Finish switch-%s-%d", label, control_statement_count);
03089          switch_end->app = strdup("NoOp");
03090          switch_end->appargs = strdup(buf1);
03091          switch_end->origin = p;
03092          switch_end->exten = exten;
03093 
03094          linkprio(exten, switch_test);
03095          linkprio(exten, switch_end);
03096          
03097          exten->loop_break = switch_end;
03098          exten->loop_continue = 0;
03099          default_exists = 0;
03100          
03101          for (p2=p->u2.statements; p2; p2=p2->next) {
03102             /* now, for each case/default put the body of the for loop here */
03103             if (p2->type == PV_CASE) {
03104                /* ok, generate a extension and link it in */
03105                switch_case = new_exten();
03106                switch_case->context = this_context;
03107                switch_case->is_switch = 1;
03108                /* the break/continue locations are inherited from parent */
03109                switch_case->loop_break = exten->loop_break;
03110                switch_case->loop_continue = exten->loop_continue;
03111                
03112                linkexten(exten,switch_case);
03113                snprintf(buf1,sizeof(buf1),"sw-%d-%s", local_control_statement_count, p2->u1.str);
03114                switch_case->name = strdup(buf1);
03115                snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, p2->u1.str, local_control_statement_count);
03116                
03117                gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the case body statements here */
03118 
03119                /* here is where we write code to "fall thru" to the next case... if there is one... */
03120                for (p3=p2->u2.statements; p3; p3=p3->next) {
03121                   if (!p3->next)
03122                      break;
03123                }
03124                /* p3 now points the last statement... */
03125                if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN) ) {
03126                   /* is there a following CASE/PATTERN/DEFAULT? */
03127                   if (p2->next && p2->next->type == PV_CASE) {
03128                      fall_thru = new_prio();
03129                      fall_thru->type = AEL_APPCALL;
03130                      fall_thru->app = strdup("Goto");
03131                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, p2->next->u1.str);
03132                      fall_thru->appargs = strdup(buf1);
03133                      linkprio(switch_case, fall_thru);
03134                   } else if (p2->next && p2->next->type == PV_PATTERN) {
03135                      fall_thru = new_prio();
03136                      fall_thru->type = AEL_APPCALL;
03137                      fall_thru->app = strdup("Goto");
03138                      gen_match_to_pattern(p2->next->u1.str, buf2);
03139                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10", local_control_statement_count, buf2);
03140                      fall_thru->appargs = strdup(buf1);
03141                      linkprio(switch_case, fall_thru);
03142                   } else if (p2->next && p2->next->type == PV_DEFAULT) {
03143                      fall_thru = new_prio();
03144                      fall_thru->type = AEL_APPCALL;
03145                      fall_thru->app = strdup("Goto");
03146                      snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03147                      fall_thru->appargs = strdup(buf1);
03148                      linkprio(switch_case, fall_thru);
03149                   } else if (!p2->next) {
03150                      fall_thru = new_prio();
03151                      fall_thru->type = AEL_CONTROL1;
03152                      fall_thru->goto_true = switch_end;
03153                      fall_thru->app = strdup("Goto");
03154                      linkprio(switch_case, fall_thru);
03155                   }
03156                }
03157                if (switch_case->return_needed) {
03158                   char buf[2000];
03159                   struct ael_priority *np2 = new_prio();
03160                   np2->type = AEL_APPCALL;
03161                   np2->app = strdup("NoOp");
03162                   snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03163                   np2->appargs = strdup(buf);
03164                   linkprio(switch_case, np2);
03165                   switch_case-> return_target = np2;
03166                }
03167             } else if (p2->type == PV_PATTERN) {
03168                /* ok, generate a extension and link it in */
03169                switch_case = new_exten();
03170                switch_case->context = this_context;
03171                switch_case->is_switch = 1;
03172                /* the break/continue locations are inherited from parent */
03173                switch_case->loop_break = exten->loop_break;
03174                switch_case->loop_continue = exten->loop_continue;
03175                
03176                linkexten(exten,switch_case);
03177                snprintf(buf1,sizeof(buf1),"_sw-%d-%s", local_control_statement_count, p2->u1.str);
03178                switch_case->name = strdup(buf1);
03179                snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, p2->u1.str, local_control_statement_count);
03180                
03181                gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the while body statements here */
03182                /* here is where we write code to "fall thru" to the next case... if there is one... */
03183                for (p3=p2->u2.statements; p3; p3=p3->next) {
03184                   if (!p3->next)
03185                      break;
03186                }
03187                /* p3 now points the last statement... */
03188                if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03189                   /* is there a following CASE/PATTERN/DEFAULT? */
03190                   if (p2->next && p2->next->type == PV_CASE) {
03191                      fall_thru = new_prio();
03192                      fall_thru->type = AEL_APPCALL;
03193                      fall_thru->app = strdup("Goto");
03194                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, p2->next->u1.str);
03195                      fall_thru->appargs = strdup(buf1);
03196                      linkprio(switch_case, fall_thru);
03197                   } else if (p2->next && p2->next->type == PV_PATTERN) {
03198                      fall_thru = new_prio();
03199                      fall_thru->type = AEL_APPCALL;
03200                      fall_thru->app = strdup("Goto");
03201                      gen_match_to_pattern(p2->next->u1.str, buf2);
03202                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03203                      fall_thru->appargs = strdup(buf1);
03204                      linkprio(switch_case, fall_thru);
03205                   } else if (p2->next && p2->next->type == PV_DEFAULT) {
03206                      fall_thru = new_prio();
03207                      fall_thru->type = AEL_APPCALL;
03208                      fall_thru->app = strdup("Goto");
03209                      snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03210                      fall_thru->appargs = strdup(buf1);
03211                      linkprio(switch_case, fall_thru);
03212                   } else if (!p2->next) {
03213                      fall_thru = new_prio();
03214                      fall_thru->type = AEL_CONTROL1;
03215                      fall_thru->goto_true = switch_end;
03216                      fall_thru->app = strdup("Goto");
03217                      linkprio(switch_case, fall_thru);
03218                   }
03219                }
03220                if (switch_case->return_needed) {
03221                   char buf[2000];
03222                   struct ael_priority *np2 = new_prio();
03223                   np2->type = AEL_APPCALL;
03224                   np2->app = strdup("NoOp");
03225                   snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03226                   np2->appargs = strdup(buf);
03227                   linkprio(switch_case, np2);
03228                   switch_case-> return_target = np2;
03229                }
03230             } else if (p2->type == PV_DEFAULT) {
03231                default_exists++;
03232                /* ok, generate a extension and link it in */
03233                switch_case = new_exten();
03234                switch_case->context = this_context;
03235                switch_case->is_switch = 1;
03236                /* the break/continue locations are inherited from parent */
03237                switch_case->loop_break = exten->loop_break;
03238                switch_case->loop_continue = exten->loop_continue;
03239                linkexten(exten,switch_case);
03240                snprintf(buf1,sizeof(buf1),"_sw-%d-.", local_control_statement_count);
03241                switch_case->name = strdup(buf1);
03242                
03243                snprintf(new_label,sizeof(new_label),"sw-%s-default-%d", label, local_control_statement_count);
03244                
03245                gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the while body statements here */
03246                
03247                /* here is where we write code to "fall thru" to the next case... if there is one... */
03248                for (p3=p2->u2.statements; p3; p3=p3->next) {
03249                   if (!p3->next)
03250                      break;
03251                }
03252                /* p3 now points the last statement... */
03253                if (!p3 || (p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
03254                   /* is there a following CASE/PATTERN/DEFAULT? */
03255                   if (p2->next && p2->next->type == PV_CASE) {
03256                      fall_thru = new_prio();
03257                      fall_thru->type = AEL_APPCALL;
03258                      fall_thru->app = strdup("Goto");
03259                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, p2->next->u1.str);
03260                      fall_thru->appargs = strdup(buf1);
03261                      linkprio(switch_case, fall_thru);
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                      snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2);
03268                      fall_thru->appargs = strdup(buf1);
03269                      linkprio(switch_case, fall_thru);
03270                   } else if (p2->next && p2->next->type == PV_DEFAULT) {
03271                      fall_thru = new_prio();
03272                      fall_thru->type = AEL_APPCALL;
03273                      fall_thru->app = strdup("Goto");
03274                      snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count);
03275                      fall_thru->appargs = strdup(buf1);
03276                      linkprio(switch_case, fall_thru);
03277                   } else if (!p2->next) {
03278                      fall_thru = new_prio();
03279                      fall_thru->type = AEL_CONTROL1;
03280                      fall_thru->goto_true = switch_end;
03281                      fall_thru->app = strdup("Goto");
03282                      linkprio(switch_case, fall_thru);
03283                   }
03284                }
03285                if (switch_case->return_needed) {
03286                   char buf[2000];
03287                   struct ael_priority *np2 = new_prio();
03288                   np2->type = AEL_APPCALL;
03289                   np2->app = strdup("NoOp");
03290                   snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03291                   np2->appargs = strdup(buf);
03292                   linkprio(switch_case, np2);
03293                   switch_case-> return_target = np2;
03294                }
03295             } else {
03296                /* what could it be??? */
03297             }
03298          }
03299          
03300          exten->loop_break = loop_break_save;
03301          exten->loop_continue = loop_continue_save;
03302          switch_test->origin = p;
03303          switch_end->origin = p;
03304          break;
03305 
03306       case PV_MACRO_CALL:
03307          pr = new_prio();
03308          pr->type = AEL_APPCALL;
03309          snprintf(buf1,sizeof(buf1),"%s", p->u1.str);
03310          for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03311             strcat(buf1,"|");
03312             strcat(buf1,p2->u1.str);
03313          }
03314          pr->app = strdup("Macro");
03315          pr->appargs = strdup(buf1);
03316          pr->origin = p;
03317          linkprio(exten, pr);
03318          break;
03319 
03320       case PV_APPLICATION_CALL:
03321          pr = new_prio();
03322          pr->type = AEL_APPCALL;
03323          buf1[0] = 0;
03324          for (p2 = p->u2.arglist; p2; p2 = p2->next) {
03325             if (p2 != p->u2.arglist )
03326                strcat(buf1,"|");
03327             substitute_commas(p2->u1.str);
03328             strcat(buf1,p2->u1.str);
03329          }
03330          pr->app = strdup(p->u1.str);
03331          pr->appargs = strdup(buf1);
03332          pr->origin = p;
03333          linkprio(exten, pr);
03334          break;
03335 
03336       case PV_BREAK:
03337          pr = new_prio();
03338          pr->type = AEL_CONTROL1; /* simple goto */
03339          pr->goto_true = exten->loop_break;
03340          pr->origin = p;
03341          linkprio(exten, pr);
03342          break;
03343 
03344       case PV_RETURN: /* hmmmm */
03345          pr = new_prio();
03346          pr->type = AEL_RETURN; /* simple goto */
03347          exten->return_needed++;
03348          pr->app = strdup("Goto");
03349          pr->appargs = strdup("");
03350          pr->origin = p;
03351          linkprio(exten, pr);
03352          break;
03353 
03354       case PV_CONTINUE:
03355          pr = new_prio();
03356          pr->type = AEL_CONTROL1; /* simple goto */
03357          pr->goto_true = exten->loop_continue;
03358          pr->origin = p;
03359          linkprio(exten, pr);
03360          break;
03361 
03362 #ifdef OLD_RAND_ACTION
03363       case PV_RANDOM:
03364          control_statement_count++;
03365          snprintf(new_label,sizeof(new_label),"rand-%s-%d", label, control_statement_count);
03366          rand_test = new_prio();
03367          rand_test->type = AEL_RAND_CONTROL;
03368          snprintf(buf1,sizeof(buf1),"$[%s]",
03369                 p->u1.str );
03370          rand_test->app = 0;
03371          rand_test->appargs = strdup(buf1);
03372          rand_test->origin = p;
03373          
03374          rand_end = new_prio();
03375          rand_end->type = AEL_APPCALL;
03376          snprintf(buf1,sizeof(buf1),"Finish rand-%s-%d", label, control_statement_count);
03377          rand_end->app = strdup("NoOp");
03378          rand_end->appargs = strdup(buf1);
03379          
03380          rand_skip = new_prio();
03381          rand_skip->type = AEL_CONTROL1; /* simple goto */
03382          rand_skip->goto_true = rand_end;
03383          rand_skip->origin  = p;
03384 
03385          rand_test->goto_true = rand_skip; /* +1, really */
03386 
03387          linkprio(exten, rand_test);
03388          
03389          if (p->u3.else_statements) {
03390             gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the else statements here */
03391          }
03392          
03393          linkprio(exten, rand_skip);
03394          
03395          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the "true" statements here */
03396 
03397          linkprio(exten, rand_end);
03398          
03399          break;
03400 #endif         
03401 
03402       case PV_IFTIME:
03403          control_statement_count++;
03404          snprintf(new_label,sizeof(new_label),"iftime-%s-%d", label, control_statement_count);
03405          
03406          if_test = new_prio();
03407          if_test->type = AEL_IFTIME_CONTROL;
03408          snprintf(buf1,sizeof(buf1),"%s|%s|%s|%s",
03409                 p->u1.list->u1.str, 
03410                 p->u1.list->next->u1.str, 
03411                 p->u1.list->next->next->u1.str, 
03412                 p->u1.list->next->next->next->u1.str);
03413          if_test->app = 0;
03414          if_test->appargs = strdup(buf1);
03415          if_test->origin = p;
03416 
03417          if_end = new_prio();
03418          if_end->type = AEL_APPCALL;
03419          snprintf(buf1,sizeof(buf1),"Finish iftime-%s-%d", label, control_statement_count);
03420          if_end->app = strdup("NoOp");
03421          if_end->appargs = strdup(buf1);
03422 
03423          if (p->u3.else_statements) {
03424             if_skip = new_prio();
03425             if_skip->type = AEL_CONTROL1; /* simple goto */
03426             if_skip->goto_true = if_end;
03427             if_skip->origin  = p;
03428 
03429          } else {
03430             if_skip = 0;
03431 
03432             if_test->goto_false = if_end;
03433          }
03434 
03435          if_false = new_prio();
03436          if_false->type = AEL_CONTROL1;
03437          if (p->u3.else_statements) {
03438             if_false->goto_true = if_skip; /* +1 */
03439          } else {
03440             if_false->goto_true = if_end;
03441          }
03442          
03443          /* link & load! */
03444          linkprio(exten, if_test);
03445          linkprio(exten, if_false);
03446          
03447          /* now, put the body of the if here */
03448          
03449          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the statements here */
03450          
03451          if (p->u3.else_statements) {
03452             linkprio(exten, if_skip);
03453             gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the statements here */
03454 
03455          }
03456          
03457          linkprio(exten, if_end);
03458          
03459          break;
03460 
03461       case PV_RANDOM:
03462       case PV_IF:
03463          control_statement_count++;
03464          snprintf(new_label,sizeof(new_label),"if-%s-%d", label, control_statement_count);
03465          
03466          if_test = new_prio();
03467          if_end = new_prio();
03468          if_test->type = AEL_IF_CONTROL;
03469          if_end->type = AEL_APPCALL;
03470          if ( p->type == PV_RANDOM )
03471             snprintf(buf1,sizeof(buf1),"$[${RAND(0,99)} < (%s)]",p->u1.str);
03472          else
03473             snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str);
03474          if_test->app = 0;
03475          if_test->appargs = strdup(buf1);
03476          snprintf(buf1,sizeof(buf1),"Finish if-%s-%d", label, control_statement_count);
03477          if_end->app = strdup("NoOp");
03478          if_end->appargs = strdup(buf1);
03479          if_test->origin = p;
03480          
03481          if (p->u3.else_statements) {
03482             if_skip = new_prio();
03483             if_skip->type = AEL_CONTROL1; /* simple goto */
03484             if_skip->goto_true = if_end;
03485             if_test->goto_false = if_skip;;
03486          } else {
03487             if_skip = 0;
03488             if_test->goto_false = if_end;;
03489          }
03490          
03491          /* link & load! */
03492          linkprio(exten, if_test);
03493          
03494          /* now, put the body of the if here */
03495          
03496          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the statements here */
03497          
03498          if (p->u3.else_statements) {
03499             linkprio(exten, if_skip);
03500             gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the statements here */
03501 
03502          }
03503          
03504          linkprio(exten, if_end);
03505          
03506          break;
03507 
03508       case PV_STATEMENTBLOCK:
03509          gen_prios(exten, label, p->u1.list, mother_exten, this_context ); /* recurse into the block */
03510          break;
03511 
03512       case PV_CATCH:
03513          control_statement_count++;
03514          /* generate an extension with name of catch, put all catch stats
03515             into this exten! */
03516          switch_case = new_exten();
03517          switch_case->context = this_context;
03518          linkexten(exten,switch_case);
03519          switch_case->name = strdup(p->u1.str);
03520          snprintf(new_label,sizeof(new_label),"catch-%s-%d",p->u1.str, control_statement_count);
03521          
03522          gen_prios(switch_case, new_label, p->u2.statements,mother_exten,this_context); /* this will link in all the catch body statements here */
03523          if (switch_case->return_needed) {
03524             char buf[2000];
03525             struct ael_priority *np2 = new_prio();
03526             np2->type = AEL_APPCALL;
03527             np2->app = strdup("NoOp");
03528             snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
03529             np2->appargs = strdup(buf);
03530             linkprio(switch_case, np2);
03531             switch_case-> return_target = np2;
03532          }
03533 
03534          break;
03535       default:
03536          break;
03537       }
03538    }
03539 }

static pval * get_contxt ( pval p  )  [static]

Definition at line 3700 of file pbx_ael.c.

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

Referenced by check_goto(), and get_goto_target().

03701 {
03702    while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
03703       
03704       p = p->dad;
03705    }
03706    
03707    return p;
03708 }

static pval * get_extension_or_contxt ( pval p  )  [static]

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

03691 {
03692    while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
03693       
03694       p = p->dad;
03695    }
03696    
03697    return p;
03698 }

static pval * get_goto_target ( pval item  )  [static]

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

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

int is_empty ( char *  arg  ) 

Definition at line 1912 of file pbx_ael.c.

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

int is_float ( char *  arg  ) 

Definition at line 1894 of file pbx_ael.c.

References s.

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

int is_int ( char *  arg  ) 

Definition at line 1903 of file pbx_ael.c.

References s.

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

static int label_inside_case ( pval label  )  [static]

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

02830 {
02831    pval *p = label;
02832    
02833    while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
02834       if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN ) {
02835          return 1;
02836       }
02837 
02838       p = p->dad;
02839    }
02840    return 0;
02841 }

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

Definition at line 2843 of file pbx_ael.c.

References exten, and ael_extension::next_exten.

Referenced by gen_prios().

02844 {
02845    add->next_exten = exten->next_exten; /* this will reverse the order. Big deal. */
02846    exten->next_exten = add;
02847 }

void linkprio ( struct ael_extension exten,
struct ael_priority prio 
)

Definition at line 2776 of file pbx_ael.c.

References ael_priority::exten, and exten.

Referenced by gen_prios().

02777 {
02778    if (!exten->plist) {
02779       exten->plist = prio;
02780       exten->plist_last = prio;
02781    } else {
02782       exten->plist_last->next = prio;
02783       exten->plist_last = prio;
02784    }
02785    if( !prio->exten )
02786       prio->exten = exten; /* don't override the switch value */
02787 }

static int load_module ( void   )  [static]

Definition at line 4084 of file pbx_ael.c.

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

04085 {
04086    ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04087    return (pbx_load_module());
04088 }

struct pval * match_pval ( pval item  ) 

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

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

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

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

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

struct ael_extension * new_exten ( void   ) 

Definition at line 2770 of file pbx_ael.c.

References calloc.

Referenced by gen_prios().

02771 {
02772    struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
02773    return x;
02774 }

struct ael_priority * new_prio ( void   ) 

Definition at line 2764 of file pbx_ael.c.

References calloc.

Referenced by gen_prios().

02765 {
02766    struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
02767    return x;
02768 }

static int pbx_load_module ( void   )  [static]

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

03972 {
03973    int errs, sem_err, sem_warn, sem_note;
03974    char *rfilename;
03975    struct ast_context *local_contexts=NULL, *con;
03976    struct pval *parse_tree;
03977 
03978    ast_log(LOG_NOTICE, "Starting AEL load process.\n");
03979    if (config[0] == '/')
03980       rfilename = (char *)config;
03981    else {
03982       rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2);
03983       sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config);
03984    }
03985    ast_log(LOG_NOTICE, "AEL load process: calculated config file name '%s'.\n", rfilename);
03986 
03987    if (access(rfilename,R_OK) != 0) {
03988       ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename);
03989       return AST_MODULE_LOAD_DECLINE;
03990    }
03991    
03992    parse_tree = ael2_parse(rfilename, &errs);
03993    ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename);
03994    ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note);
03995    if (errs == 0 && sem_err == 0) {
03996       ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename);
03997       ast_compile_ael2(&local_contexts, parse_tree);
03998       ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename);
03999       
04000       ast_merge_contexts_and_delete(&local_contexts, registrar);
04001       ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename);
04002       for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
04003          ast_context_verify_includes(con);
04004       ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename);
04005    } else {
04006       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);
04007       destroy_pval(parse_tree); /* free up the memory */
04008       return AST_MODULE_LOAD_DECLINE;
04009    }
04010    destroy_pval(parse_tree); /* free up the memory */
04011    
04012    return AST_MODULE_LOAD_SUCCESS;
04013 }

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

References pbx_load_module().

04091 {
04092    return pbx_load_module();
04093 }

static void remove_spaces_before_equals ( char *  str  )  [static]

Definition at line 2849 of file pbx_ael.c.

Referenced by gen_prios().

02850 {
02851    char *p;
02852    while( str && *str && *str != '=' )
02853    {
02854       if( *str == ' ' || *str == '\n' || *str == '\r' || *str == '\t' )
02855       {
02856          p = str;
02857          while( *p )
02858          {
02859             *p = *(p+1);
02860             p++;
02861          }
02862       }
02863       else
02864          str++;
02865    }
02866 }

void set_priorities ( struct ael_extension exten  ) 

Definition at line 3541 of file pbx_ael.c.

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

03542 {
03543    int i;
03544    struct ael_priority *pr;
03545    do {
03546       if (exten->is_switch)
03547          i = 10;
03548       else if (exten->regexten)
03549          i=2;
03550       else
03551          i=1;
03552       
03553       for (pr=exten->plist; pr; pr=pr->next) {
03554          pr->priority_num = i;
03555          
03556          if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
03557                                       but we want them to point to the right
03558                                       priority, which would be the next line
03559                                       after the label; */
03560             i++;
03561       }
03562       
03563       exten = exten->next_exten;
03564    } while ( exten );
03565 }

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

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

04078 {
04079    ast_context_destroy(NULL, registrar);
04080    ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry));
04081    return 0;
04082 }


Variable Documentation

int aeldebug = 0 [static]

Definition at line 3965 of file pbx_ael.c.

struct ast_cli_entry cli_ael[] [static]

Definition at line 4056 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 4051 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 2762 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 [static]

Definition at line 113 of file pbx_ael.c.

Referenced by check_label(), and check_pval_item().

pval* current_db [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 [static]

Definition at line 114 of file pbx_ael.c.

Referenced by check_label(), and check_pval_item().

char* days[] [static]

Definition at line 902 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 1000 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 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 Fri Aug 24 02:27:07 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1