Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:40 2007

Asterisk developer's documentation :: Codename Pineapple


pbx_ael.c File Reference


Detailed Description

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

Definition in file pbx_ael.c.

#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_macro_returns (pval *macro)
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)
static struct pvalin_context (pval *item)
static struct pvalin_macro (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


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 3611 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(), 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, PRIORITY_HINT, ael_priority::priority_num, PV_IFTIME, PV_SWITCH, strdup, pval::type, ael_priority::type, and pval::u3.

03612 {
03613    struct ael_priority *pr;
03614    char *label=0;
03615    if (!exten) {
03616       ast_log(LOG_WARNING, "This file is Empty!\n" );
03617       return;
03618    }
03619    do {
03620       struct ael_priority *last = 0;
03621       
03622       if (exten->hints) {
03623          if (ast_add_extension2(exten->context, 0 /*no replace*/, exten->name, PRIORITY_HINT, NULL, exten->cidmatch, 
03624                           exten->hints, NULL, ast_free, registrar)) {
03625             ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
03626                   exten->name);
03627          }
03628       }
03629       
03630       for (pr=exten->plist; pr; pr=pr->next) {
03631          char app[2000];
03632          char appargs[2000];
03633 
03634          /* before we can add the extension, we need to prep the app/appargs;
03635             the CONTROL types need to be done after the priority numbers are calculated.
03636          */
03637          if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
03638             last = pr;
03639             continue;
03640          }
03641          
03642          if (pr->app)
03643             strcpy(app, pr->app);
03644          else
03645             app[0] = 0;
03646          if (pr->appargs )
03647             strcpy(appargs, pr->appargs);
03648          else
03649             appargs[0] = 0;
03650          switch( pr->type ) {
03651          case AEL_APPCALL:
03652             /* easy case. Everything is all set up */
03653             break;
03654             
03655          case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
03656             /* simple, unconditional goto. */
03657             strcpy(app,"Goto");
03658             if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
03659                snprintf(appargs,sizeof(appargs),"%s|%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
03660             } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
03661                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
03662             } else
03663                snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
03664             break;
03665             
03666          case AEL_FOR_CONTROL:  /* WHILE loop test, FOR loop test */
03667             strcpy(app,"GotoIf");
03668             snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
03669             break;
03670             
03671          case AEL_IF_CONTROL:
03672             strcpy(app,"GotoIf");
03673             if (pr->origin->u3.else_statements )
03674                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
03675             else
03676                snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
03677             break;
03678 
03679          case AEL_RAND_CONTROL:
03680             strcpy(app,"Random");
03681             snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
03682             break;
03683 
03684          case AEL_IFTIME_CONTROL:
03685             strcpy(app,"GotoIfTime");
03686             snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
03687             break;
03688 
03689          case AEL_RETURN:
03690             strcpy(app,"Return");
03691             appargs[0] = 0;
03692             break;
03693             
03694          default:
03695             break;
03696          }
03697          if (last && last->type == AEL_LABEL ) {
03698             label = last->origin->u1.str;
03699          }
03700          else
03701             label = 0;
03702          
03703          if (ast_add_extension2(exten->context, 0 /*no replace*/, exten->name, pr->priority_num, (label?label:NULL), exten->cidmatch, 
03704                           app, strdup(appargs), ast_free, registrar)) {
03705             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, 
03706                   exten->name);
03707          }
03708          last = pr;
03709       }
03710       exten = exten->next_exten;
03711    } while ( exten );
03712 }

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

Definition at line 4041 of file pbx_ael.c.

References DEBUG_CONTEXTS.

04042 {
04043    aeldebug |= DEBUG_CONTEXTS;
04044    return 0;
04045 }

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

Definition at line 4035 of file pbx_ael.c.

References DEBUG_MACROS.

04036 {
04037    aeldebug |= DEBUG_MACROS;
04038    return 0;
04039 }

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

Definition at line 4023 of file pbx_ael.c.

References DEBUG_READ.

04024 {
04025    aeldebug |= DEBUG_READ;
04026    return 0;
04027 }

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

Definition at line 4029 of file pbx_ael.c.

References DEBUG_TOKENS.

04030 {
04031    aeldebug |= DEBUG_TOKENS;
04032    return 0;
04033 }

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

Definition at line 4047 of file pbx_ael.c.

04048 {
04049    aeldebug = 0;
04050    return 0;
04051 }

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

Definition at line 4053 of file pbx_ael.c.

References pbx_load_module().

04054 {
04055    return (pbx_load_module());
04056 }

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

Definition at line 2805 of file pbx_ael.c.

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

Referenced by pbx_load_module().

02806 {
02807    
02808 #ifdef AAL_ARGCHECK
02809    int argapp_errs =0;
02810    char *rfilename;
02811 #endif
02812    struct argapp *apps=0;
02813 
02814 #ifdef AAL_ARGCHECK
02815    rfilename = alloca(10 + strlen(ast_config_AST_VAR_DIR));
02816    sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR);
02817    
02818    apps = argdesc_parse(rfilename, &argapp_errs); /* giveth */
02819 #endif
02820    current_db = item;
02821    errs = warns = notes = 0;
02822 
02823    check_context_names();
02824    check_pval(item, apps, 0);
02825 
02826 #ifdef AAL_ARGCHECK
02827    argdesc_destroy(apps);  /* taketh away */
02828 #endif
02829    current_db = 0;
02830 
02831    *arg_errs = errs;
02832    *arg_warns = warns;
02833    *arg_notes = notes;
02834 }

void ast_compile_ael2 struct ast_context **  local_contexts,
struct pval root
 

Definition at line 3795 of file pbx_ael.c.

References AEL_APPCALL, AEL_LABEL, ael_priority::app, ael_priority::appargs, pval::arglist, ast_context_add_ignorepat2(), ast_context_add_include2(), ast_context_add_switch2(), ast_context_create(), ast_log(), attach_exten(), context, pval::endline, exten, pval::filename, gen_prios(), pval::hints, linkprio(), pval::list, local_contexts, LOG_WARNING, pval::macro_statements, new_exten(), new_prio(), pval::next, pbx_builtin_setvar(), PV_CONTEXT, PV_ESWITCHES, PV_EXTENSION, PV_GLOBALS, PV_IGNOREPAT, PV_INCLUDES, PV_MACRO, PV_SWITCHES, pval::regexten, remove_spaces_before_equals(), set_priorities(), pval::startline, pval::statements, pval::str, strdup, ael_priority::type, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.

Referenced by pbx_load_module().

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

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

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

03098 {
03099    struct parse_io io;
03100    int return_value = 0;
03101    
03102    memset(&io, 0, sizeof(io));
03103    io.string = expr;  /* to pass to the error routine */
03104    
03105    ast_yylex_init(&io.scanner);
03106    
03107    ast_yy_scan_string(expr, io.scanner);
03108    
03109    ast_yyparse ((void *) &io);
03110 
03111    ast_yylex_destroy(io.scanner);
03112 
03113    if (!io.val) {
03114       if (length > 1) {
03115          strcpy(buf, "0");
03116          return_value = 1;
03117       }
03118    } else {
03119       if (io.val->type == AST_EXPR_integer) {
03120          int res_length;
03121 
03122          res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i);
03123          return_value = (res_length <= length) ? res_length : length;
03124       } else {
03125 #if defined(STANDALONE) || defined(LOW_MEMORY)
03126          strncpy(buf, io.val->u.s, length - 1);
03127 #else /* !STANDALONE && !LOW_MEMORY */
03128          ast_copy_string(buf, io.val->u.s, length);
03129 #endif /* STANDALONE || LOW_MEMORY */
03130          return_value = strlen(buf);
03131          free(io.val->u.s);
03132       }
03133       free(io.val);
03134    }
03135    return return_value;
03136 }

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

References ael_extension::next_exten.

Referenced by ast_compile_ael2().

03715 {
03716    /* travel to the end of the list... */
03717    struct ael_extension *lptr;
03718    if( !*list ) {
03719       *list = newmem;
03720       return;
03721    }
03722    lptr = *list;
03723    
03724    while( lptr->next_exten ) {
03725       lptr = lptr->next_exten;
03726    }
03727    /* lptr should now pointing to the last element in the list; it has a null next_exten pointer */
03728    lptr->next_exten = newmem;
03729 }

static void check_abstract_reference pval abstract_context  )  [static]
 

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

02316 {
02317    pval *i,*j;
02318    /* find some context includes that reference this context */
02319    
02320 
02321    /* otherwise, print out a warning */
02322    for (i=current_db; i; i=i->next) {
02323       if (i->type == PV_CONTEXT) {
02324          for (j=i->u2. statements; j; j=j->next) {
02325             if ( j->type == PV_INCLUDES ) {
02326                struct pval *p4;
02327                for (p4=j->u1.list; p4; p4=p4->next) {
02328                   /* for each context pointed to, find it, then find a context/label that matches the
02329                      target here! */
02330                   if ( !strcmp(p4->u1.str, abstract_context->u1.str) )
02331                      return; /* found a match! */
02332                }
02333             }
02334          }
02335       }
02336    }
02337    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",
02338          abstract_context->filename, abstract_context->startline, abstract_context->endline, abstract_context->u1.str);
02339    warns++;
02340 }

int check_app_args pval appcall,
pval arglist,
struct argapp app
 

Definition at line 2143 of file pbx_ael.c.

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

02144 {
02145 #ifdef AAL_ARGCHECK
02146    struct argdesc *ad = app->args;
02147    pval *pa;
02148    int z;
02149    
02150    for (pa = arglist; pa; pa=pa->next) {
02151       if (!ad) {
02152          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
02153                arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
02154          warns++;
02155          return 1;
02156       } else {
02157          /* find the first entry in the ad list that will match */
02158          do {
02159             if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */
02160                break;
02161             
02162             z= option_matches( ad, pa, app);
02163             if (!z) {
02164                if ( !arglist )
02165                   arglist=appcall;
02166                
02167                if (ad->type == ARGD_REQUIRED) {
02168                   ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02169                         arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02170                   warns++;
02171                   return 1;
02172                }
02173             } else if (z && ad->dtype == ARGD_OPTIONSET) {
02174                option_matches_j( ad, pa, app);
02175             }
02176             ad = ad->next;
02177          } while (ad && !z);
02178       }
02179    }
02180    /* any app nodes left, that are not optional? */
02181    for ( ; ad; ad=ad->next) {
02182       if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
02183          if ( !arglist ) 
02184             arglist=appcall;
02185          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
02186                arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
02187          warns++;
02188          return 1;
02189       }
02190    }
02191    return 0;
02192 #else
02193    return 0;
02194 #endif
02195 }

static int check_break pval item  )  [static]
 

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

01094 {
01095    pval *p = item;
01096    
01097    while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
01098       /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make
01099          no sense */
01100       if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN 
01101          || p->type == PV_WHILE || p->type == PV_FOR   ) {
01102          return 1;
01103       }
01104       p = p->dad;
01105    }
01106    ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'break' not in switch, for, or while statement!\n",
01107          item->filename, item->startline, item->endline);
01108    errs++;
01109    
01110    return 0;
01111 }

static void check_context_names void   )  [static]
 

Definition at line 2296 of file pbx_ael.c.

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

Referenced by ael2_semantic_check().

02297 {
02298    pval *i,*j;
02299    for (i=current_db; i; i=i->next) {
02300       if (i->type == PV_CONTEXT || i->type == PV_MACRO) {
02301          for (j=i->next; j; j=j->next) {
02302             if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) {
02303                if ( !strcmp(i->u1.str, j->u1.str) )
02304                {
02305                   ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: The context name (%s) is also declared in file %s, line %d-%d!\n",
02306                         i->filename, i->startline, i->endline, i->u1.str,  j->filename, j->startline, j->endline);
02307                   warns++;
02308                }
02309             }
02310          }
02311       }
02312    }
02313 }

static int check_continue pval item  )  [static]
 

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

01114 {
01115    pval *p = item;
01116    
01117    while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
01118       /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make
01119          no sense */
01120       if( p->type == PV_WHILE || p->type == PV_FOR   ) {
01121          return 1;
01122       }
01123       p = p->dad;
01124    }
01125    ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'continue' not in 'for' or 'while' statement!\n",
01126          item->filename, item->startline, item->endline);
01127    errs++;
01128    
01129    return 0;
01130 }

static void check_day pval DAY  )  [static]
 

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

00993 {
00994    char *day;
00995    char *c;
00996    /* The following line is coincidence, really! */
00997    int s, e;
00998 
00999    day = ast_strdupa(DAY->u1.str);
01000 
01001    /* Check for all days */
01002    if (ast_strlen_zero(day) || !strcmp(day, "*")) {
01003       return;
01004    }
01005    /* Get start and ending days */
01006    c = strchr(day, '-');
01007    if (c) {
01008       *c = '\0';
01009       c++;
01010    }
01011    /* Find the start */
01012    if (sscanf(day, "%d", &s) != 1) {
01013       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number!\n",
01014             DAY->filename, DAY->startline, DAY->endline, day);
01015       warns++;
01016    }
01017    else if ((s < 1) || (s > 31)) {
01018       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",
01019             DAY->filename, DAY->startline, DAY->endline, day);
01020       warns++;
01021    }
01022    s--;
01023    if (c) {
01024       if (sscanf(c, "%d", &e) != 1) {
01025          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number!\n",
01026                DAY->filename, DAY->startline, DAY->endline, c);
01027          warns++;
01028       }
01029       else if ((e < 1) || (e > 31)) {
01030          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",
01031                DAY->filename, DAY->startline, DAY->endline, day);
01032          warns++;
01033       }
01034       e--;
01035    } else
01036       e = s;
01037 }

static void check_dow pval DOW  )  [static]
 

get_dow: Get day of week

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.

00954 {
00955    char *dow;
00956    char *c;
00957    /* The following line is coincidence, really! */
00958    int s, e;
00959    
00960    dow = ast_strdupa(DOW->u1.str);
00961 
00962    /* Check for all days */
00963    if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
00964       return;
00965    /* Get start and ending days */
00966    c = strchr(dow, '-');
00967    if (c) {
00968       *c = '\0';
00969       c++;
00970    } else
00971       c = NULL;
00972    /* Find the start */
00973    s = 0;
00974    while ((s < 7) && strcasecmp(dow, days[s])) s++;
00975    if (s >= 7) {
00976       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",
00977             DOW->filename, DOW->startline, DOW->endline, dow);
00978       warns++;
00979    }
00980    if (c) {
00981       e = 0;
00982       while ((e < 7) && strcasecmp(c, days[e])) e++;
00983       if (e >= 7) {
00984          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",
00985                DOW->filename, DOW->startline, DOW->endline, c);
00986          warns++;
00987       }
00988    } else
00989       e = s;
00990 }

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

Definition at line 857 of file pbx_ael.c.

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

00858 {
00859    int spaces = strspn(str,"\t \n");
00860    if ( !strncmp(str+spaces,"$[",2) ) {
00861       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The expression '%s' is redundantly wrapped in '$[ ]'. \n",
00862             expr->filename, expr->startline, expr->endline, str);
00863       warns++;
00864    }
00865 }

static void check_goto pval item  )  [static]
 

Definition at line 1276 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(), in_context(), in_macro(), 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 find_pval_goto_item().

01277 {
01278    /* check for the target of the goto-- does it exist? */
01279    if ( !(item->u1.list)->next && !(item->u1.list)->u1.str ) {
01280       ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto:  empty label reference found!\n",
01281             item->filename, item->startline, item->endline);
01282       errs++;
01283    }
01284    
01285    /* just one item-- the label should be in the current extension */
01286    
01287    if (item->u1.list && !item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) {
01288       struct pval *z = get_extension_or_contxt(item);
01289       struct pval *x = 0;
01290       if (z)
01291          x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), z); /* if in macro, use current context instead */
01292       /* printf("Called find_label_in_current_extension with arg %s; current_extension is %x: %d\n",
01293          (char*)((item->u1.list)->u1.str), current_extension?current_extension:current_context, current_extension?current_extension->type:current_context->type); */
01294       if (!x) {
01295          ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto:  no label %s exists in the current extension!\n",
01296                item->filename, item->startline, item->endline, item->u1.list->u1.str);
01297          errs++;
01298       }
01299       else
01300          return;
01301    }
01302    
01303    /* TWO items */
01304    if (item->u1.list->next && !item->u1.list->next->next) {
01305       /* two items */
01306       /* printf("Calling find_label_in_current_context with args %s, %s\n",
01307          (char*)((item->u1.list)->u1.str), (char *)item->u1.list->next->u1.str); */
01308       if (!strstr((item->u1.list)->u1.str,"${") 
01309          && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ {
01310          struct pval *z = get_contxt(item);
01311          struct pval *x = 0;
01312          
01313          if (z)
01314             x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, z);
01315 
01316          if (!x) {
01317             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",
01318                   item->filename, item->startline, item->endline, item->u1.list->u1.str, item->u1.list->next->u1.str );
01319             errs++;
01320          }
01321          else
01322             return;
01323       }
01324    }
01325    
01326    /* All 3 items! */
01327    if (item->u1.list->next && item->u1.list->next->next) {
01328       /* all three */
01329       pval *first = item->u1.list;
01330       pval *second = item->u1.list->next;
01331       pval *third = item->u1.list->next->next;
01332       
01333       /* printf("Calling find_label_in_current_db with args %s, %s, %s\n",
01334          (char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); */
01335       if (!strstr((item->u1.list)->u1.str,"${") 
01336          && !strstr(item->u1.list->next->u1.str,"${")
01337          && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ {
01338          struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
01339          if (!x) {
01340             struct pval *p3;
01341             struct pval *found = 0;
01342             struct pval *that_context = find_context(item->u1.list->u1.str);
01343             
01344             /* the target of the goto could be in an included context!! Fancy that!! */
01345             /* look for includes in the current context */
01346             if (that_context) {
01347                for (p3=that_context->u2.statements; p3; p3=p3->next) {
01348                   if (p3->type == PV_INCLUDES) {
01349                      struct pval *p4;
01350                      for (p4=p3->u1.list; p4; p4=p4->next) {
01351                         /* for each context pointed to, find it, then find a context/label that matches the
01352                            target here! */
01353                         char *incl_context = p4->u1.str;
01354                         /* find a matching context name */
01355                         struct pval *that_other_context = find_context(incl_context);
01356                         if (that_other_context) {
01357                            struct pval *x3;
01358                            x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
01359                            if (x3) {
01360                               found = x3;
01361                               break;
01362                            }
01363                         }
01364                      }
01365                   }
01366                }
01367                if (!found) {
01368                   ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto:  no label %s|%s exists in the context %s or its inclusions!\n",
01369                         item->filename, item->startline, item->endline, item->u1.list->next->u1.str, item->u1.list->next->next->u1.str, item->u1.list->u1.str );
01370                   errs++;
01371                } else {
01372                   struct pval *mac = in_macro(item); /* is this goto inside a macro? */
01373                   if( mac ) {    /* yes! */
01374                      struct pval *targ = in_context(found);
01375                      if( mac != targ )
01376                      {
01377                         ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n",
01378                               item->filename, item->startline, item->endline);
01379                         warns++;                      
01380                      }
01381                   }
01382                }
01383             } else {
01384                ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto:  no context %s could be found that matches the goto target!\n",
01385                      item->filename, item->startline, item->endline, item->u1.list->u1.str);
01386                errs++;
01387             }
01388          } else {
01389             struct pval *mac = in_macro(item); /* is this goto inside a macro? */
01390             if( mac ) {    /* yes! */
01391                struct pval *targ = in_context(x);
01392                if( mac != targ )
01393                {
01394                   ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n",
01395                         item->filename, item->startline, item->endline);
01396                   warns++;                      
01397                }
01398             }
01399          }
01400       }
01401    }
01402 }

static void check_includes pval includes  )  [static]
 

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

00868 {
00869    struct pval *p4;
00870    for (p4=includes->u1.list; p4; p4=p4->next) {
00871       /* for each context pointed to, find it, then find a context/label that matches the
00872          target here! */
00873       char *incl_context = p4->u1.str;
00874       /* find a matching context name */
00875       struct pval *that_other_context = find_context(incl_context);
00876       if (!that_other_context && strcmp(incl_context, "parkedcalls") != 0) {
00877          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The included context '%s' cannot be found.\n",
00878                includes->filename, includes->startline, includes->endline, incl_context);
00879          warns++;
00880       }
00881    }
00882 }

static void check_label pval item  )  [static]
 

Definition at line 1161 of file pbx_ael.c.

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

01162 {
01163    struct pval *curr;
01164    struct pval *x;
01165    int alright = 0;
01166    
01167    /* A label outside an extension just plain does not make sense! */
01168    
01169    curr = item;
01170    
01171    while( curr ) {
01172       if( curr->type == PV_MACRO || curr->type == PV_EXTENSION   ) {
01173          alright = 1;
01174          break;
01175       }
01176       curr = curr->dad;
01177    }
01178    if( !alright )
01179    {
01180       ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Label %s is not within an extension or macro!\n",
01181             item->filename, item->startline, item->endline, item->u1.str);
01182       errs++;  
01183    }
01184    
01185    
01186    /* basically, ensure that a label is not repeated in a context. Period.
01187       The method:  well, for each label, find the first label in the context
01188       with the same name. If it's not the current label, then throw an error. */
01189 
01190    
01191    /* printf("==== check_label:   ====\n"); */
01192    if( !current_extension )
01193       curr = current_context;
01194    else
01195       curr = current_extension;
01196    
01197    x = find_first_label_in_current_context((char *)item->u1.str, curr);
01198    /* 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); */
01199    if( x && x != item )
01200    {
01201       ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Duplicate label %s! Previously defined at file %s, line %d.\n",
01202             item->filename, item->startline, item->endline, item->u1.str, x->filename, x->startline);
01203       errs++;
01204    }
01205    /* printf("<<<<< check_label:   ====\n"); */
01206 }

static void check_macro_returns pval macro  )  [static]
 

Definition at line 702 of file pbx_ael.c.

References ast_log(), calloc, pval::endcol, pval::endline, pval::filename, LOG_WARNING, pval::macro_statements, pval::next, PV_RETURN, pval::startcol, pval::startline, pval::str, strdup, pval::type, pval::u1, and pval::u3.

Referenced by check_pval_item().

00703 {
00704    pval *i;
00705    if (!macro->u3.macro_statements)
00706    {
00707       pval *z = calloc(1, sizeof(struct pval));
00708       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s is empty! I will insert a return.\n",
00709             macro->filename, macro->startline, macro->endline, macro->u1.str);
00710 
00711       z->type = PV_RETURN;
00712       z->startline = macro->startline;
00713       z->endline = macro->endline;
00714       z->startcol = macro->startcol;
00715       z->endcol = macro->endcol;
00716       z->filename = strdup(macro->filename);
00717 
00718       macro->u3.macro_statements = z;
00719       return;
00720    }
00721    for (i=macro->u3.macro_statements; i; i=i->next) {
00722       /* if the last statement in the list is not return, then insert a return there */
00723       if (i->next == NULL) {
00724          if (i->type != PV_RETURN) {
00725             pval *z = calloc(1, sizeof(struct pval));
00726             ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s does not end with a return; I will insert one.\n",
00727                   macro->filename, macro->startline, macro->endline, macro->u1.str);
00728 
00729             z->type = PV_RETURN;
00730             z->startline = macro->startline;
00731             z->endline = macro->endline;
00732             z->startcol = macro->startcol;
00733             z->endcol = macro->endcol;
00734             z->filename = strdup(macro->filename);
00735 
00736             i->next = z;
00737             return;
00738          }
00739       }
00740    }
00741    return;
00742 }

static void check_month pval MON  )  [static]
 

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

01056 {
01057    char *mon;
01058    char *c;
01059    /* The following line is coincidence, really! */
01060    int s, e;
01061 
01062    mon = ast_strdupa(MON->u1.str);
01063 
01064    /* Check for all days */
01065    if (ast_strlen_zero(mon) || !strcmp(mon, "*")) 
01066       return ;
01067    /* Get start and ending days */
01068    c = strchr(mon, '-');
01069    if (c) {
01070       *c = '\0';
01071       c++;
01072    }
01073    /* Find the start */
01074    s = 0;
01075    while ((s < 12) && strcasecmp(mon, months[s])) s++;
01076    if (s >= 12) {
01077       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
01078             MON->filename, MON->startline, MON->endline, mon);
01079       warns++;
01080    }
01081    if (c) {
01082       e = 0;
01083       while ((e < 12) && strcasecmp(mon, months[e])) e++;
01084       if (e >= 12) {
01085          ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
01086                MON->filename, MON->startline, MON->endline, c);
01087          warns++;
01088       }
01089    } else
01090       e = s;
01091 }

void check_pval pval item,
struct argapp apps,
int  in_globals
 

Definition at line 2785 of file pbx_ael.c.

References check_pval_item(), and pval::next.

Referenced by ael2_semantic_check(), and check_pval_item().

02786 {
02787    pval *i;
02788 
02789    /* checks to do:
02790       1. Do goto's point to actual labels? 
02791       2. Do macro calls reference a macro?
02792       3. Does the number of macro args match the definition?
02793       4. Is a macro call missing its & at the front?
02794       5. Application calls-- we could check syntax for existing applications,
02795          but I need some some sort of universal description bnf for a general
02796         sort of method for checking arguments, in number, maybe even type, at least. 
02797         Don't want to hand code checks for hundreds of applications.
02798    */
02799    
02800    for (i=item; i; i=i->next) {
02801       check_pval_item(i,apps,in_globals);
02802    }
02803 }

void check_pval_item pval item,
struct argapp apps,
int  in_globals
 

Definition at line 2343 of file pbx_ael.c.

References pval::abstract, app, pval::arglist, ast_log(), check_abstract_reference(), check_macro_returns(), check_pval(), current_context, current_extension, pval::endline, pval::filename, find_context(), find_macro(), free, LOG_ERROR, LOG_WARNING, pval::macro_statements, pval::next, PV_APPLICATION_CALL, PV_CONTEXT, PV_MACRO, PV_MACRO_CALL, PV_RETURN, PV_WORD, pval::startline, pval::statements, pval::str, pval::type, pval::u1, pval::u2, and pval::u3.

Referenced by check_pval().

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

void check_switch_expr pval item,
struct argapp apps
 

Definition at line 2197 of file pbx_ael.c.

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

02198 {
02199 #ifdef AAL_ARGCHECK
02200    /* get and clean the variable name */
02201    char *buff1, *p;
02202    struct argapp *a,*a2;
02203    struct appsetvar *v,*v2;
02204    struct argchoice *c;
02205    pval *t;
02206    
02207    p = item->u1.str;
02208    while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) )
02209       p++;
02210    
02211    buff1 = ast_strdupa(p);
02212 
02213    while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t'))
02214       buff1[strlen(buff1)-1] = 0;
02215    /* buff1 now contains the variable name */
02216    v = 0;
02217    for (a=apps; a; a=a->next) {
02218       for (v=a->setvars;v;v=v->next) {
02219          if (strcmp(v->name,buff1) == 0) {
02220             break;
02221          }
02222       }
02223       if ( v )
02224          break;
02225    }
02226    if (v && v->vals) {
02227       /* we have a match, to a variable that has a set of determined values */
02228       int def= 0;
02229       int pat = 0;
02230       int f1 = 0;
02231       
02232       /* first of all, does this switch have a default case ? */
02233       for (t=item->u2.statements; t; t=t->next) {
02234          if (t->type == PV_DEFAULT) {
02235             def =1;
02236             break;
02237          }
02238          if (t->type == PV_PATTERN) {
02239             pat++;
02240          }
02241       }
02242       if (def || pat) /* nothing to check. All cases accounted for! */
02243          return;
02244       for (c=v->vals; c; c=c->next) {
02245          f1 = 0;
02246          for (t=item->u2.statements; t; t=t->next) {
02247             if (t->type == PV_CASE || t->type == PV_PATTERN) {
02248                if (!strcmp(t->u1.str,c->name)) {
02249                   f1 = 1;
02250                   break;
02251                }
02252             }
02253          }
02254          if (!f1) {
02255             ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n",
02256                   item->filename, item->startline, item->endline, item->u1.str, c->name);
02257             warns++;
02258          }
02259       }
02260       /* next, is there an app call in the current exten, that would set this var? */
02261       f1 = 0;
02262       t = current_extension->u2.statements;
02263       if ( t && t->type == PV_STATEMENTBLOCK )
02264          t = t->u1.statements;
02265       for (; t && t != item; t=t->next) {
02266          if (t->type == PV_APPLICATION_CALL) {
02267             /* find the application that matches the u1.str */
02268             for (a2=apps; a2; a2=a2->next) {
02269                if (strcasecmp(a2->name, t->u1.str)==0) {
02270                   for (v2=a2->setvars; v2; v2=v2->next) {
02271                      if (strcmp(v2->name, buff1) == 0) {
02272                         /* found an app that sets the var */
02273                         f1 = 1;
02274                         break;
02275                      }
02276                   }
02277                }
02278                if (f1)
02279                   break;
02280             }
02281          }
02282          if (f1)
02283             break;
02284       }
02285             
02286       /* see if it sets the var */
02287       if (!f1) {
02288          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",
02289                item->filename, item->startline, item->endline, item->u1.str);
02290          warns++;
02291       }
02292    }
02293 #endif
02294 }

static void check_timerange pval p  )  [static]
 

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

00886 {
00887    char *times;
00888    char *e;
00889    int s1, s2;
00890    int e1, e2;
00891 
00892    times = ast_strdupa(p->u1.str);
00893 
00894    /* Star is all times */
00895    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
00896       return;
00897    }
00898    /* Otherwise expect a range */
00899    e = strchr(times, '-');
00900    if (!e) {
00901       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",
00902             p->filename, p->startline, p->endline, times);
00903       warns++;
00904       return;
00905    }
00906    *e = '\0';
00907    e++;
00908    while (*e && !isdigit(*e)) 
00909       e++;
00910    if (!*e) {
00911       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n",
00912             p->filename, p->startline, p->endline, p->u1.str);
00913       warns++;
00914    }
00915    if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
00916       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) isn't quite right!\n",
00917             p->filename, p->startline, p->endline, times);
00918       warns++;
00919    }
00920    if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
00921       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) isn't quite right!\n",
00922             p->filename, p->startline, p->endline, times);
00923       warns++;
00924    }
00925 
00926    s1 = s1 * 30 + s2/2;
00927    if ((s1 < 0) || (s1 >= 24*30)) {
00928       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) is out of range!\n",
00929             p->filename, p->startline, p->endline, times);
00930       warns++;
00931    }
00932    e1 = e1 * 30 + e2/2;
00933    if ((e1 < 0) || (e1 >= 24*30)) {
00934       ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) is out of range!\n",
00935             p->filename, p->startline, p->endline, e);
00936       warns++;
00937    }
00938    return;
00939 }

void destroy_extensions struct ael_extension exten  ) 
 

Definition at line 2867 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::name, ael_priority::next, ael_priority::origin, and ael_extension::plist.

02868 {
02869    struct ael_extension *ne, *nen;
02870    for (ne=exten; ne; ne=nen) {
02871       struct ael_priority *pe, *pen;
02872       
02873       if (ne->name)
02874          free(ne->name);
02875       
02876       /* cidmatch fields are allocated with name, and freed when
02877          the name field is freed. Don't do a free for this field,
02878          unless you LIKE to see a crash! */
02879 
02880       if (ne->hints)
02881          free(ne->hints);
02882       
02883       for (pe=ne->plist; pe; pe=pen) {
02884          pen = pe->next;
02885          if (pe->app)
02886             free(pe->app);
02887          pe->app = 0;
02888          if (pe->appargs)
02889             free(pe->appargs);
02890          pe->appargs = 0;
02891          pe->origin = 0;
02892          pe->goto_true = 0;
02893          pe->goto_false = 0;
02894          free(pe);
02895       }
02896       nen = ne->next_exten;
02897       ne->next_exten = 0;
02898       ne->plist =0;
02899       ne->plist_last = 0;
02900       ne->next_exten = 0;
02901       ne->loop_break = 0;
02902       ne->loop_continue = 0;
02903       free(ne);
02904    }
02905 }

void destroy_pval pval item  ) 
 

void destroy_pval_item pval item  ) 
 

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

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

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

Definition at line 746 of file pbx_ael.c.

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

Referenced by match_pval_item().

00747 {
00748    int err1;
00749    regex_t preg;
00750    
00751    /* simple case, they match exactly, the pattern and exten name */
00752    if (!strcmp(pattern,exten) == 0)
00753       return 1;
00754    
00755    if (pattern[0] == '_') {
00756       char reg1[2000];
00757       const char *p;
00758       char *r = reg1;
00759       
00760       if ( strlen(pattern)*5 >= 2000 ) /* safety valve */ {
00761          ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n",
00762                pattern);
00763          return 0;
00764       }
00765       /* form a regular expression from the pattern, and then match it against exten */
00766       *r++ = '^'; /* what if the extension is a pattern ?? */
00767       *r++ = '_'; /* what if the extension is a pattern ?? */
00768       *r++ = '?';
00769       for (p=pattern+1; *p; p++) {
00770          switch ( *p ) {
00771          case 'X':
00772             *r++ = '[';
00773             *r++ = '0';
00774             *r++ = '-';
00775             *r++ = '9';
00776             *r++ = 'X';
00777             *r++ = ']';
00778             break;
00779             
00780          case 'Z':
00781             *r++ = '[';
00782             *r++ = '1';
00783             *r++ = '-';
00784             *r++ = '9';
00785             *r++ = 'Z';
00786             *r++ = ']';
00787             break;
00788             
00789          case 'N':
00790             *r++ = '[';
00791             *r++ = '2';
00792             *r++ = '-';
00793             *r++ = '9';
00794             *r++ = 'N';
00795             *r++ = ']';
00796             break;
00797             
00798          case '[':
00799             while ( *p && *p != ']' ) {
00800                *r++ = *p++;
00801             }
00802             if ( *p != ']') {
00803                ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The extension pattern '%s' is missing a closing bracket \n",
00804                      here->filename, here->startline, here->endline, pattern);
00805             }
00806             break;
00807             
00808          case '.':
00809          case '!':
00810             *r++ = '.';
00811             *r++ = '*';
00812             break;
00813          case '*':
00814             *r++ = '\\';
00815             *r++ = '*';
00816             break;
00817          default:
00818             *r++ = *p;
00819             break;
00820             
00821          }
00822       }
00823       *r++ = '$'; /* what if the extension is a pattern ?? */
00824       *r++ = *p++; /* put in the closing null */
00825       err1 = regcomp(&preg, reg1, REG_NOSUB|REG_EXTENDED);
00826       if ( err1 ) {
00827          char errmess[500];
00828          regerror(err1,&preg,errmess,sizeof(errmess));
00829          regfree(&preg);
00830          ast_log(LOG_WARNING, "Regcomp of %s failed, error code %d\n",
00831                reg1, err1);
00832          return 0;
00833       }
00834       err1 = regexec(&preg, exten, 0, 0, 0);
00835       regfree(&preg);
00836       
00837       if ( err1 ) {
00838          /* ast_log(LOG_NOTICE,"*****************************[%d]Extension %s did not match %s(%s)\n",
00839             err1,exten, pattern, reg1); */
00840          return 0; /* no match */
00841       } else {
00842          /* ast_log(LOG_NOTICE,"*****************************Extension %s matched %s\n",
00843             exten, pattern); */
00844          return 1;
00845       }
00846       
00847       
00848    } else {
00849       if ( strcmp(exten,pattern) == 0 ) {
00850          return 1;
00851       } else
00852          return 0;
00853    }
00854 }

struct pval * find_context char *  name  ) 
 

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

01967 {
01968    return_on_context_match = 1;
01969    count_labels = 0;
01970    match_context = name;
01971    match_exten = "*";  /* don't really need to set these, shouldn't be reached */
01972    match_label = "*";
01973    return match_pval(current_db);
01974 }

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

Definition at line 1852 of file pbx_ael.c.

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

Referenced by check_label().

01853 {
01854    /* printf("  --- Got args %s, %s\n", exten, label); */
01855    struct pval *ret;
01856    struct pval *p3;
01857    
01858    count_labels = 0;
01859    return_on_context_match = 0;
01860    match_context = "*";
01861    match_exten = "*";
01862    match_label = label;
01863    
01864    ret =  match_pval(curr_cont);
01865    if (ret)
01866       return ret;
01867                
01868    /* the target of the goto could be in an included context!! Fancy that!! */
01869    /* look for includes in the current context */
01870    for (p3=curr_cont->u2.statements; p3; p3=p3->next) {
01871       if (p3->type == PV_INCLUDES) {
01872          struct pval *p4;
01873          for (p4=p3->u1.list; p4; p4=p4->next) {
01874             /* for each context pointed to, find it, then find a context/label that matches the
01875                target here! */
01876             char *incl_context = p4->u1.str;
01877             /* find a matching context name */
01878             struct pval *that_context = find_context(incl_context);
01879             if (that_context) {
01880                struct pval *x3;
01881                x3 = find_first_label_in_current_context(label, that_context);
01882                if (x3) {
01883                   return x3;
01884                }
01885             }
01886          }
01887       }
01888    }
01889    return 0;
01890 }

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

Definition at line 1892 of file pbx_ael.c.

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

Referenced by check_goto(), and get_goto_target().

01893 {
01894    /* printf("  --- Got args %s, %s\n", exten, label); */
01895    struct pval *ret;
01896    struct pval *p3;
01897    
01898    count_labels = 0;
01899    return_on_context_match = 0;
01900    match_context = "*";
01901    match_exten = exten;
01902    match_label = label;
01903    ret =  match_pval(curr_cont->u2.statements);
01904    if (ret)
01905       return ret;
01906                
01907    /* the target of the goto could be in an included context!! Fancy that!! */
01908    /* look for includes in the current context */
01909    for (p3=curr_cont->u2.statements; p3; p3=p3->next) {
01910       if (p3->type == PV_INCLUDES) {
01911          struct pval *p4;
01912          for (p4=p3->u1.list; p4; p4=p4->next) {
01913             /* for each context pointed to, find it, then find a context/label that matches the
01914                target here! */
01915             char *incl_context = p4->u1.str;
01916             /* find a matching context name */
01917             struct pval *that_context = find_context(incl_context);
01918             if (that_context) {
01919                struct pval *x3;
01920                x3 = find_label_in_current_context(exten, label, that_context);
01921                if (x3) {
01922                   return x3;
01923                }
01924             }
01925          }
01926       }
01927    }
01928    return 0;
01929 }

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

Definition at line 1942 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_goto(), and get_goto_target().

01943 {
01944    /* printf("  --- Got args %s, %s, %s\n", context, exten, label); */
01945    count_labels = 0;
01946    return_on_context_match = 0;
01947 
01948    match_context = context;
01949    match_exten = exten;
01950    match_label = label;
01951    
01952    return match_pval(current_db);
01953 }

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

Definition at line 1931 of file pbx_ael.c.

References match_pval().

Referenced by check_goto(), and get_goto_target().

01932 {
01933    /* printf("  --- Got args %s\n", label); */
01934    count_labels = 0;
01935    return_on_context_match = 0;
01936    match_context = "*";
01937    match_exten = "*";
01938    match_label = label;
01939    return match_pval(curr_ext);
01940 }

struct pval * find_macro char *  name  ) 
 

Definition at line 1956 of file pbx_ael.c.

References current_db, and match_pval().

Referenced by check_pval_item().

01957 {
01958    return_on_context_match = 1;
01959    count_labels = 0;
01960    match_context = name;
01961    match_exten = "*";  /* don't really need to set these, shouldn't be reached */
01962    match_label = "*";
01963    return match_pval(current_db);
01964 }

static void find_pval_goto_item pval item,
int  lev
[static]
 

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

01406 {
01407    struct pval *p4;
01408    if (lev>100) {
01409       ast_log(LOG_ERROR,"find_pval_goto in infinite loop!\n\n");
01410       return;
01411    }
01412    
01413    switch ( item->type ) {
01414    case PV_MACRO:
01415       /* fields: item->u1.str     == name of macro
01416                  item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
01417                item->u2.arglist->u1.str  == argument
01418                item->u2.arglist->next   == next arg
01419 
01420                item->u3.macro_statements == pval list of statements in macro body.
01421       */
01422          
01423       /* printf("Descending into matching macro %s\n", match_context); */
01424       find_pval_gotos(item->u3.macro_statements,lev+1); /* if we're just searching for a context, don't bother descending into them */
01425       
01426       break;
01427          
01428    case PV_CONTEXT:
01429       /* fields: item->u1.str     == name of context
01430                  item->u2.statements == pval list of statements in context body
01431                item->u3.abstract == int 1 if an abstract keyword were present
01432       */
01433       break;
01434 
01435    case PV_CASE:
01436       /* fields: item->u1.str     == value of case
01437                  item->u2.statements == pval list of statements under the case
01438       */
01439       find_pval_gotos(item->u2.statements,lev+1);
01440       break;
01441          
01442    case PV_PATTERN:
01443       /* fields: item->u1.str     == value of case
01444                  item->u2.statements == pval list of statements under the case
01445       */
01446       find_pval_gotos(item->u2.statements,lev+1);
01447       break;
01448          
01449    case PV_DEFAULT:
01450       /* fields: 
01451                  item->u2.statements == pval list of statements under the case
01452       */
01453       find_pval_gotos(item->u2.statements,lev+1);
01454       break;
01455          
01456    case PV_CATCH:
01457       /* fields: item->u1.str     == name of extension to catch
01458                  item->u2.statements == pval list of statements in context body
01459       */
01460       find_pval_gotos(item->u2.statements,lev+1);
01461       break;
01462          
01463    case PV_STATEMENTBLOCK:
01464       /* fields: item->u1.list     == pval list of statements in block, one per entry in the list
01465       */
01466       find_pval_gotos(item->u1.list,lev+1);
01467       break;
01468          
01469    case PV_GOTO:
01470       /* fields: item->u1.list     == pval list of PV_WORD target names, up to 3, in order as given by user.
01471                  item->u1.list->u1.str  == where the data on a PV_WORD will always be.
01472       */
01473       check_goto(item);  /* THE WHOLE FUNCTION OF THIS ENTIRE ROUTINE!!!! */
01474       break;
01475          
01476    case PV_INCLUDES:
01477       /* fields: item->u1.list     == pval list of PV_WORD elements, one per entry in the list
01478       */
01479       for (p4=item->u1.list; p4; p4=p4->next) {
01480          /* for each context pointed to, find it, then find a context/label that matches the
01481             target here! */
01482          char *incl_context = p4->u1.str;
01483          /* find a matching context name */
01484          struct pval *that_context = find_context(incl_context);
01485          if (that_context) {
01486             find_pval_gotos(that_context,lev+1); /* keep working up the includes */
01487          }
01488       }
01489       break;
01490       
01491    case PV_FOR:
01492       /* fields: item->u1.for_init     == a string containing the initalizer
01493                  item->u2.for_test     == a string containing the loop test
01494                  item->u3.for_inc      == a string containing the loop increment
01495 
01496                item->u4.for_statements == a pval list of statements in the for ()
01497       */
01498       find_pval_gotos(item->u4.for_statements,lev+1);
01499       break;
01500          
01501    case PV_WHILE:
01502       /* fields: item->u1.str        == the while conditional, as supplied by user
01503 
01504                item->u2.statements == a pval list of statements in the while ()
01505       */
01506       find_pval_gotos(item->u2.statements,lev+1);
01507       break;
01508          
01509    case PV_RANDOM:
01510       /* fields: item->u1.str        == the random number expression, as supplied by user
01511 
01512                item->u2.statements == a pval list of statements in the if ()
01513                item->u3.else_statements == a pval list of statements in the else
01514                                     (could be zero)
01515        fall thru to PV_IF */
01516       
01517    case PV_IFTIME:
01518       /* fields: item->u1.list        == the time values, 4 of them, as PV_WORD structs in a list
01519 
01520                item->u2.statements == a pval list of statements in the if ()
01521                item->u3.else_statements == a pval list of statements in the else
01522                                     (could be zero)
01523       fall thru to PV_IF*/
01524    case PV_IF:
01525       /* fields: item->u1.str        == the if conditional, as supplied by user
01526 
01527                item->u2.statements == a pval list of statements in the if ()
01528                item->u3.else_statements == a pval list of statements in the else
01529                                     (could be zero)
01530       */
01531       find_pval_gotos(item->u2.statements,lev+1);
01532 
01533       if (item->u3.else_statements) {
01534          find_pval_gotos(item->u3.else_statements,lev+1);
01535       }
01536       break;
01537          
01538    case PV_SWITCH:
01539       /* fields: item->u1.str        == the switch expression
01540 
01541                item->u2.statements == a pval list of statements in the switch, 
01542                                     (will be case statements, most likely!)
01543       */
01544       find_pval_gotos(item->u3.else_statements,lev+1);
01545       break;
01546          
01547    case PV_EXTENSION:
01548       /* fields: item->u1.str        == the extension name, label, whatever it's called
01549 
01550                item->u2.statements == a pval list of statements in the extension
01551                item->u3.hints      == a char * hint argument
01552                item->u4.regexten   == an int boolean. non-zero says that regexten was specified
01553       */
01554 
01555       find_pval_gotos(item->u2.statements,lev+1);
01556       break;
01557 
01558    default:
01559       break;
01560    }
01561 }

static void find_pval_gotos pval item,
int  lev
[static]
 

Definition at line 1563 of file pbx_ael.c.

References find_pval_goto_item(), and pval::next.

Referenced by find_pval_goto_item().

01564 {
01565    pval *i;
01566 
01567    for (i=item; i; i=i->next) {
01568       
01569       find_pval_goto_item(i, lev);
01570    }
01571 }

static void fix_gotos_in_extensions struct ael_extension exten  )  [static]
 

Definition at line 3751 of file pbx_ael.c.

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

03752 {
03753    struct ael_extension *e;
03754    for(e=exten;e;e=e->next_exten) {
03755 
03756       struct ael_priority *p;
03757       for(p=e->plist;p;p=p->next) {
03758          
03759          if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) {
03760             
03761             /* fix the extension of the goto target to the actual extension in the post-compiled dialplan */
03762 
03763             pval *target = p->origin->u2.goto_target;
03764             struct ael_extension *z = target->u3.compiled_label;
03765             pval *pv2 = p->origin;
03766             char buf1[500];
03767             char *apparg_save = p->appargs;
03768             
03769             p->appargs = 0;
03770             if (!pv2->u1.list->next) /* just one  -- it won't hurt to repeat the extension */ {
03771                snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->u1.str);
03772                p->appargs = strdup(buf1);
03773                
03774             } else if (pv2->u1.list->next && !pv2->u1.list->next->next) /* two */ {
03775                snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->next->u1.str);
03776                p->appargs = strdup(buf1);
03777             } else if (pv2->u1.list->next && pv2->u1.list->next->next) {
03778                snprintf(buf1,sizeof(buf1),"%s|%s|%s", pv2->u1.list->u1.str, 
03779                       z->name,
03780                       pv2->u1.list->next->next->u1.str);
03781                p->appargs = strdup(buf1);
03782             }
03783             else
03784                printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n");
03785             
03786             if( apparg_save ) {
03787                free(apparg_save);
03788             }
03789          }
03790       }
03791    }
03792 }

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

Definition at line 2946 of file pbx_ael.c.

Referenced by gen_prios().

02947 {
02948    /* the result will be a string that will be matched by pattern */
02949    char *p=pattern, *t=result;
02950    while (*p) {
02951       if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
02952          *t++ = '9';
02953       else if (*p == '[') {
02954          char *z = p+1;
02955          while (*z != ']')
02956             z++;
02957          if (*(z+1)== ']')
02958             z++;
02959          *t++=*(p+1); /* use the first char in the set */
02960          p = z;
02961       } else {
02962          *t++ = *p;
02963       }
02964       p++;
02965    }
02966    *t++ = 0; /* cap it off */
02967 }

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

References AEL_APPCALL, AEL_CONTROL1, AEL_FOR_CONTROL, AEL_IF_CONTROL, AEL_IFTIME_CONTROL, AEL_LABEL, 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, 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.

Referenced by ast_compile_ael2().

02970 {
02971    pval *p,*p2,*p3;
02972    struct ael_priority *pr;
02973    struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end;
02974    struct ael_priority *while_test, *while_loop, *while_end;
02975    struct ael_priority *switch_test, *switch_end, *fall_thru;
02976    struct ael_priority *if_test, *if_end, *if_skip, *if_false;
02977 #ifdef OLD_RAND_ACTION
02978    struct ael_priority *rand_test, *rand_end, *rand_skip;
02979 #endif
02980    char buf1[2000];
02981    char buf2[2000];
02982    char *strp, *strp2;
02983    char new_label[2000];
02984    int default_exists;
02985    int local_control_statement_count;
02986    int first;
02987    struct ael_priority *loop_break_save;
02988    struct ael_priority *loop_continue_save;
02989    struct ael_extension *switch_case;
02990    
02991    for (p=statement; p; p=p->next) {
02992       switch (p->type) {
02993       case PV_VARDEC:
02994          pr = new_prio();
02995          pr->type = AEL_APPCALL;
02996          snprintf(buf1,sizeof(buf1),"%s=$[%s]", p->u1.str, p->u2.val);
02997          pr->app = strdup("Set");
02998          remove_spaces_before_equals(buf1);
02999          pr->appargs = strdup(buf1);
03000          pr->origin = p;
03001          linkprio(exten, pr);
03002          break;
03003 
03004       case PV_GOTO:
03005          pr = new_prio();
03006          pr->type = AEL_APPCALL;
03007          p->u2.goto_target = get_goto_target(p);
03008          if( p->u2.goto_target ) {
03009             p->u3.goto_target_in_case = p->u2.goto_target->u2.label_in_case = label_inside_case(p->u2.goto_target);
03010          }
03011          
03012          if (!p->u1.list->next) /* just one */ {
03013             pr->app = strdup("Goto");
03014             if (!mother_exten)
03015                pr->appargs = strdup(p->u1.list->u1.str);
03016             else {  /* for the case of simple within-extension gotos in case/pattern/default statement blocks: */ 
03017                snprintf(buf1,sizeof(buf1),"%s|%s", mother_exten->name, p->u1.list->u1.str);
03018                pr->appargs = strdup(buf1);
03019             }
03020             
03021          } else if (p->u1.list->next && !p->u1.list->next->next) /* two */ {
03022             snprintf(buf1,sizeof(buf1),"%s|%s", p->u1.list->u1.str, p->u1.list->next->u1.str);
03023             pr->app = strdup("Goto");
03024             pr->appargs = strdup(buf1);
03025          } else if (p->u1.list->next && p->u1.list->next->next) {
03026             snprintf(buf1,sizeof(buf1),"%s|%s|%s", p->u1.list->u1.str, 
03027                   p->u1.list->next->u1.str,
03028                   p->u1.list->next->next->u1.str);
03029             pr->app = strdup("Goto");
03030             pr->appargs = strdup(buf1);
03031          }
03032          pr->origin = p;
03033          linkprio(exten, pr);
03034          break;
03035 
03036       case PV_LABEL:
03037          pr = new_prio();
03038          pr->type = AEL_LABEL;
03039          pr->origin = p;
03040          p->u3.compiled_label = exten;
03041          linkprio(exten, pr);
03042          break;
03043 
03044       case PV_FOR:
03045          control_statement_count++;
03046          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
03047          loop_continue_save = exten->loop_continue;
03048          snprintf(new_label,sizeof(new_label),"for-%s-%d", label, control_statement_count);
03049          for_init = new_prio();
03050          for_inc = new_prio();
03051          for_test = new_prio();
03052          for_loop = new_prio();
03053          for_end = new_prio();
03054          for_init->type = AEL_APPCALL;
03055          for_inc->type = AEL_APPCALL;
03056          for_test->type = AEL_FOR_CONTROL;
03057          for_test->goto_false = for_end;
03058          for_loop->type = AEL_CONTROL1; /* simple goto */
03059          for_end->type = AEL_APPCALL;
03060          for_init->app = strdup("Set");
03061          
03062          strcpy(buf2,p->u1.for_init);
03063          remove_spaces_before_equals(buf2);
03064          strp = strchr(buf2, '=');
03065          strp2 = strchr(p->u1.for_init, '=');
03066          if (strp) {
03067             *(strp+1) = 0;
03068             strcat(buf2,"$[");
03069             strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03070             strcat(buf2,"]");
03071             for_init->appargs = strdup(buf2);
03072          } else
03073             for_init->appargs = strdup(p->u1.for_init);
03074 
03075          for_inc->app = strdup("Set");
03076 
03077          strcpy(buf2,p->u3.for_inc);
03078          remove_spaces_before_equals(buf2);
03079          strp = strchr(buf2, '=');
03080          strp2 = strchr(p->u3.for_inc, '=');
03081          if (strp) {
03082             *(strp+1) = 0;
03083             strcat(buf2,"$[");
03084             strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2);
03085             strcat(buf2,"]");
03086             for_inc->appargs = strdup(buf2);
03087          } else
03088             for_inc->appargs = strdup(p->u3.for_inc);
03089          snprintf(buf1,sizeof(buf1),"$[%s]",p->u2.for_test);
03090          for_test->app = 0;
03091          for_test->appargs = strdup(buf1);
03092          for_loop->goto_true = for_test;
03093          snprintf(buf1,sizeof(buf1),"Finish for-%s-%d", label, control_statement_count);
03094          for_end->app = strdup("NoOp");
03095          for_end->appargs = strdup(buf1);
03096          /* link & load! */
03097          linkprio(exten, for_init);
03098          linkprio(exten, for_test);
03099          
03100          /* now, put the body of the for loop here */
03101          exten->loop_break = for_end;
03102          exten->loop_continue = for_test;
03103          
03104          gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context); /* this will link in all the statements here */
03105          
03106          linkprio(exten, for_inc);
03107          linkprio(exten, for_loop);
03108          linkprio(exten, for_end);
03109          
03110          
03111          exten->loop_break = loop_break_save;
03112          exten->loop_continue = loop_continue_save;
03113          for_loop->origin = p;
03114          break;
03115 
03116       case PV_WHILE:
03117          control_statement_count++;
03118          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
03119          loop_continue_save = exten->loop_continue;
03120          snprintf(new_label,sizeof(new_label),"while-%s-%d", label, control_statement_count);
03121          while_test = new_prio();
03122          while_loop = new_prio();
03123          while_end = new_prio();
03124          while_test->type = AEL_FOR_CONTROL;
03125          while_test->goto_false = while_end;
03126          while_loop->type = AEL_CONTROL1; /* simple goto */
03127          while_end->type = AEL_APPCALL;
03128          snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str);
03129          while_test->app = 0;
03130          while_test->appargs = strdup(buf1);
03131          while_loop->goto_true = while_test;
03132          snprintf(buf1,sizeof(buf1),"Finish while-%s-%d", label, control_statement_count);
03133          while_end->app = strdup("NoOp");
03134          while_end->appargs = strdup(buf1);
03135 
03136          linkprio(exten, while_test);
03137          
03138          /* now, put the body of the for loop here */
03139          exten->loop_break = while_end;
03140          exten->loop_continue = while_test;
03141          
03142          gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the while body statements here */
03143 
03144          linkprio(exten, while_loop);
03145          linkprio(exten, while_end);
03146          
03147          
03148          exten->loop_break = loop_break_save;
03149          exten->loop_continue = loop_continue_save;
03150          while_loop->origin = p;
03151          break;
03152 
03153       case PV_SWITCH:
03154          control_statement_count++;
03155          local_control_statement_count = control_statement_count;
03156          loop_break_save = exten->loop_break; /* save them, then restore before leaving */
03157          loop_continue_save = exten->loop_continue;
03158          snprintf(new_label,sizeof(new_label),"sw-%s-%d", label, control_statement_count);
03159 
03160          switch_test = new_prio();
03161          switch_end = new_prio();
03162          switch_test->type = AEL_APPCALL;
03163          switch_end->type = AEL_APPCALL;
03164          snprintf(buf1,sizeof(buf1),"sw-%d-%s|1",control_statement_count, p->u1.str);
03165          switch_test->app = strdup("Goto");
03166          switch_test->appargs = strdup(buf1);
03167          snprintf(buf1,sizeof(buf1),"Finish switch-%s-%d", label, control_statement_count);
03168          switch_end->app = strdup("NoOp");
03169          switch_end->appargs = strdup(buf1);
03170          switch_end->origin = p;
03171          switch_end->exten = exten;
03172 
03173          linkprio(exten, switch_test);
03174          linkprio(exten, switch_end);
03175          
03176          exten->loop_break = switch_end;
03177          exten->loop_continue = 0;
03178          default_exists = 0;
03179          
03180          for (p2=p->u2.statements; p2; p2=p2->next) {
03181             /* now, for each case/default put the body of the for loop here */
03182             if (p2->type == PV_CASE) {
03183                /* ok, generate a extension and link it in */
03184                switch_case = new_exten();
03185                switch_case->context = this_context;
03186                /* the break/continue locations are inherited from parent */
03187                switch_case->loop_break = exten->loop_break;
03188                switch_case->loop_continue = exten->loop_continue;
03189                
03190                linkexten(exten,switch_case);
03191                snprintf(buf1,sizeof(buf1),"sw-%d-%s", local_control_statement_count, p2->u1.str);
03192                switch_case->name = strdup(buf1);
03193                snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, p2->u1.str, local_control_statement_count);
03194                
03195                gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the case body statements here */
03196 
03197                /* here is where we write code to "fall thru" to the next case... if there is one... */
03198                for (p3=p2->u2.statements; p3; p3=p3->next) {
03199                   if (!p3->next)
03200                      break;
03201                }
03202                /* p3 now points the last statement... */
03203                if (