#include "asterisk.h"
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <regex.h>
#include <sys/stat.h>
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/callerid.h"
#include "asterisk/ael_structs.h"
Go to the source code of this file.
Data Structures | |
struct | argapp |
Defines | |
#define | AST_MAX_FILENAME_LEN 256 |
#define | DEBUG_CONTEXTS (1 << 3) |
#define | DEBUG_MACROS (1 << 2) |
#define | DEBUG_READ (1 << 0) |
#define | DEBUG_TOKENS (1 << 1) |
Functions | |
void | add_extensions (struct ael_extension *exten) |
static int | ael2_debug_contexts (int fd, int argc, char *argv[]) |
static int | ael2_debug_macros (int fd, int argc, char *argv[]) |
static int | ael2_debug_read (int fd, int argc, char *argv[]) |
static int | ael2_debug_tokens (int fd, int argc, char *argv[]) |
static int | ael2_no_debug (int fd, int argc, char *argv[]) |
static int | ael2_reload (int fd, int argc, char *argv[]) |
static void | ael2_semantic_check (pval *item, int *arg_errs, int *arg_warns, int *arg_notes) |
void | ast_compile_ael2 (struct ast_context **local_contexts, struct pval *root) |
int | ast_expr (char *expr, char *buf, int length) |
void | ast_expr_clear_extra_error_info (void) |
void | ast_expr_register_extra_error_info (char *errmsg) |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Asterisk Extension Language Compiler",.load=load_module,.unload=unload_module,.reload=reload,) | |
static void | attach_exten (struct ael_extension **list, struct ael_extension *newmem) |
static void | check_abstract_reference (pval *abstract_context) |
int | check_app_args (pval *appcall, pval *arglist, struct argapp *app) |
static int | check_break (pval *item) |
static void | check_context_names (void) |
static int | check_continue (pval *item) |
static void | check_day (pval *DAY) |
static void | check_dow (pval *DOW) |
get_dow: Get day of week | |
static void | check_expr2_input (pval *expr, char *str) |
static void | check_goto (pval *item) |
static void | check_includes (pval *includes) |
static void | check_label (pval *item) |
static void | check_month (pval *MON) |
void | check_pval (pval *item, struct argapp *apps, int in_globals) |
void | check_pval_item (pval *item, struct argapp *apps, int in_globals) |
void | check_switch_expr (pval *item, struct argapp *apps) |
static void | check_timerange (pval *p) |
void | destroy_extensions (struct ael_extension *exten) |
void | destroy_pval (pval *item) |
void | destroy_pval_item (pval *item) |
static int | extension_matches (pval *here, const char *exten, const char *pattern) |
pval * | find_context (char *name) |
static struct pval * | find_first_label_in_current_context (char *label, pval *curr_cont) |
static struct pval * | find_label_in_current_context (char *exten, char *label, pval *curr_cont) |
static struct pval * | find_label_in_current_db (const char *context, const char *exten, const char *label) |
static struct pval * | find_label_in_current_extension (const char *label, pval *curr_ext) |
pval * | find_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 pval * | get_contxt (pval *p) |
static pval * | get_extension_or_contxt (pval *p) |
static pval * | get_goto_target (pval *item) |
int | is_empty (char *arg) |
int | is_float (char *arg) |
int | is_int (char *arg) |
static int | label_inside_case (pval *label) |
static void | linkexten (struct ael_extension *exten, struct ael_extension *add) |
void | linkprio (struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten) |
static int | load_module (void) |
pval * | match_pval (pval *item) |
static struct pval * | match_pval_item (pval *item) |
ael_extension * | new_exten (void) |
ael_priority * | new_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 pval * | current_context = 0 |
static pval * | current_db = 0 |
static pval * | current_extension = 0 |
static char * | days [] |
static int | errs |
static char | expr_output [2096] |
static int | in_abstract_context |
static int | label_count |
static pval * | last_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 |
Definition in file pbx_ael.c.
#define DEBUG_CONTEXTS (1 << 3) |
#define DEBUG_MACROS (1 << 2) |
#define DEBUG_READ (1 << 0) |
#define DEBUG_TOKENS (1 << 1) |
void add_extensions | ( | struct ael_extension * | exten | ) |
Definition at line 3773 of file pbx_ael.c.
References AEL_APPCALL, AEL_CONTROL1, AEL_FOR_CONTROL, AEL_IF_CONTROL, AEL_IFTIME_CONTROL, AEL_LABEL, AEL_RAND_CONTROL, AEL_RETURN, ael_priority::app, app, ael_priority::appargs, ast_add_extension2(), ast_free, ast_log(), AST_MAX_EXTENSION, pval::else_statements, ael_priority::exten, exten, ael_priority::goto_false, ael_priority::goto_true, last, LOG_WARNING, ael_extension::name, ael_priority::next, ael_priority::origin, pbx_substitute_variables_helper(), PRIORITY_HINT, ael_priority::priority_num, PV_IFTIME, PV_SWITCH, strdup, pval::type, ael_priority::type, and pval::u3.
03774 { 03775 struct ael_priority *pr; 03776 char *label=0; 03777 char realext[AST_MAX_EXTENSION]; 03778 if (!exten) { 03779 ast_log(LOG_WARNING, "This file is Empty!\n" ); 03780 return; 03781 } 03782 do { 03783 struct ael_priority *last = 0; 03784 03785 memset(realext, '\0', sizeof(realext)); 03786 pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1); 03787 if (exten->hints) { 03788 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch, 03789 exten->hints, NULL, ast_free, registrar)) { 03790 ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n", 03791 exten->name); 03792 } 03793 } 03794 03795 for (pr=exten->plist; pr; pr=pr->next) { 03796 char app[2000]; 03797 char appargs[2000]; 03798 03799 /* before we can add the extension, we need to prep the app/appargs; 03800 the CONTROL types need to be done after the priority numbers are calculated. 03801 */ 03802 if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ { 03803 last = pr; 03804 continue; 03805 } 03806 03807 if (pr->app) 03808 strcpy(app, pr->app); 03809 else 03810 app[0] = 0; 03811 if (pr->appargs ) 03812 strcpy(appargs, pr->appargs); 03813 else 03814 appargs[0] = 0; 03815 switch( pr->type ) { 03816 case AEL_APPCALL: 03817 /* easy case. Everything is all set up */ 03818 break; 03819 03820 case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */ 03821 /* simple, unconditional goto. */ 03822 strcpy(app,"Goto"); 03823 if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) { 03824 snprintf(appargs,sizeof(appargs),"%s|%d", pr->goto_true->exten->name, pr->goto_true->priority_num); 03825 } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) { 03826 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1); 03827 } else 03828 snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num); 03829 break; 03830 03831 case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */ 03832 strcpy(app,"GotoIf"); 03833 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num); 03834 break; 03835 03836 case AEL_IF_CONTROL: 03837 strcpy(app,"GotoIf"); 03838 if (pr->origin->u3.else_statements ) 03839 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1); 03840 else 03841 snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num); 03842 break; 03843 03844 case AEL_RAND_CONTROL: 03845 strcpy(app,"Random"); 03846 snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1); 03847 break; 03848 03849 case AEL_IFTIME_CONTROL: 03850 strcpy(app,"GotoIfTime"); 03851 snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2); 03852 break; 03853 03854 case AEL_RETURN: 03855 strcpy(app,"Goto"); 03856 snprintf(appargs,sizeof(appargs), "%d", exten->return_target->priority_num); 03857 break; 03858 03859 default: 03860 break; 03861 } 03862 if (last && last->type == AEL_LABEL ) { 03863 label = last->origin->u1.str; 03864 } 03865 else 03866 label = 0; 03867 03868 if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch, 03869 app, strdup(appargs), ast_free, registrar)) { 03870 ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num, 03871 exten->name); 03872 } 03873 last = pr; 03874 } 03875 exten = exten->next_exten; 03876 } while ( exten ); 03877 }
static int ael2_debug_contexts | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 4234 of file pbx_ael.c.
References DEBUG_CONTEXTS.
04235 { 04236 aeldebug |= DEBUG_CONTEXTS; 04237 return 0; 04238 }
static int ael2_debug_macros | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 4228 of file pbx_ael.c.
References DEBUG_MACROS.
04229 { 04230 aeldebug |= DEBUG_MACROS; 04231 return 0; 04232 }
static int ael2_debug_read | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 4216 of file pbx_ael.c.
References DEBUG_READ.
04217 { 04218 aeldebug |= DEBUG_READ; 04219 return 0; 04220 }
static int ael2_debug_tokens | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 4222 of file pbx_ael.c.
References DEBUG_TOKENS.
04223 { 04224 aeldebug |= DEBUG_TOKENS; 04225 return 0; 04226 }
static int ael2_no_debug | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
static int ael2_reload | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 4246 of file pbx_ael.c.
References pbx_load_module().
04247 { 04248 return (pbx_load_module()); 04249 }
static void ael2_semantic_check | ( | pval * | item, | |
int * | arg_errs, | |||
int * | arg_warns, | |||
int * | arg_notes | |||
) | [static] |
Definition at line 2731 of file pbx_ael.c.
References app, argdesc_destroy(), argdesc_parse(), ast_config_AST_VAR_DIR, ast_log(), AST_MAX_FILENAME_LEN, check_context_names(), check_pval(), current_db, LOG_ERROR, LOG_NOTICE, and LOG_WARNING.
Referenced by pbx_load_module().
02732 { 02733 02734 #ifdef AAL_ARGCHECK 02735 int argapp_errs =0; 02736 char *rfilename, *rdirname, *xappsfilename; 02737 DIR *dir = NULL; 02738 struct dirent *de; 02739 #endif 02740 struct argapp *apps=0, *xapps=0, *app; 02741 02742 if (!item) 02743 return; /* don't check an empty tree */ 02744 #ifdef AAL_ARGCHECK 02745 rfilename = alloca(10 + strlen(ast_config_AST_VAR_DIR)); 02746 sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR); 02747 02748 apps = argdesc_parse(rfilename, &argapp_errs); /* giveth */ 02749 02750 if (argapp_errs == 0) { 02751 ast_log(LOG_NOTICE, "AEL load process: parsed default apps desc file '%s'.\n", rfilename); 02752 } else { 02753 ast_log(LOG_ERROR, "AEL load process: %d errors found parsing apps file '%s'.\n", argapp_errs, rfilename); 02754 } 02755 02756 // Open applist.d/ for extra applists 02757 rdirname = alloca(16 + strlen(ast_config_AST_VAR_DIR)); 02758 sprintf(rdirname, "%s/applist.d", ast_config_AST_VAR_DIR); 02759 dir = opendir(rdirname); 02760 if (!dir) { 02761 ast_log(LOG_WARNING, "Unable to open ael2 extra apps dir. %s is not a valid directory\n", rdirname); 02762 } else { 02763 // Reset errors count 02764 argapp_errs = 0; 02765 // Load apps from each file named *.apps into AST_VAR_DIR/applist.d/ 02766 xappsfilename = alloca(AST_MAX_FILENAME_LEN + strlen(rdirname)); 02767 while ((de = readdir(dir))) { 02768 xappsfilename[0] = 0; 02769 if ((strlen(de->d_name) > 4) && !strcasecmp(de->d_name + strlen(de->d_name) - 5, ".apps")) { 02770 sprintf(xappsfilename, "%s/%s", rdirname, de->d_name); 02771 xapps = argdesc_parse(xappsfilename, &argapp_errs); 02772 // If xapps list is not empty prepend it to apps 02773 if(xapps != NULL) { 02774 if (argapp_errs == 0) { 02775 ast_log(LOG_NOTICE, "AEL load process: parsed extra apps desc file '%s'.\n", xappsfilename); 02776 } else { 02777 ast_log(LOG_ERROR, "AEL load process: %d errors found parsing extra apps file '%s'.\n", argapp_errs, xappsfilename); 02778 } 02779 app=xapps; 02780 while (app->next != NULL) { 02781 app=app->next; 02782 } 02783 app->next = apps; 02784 apps = xapps; 02785 } else { 02786 ast_log(LOG_WARNING, "AEL load process: no apps desc found into file '%s'.\n", xappsfilename); 02787 } 02788 } 02789 } 02790 } 02791 #endif 02792 current_db = item; 02793 errs = warns = notes = 0; 02794 02795 check_context_names(); 02796 check_pval(item, apps, 0); 02797 02798 #ifdef AAL_ARGCHECK 02799 argdesc_destroy(apps); /* taketh away */ 02800 #endif 02801 current_db = 0; 02802 02803 *arg_errs = errs; 02804 *arg_warns = warns; 02805 *arg_notes = notes; 02806 }
void ast_compile_ael2 | ( | struct ast_context ** | local_contexts, | |
struct pval * | root | |||
) |
Definition at line 3960 of file pbx_ael.c.
References context, exten, pval::list, pval::next, pbx_builtin_setvar(), PV_GLOBALS, pval::str, pval::type, pval::u1, pval::u2, and pval::val.
Referenced by pbx_load_module().
03961 { 03962 pval *p,*p2; 03963 struct ast_context *context; 03964 char buf[2000]; 03965 struct ael_extension *exten; 03966 struct ael_extension *exten_list = 0; 03967 03968 for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there 03969 when we try to eval them */ 03970 switch (p->type) { 03971 case PV_GLOBALS: 03972 /* just VARDEC elements */ 03973 for (p2=p->u1.list; p2; p2=p2->next) { 03974 char buf2[2000]; 03975 snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val); 03976 pbx_builtin_setvar(NULL, buf2); 03977 } 03978 break; 03979 default: 03980 break; 03981 } 03982 } 03983 03984 for (p=root; p; p=p->next ) { 03985 pval *lp; 03986 int argc; 03987 03988 switch (p->type) { 03989 case PV_MACRO: 03990 strcpy(buf,"macro-"); 03991 strcat(buf,p->u1.str); 03992 context = ast_context_create(local_contexts, buf, registrar); 03993 03994 exten = new_exten(); 03995 exten->context = context; 03996 exten->name = strdup("s"); 03997 argc = 1; 03998 for (lp=p->u2.arglist; lp; lp=lp->next) { 03999 /* for each arg, set up a "Set" command */ 04000 struct ael_priority *np2 = new_prio(); 04001 np2->type = AEL_APPCALL; 04002 np2->app = strdup("Set"); 04003 snprintf(buf,sizeof(buf),"%s=${ARG%d}", lp->u1.str, argc++); 04004 remove_spaces_before_equals(buf); 04005 np2->appargs = strdup(buf); 04006 linkprio(exten, np2, NULL); 04007 } 04008 /* add any includes */ 04009 for (p2=p->u3.macro_statements; p2; p2=p2->next) { 04010 pval *p3; 04011 04012 switch (p2->type) { 04013 case PV_INCLUDES: 04014 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04015 if ( p3->u2.arglist ) { 04016 snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s", 04017 p3->u1.str, 04018 p3->u2.arglist->u1.str, 04019 p3->u2.arglist->next->u1.str, 04020 p3->u2.arglist->next->next->u1.str, 04021 p3->u2.arglist->next->next->next->u1.str); 04022 ast_context_add_include2(context, buf, registrar); 04023 } else 04024 ast_context_add_include2(context, p3->u1.str, registrar); 04025 } 04026 break; 04027 default: 04028 break; 04029 } 04030 } 04031 /* CONTAINS APPCALLS, CATCH, just like extensions... */ 04032 gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context ); 04033 if (exten->return_needed) { 04034 struct ael_priority *np2 = new_prio(); 04035 np2->type = AEL_APPCALL; 04036 np2->app = strdup("NoOp"); 04037 snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name); 04038 np2->appargs = strdup(buf); 04039 linkprio(exten, np2, NULL); 04040 exten-> return_target = np2; 04041 } 04042 04043 set_priorities(exten); 04044 attach_exten(&exten_list, exten); 04045 break; 04046 04047 case PV_GLOBALS: 04048 /* already done */ 04049 break; 04050 04051 case PV_CONTEXT: 04052 context = ast_context_find_or_create(local_contexts, p->u1.str, registrar); 04053 04054 /* contexts contain: ignorepat, includes, switches, eswitches, extensions, */ 04055 for (p2=p->u2.statements; p2; p2=p2->next) { 04056 pval *p3; 04057 char *s3; 04058 04059 switch (p2->type) { 04060 case PV_EXTENSION: 04061 exten = new_exten(); 04062 exten->name = strdup(p2->u1.str); 04063 exten->context = context; 04064 04065 if( (s3=strchr(exten->name, '/') ) != 0 ) 04066 { 04067 *s3 = 0; 04068 exten->cidmatch = s3+1; 04069 } 04070 04071 if ( p2->u3.hints ) 04072 exten->hints = strdup(p2->u3.hints); 04073 exten->regexten = p2->u4.regexten; 04074 gen_prios(exten, p->u1.str, p2->u2.statements, 0, context ); 04075 if (exten->return_needed) { 04076 struct ael_priority *np2 = new_prio(); 04077 np2->type = AEL_APPCALL; 04078 np2->app = strdup("NoOp"); 04079 snprintf(buf,sizeof(buf),"End of Extension %s", exten->name); 04080 np2->appargs = strdup(buf); 04081 linkprio(exten, np2, NULL); 04082 exten-> return_target = np2; 04083 } 04084 /* is the last priority in the extension a label? Then add a trailing no-op */ 04085 if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) { 04086 struct ael_priority *np2 = new_prio(); 04087 np2->type = AEL_APPCALL; 04088 np2->app = strdup("NoOp"); 04089 snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str); 04090 np2->appargs = strdup(buf); 04091 linkprio(exten, np2, NULL); 04092 } 04093 04094 set_priorities(exten); 04095 attach_exten(&exten_list, exten); 04096 break; 04097 04098 case PV_IGNOREPAT: 04099 ast_context_add_ignorepat2(context, p2->u1.str, registrar); 04100 break; 04101 04102 case PV_INCLUDES: 04103 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04104 if ( p3->u2.arglist ) { 04105 snprintf(buf,sizeof(buf), "%s|%s|%s|%s|%s", 04106 p3->u1.str, 04107 p3->u2.arglist->u1.str, 04108 p3->u2.arglist->next->u1.str, 04109 p3->u2.arglist->next->next->u1.str, 04110 p3->u2.arglist->next->next->next->u1.str); 04111 ast_context_add_include2(context, buf, registrar); 04112 } else 04113 ast_context_add_include2(context, p3->u1.str, registrar); 04114 } 04115 break; 04116 04117 case PV_SWITCHES: 04118 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04119 char *c = strchr(p3->u1.str, '/'); 04120 if (c) { 04121 *c = '\0'; 04122 c++; 04123 } else 04124 c = ""; 04125 04126 ast_context_add_switch2(context, p3->u1.str, c, 0, registrar); 04127 } 04128 break; 04129 04130 case PV_ESWITCHES: 04131 for (p3 = p2->u1.list; p3 ;p3=p3->next) { 04132 char *c = strchr(p3->u1.str, '/'); 04133 if (c) { 04134 *c = '\0'; 04135 c++; 04136 } else 04137 c = ""; 04138 04139 ast_context_add_switch2(context, p3->u1.str, c, 1, registrar); 04140 } 04141 break; 04142 default: 04143 break; 04144 } 04145 } 04146 04147 break; 04148 04149 default: 04150 /* huh? what? */ 04151 break; 04152 04153 } 04154 } 04155 /* moved these from being done after a macro or extension were processed, 04156 to after all processing is done, for the sake of fixing gotos to labels inside cases... */ 04157 /* I guess this would be considered 2nd pass of compiler now... */ 04158 fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */ 04159 add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */ 04160 destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */ 04161 04162 }
int ast_expr | ( | char * | expr, | |
char * | buf, | |||
int | length | |||
) |
Definition at line 2288 of file ast_expr2f.c.
References AST_EXPR_integer, ast_yy_scan_string(), ast_yylex_destroy(), ast_yylex_init(), ast_yyparse(), free, and io.
Referenced by check_pval_item(), and pbx_substitute_variables_helper_full().
02289 { 02290 struct parse_io io; 02291 int return_value = 0; 02292 02293 memset(&io, 0, sizeof(io)); 02294 io.string = expr; /* to pass to the error routine */ 02295 02296 ast_yylex_init(&io.scanner); 02297 02298 ast_yy_scan_string(expr, io.scanner); 02299 02300 ast_yyparse ((void *) &io); 02301 02302 ast_yylex_destroy(io.scanner); 02303 02304 if (!io.val) { 02305 if (length > 1) { 02306 strcpy(buf, "0"); 02307 return_value = 1; 02308 } 02309 } else { 02310 if (io.val->type == AST_EXPR_integer) { 02311 int res_length; 02312 02313 res_length = snprintf(buf, length, "%ld", (long int) io.val->u.i); 02314 return_value = (res_length <= length) ? res_length : length; 02315 } else { 02316 #if defined(STANDALONE) || defined(LOW_MEMORY) || defined(STANDALONE_AEL) 02317 strncpy(buf, io.val->u.s, length - 1); 02318 #else /* !STANDALONE && !LOW_MEMORY */ 02319 ast_copy_string(buf, io.val->u.s, length); 02320 #endif /* STANDALONE || LOW_MEMORY */ 02321 return_value = strlen(buf); 02322 free(io.val->u.s); 02323 } 02324 free(io.val); 02325 } 02326 return return_value; 02327 }
void ast_expr_clear_extra_error_info | ( | void | ) |
void ast_expr_register_extra_error_info | ( | char * | errmsg | ) |
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_DEFAULT | , | |||
"Asterisk Extension Language Compiler" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
static void attach_exten | ( | struct ael_extension ** | list, | |
struct ael_extension * | newmem | |||
) | [static] |
Definition at line 3879 of file pbx_ael.c.
References ael_extension::next_exten.
03880 { 03881 /* travel to the end of the list... */ 03882 struct ael_extension *lptr; 03883 if( !*list ) { 03884 *list = newmem; 03885 return; 03886 } 03887 lptr = *list; 03888 03889 while( lptr->next_exten ) { 03890 lptr = lptr->next_exten; 03891 } 03892 /* lptr should now pointing to the last element in the list; it has a null next_exten pointer */ 03893 lptr->next_exten = newmem; 03894 }
static void check_abstract_reference | ( | pval * | abstract_context | ) | [static] |
Definition at line 2264 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().
02265 { 02266 pval *i,*j; 02267 /* find some context includes that reference this context */ 02268 02269 02270 /* otherwise, print out a warning */ 02271 for (i=current_db; i; i=i->next) { 02272 if (i->type == PV_CONTEXT) { 02273 for (j=i->u2. statements; j; j=j->next) { 02274 if ( j->type == PV_INCLUDES ) { 02275 struct pval *p4; 02276 for (p4=j->u1.list; p4; p4=p4->next) { 02277 /* for each context pointed to, find it, then find a context/label that matches the 02278 target here! */ 02279 if ( !strcmp(p4->u1.str, abstract_context->u1.str) ) 02280 return; /* found a match! */ 02281 } 02282 } 02283 } 02284 } 02285 } 02286 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", 02287 abstract_context->filename, abstract_context->startline, abstract_context->endline, abstract_context->u1.str); 02288 warns++; 02289 }
Definition at line 2065 of file pbx_ael.c.
References app, ARGD_OPTIONSET, ARGD_REQUIRED, ARGD_VARARG, ast_log(), argdesc::dtype, pval::endline, pval::filename, LOG_WARNING, argdesc::name, argdesc::next, pval::next, pval::startline, pval::str, argdesc::type, and pval::u1.
Referenced by check_pval_item().
02066 { 02067 #ifdef AAL_ARGCHECK 02068 struct argdesc *ad = app->args; 02069 pval *pa; 02070 int z; 02071 02072 for (pa = arglist; pa; pa=pa->next) { 02073 if (!ad) { 02074 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n", 02075 arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name); 02076 warns++; 02077 return 1; 02078 } else { 02079 /* find the first entry in the ad list that will match */ 02080 do { 02081 if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */ 02082 break; 02083 02084 z= option_matches( ad, pa, app); 02085 if (!z) { 02086 if ( !arglist ) 02087 arglist=appcall; 02088 02089 if (ad->type == ARGD_REQUIRED) { 02090 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", 02091 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); 02092 warns++; 02093 return 1; 02094 } 02095 } else if (z && ad->dtype == ARGD_OPTIONSET) { 02096 option_matches_j( ad, pa, app); 02097 } 02098 ad = ad->next; 02099 } while (ad && !z); 02100 } 02101 } 02102 /* any app nodes left, that are not optional? */ 02103 for ( ; ad; ad=ad->next) { 02104 if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) { 02105 if ( !arglist ) 02106 arglist=appcall; 02107 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n", 02108 arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name); 02109 warns++; 02110 return 1; 02111 } 02112 } 02113 return 0; 02114 #else 02115 return 0; 02116 #endif 02117 }
static int check_break | ( | pval * | item | ) | [static] |
Definition at line 1058 of file pbx_ael.c.
References ast_log(), pval::dad, pval::endline, pval::filename, LOG_ERROR, PV_CASE, PV_CONTEXT, PV_DEFAULT, PV_FOR, PV_MACRO, PV_PATTERN, PV_WHILE, pval::startline, and pval::type.
Referenced by check_pval_item().
01059 { 01060 pval *p = item; 01061 01062 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ { 01063 /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make 01064 no sense */ 01065 if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN 01066 || p->type == PV_WHILE || p->type == PV_FOR ) { 01067 return 1; 01068 } 01069 p = p->dad; 01070 } 01071 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'break' not in switch, for, or while statement!\n", 01072 item->filename, item->startline, item->endline); 01073 errs++; 01074 01075 return 0; 01076 }
static void check_context_names | ( | void | ) | [static] |
Definition at line 2245 of file pbx_ael.c.
References pval::abstract, ast_log(), current_db, pval::endline, pval::filename, LOG_ERROR, pval::next, PV_CONTEXT, PV_MACRO, pval::startline, pval::str, pval::type, pval::u1, and pval::u3.
Referenced by ael2_semantic_check().
02246 { 02247 pval *i,*j; 02248 for (i=current_db; i; i=i->next) { 02249 if (i->type == PV_CONTEXT || i->type == PV_MACRO) { 02250 for (j=i->next; j; j=j->next) { 02251 if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) { 02252 if ( !strcmp(i->u1.str, j->u1.str) && !(i->u3.abstract&2) && !(j->u3.abstract&2) ) 02253 { 02254 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: The context name (%s) is also declared in file %s, line %d-%d! (and neither is marked 'extend')\n", 02255 i->filename, i->startline, i->endline, i->u1.str, j->filename, j->startline, j->endline); 02256 errs++; 02257 } 02258 } 02259 } 02260 } 02261 } 02262 }
static int check_continue | ( | pval * | item | ) | [static] |
Definition at line 1078 of file pbx_ael.c.
References ast_log(), pval::dad, pval::endline, pval::filename, LOG_ERROR, PV_CONTEXT, PV_FOR, PV_MACRO, PV_WHILE, pval::startline, and pval::type.
Referenced by check_pval_item().
01079 { 01080 pval *p = item; 01081 01082 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ { 01083 /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make 01084 no sense */ 01085 if( p->type == PV_WHILE || p->type == PV_FOR ) { 01086 return 1; 01087 } 01088 p = p->dad; 01089 } 01090 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'continue' not in 'for' or 'while' statement!\n", 01091 item->filename, item->startline, item->endline); 01092 errs++; 01093 01094 return 0; 01095 }
static void check_day | ( | pval * | DAY | ) | [static] |
Definition at line 957 of file pbx_ael.c.
References ast_log(), ast_strdupa, ast_strlen_zero(), pval::endline, pval::filename, LOG_WARNING, s, pval::startline, pval::str, and pval::u1.
Referenced by check_pval_item().
00958 { 00959 char *day; 00960 char *c; 00961 /* The following line is coincidence, really! */ 00962 int s, e; 00963 00964 day = ast_strdupa(DAY->u1.str); 00965 00966 /* Check for all days */ 00967 if (ast_strlen_zero(day) || !strcmp(day, "*")) { 00968 return; 00969 } 00970 /* Get start and ending days */ 00971 c = strchr(day, '-'); 00972 if (c) { 00973 *c = '\0'; 00974 c++; 00975 } 00976 /* Find the start */ 00977 if (sscanf(day, "%d", &s) != 1) { 00978 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number!\n", 00979 DAY->filename, DAY->startline, DAY->endline, day); 00980 warns++; 00981 } 00982 else if ((s < 1) || (s > 31)) { 00983 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", 00984 DAY->filename, DAY->startline, DAY->endline, day); 00985 warns++; 00986 } 00987 s--; 00988 if (c) { 00989 if (sscanf(c, "%d", &e) != 1) { 00990 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number!\n", 00991 DAY->filename, DAY->startline, DAY->endline, c); 00992 warns++; 00993 } 00994 else if ((e < 1) || (e > 31)) { 00995 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", 00996 DAY->filename, DAY->startline, DAY->endline, day); 00997 warns++; 00998 } 00999 e--; 01000 } else 01001 e = s; 01002 }
static void check_dow | ( | pval * | DOW | ) | [static] |
get_dow: Get day of week
Definition at line 918 of file pbx_ael.c.
References ast_log(), ast_strdupa, ast_strlen_zero(), pval::endline, pval::filename, LOG_WARNING, s, pval::startline, pval::str, and pval::u1.
Referenced by check_pval_item().
00919 { 00920 char *dow; 00921 char *c; 00922 /* The following line is coincidence, really! */ 00923 int s, e; 00924 00925 dow = ast_strdupa(DOW->u1.str); 00926 00927 /* Check for all days */ 00928 if (ast_strlen_zero(dow) || !strcmp(dow, "*")) 00929 return; 00930 /* Get start and ending days */ 00931 c = strchr(dow, '-'); 00932 if (c) { 00933 *c = '\0'; 00934 c++; 00935 } else 00936 c = NULL; 00937 /* Find the start */ 00938 s = 0; 00939 while ((s < 7) && strcasecmp(dow, days[s])) s++; 00940 if (s >= 7) { 00941 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", 00942 DOW->filename, DOW->startline, DOW->endline, dow); 00943 warns++; 00944 } 00945 if (c) { 00946 e = 0; 00947 while ((e < 7) && strcasecmp(c, days[e])) e++; 00948 if (e >= 7) { 00949 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", 00950 DOW->filename, DOW->startline, DOW->endline, c); 00951 warns++; 00952 } 00953 } else 00954 e = s; 00955 }
static void check_expr2_input | ( | pval * | expr, | |
char * | str | |||
) | [static] |
Definition at line 821 of file pbx_ael.c.
References ast_log(), pval::endline, pval::filename, LOG_WARNING, and pval::startline.
Referenced by check_pval_item().
00822 { 00823 int spaces = strspn(str,"\t \n"); 00824 if ( !strncmp(str+spaces,"$[",2) ) { 00825 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The expression '%s' is redundantly wrapped in '$[ ]'. \n", 00826 expr->filename, expr->startline, expr->endline, str); 00827 warns++; 00828 } 00829 }
static void check_goto | ( | pval * | item | ) | [static] |
Definition at line 1193 of file pbx_ael.c.
References ast_log(), pval::endline, pval::filename, find_context(), find_label_in_current_context(), find_label_in_current_db(), find_label_in_current_extension(), get_contxt(), get_extension_or_contxt(), pval::list, LOG_ERROR, LOG_WARNING, pval::next, PV_INCLUDES, pval::startline, pval::statements, pval::str, pval::type, pval::u1, and pval::u2.
Referenced by check_pval_item(), and find_pval_goto_item().
01194 { 01195 /* check for the target of the goto-- does it exist? */ 01196 if ( !(item->u1.list)->next && !(item->u1.list)->u1.str ) { 01197 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: empty label reference found!\n", 01198 item->filename, item->startline, item->endline); 01199 errs++; 01200 } 01201 01202 /* just one item-- the label should be in the current extension */ 01203 01204 if (item->u1.list && !item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) { 01205 struct pval *z = get_extension_or_contxt(item); 01206 struct pval *x = 0; 01207 if (z) 01208 x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), z); /* if in macro, use current context instead */ 01209 /* printf("Called find_label_in_current_extension with arg %s; current_extension is %x: %d\n", 01210 (char*)((item->u1.list)->u1.str), current_extension?current_extension:current_context, current_extension?current_extension->type:current_context->type); */ 01211 if (!x) { 01212 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s exists in the current extension!\n", 01213 item->filename, item->startline, item->endline, item->u1.list->u1.str); 01214 errs++; 01215 } 01216 else 01217 return; 01218 } 01219 01220 /* TWO items */ 01221 if (item->u1.list->next && !item->u1.list->next->next) { 01222 /* two items */ 01223 /* printf("Calling find_label_in_current_context with args %s, %s\n", 01224 (char*)((item->u1.list)->u1.str), (char *)item->u1.list->next->u1.str); */ 01225 if (!strstr((item->u1.list)->u1.str,"${") 01226 && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ { 01227 struct pval *z = get_contxt(item); 01228 struct pval *x = 0; 01229 01230 if (z) 01231 x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, z); 01232 01233 if (!x) { 01234 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", 01235 item->filename, item->startline, item->endline, item->u1.list->u1.str, item->u1.list->next->u1.str ); 01236 errs++; 01237 } 01238 else 01239 return; 01240 } 01241 } 01242 01243 /* All 3 items! */ 01244 if (item->u1.list->next && item->u1.list->next->next) { 01245 /* all three */ 01246 pval *first = item->u1.list; 01247 pval *second = item->u1.list->next; 01248 pval *third = item->u1.list->next->next; 01249 01250 /* printf("Calling find_label_in_current_db with args %s, %s, %s\n", 01251 (char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); */ 01252 if (!strstr((item->u1.list)->u1.str,"${") 01253 && !strstr(item->u1.list->next->u1.str,"${") 01254 && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ { 01255 struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); 01256 if (!x) { 01257 struct pval *p3; 01258 struct pval *found = 0; 01259 struct pval *that_context = find_context(item->u1.list->u1.str); 01260 01261 /* the target of the goto could be in an included context!! Fancy that!! */ 01262 /* look for includes in the current context */ 01263 if (that_context) { 01264 for (p3=that_context->u2.statements; p3; p3=p3->next) { 01265 if (p3->type == PV_INCLUDES) { 01266 struct pval *p4; 01267 for (p4=p3->u1.list; p4; p4=p4->next) { 01268 /* for each context pointed to, find it, then find a context/label that matches the 01269 target here! */ 01270 char *incl_context = p4->u1.str; 01271 /* find a matching context name */ 01272 struct pval *that_other_context = find_context(incl_context); 01273 if (that_other_context) { 01274 struct pval *x3; 01275 x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context); 01276 if (x3) { 01277 found = x3; 01278 break; 01279 } 01280 } 01281 } 01282 } 01283 } 01284 if (!found) { 01285 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s|%s exists in the context %s or its inclusions!\n", 01286 item->filename, item->startline, item->endline, item->u1.list->next->u1.str, item->u1.list->next->next->u1.str, item->u1.list->u1.str ); 01287 errs++; 01288 } 01289 } else { 01290 /* here is where code would go to check for target existence in extensions.conf files */ 01291 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: no context %s could be found that matches the goto target!\n", 01292 item->filename, item->startline, item->endline, item->u1.list->u1.str); 01293 warns++; /* this is just a warning, because this context could be in extensions.conf or somewhere */ 01294 } 01295 } 01296 } 01297 } 01298 }
static void check_includes | ( | pval * | includes | ) | [static] |
Definition at line 831 of file pbx_ael.c.
References ast_log(), pval::endline, pval::filename, find_context(), pval::list, LOG_WARNING, pval::next, pval::startline, pval::str, and pval::u1.
Referenced by check_pval_item().
00832 { 00833 struct pval *p4; 00834 for (p4=includes->u1.list; p4; p4=p4->next) { 00835 /* for each context pointed to, find it, then find a context/label that matches the 00836 target here! */ 00837 char *incl_context = p4->u1.str; 00838 /* find a matching context name */ 00839 struct pval *that_other_context = find_context(incl_context); 00840 if (!that_other_context && strcmp(incl_context, "parkedcalls") != 0) { 00841 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The included context '%s' cannot be found.\n\ 00842 (You may ignore this warning if '%s' exists in extensions.conf, or is created by another module. I cannot check for those.)\n", 00843 includes->filename, includes->startline, includes->endline, incl_context, incl_context); 00844 warns++; 00845 } 00846 } 00847 }
static void check_label | ( | pval * | item | ) | [static] |
Definition at line 1100 of file pbx_ael.c.
References ast_log(), current_context, current_extension, pval::endline, pval::filename, find_first_label_in_current_context(), LOG_ERROR, pval::startline, pval::str, and pval::u1.
Referenced by check_pval_item().
01101 { 01102 /* basically, ensure that a label is not repeated in a context. Period. 01103 The method: well, for each label, find the first label in the context 01104 with the same name. If it's not the current label, then throw an error. */ 01105 struct pval *curr; 01106 struct pval *x; 01107 01108 /* printf("==== check_label: ====\n"); */ 01109 if( !current_extension ) 01110 curr = current_context; 01111 else 01112 curr = current_extension; 01113 01114 x = find_first_label_in_current_context((char *)item->u1.str, curr); 01115 /* 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); */ 01116 if( x && x != item ) 01117 { 01118 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Duplicate label %s! Previously defined at file %s, line %d.\n", 01119 item->filename, item->startline, item->endline, item->u1.str, x->filename, x->startline); 01120 errs++; 01121 } 01122 /* printf("<<<<< check_label: ====\n"); */ 01123 }
static void check_month | ( | pval * | MON | ) | [static] |
Definition at line 1020 of file pbx_ael.c.
References ast_log(), ast_strdupa, ast_strlen_zero(), pval::endline, pval::filename, LOG_WARNING, s, pval::startline, pval::str, and pval::u1.
Referenced by check_pval_item().
01021 { 01022 char *mon; 01023 char *c; 01024 /* The following line is coincidence, really! */ 01025 int s, e; 01026 01027 mon = ast_strdupa(MON->u1.str); 01028 01029 /* Check for all days */ 01030 if (ast_strlen_zero(mon) || !strcmp(mon, "*")) 01031 return ; 01032 /* Get start and ending days */ 01033 c = strchr(mon, '-'); 01034 if (c) { 01035 *c = '\0'; 01036 c++; 01037 } 01038 /* Find the start */ 01039 s = 0; 01040 while ((s < 12) && strcasecmp(mon, months[s])) s++; 01041 if (s >= 12) { 01042 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n", 01043 MON->filename, MON->startline, MON->endline, mon); 01044 warns++; 01045 } 01046 if (c) { 01047 e = 0; 01048 while ((e < 12) && strcasecmp(mon, months[e])) e++; 01049 if (e >= 12) { 01050 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n", 01051 MON->filename, MON->startline, MON->endline, c); 01052 warns++; 01053 } 01054 } else 01055 e = s; 01056 }
Definition at line 2711 of file pbx_ael.c.
References check_pval_item(), and pval::next.
Referenced by ael2_semantic_check(), and check_pval_item().
02712 { 02713 pval *i; 02714 02715 /* checks to do: 02716 1. Do goto's point to actual labels? 02717 2. Do macro calls reference a macro? 02718 3. Does the number of macro args match the definition? 02719 4. Is a macro call missing its & at the front? 02720 5. Application calls-- we could check syntax for existing applications, 02721 but I need some some sort of universal description bnf for a general 02722 sort of method for checking arguments, in number, maybe even type, at least. 02723 Don't want to hand code checks for hundreds of applications. 02724 */ 02725 02726 for (i=item; i; i=i->next) { 02727 check_pval_item(i,apps,in_globals); 02728 } 02729 }
Definition at line 2292 of file pbx_ael.c.
References pval::abstract, app, pval::arglist, ast_expr(), ast_expr_clear_extra_error_info(), ast_expr_register_extra_error_info(), ast_log(), check_abstract_reference(), check_app_args(), check_break(), check_continue(), check_day(), check_dow(), check_expr2_input(), check_goto(), check_includes(), check_label(), check_month(), check_pval(), check_switch_expr(), check_timerange(), current_context, current_extension, pval::else_statements, pval::endcol, pval::endline, pval::filename, find_context(), find_macro(), find_pval_gotos(), pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, pval::list, LOG_ERROR, LOG_WARNING, pval::macro_statements, pval::next, PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTEXT, PV_CONTINUE, PV_DEFAULT, PV_ESWITCHES, PV_EXTENSION, PV_FOR, PV_GLOBALS, PV_GOTO, PV_IF, PV_IFTIME, PV_IGNOREPAT, PV_INCLUDES, PV_LABEL, PV_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pval::startcol, pval::startline, pval::statements, pval::str, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.
Referenced by check_pval().
02293 { 02294 pval *lp; 02295 #ifdef AAL_ARGCHECK 02296 struct argapp *app, *found; 02297 #endif 02298 struct pval *macro_def; 02299 struct pval *app_def; 02300 02301 char errmsg[4096]; 02302 char *strp; 02303 02304 switch (item->type) { 02305 case PV_WORD: 02306 /* fields: item->u1.str == string associated with this (word). 02307 item->u2.arglist == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */ 02308 break; 02309 02310 case PV_MACRO: 02311 /* fields: item->u1.str == name of macro 02312 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user 02313 item->u2.arglist->u1.str == argument 02314 item->u2.arglist->next == next arg 02315 02316 item->u3.macro_statements == pval list of statements in macro body. 02317 */ 02318 in_abstract_context = 0; 02319 current_context = item; 02320 current_extension = 0; 02321 for (lp=item->u2.arglist; lp; lp=lp->next) { 02322 02323 } 02324 check_pval(item->u3.macro_statements, apps,in_globals); 02325 break; 02326 02327 case PV_CONTEXT: 02328 /* fields: item->u1.str == name of context 02329 item->u2.statements == pval list of statements in context body 02330 item->u3.abstract == int 1 if an abstract keyword were present 02331 */ 02332 current_context = item; 02333 current_extension = 0; 02334 if ( item->u3.abstract ) { 02335 in_abstract_context = 1; 02336 check_abstract_reference(item); 02337 } else 02338 in_abstract_context = 0; 02339 check_pval(item->u2.statements, apps,in_globals); 02340 break; 02341 02342 case PV_MACRO_CALL: 02343 /* fields: item->u1.str == name of macro to call 02344 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 02345 item->u2.arglist->u1.str == argument 02346 item->u2.arglist->next == next arg 02347 */ 02348 macro_def = find_macro(item->u1.str); 02349 if (!macro_def) { 02350 /* here is a good place to check to see if the definition is in extensions.conf! */ 02351 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s ! Hopefully it is present in extensions.conf! \n", 02352 item->filename, item->startline, item->endline, item->u1.str); 02353 warns++; 02354 } else if (macro_def->type != PV_MACRO) { 02355 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n", 02356 item->filename, item->startline, item->endline, item->u1.str); 02357 errs++; 02358 } else { 02359 /* macro_def is a MACRO, so do the args match in number? */ 02360 int hereargs = 0; 02361 int thereargs = 0; 02362 02363 for (lp=item->u2.arglist; lp; lp=lp->next) { 02364 hereargs++; 02365 } 02366 for (lp=macro_def->u2.arglist; lp; lp=lp->next) { 02367 thereargs++; 02368 } 02369 if (hereargs != thereargs ) { 02370 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", 02371 item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs); 02372 errs++; 02373 } 02374 } 02375 break; 02376 02377 case PV_APPLICATION_CALL: 02378 /* fields: item->u1.str == name of application to call 02379 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 02380 item->u2.arglist->u1.str == argument 02381 item->u2.arglist->next == next arg 02382 */ 02383 /* Need to check to see if the application is available! */ 02384 app_def = find_context(item->u1.str); 02385 if (app_def && app_def->type == PV_MACRO) { 02386 ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n", 02387 item->filename, item->startline, item->endline, item->u1.str); 02388 errs++; 02389 } 02390 if (strcasecmp(item->u1.str,"GotoIf") == 0 02391 || strcasecmp(item->u1.str,"GotoIfTime") == 0 02392 || strcasecmp(item->u1.str,"while") == 0 02393 || strcasecmp(item->u1.str,"endwhile") == 0 02394 || strcasecmp(item->u1.str,"random") == 0 02395 || strcasecmp(item->u1.str,"execIf") == 0 ) { 02396 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s needs to be re-written using AEL if, while, goto, etc. keywords instead!\n", 02397 item->filename, item->startline, item->endline, item->u1.str); 02398 warns++; 02399 } 02400 #ifdef AAL_ARGCHECK 02401 found = 0; 02402 for (app=apps; app; app=app->next) { 02403 if (strcasecmp(app->name, item->u1.str) == 0) { 02404 found =app; 02405 break; 02406 } 02407 } 02408 if (!found) { 02409 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n", 02410 item->filename, item->startline, item->endline, item->u1.str); 02411 warns++; 02412 } else 02413 check_app_args(item, item->u2.arglist, app); 02414 #endif 02415 break; 02416 02417 case PV_CASE: 02418 /* fields: item->u1.str == value of case 02419 item->u2.statements == pval list of statements under the case 02420 */ 02421 /* Make sure sequence of statements under case is terminated with goto, return, or break */ 02422 /* find the last statement */ 02423 check_pval(item->u2.statements, apps,in_globals); 02424 break; 02425 02426 case PV_PATTERN: 02427 /* fields: item->u1.str == value of case 02428 item->u2.statements == pval list of statements under the case 02429 */ 02430 /* Make sure sequence of statements under case is terminated with goto, return, or break */ 02431 /* find the last statement */ 02432 02433 check_pval(item->u2.statements, apps,in_globals); 02434 break; 02435 02436 case PV_DEFAULT: 02437 /* fields: 02438 item->u2.statements == pval list of statements under the case 02439 */ 02440 02441 check_pval(item->u2.statements, apps,in_globals); 02442 break; 02443 02444 case PV_CATCH: 02445 /* fields: item->u1.str == name of extension to catch 02446 item->u2.statements == pval list of statements in context body 02447 */ 02448 check_pval(item->u2.statements, apps,in_globals); 02449 break; 02450 02451 case PV_SWITCHES: 02452 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 02453 */ 02454 check_pval(item->u1.list, apps,in_globals); 02455 break; 02456 02457 case PV_ESWITCHES: 02458 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 02459 */ 02460 check_pval(item->u1.list, apps,in_globals); 02461 break; 02462 02463 case PV_INCLUDES: 02464 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 02465 */ 02466 check_pval(item->u1.list, apps,in_globals); 02467 check_includes(item); 02468 for (lp=item->u1.list; lp; lp=lp->next){ 02469 char *incl_context = lp->u1.str; 02470 struct pval *that_context = find_context(incl_context); 02471 02472 if ( lp->u2.arglist ) { 02473 check_timerange(lp->u2.arglist); 02474 check_dow(lp->u2.arglist->next); 02475 check_day(lp->u2.arglist->next->next); 02476 check_month(lp->u2.arglist->next->next->next); 02477 } 02478 02479 if (that_context) { 02480 find_pval_gotos(that_context->u2.statements,0); 02481 02482 } 02483 } 02484 break; 02485 02486 case PV_STATEMENTBLOCK: 02487 /* fields: item->u1.list == pval list of statements in block, one per entry in the list 02488 */ 02489 check_pval(item->u1.list, apps,in_globals); 02490 break; 02491 02492 case PV_VARDEC: 02493 /* fields: item->u1.str == variable name 02494 item->u2.val == variable value to assign 02495 */ 02496 /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */ 02497 if( !in_globals ) { /* don't check stuff inside the globals context; no wrapping in $[ ] there... */ 02498 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); 02499 ast_expr_register_extra_error_info(errmsg); 02500 ast_expr(item->u2.val, expr_output, sizeof(expr_output)); 02501 ast_expr_clear_extra_error_info(); 02502 if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) { 02503 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02504 item->filename, item->startline, item->endline, item->u2.val); 02505 warns++; 02506 } 02507 check_expr2_input(item,item->u2.val); 02508 } 02509 break; 02510 02511 case PV_GOTO: 02512 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. 02513 item->u1.list->u1.str == where the data on a PV_WORD will always be. 02514 */ 02515 /* don't check goto's in abstract contexts */ 02516 if ( in_abstract_context ) 02517 break; 02518 02519 check_goto(item); 02520 break; 02521 02522 case PV_LABEL: 02523 /* fields: item->u1.str == label name 02524 */ 02525 if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) { 02526 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n", 02527 item->filename, item->startline, item->endline, item->u1.str); 02528 warns++; 02529 } 02530 02531 check_label(item); 02532 break; 02533 02534 case PV_FOR: 02535 /* fields: item->u1.for_init == a string containing the initalizer 02536 item->u2.for_test == a string containing the loop test 02537 item->u3.for_inc == a string containing the loop increment 02538 02539 item->u4.for_statements == a pval list of statements in the for () 02540 */ 02541 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); 02542 ast_expr_register_extra_error_info(errmsg); 02543 02544 strp = strchr(item->u1.for_init, '='); 02545 if (strp) { 02546 ast_expr(strp+1, expr_output, sizeof(expr_output)); 02547 } 02548 ast_expr(item->u2.for_test, expr_output, sizeof(expr_output)); 02549 strp = strchr(item->u3.for_inc, '='); 02550 if (strp) { 02551 ast_expr(strp+1, expr_output, sizeof(expr_output)); 02552 } 02553 if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) { 02554 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02555 item->filename, item->startline, item->endline, item->u2.for_test); 02556 warns++; 02557 } 02558 if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) { 02559 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02560 item->filename, item->startline, item->endline, item->u3.for_inc); 02561 warns++; 02562 } 02563 check_expr2_input(item,item->u2.for_test); 02564 check_expr2_input(item,item->u3.for_inc); 02565 02566 ast_expr_clear_extra_error_info(); 02567 check_pval(item->u4.for_statements, apps,in_globals); 02568 break; 02569 02570 case PV_WHILE: 02571 /* fields: item->u1.str == the while conditional, as supplied by user 02572 02573 item->u2.statements == a pval list of statements in the while () 02574 */ 02575 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, while expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str); 02576 ast_expr_register_extra_error_info(errmsg); 02577 ast_expr(item->u1.str, expr_output, sizeof(expr_output)); 02578 ast_expr_clear_extra_error_info(); 02579 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { 02580 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n", 02581 item->filename, item->startline, item->endline, item->u1.str); 02582 warns++; 02583 } 02584 check_expr2_input(item,item->u1.str); 02585 check_pval(item->u2.statements, apps,in_globals); 02586 break; 02587 02588 case PV_BREAK: 02589 /* fields: none 02590 */ 02591 check_break(item); 02592 break; 02593 02594 case PV_RETURN: 02595 /* fields: none 02596 */ 02597 break; 02598 02599 case PV_CONTINUE: 02600 /* fields: none 02601 */ 02602 check_continue(item); 02603 break; 02604 02605 case PV_RANDOM: 02606 /* fields: item->u1.str == the random number expression, as supplied by user 02607 02608 item->u2.statements == a pval list of statements in the if () 02609 item->u3.else_statements == a pval list of statements in the else 02610 (could be zero) 02611 */ 02612 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, random expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str); 02613 ast_expr_register_extra_error_info(errmsg); 02614 ast_expr(item->u1.str, expr_output, sizeof(expr_output)); 02615 ast_expr_clear_extra_error_info(); 02616 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { 02617 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n", 02618 item->filename, item->startline, item->endline, item->u1.str); 02619 warns++; 02620 } 02621 check_expr2_input(item,item->u1.str); 02622 check_pval(item->u2.statements, apps,in_globals); 02623 if (item->u3.else_statements) { 02624 check_pval(item->u3.else_statements, apps,in_globals); 02625 } 02626 break; 02627 02628 case PV_IFTIME: 02629 /* fields: item->u1.list == the if time values, 4 of them, each in PV_WORD, linked list 02630 02631 item->u2.statements == a pval list of statements in the if () 02632 item->u3.else_statements == a pval list of statements in the else 02633 (could be zero) 02634 */ 02635 if ( item->u2.arglist ) { 02636 check_timerange(item->u1.list); 02637 check_dow(item->u1.list->next); 02638 check_day(item->u1.list->next->next); 02639 check_month(item->u1.list->next->next->next); 02640 } 02641 02642 check_pval(item->u2.statements, apps,in_globals); 02643 if (item->u3.else_statements) { 02644 check_pval(item->u3.else_statements, apps,in_globals); 02645 } 02646 break; 02647 02648 case PV_IF: 02649 /* fields: item->u1.str == the if conditional, as supplied by user 02650 02651 item->u2.statements == a pval list of statements in the if () 02652 item->u3.else_statements == a pval list of statements in the else 02653 (could be zero) 02654 */ 02655 snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, if expr '%s':", config, item->startline, item->startcol, item->endcol, item->u1.str); 02656 ast_expr_register_extra_error_info(errmsg); 02657 ast_expr(item->u1.str, expr_output, sizeof(expr_output)); 02658 ast_expr_clear_extra_error_info(); 02659 if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) { 02660 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n", 02661 item->filename, item->startline, item->endline, item->u1.str); 02662 warns++; 02663 } 02664 check_expr2_input(item,item->u1.str); 02665 check_pval(item->u2.statements, apps,in_globals); 02666 if (item->u3.else_statements) { 02667 check_pval(item->u3.else_statements, apps,in_globals); 02668 } 02669 break; 02670 02671 case PV_SWITCH: 02672 /* fields: item->u1.str == the switch expression 02673 02674 item->u2.statements == a pval list of statements in the switch, 02675 (will be case statements, most likely!) 02676 */ 02677 /* we can check the switch expression, see if it matches any of the app variables... 02678 if it does, then, are all the possible cases accounted for? */ 02679 check_switch_expr(item, apps); 02680 check_pval(item->u2.statements, apps,in_globals); 02681 break; 02682 02683 case PV_EXTENSION: 02684 /* fields: item->u1.str == the extension name, label, whatever it's called 02685 02686 item->u2.statements == a pval list of statements in the extension 02687 item->u3.hints == a char * hint argument 02688 item->u4.regexten == an int boolean. non-zero says that regexten was specified 02689 */ 02690 current_extension = item ; 02691 02692 check_pval(item->u2.statements, apps,in_globals); 02693 break; 02694 02695 case PV_IGNOREPAT: 02696 /* fields: item->u1.str == the ignorepat data 02697 */ 02698 break; 02699 02700 case PV_GLOBALS: 02701 /* fields: item->u1.statements == pval list of statements, usually vardecs 02702 */ 02703 in_abstract_context = 0; 02704 check_pval(item->u1.statements, apps, 1); 02705 break; 02706 default: 02707 break; 02708 } 02709 }
Definition at line 2119 of file pbx_ael.c.
References ast_strdupa, appsetvar::name, appsetvar::next, argapp::next, argapp::setvars, pval::str, t, and pval::u1.
Referenced by check_pval_item().
02120 { 02121 #ifdef AAL_ARGCHECK 02122 /* get and clean the variable name */ 02123 char *buff1, *p; 02124 struct argapp *a,*a2; 02125 struct appsetvar *v,*v2; 02126 struct argchoice *c; 02127 pval *t; 02128 02129 p = item->u1.str; 02130 while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) ) 02131 p++; 02132 02133 buff1 = ast_strdupa(p); 02134 02135 while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t')) 02136 buff1[strlen(buff1)-1] = 0; 02137 /* buff1 now contains the variable name */ 02138 v = 0; 02139 for (a=apps; a; a=a->next) { 02140 for (v=a->setvars;v;v=v->next) { 02141 if (strcmp(v->name,buff1) == 0) { 02142 break; 02143 } 02144 } 02145 if ( v ) 02146 break; 02147 } 02148 if (v && v->vals) { 02149 /* we have a match, to a variable that has a set of determined values */ 02150 int def= 0; 02151 int pat = 0; 02152 int f1 = 0; 02153 02154 /* first of all, does this switch have a default case ? */ 02155 for (t=item->u2.statements; t; t=t->next) { 02156 if (t->type == PV_DEFAULT) { 02157 def =1; 02158 break; 02159 } 02160 if (t->type == PV_PATTERN) { 02161 pat++; 02162 } 02163 } 02164 if (def || pat) /* nothing to check. All cases accounted for! */ 02165 return; 02166 for (c=v->vals; c; c=c->next) { 02167 f1 = 0; 02168 for (t=item->u2.statements; t; t=t->next) { 02169 if (t->type == PV_CASE || t->type == PV_PATTERN) { 02170 if (!strcmp(t->u1.str,c->name)) { 02171 f1 = 1; 02172 break; 02173 } 02174 } 02175 } 02176 if (!f1) { 02177 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n", 02178 item->filename, item->startline, item->endline, item->u1.str, c->name); 02179 warns++; 02180 } 02181 } 02182 /* next, is there an app call in the current exten, that would set this var? */ 02183 f1 = 0; 02184 t = current_extension->u2.statements; 02185 if ( t && t->type == PV_STATEMENTBLOCK ) 02186 t = t->u1.statements; 02187 for (; t && t != item; t=t->next) { 02188 if (t->type == PV_APPLICATION_CALL) { 02189 /* find the application that matches the u1.str */ 02190 for (a2=apps; a2; a2=a2->next) { 02191 if (strcasecmp(a2->name, t->u1.str)==0) { 02192 for (v2=a2->setvars; v2; v2=v2->next) { 02193 if (strcmp(v2->name, buff1) == 0) { 02194 /* found an app that sets the var */ 02195 f1 = 1; 02196 break; 02197 } 02198 } 02199 } 02200 if (f1) 02201 break; 02202 } 02203 } 02204 if (f1) 02205 break; 02206 } 02207 02208 /* see if it sets the var */ 02209 if (!f1) { 02210 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", 02211 item->filename, item->startline, item->endline, item->u1.str); 02212 warns++; 02213 } 02214 } 02215 #else 02216 pval *t,*tl=0,*p2; 02217 int def= 0; 02218 02219 /* first of all, does this switch have a default case ? */ 02220 for (t=item->u2.statements; t; t=t->next) { 02221 if (t->type == PV_DEFAULT) { 02222 def =1; 02223 break; 02224 } 02225 tl = t; 02226 } 02227 if (def) /* nothing to check. All cases accounted for! */ 02228 return; 02229 /* if no default, warn and insert a default case at the end */ 02230 p2 = tl->next = calloc(1, sizeof(struct pval)); 02231 02232 p2->type = PV_DEFAULT; 02233 p2->startline = tl->startline; 02234 p2->endline = tl->endline; 02235 p2->startcol = tl->startcol; 02236 p2->endcol = tl->endcol; 02237 p2->filename = strdup(tl->filename); 02238 ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n", 02239 p2->filename, p2->startline, p2->endline); 02240 warns++; 02241 02242 #endif 02243 }
static void check_timerange | ( | pval * | p | ) | [static] |
Definition at line 850 of file pbx_ael.c.
References ast_log(), ast_strdupa, ast_strlen_zero(), pval::endline, pval::filename, LOG_WARNING, pval::startline, pval::str, and pval::u1.
Referenced by check_pval_item().
00851 { 00852 char *times; 00853 char *e; 00854 int s1, s2; 00855 int e1, e2; 00856 00857 times = ast_strdupa(p->u1.str); 00858 00859 /* Star is all times */ 00860 if (ast_strlen_zero(times) || !strcmp(times, "*")) { 00861 return; 00862 } 00863 /* Otherwise expect a range */ 00864 e = strchr(times, '-'); 00865 if (!e) { 00866 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", 00867 p->filename, p->startline, p->endline, times); 00868 warns++; 00869 return; 00870 } 00871 *e = '\0'; 00872 e++; 00873 while (*e && !isdigit(*e)) 00874 e++; 00875 if (!*e) { 00876 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n", 00877 p->filename, p->startline, p->endline, p->u1.str); 00878 warns++; 00879 } 00880 if (sscanf(times, "%d:%d", &s1, &s2) != 2) { 00881 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) isn't quite right!\n", 00882 p->filename, p->startline, p->endline, times); 00883 warns++; 00884 } 00885 if (sscanf(e, "%d:%d", &e1, &e2) != 2) { 00886 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) isn't quite right!\n", 00887 p->filename, p->startline, p->endline, times); 00888 warns++; 00889 } 00890 00891 s1 = s1 * 30 + s2/2; 00892 if ((s1 < 0) || (s1 >= 24*30)) { 00893 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) is out of range!\n", 00894 p->filename, p->startline, p->endline, times); 00895 warns++; 00896 } 00897 e1 = e1 * 30 + e2/2; 00898 if ((e1 < 0) || (e1 >= 24*30)) { 00899 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) is out of range!\n", 00900 p->filename, p->startline, p->endline, e); 00901 warns++; 00902 } 00903 return; 00904 }
void destroy_extensions | ( | struct ael_extension * | exten | ) |
Definition at line 2868 of file pbx_ael.c.
References ael_priority::app, ael_priority::appargs, exten, free, ael_priority::goto_false, ael_priority::goto_true, ael_extension::hints, ael_extension::loop_break, ael_extension::loop_continue, ael_extension::name, ael_priority::next, ael_extension::next_exten, ael_priority::origin, ael_extension::plist, and ael_extension::plist_last.
02869 { 02870 struct ael_extension *ne, *nen; 02871 for (ne=exten; ne; ne=nen) { 02872 struct ael_priority *pe, *pen; 02873 02874 if (ne->name) 02875 free(ne->name); 02876 02877 /* cidmatch fields are allocated with name, and freed when 02878 the name field is freed. Don't do a free for this field, 02879 unless you LIKE to see a crash! */ 02880 02881 if (ne->hints) 02882 free(ne->hints); 02883 02884 for (pe=ne->plist; pe; pe=pen) { 02885 pen = pe->next; 02886 if (pe->app) 02887 free(pe->app); 02888 pe->app = 0; 02889 if (pe->appargs) 02890 free(pe->appargs); 02891 pe->appargs = 0; 02892 pe->origin = 0; 02893 pe->goto_true = 0; 02894 pe->goto_false = 0; 02895 free(pe); 02896 } 02897 nen = ne->next_exten; 02898 ne->next_exten = 0; 02899 ne->plist =0; 02900 ne->plist_last = 0; 02901 ne->next_exten = 0; 02902 ne->loop_break = 0; 02903 ne->loop_continue = 0; 02904 free(ne); 02905 } 02906 }
void destroy_pval | ( | pval * | item | ) |
void destroy_pval_item | ( | pval * | item | ) |
Definition at line 4316 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().
04317 { 04318 if (item == NULL) { 04319 ast_log(LOG_WARNING, "null item\n"); 04320 return; 04321 } 04322 04323 if (item->filename) 04324 free(item->filename); 04325 04326 switch (item->type) { 04327 case PV_WORD: 04328 /* fields: item->u1.str == string associated with this (word). */ 04329 if (item->u1.str ) 04330 free(item->u1.str); 04331 if ( item->u2.arglist ) 04332 destroy_pval(item->u2.arglist); 04333 break; 04334 04335 case PV_MACRO: 04336 /* fields: item->u1.str == name of macro 04337 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user 04338 item->u2.arglist->u1.str == argument 04339 item->u2.arglist->next == next arg 04340 04341 item->u3.macro_statements == pval list of statements in macro body. 04342 */ 04343 destroy_pval(item->u2.arglist); 04344 if (item->u1.str ) 04345 free(item->u1.str); 04346 destroy_pval(item->u3.macro_statements); 04347 break; 04348 04349 case PV_CONTEXT: 04350 /* fields: item->u1.str == name of context 04351 item->u2.statements == pval list of statements in context body 04352 item->u3.abstract == int 1 if an abstract keyword were present 04353 */ 04354 if (item->u1.str) 04355 free(item->u1.str); 04356 destroy_pval(item->u2.statements); 04357 break; 04358 04359 case PV_MACRO_CALL: 04360 /* fields: item->u1.str == name of macro to call 04361 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 04362 item->u2.arglist->u1.str == argument 04363 item->u2.arglist->next == next arg 04364 */ 04365 if (item->u1.str) 04366 free(item->u1.str); 04367 destroy_pval(item->u2.arglist); 04368 break; 04369 04370 case PV_APPLICATION_CALL: 04371 /* fields: item->u1.str == name of application to call 04372 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 04373 item->u2.arglist->u1.str == argument 04374 item->u2.arglist->next == next arg 04375 */ 04376 if (item->u1.str) 04377 free(item->u1.str); 04378 destroy_pval(item->u2.arglist); 04379 break; 04380 04381 case PV_CASE: 04382 /* fields: item->u1.str == value of case 04383 item->u2.statements == pval list of statements under the case 04384 */ 04385 if (item->u1.str) 04386 free(item->u1.str); 04387 destroy_pval(item->u2.statements); 04388 break; 04389 04390 case PV_PATTERN: 04391 /* fields: item->u1.str == value of case 04392 item->u2.statements == pval list of statements under the case 04393 */ 04394 if (item->u1.str) 04395 free(item->u1.str); 04396 destroy_pval(item->u2.statements); 04397 break; 04398 04399 case PV_DEFAULT: 04400 /* fields: 04401 item->u2.statements == pval list of statements under the case 04402 */ 04403 destroy_pval(item->u2.statements); 04404 break; 04405 04406 case PV_CATCH: 04407 /* fields: item->u1.str == name of extension to catch 04408 item->u2.statements == pval list of statements in context body 04409 */ 04410 if (item->u1.str) 04411 free(item->u1.str); 04412 destroy_pval(item->u2.statements); 04413 break; 04414 04415 case PV_SWITCHES: 04416 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04417 */ 04418 destroy_pval(item->u1.list); 04419 break; 04420 04421 case PV_ESWITCHES: 04422 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04423 */ 04424 destroy_pval(item->u1.list); 04425 break; 04426 04427 case PV_INCLUDES: 04428 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 04429 item->u2.arglist == pval list of 4 PV_WORD elements for time values 04430 */ 04431 destroy_pval(item->u1.list); 04432 break; 04433 04434 case PV_STATEMENTBLOCK: 04435 /* fields: item->u1.list == pval list of statements in block, one per entry in the list 04436 */ 04437 destroy_pval(item->u1.list); 04438 break; 04439 04440 case PV_VARDEC: 04441 /* fields: item->u1.str == variable name 04442 item->u2.val == variable value to assign 04443 */ 04444 if (item->u1.str) 04445 free(item->u1.str); 04446 if (item->u2.val) 04447 free(item->u2.val); 04448 break; 04449 04450 case PV_GOTO: 04451 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. 04452 item->u1.list->u1.str == where the data on a PV_WORD will always be. 04453 */ 04454 04455 destroy_pval(item->u1.list); 04456 break; 04457 04458 case PV_LABEL: 04459 /* fields: item->u1.str == label name 04460 */ 04461 if (item->u1.str) 04462 free(item->u1.str); 04463 break; 04464 04465 case PV_FOR: 04466 /* fields: item->u1.for_init == a string containing the initalizer 04467 item->u2.for_test == a string containing the loop test 04468 item->u3.for_inc == a string containing the loop increment 04469 04470 item->u4.for_statements == a pval list of statements in the for () 04471 */ 04472 if (item->u1.for_init) 04473 free(item->u1.for_init); 04474 if (item->u2.for_test) 04475 free(item->u2.for_test); 04476 if (item->u3.for_inc) 04477 free(item->u3.for_inc); 04478 destroy_pval(item->u4.for_statements); 04479 break; 04480 04481 case PV_WHILE: 04482 /* fields: item->u1.str == the while conditional, as supplied by user 04483 04484 item->u2.statements == a pval list of statements in the while () 04485 */ 04486 if (item->u1.str) 04487 free(item->u1.str); 04488 destroy_pval(item->u2.statements); 04489 break; 04490 04491 case PV_BREAK: 04492 /* fields: none 04493 */ 04494 break; 04495 04496 case PV_RETURN: 04497 /* fields: none 04498 */ 04499 break; 04500 04501 case PV_CONTINUE: 04502 /* fields: none 04503 */ 04504 break; 04505 04506 case PV_IFTIME: 04507 /* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list 04508 04509 item->u2.statements == a pval list of statements in the if () 04510 item->u3.else_statements == a pval list of statements in the else 04511 (could be zero) 04512 */ 04513 destroy_pval(item->u1.list); 04514 destroy_pval(item->u2.statements); 04515 if (item->u3.else_statements) { 04516 destroy_pval(item->u3.else_statements); 04517 } 04518 break; 04519 04520 case PV_RANDOM: 04521 /* fields: item->u1.str == the random percentage, as supplied by user 04522 04523 item->u2.statements == a pval list of statements in the true part () 04524 item->u3.else_statements == a pval list of statements in the else 04525 (could be zero) 04526 fall thru to If */ 04527 case PV_IF: 04528 /* fields: item->u1.str == the if conditional, as supplied by user 04529 04530 item->u2.statements == a pval list of statements in the if () 04531 item->u3.else_statements == a pval list of statements in the else 04532 (could be zero) 04533 */ 04534 if (item->u1.str) 04535 free(item->u1.str); 04536 destroy_pval(item->u2.statements); 04537 if (item->u3.else_statements) { 04538 destroy_pval(item->u3.else_statements); 04539 } 04540 break; 04541 04542 case PV_SWITCH: 04543 /* fields: item->u1.str == the switch expression 04544 04545 item->u2.statements == a pval list of statements in the switch, 04546 (will be case statements, most likely!) 04547 */ 04548 if (item->u1.str) 04549 free(item->u1.str); 04550 destroy_pval(item->u2.statements); 04551 break; 04552 04553 case PV_EXTENSION: 04554 /* fields: item->u1.str == the extension name, label, whatever it's called 04555 04556 item->u2.statements == a pval list of statements in the extension 04557 item->u3.hints == a char * hint argument 04558 item->u4.regexten == an int boolean. non-zero says that regexten was specified 04559 */ 04560 if (item->u1.str) 04561 free(item->u1.str); 04562 if (item->u3.hints) 04563 free(item->u3.hints); 04564 destroy_pval(item->u2.statements); 04565 break; 04566 04567 case PV_IGNOREPAT: 04568 /* fields: item->u1.str == the ignorepat data 04569 */ 04570 if (item->u1.str) 04571 free(item->u1.str); 04572 break; 04573 04574 case PV_GLOBALS: 04575 /* fields: item->u1.statements == pval list of statements, usually vardecs 04576 */ 04577 destroy_pval(item->u1.statements); 04578 break; 04579 } 04580 free(item); 04581 }
static int extension_matches | ( | pval * | here, | |
const char * | exten, | |||
const char * | pattern | |||
) | [static] |
Definition at line 710 of file pbx_ael.c.
References ast_log(), pval::endline, pval::filename, LOG_ERROR, LOG_WARNING, and pval::startline.
Referenced by match_pval_item().
00711 { 00712 int err1; 00713 regex_t preg; 00714 00715 /* simple case, they match exactly, the pattern and exten name */ 00716 if( !strcmp(pattern,exten) == 0 ) 00717 return 1; 00718 00719 if ( pattern[0] == '_' ) { 00720 char reg1[2000]; 00721 const char *p; 00722 char *r = reg1; 00723 00724 if ( strlen(pattern)*5 >= 2000 ) /* safety valve */ { 00725 ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n", 00726 pattern); 00727 return 0; 00728 } 00729 /* form a regular expression from the pattern, and then match it against exten */ 00730 *r++ = '^'; /* what if the extension is a pattern ?? */ 00731 *r++ = '_'; /* what if the extension is a pattern ?? */ 00732 *r++ = '?'; 00733 for (p=pattern+1; *p; p++) { 00734 switch ( *p ) { 00735 case 'X': 00736 *r++ = '['; 00737 *r++ = '0'; 00738 *r++ = '-'; 00739 *r++ = '9'; 00740 *r++ = 'X'; 00741 *r++ = ']'; 00742 break; 00743 00744 case 'Z': 00745 *r++ = '['; 00746 *r++ = '1'; 00747 *r++ = '-'; 00748 *r++ = '9'; 00749 *r++ = 'Z'; 00750 *r++ = ']'; 00751 break; 00752 00753 case 'N': 00754 *r++ = '['; 00755 *r++ = '2'; 00756 *r++ = '-'; 00757 *r++ = '9'; 00758 *r++ = 'N'; 00759 *r++ = ']'; 00760 break; 00761 00762 case '[': 00763 while ( *p && *p != ']' ) { 00764 *r++ = *p++; 00765 } 00766 if ( *p != ']') { 00767 ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The extension pattern '%s' is missing a closing bracket \n", 00768 here->filename, here->startline, here->endline, pattern); 00769 } 00770 break; 00771 00772 case '.': 00773 case '!': 00774 *r++ = '.'; 00775 *r++ = '*'; 00776 break; 00777 case '*': 00778 *r++ = '\\'; 00779 *r++ = '*'; 00780 break; 00781 default: 00782 *r++ = *p; 00783 break; 00784 00785 } 00786 } 00787 *r++ = '$'; /* what if the extension is a pattern ?? */ 00788 *r++ = *p++; /* put in the closing null */ 00789 err1 = regcomp(&preg, reg1, REG_NOSUB|REG_EXTENDED); 00790 if ( err1 ) { 00791 char errmess[500]; 00792 regerror(err1,&preg,errmess,sizeof(errmess)); 00793 regfree(&preg); 00794 ast_log(LOG_WARNING, "Regcomp of %s failed, error code %d\n", 00795 reg1, err1); 00796 return 0; 00797 } 00798 err1 = regexec(&preg, exten, 0, 0, 0); 00799 regfree(&preg); 00800 00801 if ( err1 ) { 00802 /* ast_log(LOG_NOTICE,"*****************************[%d]Extension %s did not match %s(%s)\n", 00803 err1,exten, pattern, reg1); */ 00804 return 0; /* no match */ 00805 } else { 00806 /* ast_log(LOG_NOTICE,"*****************************Extension %s matched %s\n", 00807 exten, pattern); */ 00808 return 1; 00809 } 00810 00811 00812 } else { 00813 if ( strcmp(exten,pattern) == 0 ) { 00814 return 1; 00815 } else 00816 return 0; 00817 } 00818 }
struct pval * find_context | ( | char * | name | ) |
Definition at line 1888 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().
01889 { 01890 return_on_context_match = 1; 01891 count_labels = 0; 01892 match_context = name; 01893 match_exten = "*"; /* don't really need to set these, shouldn't be reached */ 01894 match_label = "*"; 01895 return match_pval(current_db); 01896 }
Definition at line 1767 of file pbx_ael.c.
References find_context(), pval::list, pval::macro_statements, match_pval(), pval::next, PV_INCLUDES, PV_MACRO, pval::statements, pval::str, pval::type, pval::u1, pval::u2, and pval::u3.
Referenced by check_label().
01768 { 01769 /* printf(" --- Got args %s, %s\n", exten, label); */ 01770 struct pval *ret; 01771 struct pval *p3; 01772 struct pval *startpt = ((curr_cont->type==PV_MACRO)?curr_cont->u3.macro_statements: curr_cont->u2.statements); 01773 01774 count_labels = 0; 01775 return_on_context_match = 0; 01776 match_context = "*"; 01777 match_exten = "*"; 01778 match_label = label; 01779 01780 ret = match_pval(curr_cont); 01781 if (ret) 01782 return ret; 01783 01784 /* the target of the goto could be in an included context!! Fancy that!! */ 01785 /* look for includes in the current context */ 01786 for (p3=startpt; p3; p3=p3->next) { 01787 if (p3->type == PV_INCLUDES) { 01788 struct pval *p4; 01789 for (p4=p3->u1.list; p4; p4=p4->next) { 01790 /* for each context pointed to, find it, then find a context/label that matches the 01791 target here! */ 01792 char *incl_context = p4->u1.str; 01793 /* find a matching context name */ 01794 struct pval *that_context = find_context(incl_context); 01795 if (that_context) { 01796 struct pval *x3; 01797 x3 = find_first_label_in_current_context(label, that_context); 01798 if (x3) { 01799 return x3; 01800 } 01801 } 01802 } 01803 } 01804 } 01805 return 0; 01806 }
struct pval * find_label_in_current_context | ( | char * | exten, | |
char * | label, | |||
pval * | curr_cont | |||
) | [static] |
Definition at line 1808 of file pbx_ael.c.
References find_context(), pval::list, pval::macro_statements, match_pval(), pval::next, PV_INCLUDES, PV_MACRO, pval::statements, pval::str, pval::type, pval::u1, pval::u2, and pval::u3.
Referenced by check_goto(), and get_goto_target().
01809 { 01810 /* printf(" --- Got args %s, %s\n", exten, label); */ 01811 struct pval *ret; 01812 struct pval *p3; 01813 struct pval *startpt; 01814 01815 count_labels = 0; 01816 return_on_context_match = 0; 01817 match_context = "*"; 01818 match_exten = exten; 01819 match_label = label; 01820 if (curr_cont->type == PV_MACRO) 01821 startpt = curr_cont->u3.macro_statements; 01822 else 01823 startpt = curr_cont->u2.statements; 01824 01825 ret = match_pval(startpt); 01826 if (ret) 01827 return ret; 01828 01829 /* the target of the goto could be in an included context!! Fancy that!! */ 01830 /* look for includes in the current context */ 01831 for (p3=startpt; p3; p3=p3->next) { 01832 if (p3->type == PV_INCLUDES) { 01833 struct pval *p4; 01834 for (p4=p3->u1.list; p4; p4=p4->next) { 01835 /* for each context pointed to, find it, then find a context/label that matches the 01836 target here! */ 01837 char *incl_context = p4->u1.str; 01838 /* find a matching context name */ 01839 struct pval *that_context = find_context(incl_context); 01840 if (that_context) { 01841 struct pval *x3; 01842 x3 = find_label_in_current_context(exten, label, that_context); 01843 if (x3) { 01844 return x3; 01845 } 01846 } 01847 } 01848 } 01849 } 01850 return 0; 01851 }
static struct pval * find_label_in_current_db | ( | const char * | context, | |
const char * | exten, | |||
const char * | label | |||
) | [static] |
Definition at line 1864 of file pbx_ael.c.
References current_db, and match_pval().
Referenced by check_goto(), and get_goto_target().
01865 { 01866 /* printf(" --- Got args %s, %s, %s\n", context, exten, label); */ 01867 count_labels = 0; 01868 return_on_context_match = 0; 01869 01870 match_context = context; 01871 match_exten = exten; 01872 match_label = label; 01873 01874 return match_pval(current_db); 01875 }
static struct pval * find_label_in_current_extension | ( | const char * | label, | |
pval * | curr_ext | |||
) | [static] |
Definition at line 1853 of file pbx_ael.c.
References match_pval().
Referenced by check_goto(), and get_goto_target().
01854 { 01855 /* printf(" --- Got args %s\n", label); */ 01856 count_labels = 0; 01857 return_on_context_match = 0; 01858 match_context = "*"; 01859 match_exten = "*"; 01860 match_label = label; 01861 return match_pval(curr_ext); 01862 }
struct pval * find_macro | ( | char * | name | ) |
Definition at line 1878 of file pbx_ael.c.
References current_db, and match_pval().
Referenced by check_pval_item().
01879 { 01880 return_on_context_match = 1; 01881 count_labels = 0; 01882 match_context = name; 01883 match_exten = "*"; /* don't really need to set these, shouldn't be reached */ 01884 match_label = "*"; 01885 return match_pval(current_db); 01886 }
static void find_pval_goto_item | ( | pval * | item, | |
int | lev | |||
) | [static] |
Definition at line 1301 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().
01302 { 01303 struct pval *p4; 01304 if (lev>100) { 01305 ast_log(LOG_ERROR,"find_pval_goto in infinite loop!\n\n"); 01306 return; 01307 } 01308 01309 switch ( item->type ) { 01310 case PV_MACRO: 01311 /* fields: item->u1.str == name of macro 01312 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user 01313 item->u2.arglist->u1.str == argument 01314 item->u2.arglist->next == next arg 01315 01316 item->u3.macro_statements == pval list of statements in macro body. 01317 */ 01318 01319 /* printf("Descending into matching macro %s\n", match_context); */ 01320 find_pval_gotos(item->u3.macro_statements,lev+1); /* if we're just searching for a context, don't bother descending into them */ 01321 01322 break; 01323 01324 case PV_CONTEXT: 01325 /* fields: item->u1.str == name of context 01326 item->u2.statements == pval list of statements in context body 01327 item->u3.abstract == int 1 if an abstract keyword were present 01328 */ 01329 break; 01330 01331 case PV_CASE: 01332 /* fields: item->u1.str == value of case 01333 item->u2.statements == pval list of statements under the case 01334 */ 01335 find_pval_gotos(item->u2.statements,lev+1); 01336 break; 01337 01338 case PV_PATTERN: 01339 /* fields: item->u1.str == value of case 01340 item->u2.statements == pval list of statements under the case 01341 */ 01342 find_pval_gotos(item->u2.statements,lev+1); 01343 break; 01344 01345 case PV_DEFAULT: 01346 /* fields: 01347 item->u2.statements == pval list of statements under the case 01348 */ 01349 find_pval_gotos(item->u2.statements,lev+1); 01350 break; 01351 01352 case PV_CATCH: 01353 /* fields: item->u1.str == name of extension to catch 01354 item->u2.statements == pval list of statements in context body 01355 */ 01356 find_pval_gotos(item->u2.statements,lev+1); 01357 break; 01358 01359 case PV_STATEMENTBLOCK: 01360 /* fields: item->u1.list == pval list of statements in block, one per entry in the list 01361 */ 01362 find_pval_gotos(item->u1.list,lev+1); 01363 break; 01364 01365 case PV_GOTO: 01366 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. 01367 item->u1.list->u1.str == where the data on a PV_WORD will always be. 01368 */ 01369 check_goto(item); /* THE WHOLE FUNCTION OF THIS ENTIRE ROUTINE!!!! */ 01370 break; 01371 01372 case PV_INCLUDES: 01373 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 01374 */ 01375 for (p4=item->u1.list; p4; p4=p4->next) { 01376 /* for each context pointed to, find it, then find a context/label that matches the 01377 target here! */ 01378 char *incl_context = p4->u1.str; 01379 /* find a matching context name */ 01380 struct pval *that_context = find_context(incl_context); 01381 if (that_context) { 01382 find_pval_gotos(that_context,lev+1); /* keep working up the includes */ 01383 } 01384 } 01385 break; 01386 01387 case PV_FOR: 01388 /* fields: item->u1.for_init == a string containing the initalizer 01389 item->u2.for_test == a string containing the loop test 01390 item->u3.for_inc == a string containing the loop increment 01391 01392 item->u4.for_statements == a pval list of statements in the for () 01393 */ 01394 find_pval_gotos(item->u4.for_statements,lev+1); 01395 break; 01396 01397 case PV_WHILE: 01398 /* fields: item->u1.str == the while conditional, as supplied by user 01399 01400 item->u2.statements == a pval list of statements in the while () 01401 */ 01402 find_pval_gotos(item->u2.statements,lev+1); 01403 break; 01404 01405 case PV_RANDOM: 01406 /* fields: item->u1.str == the random number expression, as supplied by user 01407 01408 item->u2.statements == a pval list of statements in the if () 01409 item->u3.else_statements == a pval list of statements in the else 01410 (could be zero) 01411 fall thru to PV_IF */ 01412 01413 case PV_IFTIME: 01414 /* fields: item->u1.list == the time values, 4 of them, as PV_WORD structs in a list 01415 01416 item->u2.statements == a pval list of statements in the if () 01417 item->u3.else_statements == a pval list of statements in the else 01418 (could be zero) 01419 fall thru to PV_IF*/ 01420 case PV_IF: 01421 /* fields: item->u1.str == the if conditional, as supplied by user 01422 01423 item->u2.statements == a pval list of statements in the if () 01424 item->u3.else_statements == a pval list of statements in the else 01425 (could be zero) 01426 */ 01427 find_pval_gotos(item->u2.statements,lev+1); 01428 01429 if (item->u3.else_statements) { 01430 find_pval_gotos(item->u3.else_statements,lev+1); 01431 } 01432 break; 01433 01434 case PV_SWITCH: 01435 /* fields: item->u1.str == the switch expression 01436 01437 item->u2.statements == a pval list of statements in the switch, 01438 (will be case statements, most likely!) 01439 */ 01440 find_pval_gotos(item->u3.else_statements,lev+1); 01441 break; 01442 01443 case PV_EXTENSION: 01444 /* fields: item->u1.str == the extension name, label, whatever it's called 01445 01446 item->u2.statements == a pval list of statements in the extension 01447 item->u3.hints == a char * hint argument 01448 item->u4.regexten == an int boolean. non-zero says that regexten was specified 01449 */ 01450 01451 find_pval_gotos(item->u2.statements,lev+1); 01452 break; 01453 01454 default: 01455 break; 01456 } 01457 }
static void find_pval_gotos | ( | pval * | item, | |
int | lev | |||
) | [static] |
Definition at line 1459 of file pbx_ael.c.
References find_pval_goto_item(), and pval::next.
Referenced by check_pval_item(), and find_pval_goto_item().
01460 { 01461 pval *i; 01462 01463 for (i=item; i; i=i->next) { 01464 01465 find_pval_goto_item(i, lev); 01466 } 01467 }
static void fix_gotos_in_extensions | ( | struct ael_extension * | exten | ) | [static] |
Definition at line 3916 of file pbx_ael.c.
References exten, ael_priority::next, ael_extension::next_exten, ael_extension::plist, PV_GOTO, and strdup.
03917 { 03918 struct ael_extension *e; 03919 for(e=exten;e;e=e->next_exten) { 03920 03921 struct ael_priority *p; 03922 for(p=e->plist;p;p=p->next) { 03923 03924 if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) { 03925 03926 /* fix the extension of the goto target to the actual extension in the post-compiled dialplan */ 03927 03928 pval *target = p->origin->u2.goto_target; 03929 struct ael_extension *z = target->u3.compiled_label; 03930 pval *pv2 = p->origin; 03931 char buf1[500]; 03932 char *apparg_save = p->appargs; 03933 03934 p->appargs = 0; 03935 if (!pv2->u1.list->next) /* just one -- it won't hurt to repeat the extension */ { 03936 snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->u1.str); 03937 p->appargs = strdup(buf1); 03938 03939 } else if (pv2->u1.list->next && !pv2->u1.list->next->next) /* two */ { 03940 snprintf(buf1,sizeof(buf1),"%s|%s", z->name, pv2->u1.list->next->u1.str); 03941 p->appargs = strdup(buf1); 03942 } else if (pv2->u1.list->next && pv2->u1.list->next->next) { 03943 snprintf(buf1,sizeof(buf1),"%s|%s|%s", pv2->u1.list->u1.str, 03944 z->name, 03945 pv2->u1.list->next->next->u1.str); 03946 p->appargs = strdup(buf1); 03947 } 03948 else 03949 printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n"); 03950 03951 if( apparg_save ) { 03952 free(apparg_save); 03953 } 03954 } 03955 } 03956 } 03957 }
static void gen_match_to_pattern | ( | char * | pattern, | |
char * | result | |||
) | [static] |
Definition at line 2947 of file pbx_ael.c.
References t.
Referenced by gen_prios().
02948 { 02949 /* the result will be a string that will be matched by pattern */ 02950 char *p=pattern, *t=result; 02951 while (*p) { 02952 if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z') 02953 *t++ = '9'; 02954 else if (*p == '[') { 02955 char *z = p+1; 02956 while (*z != ']') 02957 z++; 02958 if (*(z+1)== ']') 02959 z++; 02960 *t++=*(p+1); /* use the first char in the set */ 02961 p = z; 02962 } else { 02963 *t++ = *p; 02964 } 02965 p++; 02966 } 02967 *t++ = 0; /* cap it off */ 02968 }
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 2970 of file pbx_ael.c.
References AEL_APPCALL, AEL_CONTROL1, AEL_FOR_CONTROL, AEL_IF_CONTROL, AEL_IFTIME_CONTROL, AEL_LABEL, AEL_RAND_CONTROL, AEL_RETURN, ael_priority::app, ael_priority::appargs, pval::arglist, pval::compiled_label, ael_extension::context, control_statement_count, pval::else_statements, ael_priority::exten, exten, pval::for_inc, pval::for_init, pval::for_statements, pval::for_test, free, gen_match_to_pattern(), get_goto_target(), ael_priority::goto_false, pval::goto_target, pval::goto_target_in_case, ael_priority::goto_true, ael_extension::has_switch, ael_extension::is_switch, pval::label_in_case, label_inside_case(), linkexten(), linkprio(), pval::list, ael_extension::loop_break, ael_extension::loop_continue, ael_extension::name, new_exten(), new_prio(), pval::next, ael_priority::origin, PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTINUE, PV_DEFAULT, PV_FOR, PV_GOTO, PV_IF, PV_IFTIME, PV_LABEL, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_VARDEC, PV_WHILE, remove_spaces_before_equals(), ael_extension::return_needed, pval::statements, pval::str, strdup, substitute_commas(), ael_priority::type, pval::type, pval::u1, pval::u2, pval::u3, pval::u4, and pval::val.
02971 { 02972 pval *p,*p2,*p3; 02973 struct ael_priority *pr; 02974 struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end; 02975 struct ael_priority *while_test, *while_loop, *while_end; 02976 struct ael_priority *switch_set, *switch_test, *switch_end, *fall_thru, *switch_empty; 02977 struct ael_priority *if_test, *if_end, *if_skip, *if_false; 02978 #ifdef OLD_RAND_ACTION 02979 struct ael_priority *rand_test, *rand_end, *rand_skip; 02980 #endif 02981 char buf1[2000]; 02982 char buf2[2000]; 02983 char *strp, *strp2; 02984 char new_label[2000]; 02985 int default_exists; 02986 int local_control_statement_count; 02987 struct ael_priority *loop_break_save; 02988 struct ael_priority *loop_continue_save; 02989 struct ael_extension *switch_case,*switch_null; 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, mother_exten); 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, mother_exten); 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, mother_exten); 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 if (strp) { 03066 strp2 = strchr(p->u1.for_init, '='); 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 /* for_init->app = strdup("Set"); just set! */ 03073 } else { 03074 strp2 = p->u1.for_init; 03075 while (*strp2 && isspace(*strp2)) 03076 strp2++; 03077 if (*strp2 == '&') { /* itsa macro call */ 03078 char *strp3 = strp2+1; 03079 while (*strp3 && isspace(*strp3)) 03080 strp3++; 03081 strcpy(buf2, strp3); 03082 strp3 = strchr(buf2,'('); 03083 if (strp3) { 03084 *strp3 = '|'; 03085 } 03086 while ((strp3=strchr(buf2,','))) { 03087 *strp3 = '|'; 03088 } 03089 strp3 = strrchr(buf2, ')'); 03090 if (strp3) 03091 *strp3 = 0; /* remove the closing paren */ 03092 03093 for_init->appargs = strdup(buf2); 03094 if (for_init->app) 03095 free(for_init->app); 03096 for_init->app = strdup("Macro"); 03097 } else { /* must be a regular app call */ 03098 char *strp3; 03099 strcpy(buf2, strp2); 03100 strp3 = strchr(buf2,'('); 03101 if (strp3) { 03102 *strp3 = 0; 03103 if (for_init->app) 03104 free(for_init->app); 03105 for_init->app = strdup(buf2); 03106 for_init->appargs = strdup(strp3+1); 03107 strp3 = strrchr(for_init->appargs, ')'); 03108 if (strp3) 03109 *strp3 = 0; /* remove the closing paren */ 03110 } 03111 } 03112 } 03113 03114 strcpy(buf2,p->u3.for_inc); 03115 remove_spaces_before_equals(buf2); 03116 strp = strchr(buf2, '='); 03117 if (strp) { /* there's an = in this part; that means an assignment. set it up */ 03118 strp2 = strchr(p->u3.for_inc, '='); 03119 *(strp+1) = 0; 03120 strcat(buf2,"$["); 03121 strncat(buf2,strp2+1, sizeof(buf2)-strlen(strp2+1)-2); 03122 strcat(buf2,"]"); 03123 for_inc->appargs = strdup(buf2); 03124 for_inc->app = strdup("Set"); 03125 } else { 03126 strp2 = p->u3.for_inc; 03127 while (*strp2 && isspace(*strp2)) 03128 strp2++; 03129 if (*strp2 == '&') { /* itsa macro call */ 03130 char *strp3 = strp2+1; 03131 while (*strp3 && isspace(*strp3)) 03132 strp3++; 03133 strcpy(buf2, strp3); 03134 strp3 = strchr(buf2,'('); 03135 if (strp3) { 03136 *strp3 = '|'; 03137 } 03138 while ((strp3=strchr(buf2,','))) { 03139 *strp3 = '|'; 03140 } 03141 strp3 = strrchr(buf2, ')'); 03142 if (strp3) 03143 *strp3 = 0; /* remove the closing paren */ 03144 03145 for_inc->appargs = strdup(buf2); 03146 03147 for_inc->app = strdup("Macro"); 03148 } else { /* must be a regular app call */ 03149 char *strp3; 03150 strcpy(buf2, strp2); 03151 strp3 = strchr(buf2,'('); 03152 if (strp3) { 03153 *strp3 = 0; 03154 for_inc->app = strdup(buf2); 03155 for_inc->appargs = strdup(strp3+1); 03156 strp3 = strrchr(for_inc->appargs, ')'); 03157 if (strp3) 03158 *strp3 = 0; /* remove the closing paren */ 03159 } 03160 } 03161 } 03162 snprintf(buf1,sizeof(buf1),"$[%s]",p->u2.for_test); 03163 for_test->app = 0; 03164 for_test->appargs = strdup(buf1); 03165 for_loop->goto_true = for_test; 03166 snprintf(buf1,sizeof(buf1),"Finish for-%s-%d", label, control_statement_count); 03167 for_end->app = strdup("NoOp"); 03168 for_end->appargs = strdup(buf1); 03169 /* link & load! */ 03170 linkprio(exten, for_init, mother_exten); 03171 linkprio(exten, for_test, mother_exten); 03172 03173 /* now, put the body of the for loop here */ 03174 exten->loop_break = for_end; 03175 exten->loop_continue = for_inc; 03176 03177 gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context); /* this will link in all the statements here */ 03178 03179 linkprio(exten, for_inc, mother_exten); 03180 linkprio(exten, for_loop, mother_exten); 03181 linkprio(exten, for_end, mother_exten); 03182 03183 03184 exten->loop_break = loop_break_save; 03185 exten->loop_continue = loop_continue_save; 03186 for_loop->origin = p; 03187 break; 03188 03189 case PV_WHILE: 03190 control_statement_count++; 03191 loop_break_save = exten->loop_break; /* save them, then restore before leaving */ 03192 loop_continue_save = exten->loop_continue; 03193 snprintf(new_label,sizeof(new_label),"while-%s-%d", label, control_statement_count); 03194 while_test = new_prio(); 03195 while_loop = new_prio(); 03196 while_end = new_prio(); 03197 while_test->type = AEL_FOR_CONTROL; 03198 while_test->goto_false = while_end; 03199 while_loop->type = AEL_CONTROL1; /* simple goto */ 03200 while_end->type = AEL_APPCALL; 03201 snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str); 03202 while_test->app = 0; 03203 while_test->appargs = strdup(buf1); 03204 while_loop->goto_true = while_test; 03205 snprintf(buf1,sizeof(buf1),"Finish while-%s-%d", label, control_statement_count); 03206 while_end->app = strdup("NoOp"); 03207 while_end->appargs = strdup(buf1); 03208 03209 linkprio(exten, while_test, mother_exten); 03210 03211 /* now, put the body of the for loop here */ 03212 exten->loop_break = while_end; 03213 exten->loop_continue = while_test; 03214 03215 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the while body statements here */ 03216 03217 linkprio(exten, while_loop, mother_exten); 03218 linkprio(exten, while_end, mother_exten); 03219 03220 03221 exten->loop_break = loop_break_save; 03222 exten->loop_continue = loop_continue_save; 03223 while_loop->origin = p; 03224 break; 03225 03226 case PV_SWITCH: 03227 control_statement_count++; 03228 local_control_statement_count = control_statement_count; 03229 loop_break_save = exten->loop_break; /* save them, then restore before leaving */ 03230 loop_continue_save = exten->loop_continue; 03231 snprintf(new_label,sizeof(new_label),"sw-%s-%d", label, control_statement_count); 03232 if ((mother_exten && !mother_exten->has_switch)) { 03233 switch_set = new_prio(); 03234 switch_set->type = AEL_APPCALL; 03235 switch_set->app = strdup("Set"); 03236 switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}"); 03237 linkprio(exten, switch_set, mother_exten); 03238 mother_exten->has_switch = 1; 03239 } else if ((exten && !exten->has_switch)) { 03240 switch_set = new_prio(); 03241 switch_set->type = AEL_APPCALL; 03242 switch_set->app = strdup("Set"); 03243 switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}"); 03244 linkprio(exten, switch_set, exten); 03245 exten->has_switch = 1; 03246 } 03247 switch_test = new_prio(); 03248 switch_end = new_prio(); 03249 switch_test->type = AEL_APPCALL; 03250 switch_end->type = AEL_APPCALL; 03251 strncpy(buf2,p->u1.str,sizeof(buf2)); 03252 buf2[sizeof(buf2)-1] = 0; /* just in case */ 03253 substitute_commas(buf2); 03254 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",control_statement_count, buf2); 03255 switch_test->app = strdup("Goto"); 03256 switch_test->appargs = strdup(buf1); 03257 snprintf(buf1,sizeof(buf1),"Finish switch-%s-%d", label, control_statement_count); 03258 switch_end->app = strdup("NoOp"); 03259 switch_end->appargs = strdup(buf1); 03260 switch_end->origin = p; 03261 switch_end->exten = exten; 03262 03263 linkprio(exten, switch_test, mother_exten); 03264 linkprio(exten, switch_end, mother_exten); 03265 03266 exten->loop_break = switch_end; 03267 exten->loop_continue = 0; 03268 default_exists = 0; 03269 03270 for (p2=p->u2.statements; p2; p2=p2->next) { 03271 /* now, for each case/default put the body of the for loop here */ 03272 if (p2->type == PV_CASE) { 03273 /* ok, generate a extension and link it in */ 03274 switch_case = new_exten(); 03275 switch_case->context = this_context; 03276 switch_case->is_switch = 1; 03277 /* the break/continue locations are inherited from parent */ 03278 switch_case->loop_break = exten->loop_break; 03279 switch_case->loop_continue = exten->loop_continue; 03280 03281 linkexten(exten,switch_case); 03282 strncpy(buf2,p2->u1.str,sizeof(buf2)); 03283 buf2[sizeof(buf2)-1] = 0; /* just in case */ 03284 substitute_commas(buf2); 03285 snprintf(buf1,sizeof(buf1),"sw-%d-%s", local_control_statement_count, buf2); 03286 switch_case->name = strdup(buf1); 03287 snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count); 03288 03289 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the case body statements here */ 03290 03291 /* here is where we write code to "fall thru" to the next case... if there is one... */ 03292 for (p3=p2->u2.statements; p3; p3=p3->next) { 03293 if (!p3->next) 03294 break; 03295 } 03296 /* p3 now points the last statement... */ 03297 if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN) ) { 03298 /* is there a following CASE/PATTERN/DEFAULT? */ 03299 if (p2->next && p2->next->type == PV_CASE) { 03300 fall_thru = new_prio(); 03301 fall_thru->type = AEL_APPCALL; 03302 fall_thru->app = strdup("Goto"); 03303 strncpy(buf2,p2->next->u1.str,sizeof(buf2)); 03304 buf2[sizeof(buf2)-1] = 0; /* just in case */ 03305 substitute_commas(buf2); 03306 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2); 03307 fall_thru->appargs = strdup(buf1); 03308 linkprio(switch_case, fall_thru, mother_exten); 03309 } else if (p2->next && p2->next->type == PV_PATTERN) { 03310 fall_thru = new_prio(); 03311 fall_thru->type = AEL_APPCALL; 03312 fall_thru->app = strdup("Goto"); 03313 gen_match_to_pattern(p2->next->u1.str, buf2); 03314 substitute_commas(buf2); 03315 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10", local_control_statement_count, buf2); 03316 fall_thru->appargs = strdup(buf1); 03317 linkprio(switch_case, fall_thru, mother_exten); 03318 } else if (p2->next && p2->next->type == PV_DEFAULT) { 03319 fall_thru = new_prio(); 03320 fall_thru->type = AEL_APPCALL; 03321 fall_thru->app = strdup("Goto"); 03322 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count); 03323 fall_thru->appargs = strdup(buf1); 03324 linkprio(switch_case, fall_thru, mother_exten); 03325 } else if (!p2->next) { 03326 fall_thru = new_prio(); 03327 fall_thru->type = AEL_CONTROL1; 03328 fall_thru->goto_true = switch_end; 03329 fall_thru->app = strdup("Goto"); 03330 linkprio(switch_case, fall_thru, mother_exten); 03331 } 03332 } 03333 if (switch_case->return_needed) { 03334 char buf[2000]; 03335 struct ael_priority *np2 = new_prio(); 03336 np2->type = AEL_APPCALL; 03337 np2->app = strdup("NoOp"); 03338 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name); 03339 np2->appargs = strdup(buf); 03340 linkprio(switch_case, np2, mother_exten); 03341 switch_case-> return_target = np2; 03342 } 03343 } else if (p2->type == PV_PATTERN) { 03344 /* ok, generate a extension and link it in */ 03345 switch_case = new_exten(); 03346 switch_case->context = this_context; 03347 switch_case->is_switch = 1; 03348 /* the break/continue locations are inherited from parent */ 03349 switch_case->loop_break = exten->loop_break; 03350 switch_case->loop_continue = exten->loop_continue; 03351 03352 linkexten(exten,switch_case); 03353 strncpy(buf2,p2->u1.str,sizeof(buf2)); 03354 buf2[sizeof(buf2)-1] = 0; /* just in case */ 03355 substitute_commas(buf2); 03356 snprintf(buf1,sizeof(buf1),"_sw-%d-%s", local_control_statement_count, buf2); 03357 switch_case->name = strdup(buf1); 03358 snprintf(new_label,sizeof(new_label),"sw-%s-%s-%d", label, buf2, local_control_statement_count); 03359 03360 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the while body statements here */ 03361 /* here is where we write code to "fall thru" to the next case... if there is one... */ 03362 for (p3=p2->u2.statements; p3; p3=p3->next) { 03363 if (!p3->next) 03364 break; 03365 } 03366 /* p3 now points the last statement... */ 03367 if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) { 03368 /* is there a following CASE/PATTERN/DEFAULT? */ 03369 if (p2->next && p2->next->type == PV_CASE) { 03370 fall_thru = new_prio(); 03371 fall_thru->type = AEL_APPCALL; 03372 fall_thru->app = strdup("Goto"); 03373 strncpy(buf2,p2->next->u1.str,sizeof(buf2)); 03374 buf2[sizeof(buf2)-1] = 0; /* just in case */ 03375 substitute_commas(buf2); 03376 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2); 03377 fall_thru->appargs = strdup(buf1); 03378 linkprio(switch_case, fall_thru, mother_exten); 03379 } else if (p2->next && p2->next->type == PV_PATTERN) { 03380 fall_thru = new_prio(); 03381 fall_thru->type = AEL_APPCALL; 03382 fall_thru->app = strdup("Goto"); 03383 gen_match_to_pattern(p2->next->u1.str, buf2); 03384 substitute_commas(buf2); 03385 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2); 03386 fall_thru->appargs = strdup(buf1); 03387 linkprio(switch_case, fall_thru, mother_exten); 03388 } else if (p2->next && p2->next->type == PV_DEFAULT) { 03389 fall_thru = new_prio(); 03390 fall_thru->type = AEL_APPCALL; 03391 fall_thru->app = strdup("Goto"); 03392 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count); 03393 fall_thru->appargs = strdup(buf1); 03394 linkprio(switch_case, fall_thru, mother_exten); 03395 } else if (!p2->next) { 03396 fall_thru = new_prio(); 03397 fall_thru->type = AEL_CONTROL1; 03398 fall_thru->goto_true = switch_end; 03399 fall_thru->app = strdup("Goto"); 03400 linkprio(switch_case, fall_thru, mother_exten); 03401 } 03402 } 03403 if (switch_case->return_needed) { 03404 char buf[2000]; 03405 struct ael_priority *np2 = new_prio(); 03406 np2->type = AEL_APPCALL; 03407 np2->app = strdup("NoOp"); 03408 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name); 03409 np2->appargs = strdup(buf); 03410 linkprio(switch_case, np2, mother_exten); 03411 switch_case-> return_target = np2; 03412 } 03413 } else if (p2->type == PV_DEFAULT) { 03414 /* ok, generate a extension and link it in */ 03415 switch_case = new_exten(); 03416 switch_case->context = this_context; 03417 switch_case->is_switch = 1; 03418 03419 /* new: the default case intros a pattern with ., which covers ALMOST everything. 03420 but it doesn't cover a NULL pattern. So, we'll define a null extension to match 03421 that goto's the default extension. */ 03422 03423 default_exists++; 03424 switch_null = new_exten(); 03425 switch_null->context = this_context; 03426 switch_null->is_switch = 1; 03427 switch_empty = new_prio(); 03428 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count); 03429 switch_empty->app = strdup("Goto"); 03430 switch_empty->appargs = strdup(buf1); 03431 linkprio(switch_null, switch_empty, mother_exten); 03432 snprintf(buf1,sizeof(buf1),"sw-%d-", local_control_statement_count); 03433 switch_null->name = strdup(buf1); 03434 switch_null->loop_break = exten->loop_break; 03435 switch_null->loop_continue = exten->loop_continue; 03436 linkexten(exten,switch_null); 03437 03438 /* the break/continue locations are inherited from parent */ 03439 switch_case->loop_break = exten->loop_break; 03440 switch_case->loop_continue = exten->loop_continue; 03441 linkexten(exten,switch_case); 03442 snprintf(buf1,sizeof(buf1),"_sw-%d-.", local_control_statement_count); 03443 switch_case->name = strdup(buf1); 03444 03445 snprintf(new_label,sizeof(new_label),"sw-%s-default-%d", label, local_control_statement_count); 03446 03447 gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context); /* this will link in all the default: body statements here */ 03448 03449 /* here is where we write code to "fall thru" to the next case... if there is one... */ 03450 for (p3=p2->u2.statements; p3; p3=p3->next) { 03451 if (!p3->next) 03452 break; 03453 } 03454 /* p3 now points the last statement... */ 03455 if (!p3 || (p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) { 03456 /* is there a following CASE/PATTERN/DEFAULT? */ 03457 if (p2->next && p2->next->type == PV_CASE) { 03458 fall_thru = new_prio(); 03459 fall_thru->type = AEL_APPCALL; 03460 fall_thru->app = strdup("Goto"); 03461 strncpy(buf2,p2->next->u1.str,sizeof(buf2)); 03462 buf2[sizeof(buf2)-1] = 0; /* just in case */ 03463 substitute_commas(buf2); 03464 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2); 03465 fall_thru->appargs = strdup(buf1); 03466 linkprio(switch_case, fall_thru, mother_exten); 03467 } else if (p2->next && p2->next->type == PV_PATTERN) { 03468 fall_thru = new_prio(); 03469 fall_thru->type = AEL_APPCALL; 03470 fall_thru->app = strdup("Goto"); 03471 gen_match_to_pattern(p2->next->u1.str, buf2); 03472 substitute_commas(buf2); 03473 snprintf(buf1,sizeof(buf1),"sw-%d-%s|10",local_control_statement_count, buf2); 03474 fall_thru->appargs = strdup(buf1); 03475 linkprio(switch_case, fall_thru, mother_exten); 03476 } else if (p2->next && p2->next->type == PV_DEFAULT) { 03477 fall_thru = new_prio(); 03478 fall_thru->type = AEL_APPCALL; 03479 fall_thru->app = strdup("Goto"); 03480 snprintf(buf1,sizeof(buf1),"sw-%d-.|10",local_control_statement_count); 03481 fall_thru->appargs = strdup(buf1); 03482 linkprio(switch_case, fall_thru, mother_exten); 03483 } else if (!p2->next) { 03484 fall_thru = new_prio(); 03485 fall_thru->type = AEL_CONTROL1; 03486 fall_thru->goto_true = switch_end; 03487 fall_thru->app = strdup("Goto"); 03488 linkprio(switch_case, fall_thru, mother_exten); 03489 } 03490 } 03491 if (switch_case->return_needed) { 03492 char buf[2000]; 03493 struct ael_priority *np2 = new_prio(); 03494 np2->type = AEL_APPCALL; 03495 np2->app = strdup("NoOp"); 03496 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name); 03497 np2->appargs = strdup(buf); 03498 linkprio(switch_case, np2, mother_exten); 03499 switch_case-> return_target = np2; 03500 } 03501 } else { 03502 /* what could it be??? */ 03503 } 03504 } 03505 03506 exten->loop_break = loop_break_save; 03507 exten->loop_continue = loop_continue_save; 03508 switch_test->origin = p; 03509 switch_end->origin = p; 03510 break; 03511 03512 case PV_MACRO_CALL: 03513 pr = new_prio(); 03514 pr->type = AEL_APPCALL; 03515 snprintf(buf1,sizeof(buf1),"%s", p->u1.str); 03516 for (p2 = p->u2.arglist; p2; p2 = p2->next) { 03517 strcat(buf1,"|"); 03518 strcat(buf1,p2->u1.str); 03519 } 03520 pr->app = strdup("Macro"); 03521 pr->appargs = strdup(buf1); 03522 pr->origin = p; 03523 linkprio(exten, pr, mother_exten); 03524 break; 03525 03526 case PV_APPLICATION_CALL: 03527 pr = new_prio(); 03528 pr->type = AEL_APPCALL; 03529 buf1[0] = 0; 03530 for (p2 = p->u2.arglist; p2; p2 = p2->next) { 03531 if (p2 != p->u2.arglist ) 03532 strcat(buf1,"|"); 03533 substitute_commas(p2->u1.str); 03534 strcat(buf1,p2->u1.str); 03535 } 03536 pr->app = strdup(p->u1.str); 03537 pr->appargs = strdup(buf1); 03538 pr->origin = p; 03539 linkprio(exten, pr, mother_exten); 03540 break; 03541 03542 case PV_BREAK: 03543 pr = new_prio(); 03544 pr->type = AEL_CONTROL1; /* simple goto */ 03545 pr->goto_true = exten->loop_break; 03546 pr->origin = p; 03547 linkprio(exten, pr, mother_exten); 03548 break; 03549 03550 case PV_RETURN: /* hmmmm */ 03551 pr = new_prio(); 03552 pr->type = AEL_RETURN; /* simple goto */ 03553 exten->return_needed++; 03554 pr->app = strdup("Goto"); 03555 pr->appargs = strdup(""); 03556 pr->origin = p; 03557 linkprio(exten, pr, mother_exten); 03558 break; 03559 03560 case PV_CONTINUE: 03561 pr = new_prio(); 03562 pr->type = AEL_CONTROL1; /* simple goto */ 03563 pr->goto_true = exten->loop_continue; 03564 pr->origin = p; 03565 linkprio(exten, pr, mother_exten); 03566 break; 03567 03568 #ifdef OLD_RAND_ACTION 03569 case PV_RANDOM: 03570 control_statement_count++; 03571 snprintf(new_label,sizeof(new_label),"rand-%s-%d", label, control_statement_count); 03572 rand_test = new_prio(); 03573 rand_test->type = AEL_RAND_CONTROL; 03574 snprintf(buf1,sizeof(buf1),"$[%s]", 03575 p->u1.str ); 03576 rand_test->app = 0; 03577 rand_test->appargs = strdup(buf1); 03578 rand_test->origin = p; 03579 03580 rand_end = new_prio(); 03581 rand_end->type = AEL_APPCALL; 03582 snprintf(buf1,sizeof(buf1),"Finish rand-%s-%d", label, control_statement_count); 03583 rand_end->app = strdup("NoOp"); 03584 rand_end->appargs = strdup(buf1); 03585 03586 rand_skip = new_prio(); 03587 rand_skip->type = AEL_CONTROL1; /* simple goto */ 03588 rand_skip->goto_true = rand_end; 03589 rand_skip->origin = p; 03590 03591 rand_test->goto_true = rand_skip; /* +1, really */ 03592 03593 linkprio(exten, rand_test, mother_exten); 03594 03595 if (p->u3.else_statements) { 03596 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the else statements here */ 03597 } 03598 03599 linkprio(exten, rand_skip, mother_exten); 03600 03601 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the "true" statements here */ 03602 03603 linkprio(exten, rand_end, mother_exten); 03604 03605 break; 03606 #endif 03607 03608 case PV_IFTIME: 03609 control_statement_count++; 03610 snprintf(new_label,sizeof(new_label),"iftime-%s-%d", label, control_statement_count); 03611 03612 if_test = new_prio(); 03613 if_test->type = AEL_IFTIME_CONTROL; 03614 snprintf(buf1,sizeof(buf1),"%s|%s|%s|%s", 03615 p->u1.list->u1.str, 03616 p->u1.list->next->u1.str, 03617 p->u1.list->next->next->u1.str, 03618 p->u1.list->next->next->next->u1.str); 03619 if_test->app = 0; 03620 if_test->appargs = strdup(buf1); 03621 if_test->origin = p; 03622 03623 if_end = new_prio(); 03624 if_end->type = AEL_APPCALL; 03625 snprintf(buf1,sizeof(buf1),"Finish iftime-%s-%d", label, control_statement_count); 03626 if_end->app = strdup("NoOp"); 03627 if_end->appargs = strdup(buf1); 03628 03629 if (p->u3.else_statements) { 03630 if_skip = new_prio(); 03631 if_skip->type = AEL_CONTROL1; /* simple goto */ 03632 if_skip->goto_true = if_end; 03633 if_skip->origin = p; 03634 03635 } else { 03636 if_skip = 0; 03637 03638 if_test->goto_false = if_end; 03639 } 03640 03641 if_false = new_prio(); 03642 if_false->type = AEL_CONTROL1; 03643 if (p->u3.else_statements) { 03644 if_false->goto_true = if_skip; /* +1 */ 03645 } else { 03646 if_false->goto_true = if_end; 03647 } 03648 03649 /* link & load! */ 03650 linkprio(exten, if_test, mother_exten); 03651 linkprio(exten, if_false, mother_exten); 03652 03653 /* now, put the body of the if here */ 03654 03655 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the statements here */ 03656 03657 if (p->u3.else_statements) { 03658 linkprio(exten, if_skip, mother_exten); 03659 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the statements here */ 03660 03661 } 03662 03663 linkprio(exten, if_end, mother_exten); 03664 03665 break; 03666 03667 case PV_RANDOM: 03668 case PV_IF: 03669 control_statement_count++; 03670 snprintf(new_label,sizeof(new_label),"if-%s-%d", label, control_statement_count); 03671 03672 if_test = new_prio(); 03673 if_end = new_prio(); 03674 if_test->type = AEL_IF_CONTROL; 03675 if_end->type = AEL_APPCALL; 03676 if ( p->type == PV_RANDOM ) 03677 snprintf(buf1,sizeof(buf1),"$[${RAND(0,99)} < (%s)]",p->u1.str); 03678 else 03679 snprintf(buf1,sizeof(buf1),"$[%s]",p->u1.str); 03680 if_test->app = 0; 03681 if_test->appargs = strdup(buf1); 03682 snprintf(buf1,sizeof(buf1),"Finish if-%s-%d", label, control_statement_count); 03683 if_end->app = strdup("NoOp"); 03684 if_end->appargs = strdup(buf1); 03685 if_test->origin = p; 03686 03687 if (p->u3.else_statements) { 03688 if_skip = new_prio(); 03689 if_skip->type = AEL_CONTROL1; /* simple goto */ 03690 if_skip->goto_true = if_end; 03691 if_test->goto_false = if_skip;; 03692 } else { 03693 if_skip = 0; 03694 if_test->goto_false = if_end;; 03695 } 03696 03697 /* link & load! */ 03698 linkprio(exten, if_test, mother_exten); 03699 03700 /* now, put the body of the if here */ 03701 03702 gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context); /* this will link in all the statements here */ 03703 03704 if (p->u3.else_statements) { 03705 linkprio(exten, if_skip, mother_exten); 03706 gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context); /* this will link in all the statements here */ 03707 03708 } 03709 03710 linkprio(exten, if_end, mother_exten); 03711 03712 break; 03713 03714 case PV_STATEMENTBLOCK: 03715 gen_prios(exten, label, p->u1.list, mother_exten, this_context ); /* recurse into the block */ 03716 break; 03717 03718 case PV_CATCH: 03719 control_statement_count++; 03720 /* generate an extension with name of catch, put all catch stats 03721 into this exten! */ 03722 switch_case = new_exten(); 03723 switch_case->context = this_context; 03724 linkexten(exten,switch_case); 03725 switch_case->name = strdup(p->u1.str); 03726 snprintf(new_label,sizeof(new_label),"catch-%s-%d",p->u1.str, control_statement_count); 03727 03728 gen_prios(switch_case, new_label, p->u2.statements,mother_exten,this_context); /* this will link in all the catch body statements here */ 03729 if (switch_case->return_needed) { 03730 char buf[2000]; 03731 struct ael_priority *np2 = new_prio(); 03732 np2->type = AEL_APPCALL; 03733 np2->app = strdup("NoOp"); 03734 snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name); 03735 np2->appargs = strdup(buf); 03736 linkprio(switch_case, np2, mother_exten); 03737 switch_case-> return_target = np2; 03738 } 03739 03740 break; 03741 default: 03742 break; 03743 } 03744 } 03745 }
Definition at line 3906 of file pbx_ael.c.
References pval::dad, PV_CONTEXT, PV_MACRO, and pval::type.
Referenced by check_goto(), and get_goto_target().
03907 { 03908 while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) { 03909 03910 p = p->dad; 03911 } 03912 03913 return p; 03914 }
Definition at line 3896 of file pbx_ael.c.
References pval::dad, PV_CONTEXT, PV_EXTENSION, PV_MACRO, and pval::type.
Referenced by check_goto(), and get_goto_target().
03897 { 03898 while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) { 03899 03900 p = p->dad; 03901 } 03902 03903 return p; 03904 }
Definition at line 1125 of file pbx_ael.c.
References find_context(), find_label_in_current_context(), find_label_in_current_db(), find_label_in_current_extension(), get_contxt(), get_extension_or_contxt(), pval::list, pval::next, PV_INCLUDES, pval::statements, pval::str, pval::type, pval::u1, and pval::u2.
Referenced by gen_prios().
01126 { 01127 /* just one item-- the label should be in the current extension */ 01128 pval *curr_ext = get_extension_or_contxt(item); /* containing exten, or macro */ 01129 pval *curr_cont; 01130 01131 if (item->u1.list && !item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) { 01132 struct pval *x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), curr_ext); 01133 return x; 01134 } 01135 01136 curr_cont = get_contxt(item); 01137 01138 /* TWO items */ 01139 if (item->u1.list->next && !item->u1.list->next->next) { 01140 if (!strstr((item->u1.list)->u1.str,"${") 01141 && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ { 01142 struct pval *x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, curr_cont); 01143 return x; 01144 } 01145 } 01146 01147 /* All 3 items! */ 01148 if (item->u1.list->next && item->u1.list->next->next) { 01149 /* all three */ 01150 pval *first = item->u1.list; 01151 pval *second = item->u1.list->next; 01152 pval *third = item->u1.list->next->next; 01153 01154 if (!strstr((item->u1.list)->u1.str,"${") 01155 && !strstr(item->u1.list->next->u1.str,"${") 01156 && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ { 01157 struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); 01158 if (!x) { 01159 01160 struct pval *p3; 01161 struct pval *that_context = find_context(item->u1.list->u1.str); 01162 01163 /* the target of the goto could be in an included context!! Fancy that!! */ 01164 /* look for includes in the current context */ 01165 if (that_context) { 01166 for (p3=that_context->u2.statements; p3; p3=p3->next) { 01167 if (p3->type == PV_INCLUDES) { 01168 struct pval *p4; 01169 for (p4=p3->u1.list; p4; p4=p4->next) { 01170 /* for each context pointed to, find it, then find a context/label that matches the 01171 target here! */ 01172 char *incl_context = p4->u1.str; 01173 /* find a matching context name */ 01174 struct pval *that_other_context = find_context(incl_context); 01175 if (that_other_context) { 01176 struct pval *x3; 01177 x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context); 01178 if (x3) { 01179 return x3; 01180 } 01181 } 01182 } 01183 } 01184 } 01185 } 01186 } 01187 return x; 01188 } 01189 } 01190 return 0; 01191 }
int is_empty | ( | char * | arg | ) |
int is_float | ( | char * | arg | ) |
int is_int | ( | char * | arg | ) |
static int label_inside_case | ( | pval * | label | ) | [static] |
Definition at line 2908 of file pbx_ael.c.
References pval::dad, PV_CASE, PV_CONTEXT, PV_DEFAULT, PV_MACRO, PV_PATTERN, and pval::type.
Referenced by gen_prios().
02909 { 02910 pval *p = label; 02911 02912 while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ { 02913 if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN ) { 02914 return 1; 02915 } 02916 02917 p = p->dad; 02918 } 02919 return 0; 02920 }
static void linkexten | ( | struct ael_extension * | exten, | |
struct ael_extension * | add | |||
) | [static] |
Definition at line 2922 of file pbx_ael.c.
References exten, and ael_extension::next_exten.
Referenced by gen_prios().
02923 { 02924 add->next_exten = exten->next_exten; /* this will reverse the order. Big deal. */ 02925 exten->next_exten = add; 02926 }
void linkprio | ( | struct ael_extension * | exten, | |
struct ael_priority * | prio, | |||
struct ael_extension * | mother_exten | |||
) |
Definition at line 2826 of file pbx_ael.c.
References ael_priority::appargs, ael_priority::exten, exten, free, ael_extension::has_switch, and malloc.
Referenced by gen_prios().
02827 { 02828 char *p1, *p2; 02829 02830 if (!exten->plist) { 02831 exten->plist = prio; 02832 exten->plist_last = prio; 02833 } else { 02834 exten->plist_last->next = prio; 02835 exten->plist_last = prio; 02836 } 02837 if( !prio->exten ) 02838 prio->exten = exten; /* don't override the switch value */ 02839 /* The following code will cause all priorities within an extension 02840 to have ${EXTEN} or ${EXTEN: replaced with ~~EXTEN~~, which is 02841 set just before the first switch in an exten. The switches 02842 will muck up the original ${EXTEN} value, so we save it away 02843 and the user accesses this copy instead. */ 02844 if (prio->appargs && ((mother_exten && mother_exten->has_switch) || exten->has_switch) ) { 02845 while ((p1 = strstr(prio->appargs, "${EXTEN}"))) { 02846 p2 = malloc(strlen(prio->appargs)+5); 02847 *p1 = 0; 02848 strcpy(p2, prio->appargs); 02849 strcat(p2, "${~~EXTEN~~}"); 02850 if (*(p1+8)) 02851 strcat(p2, p1+8); 02852 free(prio->appargs); 02853 prio->appargs = p2; 02854 } 02855 while ((p1 = strstr(prio->appargs, "${EXTEN:"))) { 02856 p2 = malloc(strlen(prio->appargs)+5); 02857 *p1 = 0; 02858 strcpy(p2, prio->appargs); 02859 strcat(p2, "${~~EXTEN~~:"); 02860 if (*(p1+8)) 02861 strcat(p2, p1+8); 02862 free(prio->appargs); 02863 prio->appargs = p2; 02864 } 02865 } 02866 }
static int load_module | ( | void | ) | [static] |
Definition at line 4284 of file pbx_ael.c.
References ast_cli_register_multiple(), cli_ael, and pbx_load_module().
04285 { 04286 ast_cli_register_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry)); 04287 return (pbx_load_module()); 04288 }
Definition at line 1739 of file pbx_ael.c.
References match_pval_item(), and pval::next.
Referenced by find_context(), find_first_label_in_current_context(), find_label_in_current_context(), find_label_in_current_db(), find_label_in_current_extension(), find_macro(), and match_pval_item().
01740 { 01741 pval *i; 01742 01743 for (i=item; i; i=i->next) { 01744 pval *x; 01745 /* printf(" -- match pval: item %d\n", i->type); */ 01746 01747 if ((x = match_pval_item(i))) { 01748 /* printf("match_pval: returning x=%x\n", (int)x); */ 01749 return x; /* cut the search short */ 01750 } 01751 } 01752 return 0; 01753 }
Definition at line 1472 of file pbx_ael.c.
References pval::else_statements, extension_matches(), pval::for_statements, last_matched_label, pval::list, pval::macro_statements, match_pval(), pval::next, PV_CASE, PV_CATCH, PV_CONTEXT, PV_DEFAULT, PV_EXTENSION, PV_FOR, PV_IF, PV_IFTIME, PV_LABEL, PV_MACRO, PV_PATTERN, PV_RANDOM, PV_STATEMENTBLOCK, PV_SWITCH, PV_WHILE, pval::statements, pval::str, pval::type, pval::u1, pval::u2, pval::u3, and pval::u4.
Referenced by match_pval().
01473 { 01474 pval *x; 01475 01476 switch ( item->type ) { 01477 case PV_MACRO: 01478 /* fields: item->u1.str == name of macro 01479 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user 01480 item->u2.arglist->u1.str == argument 01481 item->u2.arglist->next == next arg 01482 01483 item->u3.macro_statements == pval list of statements in macro body. 01484 */ 01485 /* printf(" matching in MACRO %s, match_context=%s; retoncontmtch=%d; \n", item->u1.str, match_context, return_on_context_match); */ 01486 if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) { 01487 01488 /* printf("MACRO: match context is: %s\n", match_context); */ 01489 01490 if (return_on_context_match && !strcmp(item->u1.str, match_context)) /* if we're just searching for a context, don't bother descending into them */ { 01491 /* printf("Returning on matching macro %s\n", match_context); */ 01492 return item; 01493 } 01494 01495 01496 if (!return_on_context_match) { 01497 /* printf("Descending into matching macro %s/%s\n", match_context, item->u1.str); */ 01498 if ((x=match_pval(item->u3.macro_statements))) { 01499 /* printf("Responded with pval match %x\n", x); */ 01500 return x; 01501 } 01502 } 01503 } else { 01504 /* printf("Skipping context/macro %s\n", item->u1.str); */ 01505 } 01506 01507 break; 01508 01509 case PV_CONTEXT: 01510 /* fields: item->u1.str == name of context 01511 item->u2.statements == pval list of statements in context body 01512 item->u3.abstract == int 1 if an abstract keyword were present 01513 */ 01514 /* printf(" matching in CONTEXT\n"); */ 01515 if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) { 01516 if (return_on_context_match && !strcmp(item->u1.str, match_context)) { 01517 /* printf("Returning on matching context %s\n", match_context); */ 01518 /* printf("non-CONTEXT: Responded with pval match %x\n", x); */ 01519 return item; 01520 } 01521 01522 if (!return_on_context_match ) { 01523 /* printf("Descending into matching context %s\n", match_context); */ 01524 if ((x=match_pval(item->u2.statements))) /* if we're just searching for a context, don't bother descending into them */ { 01525 /* printf("CONTEXT: Responded with pval match %x\n", x); */ 01526 return x; 01527 } 01528 } 01529 } else { 01530 /* printf("Skipping context/macro %s\n", item->u1.str); */ 01531 } 01532 break; 01533 01534 case PV_CASE: 01535 /* fields: item->u1.str == value of case 01536 item->u2.statements == pval list of statements under the case 01537 */ 01538 /* printf(" matching in CASE\n"); */ 01539 if ((x=match_pval(item->u2.statements))) { 01540 /* printf("CASE: Responded with pval match %x\n", x); */ 01541 return x; 01542 } 01543 break; 01544 01545 case PV_PATTERN: 01546 /* fields: item->u1.str == value of case 01547 item->u2.statements == pval list of statements under the case 01548 */ 01549 /* printf(" matching in PATTERN\n"); */ 01550 if ((x=match_pval(item->u2.statements))) { 01551 /* printf("PATTERN: Responded with pval match %x\n", x); */ 01552 return x; 01553 } 01554 break; 01555 01556 case PV_DEFAULT: 01557 /* fields: 01558 item->u2.statements == pval list of statements under the case 01559 */ 01560 /* printf(" matching in DEFAULT\n"); */ 01561 if ((x=match_pval(item->u2.statements))) { 01562 /* printf("DEFAULT: Responded with pval match %x\n", x); */ 01563 return x; 01564 } 01565 break; 01566 01567 case PV_CATCH: 01568 /* fields: item->u1.str == name of extension to catch 01569 item->u2.statements == pval list of statements in context body 01570 */ 01571 /* printf(" matching in CATCH\n"); */ 01572 if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) { 01573 /* printf("Descending into matching catch %s => %s\n", match_exten, item->u1.str); */ 01574 if (strcmp(match_label,"1") == 0) { 01575 if (item->u2.statements) { 01576 struct pval *p5 = item->u2.statements; 01577 while (p5 && p5->type == PV_LABEL) /* find the first non-label statement in this context. If it exists, there's a "1" */ 01578 p5 = p5->next; 01579 if (p5) 01580 return p5; 01581 else 01582 return 0; 01583 } 01584 else 01585 return 0; 01586 } 01587 01588 if ((x=match_pval(item->u2.statements))) { 01589 /* printf("CATCH: Responded with pval match %x\n", (unsigned int)x); */ 01590 return x; 01591 } 01592 } else { 01593 /* printf("Skipping catch %s\n", item->u1.str); */ 01594 } 01595 break; 01596 01597 case PV_STATEMENTBLOCK: 01598 /* fields: item->u1.list == pval list of statements in block, one per entry in the list 01599 */ 01600 /* printf(" matching in STATEMENTBLOCK\n"); */ 01601 if ((x=match_pval(item->u1.list))) { 01602 /* printf("STATEMENTBLOCK: Responded with pval match %x\n", x); */ 01603 return x; 01604 } 01605 break; 01606 01607 case PV_LABEL: 01608 /* fields: item->u1.str == label name 01609 */ 01610 /* printf("PV_LABEL %s (cont=%s, exten=%s\n", 01611 item->u1.str, current_context->u1.str, (current_extension?current_extension->u1.str:"<macro>"));*/ 01612 01613 if (count_labels) { 01614 if (!strcmp(match_label, item->u1.str)) { 01615 label_count++; 01616 last_matched_label = item; 01617 } 01618 01619 } else { 01620 if (!strcmp(match_label, item->u1.str)) { 01621 /* printf("LABEL: Responded with pval match %x\n", x); */ 01622 return item; 01623 } 01624 } 01625 break; 01626 01627 case PV_FOR: 01628 /* fields: item->u1.for_init == a string containing the initalizer 01629 item->u2.for_test == a string containing the loop test 01630 item->u3.for_inc == a string containing the loop increment 01631 01632 item->u4.for_statements == a pval list of statements in the for () 01633 */ 01634 /* printf(" matching in FOR\n"); */ 01635 if ((x=match_pval(item->u4.for_statements))) { 01636 /* printf("FOR: Responded with pval match %x\n", x);*/ 01637 return x; 01638 } 01639 break; 01640 01641 case PV_WHILE: 01642 /* fields: item->u1.str == the while conditional, as supplied by user 01643 01644 item->u2.statements == a pval list of statements in the while () 01645 */ 01646 /* printf(" matching in WHILE\n"); */ 01647 if ((x=match_pval(item->u2.statements))) { 01648 /* printf("WHILE: Responded with pval match %x\n", x); */ 01649 return x; 01650 } 01651 break; 01652 01653 case PV_RANDOM: 01654 /* fields: item->u1.str == the random number expression, as supplied by user 01655 01656 item->u2.statements == a pval list of statements in the if () 01657 item->u3.else_statements == a pval list of statements in the else 01658 (could be zero) 01659 fall thru to PV_IF */ 01660 01661 case PV_IFTIME: 01662 /* fields: item->u1.list == the time values, 4 of them, as PV_WORD structs in a list 01663 01664 item->u2.statements == a pval list of statements in the if () 01665 item->u3.else_statements == a pval list of statements in the else 01666 (could be zero) 01667 fall thru to PV_IF*/ 01668 case PV_IF: 01669 /* fields: item->u1.str == the if conditional, as supplied by user 01670 01671 item->u2.statements == a pval list of statements in the if () 01672 item->u3.else_statements == a pval list of statements in the else 01673 (could be zero) 01674 */ 01675 /* printf(" matching in IF/IFTIME/RANDOM\n"); */ 01676 if ((x=match_pval(item->u2.statements))) { 01677 return x; 01678 } 01679 if (item->u3.else_statements) { 01680 if ((x=match_pval(item->u3.else_statements))) { 01681 /* printf("IF/IFTIME/RANDOM: Responded with pval match %x\n", x); */ 01682 return x; 01683 } 01684 } 01685 break; 01686 01687 case PV_SWITCH: 01688 /* fields: item->u1.str == the switch expression 01689 01690 item->u2.statements == a pval list of statements in the switch, 01691 (will be case statements, most likely!) 01692 */ 01693 /* printf(" matching in SWITCH\n"); */ 01694 if ((x=match_pval(item->u2.statements))) { 01695 /* printf("SWITCH: Responded with pval match %x\n", x); */ 01696 return x; 01697 } 01698 break; 01699 01700 case PV_EXTENSION: 01701 /* fields: item->u1.str == the extension name, label, whatever it's called 01702 01703 item->u2.statements == a pval list of statements in the extension 01704 item->u3.hints == a char * hint argument 01705 item->u4.regexten == an int boolean. non-zero says that regexten was specified 01706 */ 01707 /* printf(" matching in EXTENSION\n"); */ 01708 if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) { 01709 /* printf("Descending into matching exten %s => %s\n", match_exten, item->u1.str); */ 01710 if (strcmp(match_label,"1") == 0) { 01711 if (item->u2.statements) { 01712 struct pval *p5 = item->u2.statements; 01713 while (p5 && p5->type == PV_LABEL) /* find the first non-label statement in this context. If it exists, there's a "1" */ 01714 p5 = p5->next; 01715 if (p5) 01716 return p5; 01717 else 01718 return 0; 01719 } 01720 else 01721 return 0; 01722 } 01723 01724 if ((x=match_pval(item->u2.statements))) { 01725 /* printf("EXTENSION: Responded with pval match %x\n", x); */ 01726 return x; 01727 } 01728 } else { 01729 /* printf("Skipping exten %s\n", item->u1.str); */ 01730 } 01731 break; 01732 default: 01733 /* printf(" matching in default = %d\n", item->type); */ 01734 break; 01735 } 01736 return 0; 01737 }
struct ael_extension * new_exten | ( | void | ) |
Definition at line 2820 of file pbx_ael.c.
References calloc.
Referenced by gen_prios().
02821 { 02822 struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1); 02823 return x; 02824 }
struct ael_priority * new_prio | ( | void | ) |
Definition at line 2814 of file pbx_ael.c.
References calloc.
Referenced by gen_prios().
02815 { 02816 struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1); 02817 return x; 02818 }
static int pbx_load_module | ( | void | ) | [static] |
Definition at line 4171 of file pbx_ael.c.
References ael2_parse(), ael2_semantic_check(), ast_compile_ael2(), ast_config_AST_CONFIG_DIR, ast_context_verify_includes(), ast_log(), ast_merge_contexts_and_delete(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_walk_contexts(), destroy_pval(), local_contexts, LOG_ERROR, and LOG_NOTICE.
Referenced by ael2_reload(), handle_reload_extensions(), load_module(), and reload().
04172 { 04173 int errs=0, sem_err=0, sem_warn=0, sem_note=0; 04174 char *rfilename; 04175 struct ast_context *local_contexts=NULL, *con; 04176 struct pval *parse_tree; 04177 04178 ast_log(LOG_NOTICE, "Starting AEL load process.\n"); 04179 if (config[0] == '/') 04180 rfilename = (char *)config; 04181 else { 04182 rfilename = alloca(strlen(config) + strlen(ast_config_AST_CONFIG_DIR) + 2); 04183 sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, config); 04184 } 04185 ast_log(LOG_NOTICE, "AEL load process: calculated config file name '%s'.\n", rfilename); 04186 04187 if (access(rfilename,R_OK) != 0) { 04188 ast_log(LOG_NOTICE, "File %s not found; AEL declining load\n", rfilename); 04189 return AST_MODULE_LOAD_DECLINE; 04190 } 04191 04192 parse_tree = ael2_parse(rfilename, &errs); 04193 ast_log(LOG_NOTICE, "AEL load process: parsed config file name '%s'.\n", rfilename); 04194 ael2_semantic_check(parse_tree, &sem_err, &sem_warn, &sem_note); 04195 if (errs == 0 && sem_err == 0) { 04196 ast_log(LOG_NOTICE, "AEL load process: checked config file name '%s'.\n", rfilename); 04197 ast_compile_ael2(&local_contexts, parse_tree); 04198 ast_log(LOG_NOTICE, "AEL load process: compiled config file name '%s'.\n", rfilename); 04199 04200 ast_merge_contexts_and_delete(&local_contexts, registrar); 04201 ast_log(LOG_NOTICE, "AEL load process: merged config file name '%s'.\n", rfilename); 04202 for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con)) 04203 ast_context_verify_includes(con); 04204 ast_log(LOG_NOTICE, "AEL load process: verified config file name '%s'.\n", rfilename); 04205 } else { 04206 ast_log(LOG_ERROR, "Sorry, but %d syntax errors and %d semantic errors were detected. It doesn't make sense to compile.\n", errs, sem_err); 04207 destroy_pval(parse_tree); /* free up the memory */ 04208 return AST_MODULE_LOAD_DECLINE; 04209 } 04210 destroy_pval(parse_tree); /* free up the memory */ 04211 04212 return AST_MODULE_LOAD_SUCCESS; 04213 }
static void print_pval | ( | FILE * | fin, | |
pval * | item, | |||
int | depth | |||
) | [static] |
Definition at line 177 of file pbx_ael.c.
References pval::arglist, pval::next, PV_MACRO, PV_WORD, pval::str, pval::type, pval::u1, and pval::u2.
Referenced by print_pval_list().
00178 { 00179 int i; 00180 pval *lp; 00181 00182 for (i=0; i<depth; i++) { 00183 fprintf(fin, "\t"); /* depth == indentation */ 00184 } 00185 00186 switch ( item->type ) { 00187 case PV_WORD: 00188 fprintf(fin,"%s;\n", item->u1.str); /* usually, words are encapsulated in something else */ 00189 break; 00190 00191 case PV_MACRO: 00192 fprintf(fin,"macro %s(", item->u1.str); 00193 for (lp=item->u2.arglist; lp; lp=lp->next) { 00194 if (lp != item->u2.arglist ) 00195 fprintf(fin,", "); 00196 fprintf(fin,"%s", lp->u1.str); 00197 } 00198 fprintf(fin,") {\n"); 00199 print_pval_list(fin,item->u3.macro_statements,depth+1); 00200 for (i=0; i<depth; i++) { 00201 fprintf(fin,"\t"); /* depth == indentation */ 00202 } 00203 fprintf(fin,"};\n\n"); 00204 break; 00205 00206 case PV_CONTEXT: 00207 if ( item->u3.abstract ) 00208 fprintf(fin,"abstract context %s {\n", item->u1.str); 00209 else 00210 fprintf(fin,"context %s {\n", item->u1.str); 00211 print_pval_list(fin,item->u2.statements,depth+1); 00212 for (i=0; i<depth; i++) { 00213 fprintf(fin,"\t"); /* depth == indentation */ 00214 } 00215 fprintf(fin,"};\n\n"); 00216 break; 00217 00218 case PV_MACRO_CALL: 00219 fprintf(fin,"&%s(", item->u1.str); 00220 for (lp=item->u2.arglist; lp; lp=lp->next) { 00221 if ( lp != item->u2.arglist ) 00222 fprintf(fin,", "); 00223 fprintf(fin,"%s", lp->u1.str); 00224 } 00225 fprintf(fin,");\n"); 00226 break; 00227 00228 case PV_APPLICATION_CALL: 00229 fprintf(fin,"%s(", item->u1.str); 00230 for (lp=item->u2.arglist; lp; lp=lp->next) { 00231 if ( lp != item->u2.arglist ) 00232 fprintf(fin,","); 00233 fprintf(fin,"%s", lp->u1.str); 00234 } 00235 fprintf(fin,");\n"); 00236 break; 00237 00238 case PV_CASE: 00239 fprintf(fin,"case %s:\n", item->u1.str); 00240 print_pval_list(fin,item->u2.statements, depth+1); 00241 break; 00242 00243 case PV_PATTERN: 00244 fprintf(fin,"pattern %s:\n", item->u1.str); 00245 print_pval_list(fin,item->u2.statements, depth+1); 00246 break; 00247 00248 case PV_DEFAULT: 00249 fprintf(fin,"default:\n"); 00250 print_pval_list(fin,item->u2.statements, depth+1); 00251 break; 00252 00253 case PV_CATCH: 00254 fprintf(fin,"catch %s {\n", item->u1.str); 00255 print_pval_list(fin,item->u2.statements, depth+1); 00256 for (i=0; i<depth; i++) { 00257 fprintf(fin,"\t"); /* depth == indentation */ 00258 } 00259 fprintf(fin,"};\n"); 00260 break; 00261 00262 case PV_SWITCHES: 00263 fprintf(fin,"switches {\n"); 00264 print_pval_list(fin,item->u1.list,depth+1); 00265 for (i=0; i<depth; i++) { 00266 fprintf(fin,"\t"); /* depth == indentation */ 00267 } 00268 fprintf(fin,"};\n"); 00269 break; 00270 00271 case PV_ESWITCHES: 00272 fprintf(fin,"eswitches {\n"); 00273 print_pval_list(fin,item->u1.list,depth+1); 00274 for (i=0; i<depth; i++) { 00275 fprintf(fin,"\t"); /* depth == indentation */ 00276 } 00277 fprintf(fin,"};\n"); 00278 break; 00279 00280 case PV_INCLUDES: 00281 fprintf(fin,"includes {\n"); 00282 for (lp=item->u1.list; lp; lp=lp->next) { 00283 for (i=0; i<depth+1; i++) { 00284 fprintf(fin,"\t"); /* depth == indentation */ 00285 } 00286 fprintf(fin,"%s", lp->u1.str); /* usually, words are encapsulated in something else */ 00287 if ( lp->u2.arglist ) 00288 fprintf(fin,"|%s|%s|%s|%s", 00289 lp->u2.arglist->u1.str, 00290 lp->u2.arglist->next->u1.str, 00291 lp->u2.arglist->next->next->u1.str, 00292 lp->u2.arglist->next->next->next->u1.str 00293 ); 00294 fprintf(fin,";\n"); /* usually, words are encapsulated in something else */ 00295 } 00296 00297 print_pval_list(fin,item->u1.list,depth+1); 00298 for (i=0; i<depth; i++) { 00299 fprintf(fin,"\t"); /* depth == indentation */ 00300 } 00301 fprintf(fin,"};\n"); 00302 break; 00303 00304 case PV_STATEMENTBLOCK: 00305 fprintf(fin,"{\n"); 00306 print_pval_list(fin,item->u1.list, depth+1); 00307 for (i=0; i<depth; i++) { 00308 fprintf(fin,"\t"); /* depth == indentation */ 00309 } 00310 fprintf(fin,"};\n"); 00311 break; 00312 00313 case PV_VARDEC: 00314 fprintf(fin,"%s=%s;\n", item->u1.str, item->u2.val); 00315 break; 00316 00317 case PV_GOTO: 00318 fprintf(fin,"goto %s", item->u1.list->u1.str); 00319 if ( item->u1.list->next ) 00320 fprintf(fin,"|%s", item->u1.list->next->u1.str); 00321 if ( item->u1.list->next && item->u1.list->next->next ) 00322 fprintf(fin,"|%s", item->u1.list->next->next->u1.str); 00323 fprintf(fin,"\n"); 00324 break; 00325 00326 case PV_LABEL: 00327 fprintf(fin,"%s:\n", item->u1.str); 00328 break; 00329 00330 case PV_FOR: 00331 fprintf(fin,"for (%s; %s; %s)\n", item->u1.for_init, item->u2.for_test, item->u3.for_inc); 00332 print_pval_list(fin,item->u4.for_statements,depth+1); 00333 break; 00334 00335 case PV_WHILE: 00336 fprintf(fin,"while (%s)\n", item->u1.str); 00337 print_pval_list(fin,item->u2.statements,depth+1); 00338 break; 00339 00340 case PV_BREAK: 00341 fprintf(fin,"break;\n"); 00342 break; 00343 00344 case PV_RETURN: 00345 fprintf(fin,"return;\n"); 00346 break; 00347 00348 case PV_CONTINUE: 00349 fprintf(fin,"continue;\n"); 00350 break; 00351 00352 case PV_RANDOM: 00353 case PV_IFTIME: 00354 case PV_IF: 00355 if ( item->type == PV_IFTIME ) { 00356 00357 fprintf(fin,"ifTime ( %s|%s|%s|%s )\n", 00358 item->u1.list->u1.str, 00359 item->u1.list->next->u1.str, 00360 item->u1.list->next->next->u1.str, 00361 item->u1.list->next->next->next->u1.str 00362 ); 00363 } else if ( item->type == PV_RANDOM ) { 00364 fprintf(fin,"random ( %s )\n", item->u1.str ); 00365 } else 00366 fprintf(fin,"if ( %s )\n", item->u1.str); 00367 if ( item->u2.statements && item->u2.statements->next ) { 00368 for (i=0; i<depth; i++) { 00369 fprintf(fin,"\t"); /* depth == indentation */ 00370 } 00371 fprintf(fin,"{\n"); 00372 print_pval_list(fin,item->u2.statements,depth+1); 00373 for (i=0; i<depth; i++) { 00374 fprintf(fin,"\t"); /* depth == indentation */ 00375 } 00376 if ( item->u3.else_statements ) 00377 fprintf(fin,"}\n"); 00378 else 00379 fprintf(fin,"};\n"); 00380 } else if (item->u2.statements ) { 00381 print_pval_list(fin,item->u2.statements,depth+1); 00382 } else { 00383 if (item->u3.else_statements ) 00384 fprintf(fin, " {} "); 00385 else 00386 fprintf(fin, " {}; "); 00387 } 00388 if ( item->u3.else_statements ) { 00389 for (i=0; i<depth; i++) { 00390 fprintf(fin,"\t"); /* depth == indentation */ 00391 } 00392 fprintf(fin,"else\n"); 00393 print_pval_list(fin,item->u3.else_statements, depth); 00394 } 00395 break; 00396 00397 case PV_SWITCH: 00398 fprintf(fin,"switch( %s ) {\n", item->u1.str); 00399 print_pval_list(fin,item->u2.statements,depth+1); 00400 for (i=0; i<depth; i++) { 00401 fprintf(fin,"\t"); /* depth == indentation */ 00402 } 00403 fprintf(fin,"}\n"); 00404 break; 00405 00406 case PV_EXTENSION: 00407 if ( item->u4.regexten ) 00408 fprintf(fin, "regexten "); 00409 if ( item->u3.hints ) 00410 fprintf(fin,"hints(%s) ", item->u3.hints); 00411 00412 fprintf(fin,"%s => \n", item->u1.str); 00413 print_pval_list(fin,item->u2.statements,depth+1); 00414 break; 00415 00416 case PV_IGNOREPAT: 00417 fprintf(fin,"ignorepat => %s\n", item->u1.str); 00418 break; 00419 00420 case PV_GLOBALS: 00421 fprintf(fin,"globals {\n"); 00422 print_pval_list(fin,item->u1.statements,depth+1); 00423 for (i=0; i<depth; i++) { 00424 fprintf(fin,"\t"); /* depth == indentation */ 00425 } 00426 fprintf(fin,"}\n"); 00427 break; 00428 } 00429 }
static void print_pval_list | ( | FILE * | fin, | |
pval * | item, | |||
int | depth | |||
) | [static] |
Definition at line 431 of file pbx_ael.c.
References pval::next, and print_pval().
00432 { 00433 pval *i; 00434 00435 for (i=item; i; i=i->next) { 00436 print_pval(fin, i, depth); 00437 } 00438 }
static int reload | ( | void | ) | [static] |
Definition at line 4290 of file pbx_ael.c.
References pbx_load_module().
04291 { 04292 return pbx_load_module(); 04293 }
static void remove_spaces_before_equals | ( | char * | str | ) | [static] |
Definition at line 2928 of file pbx_ael.c.
Referenced by gen_prios().
02929 { 02930 char *p; 02931 while( str && *str && *str != '=' ) 02932 { 02933 if( *str == ' ' || *str == '\n' || *str == '\r' || *str == '\t' ) 02934 { 02935 p = str; 02936 while( *p ) 02937 { 02938 *p = *(p+1); 02939 p++; 02940 } 02941 } 02942 else 02943 str++; 02944 } 02945 }
void set_priorities | ( | struct ael_extension * | exten | ) |
Definition at line 3747 of file pbx_ael.c.
References exten, ael_priority::next, ael_priority::origin, ael_priority::priority_num, PV_LABEL, and pval::type.
03748 { 03749 int i; 03750 struct ael_priority *pr; 03751 do { 03752 if (exten->is_switch) 03753 i = 10; 03754 else if (exten->regexten) 03755 i=2; 03756 else 03757 i=1; 03758 03759 for (pr=exten->plist; pr; pr=pr->next) { 03760 pr->priority_num = i; 03761 03762 if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan, 03763 but we want them to point to the right 03764 priority, which would be the next line 03765 after the label; */ 03766 i++; 03767 } 03768 03769 exten = exten->next_exten; 03770 } while ( exten ); 03771 }
static void substitute_commas | ( | char * | str | ) | [static] |
Definition at line 154 of file pbx_ael.c.
Referenced by gen_prios().
00155 { 00156 char *p = str; 00157 00158 while (p && *p) 00159 { 00160 if (*p == ',' && ((p != str && *(p-1) != '\\') 00161 || p == str)) 00162 *p = '|'; 00163 if (*p == '\\' && *(p+1) == ',') { /* learning experience: the '\,' is turned into just ',' by pbx_config; So we need to do the same */ 00164 char *q = p; 00165 while (*q) { /* move the ',' and everything after it up 1 char */ 00166 *q = *(q+1); 00167 q++; 00168 } 00169 } 00170 p++; 00171 } 00172 }
void traverse_pval_item_template | ( | pval * | item, | |
int | depth | |||
) |
Definition at line 460 of file pbx_ael.c.
References pval::arglist, pval::else_statements, pval::for_statements, pval::list, pval::macro_statements, pval::next, PV_APPLICATION_CALL, PV_BREAK, PV_CASE, PV_CATCH, PV_CONTEXT, PV_CONTINUE, PV_DEFAULT, PV_ESWITCHES, PV_EXTENSION, PV_FOR, PV_GLOBALS, PV_GOTO, PV_IF, PV_IFTIME, PV_IGNOREPAT, PV_INCLUDES, PV_LABEL, PV_MACRO, PV_MACRO_CALL, PV_PATTERN, PV_RANDOM, PV_RETURN, PV_STATEMENTBLOCK, PV_SWITCH, PV_SWITCHES, PV_VARDEC, PV_WHILE, PV_WORD, pval::statements, pval::type, pval::u1, pval::u2, pval::u3, and pval::u4.
Referenced by traverse_pval_template().
00462 { 00463 pval *lp; 00464 00465 switch ( item->type ) { 00466 case PV_WORD: 00467 /* fields: item->u1.str == string associated with this (word). */ 00468 break; 00469 00470 case PV_MACRO: 00471 /* fields: item->u1.str == name of macro 00472 item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user 00473 item->u2.arglist->u1.str == argument 00474 item->u2.arglist->next == next arg 00475 00476 item->u3.macro_statements == pval list of statements in macro body. 00477 */ 00478 for (lp=item->u2.arglist; lp; lp=lp->next) { 00479 00480 } 00481 traverse_pval_item_template(item->u3.macro_statements,depth+1); 00482 break; 00483 00484 case PV_CONTEXT: 00485 /* fields: item->u1.str == name of context 00486 item->u2.statements == pval list of statements in context body 00487 item->u3.abstract == int 1 if an abstract keyword were present 00488 */ 00489 traverse_pval_item_template(item->u2.statements,depth+1); 00490 break; 00491 00492 case PV_MACRO_CALL: 00493 /* fields: item->u1.str == name of macro to call 00494 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 00495 item->u2.arglist->u1.str == argument 00496 item->u2.arglist->next == next arg 00497 */ 00498 for (lp=item->u2.arglist; lp; lp=lp->next) { 00499 } 00500 break; 00501 00502 case PV_APPLICATION_CALL: 00503 /* fields: item->u1.str == name of application to call 00504 item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user 00505 item->u2.arglist->u1.str == argument 00506 item->u2.arglist->next == next arg 00507 */ 00508 for (lp=item->u2.arglist; lp; lp=lp->next) { 00509 } 00510 break; 00511 00512 case PV_CASE: 00513 /* fields: item->u1.str == value of case 00514 item->u2.statements == pval list of statements under the case 00515 */ 00516 traverse_pval_item_template(item->u2.statements,depth+1); 00517 break; 00518 00519 case PV_PATTERN: 00520 /* fields: item->u1.str == value of case 00521 item->u2.statements == pval list of statements under the case 00522 */ 00523 traverse_pval_item_template(item->u2.statements,depth+1); 00524 break; 00525 00526 case PV_DEFAULT: 00527 /* fields: 00528 item->u2.statements == pval list of statements under the case 00529 */ 00530 traverse_pval_item_template(item->u2.statements,depth+1); 00531 break; 00532 00533 case PV_CATCH: 00534 /* fields: item->u1.str == name of extension to catch 00535 item->u2.statements == pval list of statements in context body 00536 */ 00537 traverse_pval_item_template(item->u2.statements,depth+1); 00538 break; 00539 00540 case PV_SWITCHES: 00541 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 00542 */ 00543 traverse_pval_item_template(item->u1.list,depth+1); 00544 break; 00545 00546 case PV_ESWITCHES: 00547 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 00548 */ 00549 traverse_pval_item_template(item->u1.list,depth+1); 00550 break; 00551 00552 case PV_INCLUDES: 00553 /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list 00554 item->u2.arglist == pval list of 4 PV_WORD elements for time values 00555 */ 00556 traverse_pval_item_template(item->u1.list,depth+1); 00557 traverse_pval_item_template(item->u2.arglist,depth+1); 00558 break; 00559 00560 case PV_STATEMENTBLOCK: 00561 /* fields: item->u1.list == pval list of statements in block, one per entry in the list 00562 */ 00563 traverse_pval_item_template(item->u1.list,depth+1); 00564 break; 00565 00566 case PV_VARDEC: 00567 /* fields: item->u1.str == variable name 00568 item->u2.val == variable value to assign 00569 */ 00570 break; 00571 00572 case PV_GOTO: 00573 /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. 00574 item->u1.list->u1.str == where the data on a PV_WORD will always be. 00575 */ 00576 00577 if ( item->u1.list->next ) 00578 ; 00579 if ( item->u1.list->next && item->u1.list->next->next ) 00580 ; 00581 00582 break; 00583 00584 case PV_LABEL: 00585 /* fields: item->u1.str == label name 00586 */ 00587 break; 00588 00589 case PV_FOR: 00590 /* fields: item->u1.for_init == a string containing the initalizer 00591 item->u2.for_test == a string containing the loop test 00592 item->u3.for_inc == a string containing the loop increment 00593 00594 item->u4.for_statements == a pval list of statements in the for () 00595 */ 00596 traverse_pval_item_template(item->u4.for_statements,depth+1); 00597 break; 00598 00599 case PV_WHILE: 00600 /* fields: item->u1.str == the while conditional, as supplied by user 00601 00602 item->u2.statements == a pval list of statements in the while () 00603 */ 00604 traverse_pval_item_template(item->u2.statements,depth+1); 00605 break; 00606 00607 case PV_BREAK: 00608 /* fields: none 00609 */ 00610 break; 00611 00612 case PV_RETURN: 00613 /* fields: none 00614 */ 00615 break; 00616 00617 case PV_CONTINUE: 00618 /* fields: none 00619 */ 00620 break; 00621 00622 case PV_IFTIME: 00623 /* fields: item->u1.list == there are 4 linked PV_WORDs here. 00624 00625 item->u2.statements == a pval list of statements in the if () 00626 item->u3.else_statements == a pval list of statements in the else 00627 (could be zero) 00628 */ 00629 traverse_pval_item_template(item->u2.statements,depth+1); 00630 if ( item->u3.else_statements ) { 00631 traverse_pval_item_template(item->u3.else_statements,depth+1); 00632 } 00633 break; 00634 00635 case PV_RANDOM: 00636 /* fields: item->u1.str == the random number expression, as supplied by user 00637 00638 item->u2.statements == a pval list of statements in the if () 00639 item->u3.else_statements == a pval list of statements in the else 00640 (could be zero) 00641 */ 00642 traverse_pval_item_template(item->u2.statements,depth+1); 00643 if ( item->u3.else_statements ) { 00644 traverse_pval_item_template(item->u3.else_statements,depth+1); 00645 } 00646 break; 00647 00648 case PV_IF: 00649 /* fields: item->u1.str == the if conditional, as supplied by user 00650 00651 item->u2.statements == a pval list of statements in the if () 00652 item->u3.else_statements == a pval list of statements in the else 00653 (could be zero) 00654 */ 00655 traverse_pval_item_template(item->u2.statements,depth+1); 00656 if ( item->u3.else_statements ) { 00657 traverse_pval_item_template(item->u3.else_statements,depth+1); 00658 } 00659 break; 00660 00661 case PV_SWITCH: 00662 /* fields: item->u1.str == the switch expression 00663 00664 item->u2.statements == a pval list of statements in the switch, 00665 (will be case statements, most likely!) 00666 */ 00667 traverse_pval_item_template(item->u2.statements,depth+1); 00668 break; 00669 00670 case PV_EXTENSION: 00671 /* fields: item->u1.str == the extension name, label, whatever it's called 00672 00673 item->u2.statements == a pval list of statements in the extension 00674 item->u3.hints == a char * hint argument 00675 item->u4.regexten == an int boolean. non-zero says that regexten was specified 00676 */ 00677 traverse_pval_item_template(item->u2.statements,depth+1); 00678 break; 00679 00680 case PV_IGNOREPAT: 00681 /* fields: item->u1.str == the ignorepat data 00682 */ 00683 break; 00684 00685 case PV_GLOBALS: 00686 /* fields: item->u1.statements == pval list of statements, usually vardecs 00687 */ 00688 traverse_pval_item_template(item->u1.statements,depth+1); 00689 break; 00690 } 00691 }
void traverse_pval_template | ( | pval * | item, | |
int | depth | |||
) |
Definition at line 693 of file pbx_ael.c.
References pval::next, and traverse_pval_item_template().
00695 { 00696 pval *i; 00697 00698 for (i=item; i; i=i->next) { 00699 traverse_pval_item_template(i, depth); 00700 } 00701 }
static int unload_module | ( | void | ) | [static] |
Definition at line 4277 of file pbx_ael.c.
References ast_cli_unregister_multiple(), ast_context_destroy(), and cli_ael.
04278 { 04279 ast_context_destroy(NULL, registrar); 04280 ast_cli_unregister_multiple(cli_ael, sizeof(cli_ael) / sizeof(struct ast_cli_entry)); 04281 return 0; 04282 }
struct ast_cli_entry cli_ael[] [static] |
struct ast_cli_entry cli_ael_no_debug [static] |
Initial value:
{ { "ael", "no", "debug", NULL }, ael2_no_debug, NULL, NULL }
int control_statement_count = 0 [static] |
int count_labels [static] |
pval* current_context = 0 [static] |
pval* current_db = 0 [static] |
Definition at line 115 of file pbx_ael.c.
Referenced by ael2_semantic_check(), check_abstract_reference(), check_context_names(), find_context(), find_label_in_current_db(), and find_macro().
pval* current_extension = 0 [static] |
char expr_output[2096] [static] |
int in_abstract_context [static] |
int label_count [static] |
pval* last_matched_label [static] |
const char* match_context [static] |
const char* match_exten [static] |
const char* match_label [static] |
char* registrar = "pbx_ael" [static] |
Definition at line 64 of file pbx_ael.c.
Referenced by park_add_hints(), pbx_load_module(), and pbx_load_users().
int return_on_context_match [static] |