From a40f1cc1c55923b2b86465b0a0fb362a139ab2ea Mon Sep 17 00:00:00 2001 From: Steve Murphy Date: Fri, 8 Aug 2008 00:48:35 +0000 Subject: Merged revisions 136726 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r136726 | murf | 2008-08-07 18:15:34 -0600 (Thu, 07 Aug 2008) | 32 lines (closes issue #13236) Reported by: korihor Wow, this one was a challenge! I regrouped and ran a new strategy for setting the ~~MACRO~~ value; I set it once per extension, up near the top. It is only set if there is a switch in the extension. So, I had to put in a chunk of code to detect a switch in the pval tree. I moved the code to insert the set of ~~exten~~ up to the beginning of the gen_prios routine, instead of down in the switch code. I learned that I have to push the detection of the switches down into the code, so everywhere I create a new exten in gen_prios, I make sure to pass onto it the values of the mother_exten first, and the exten next. I had to add a couple fields to the exten struct to accomplish this, in the ael_structs.h file. The checked field makes it so we don't repeat the switch search if it's been done. I also updated the regressions. ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@136746 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- res/ael/pval.c | 355 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 339 insertions(+), 16 deletions(-) (limited to 'res') diff --git a/res/ael/pval.c b/res/ael/pval.c index 39f682ec1..274c8421f 100644 --- a/res/ael/pval.c +++ b/res/ael/pval.c @@ -3076,6 +3076,263 @@ static void gen_match_to_pattern(char *pattern, char *result) *t++ = 0; /* cap it off */ } +/* ==== a set of routines to search for a switch statement contained in the pval description */ + +int find_switch_item(pval *item); +int contains_switch(pval *item); + + +int find_switch_item(pval *item) +{ + switch ( item->type ) { + case PV_LOCALVARDEC: + /* fields: item->u1.str == string associated with this (word). */ + break; + + case PV_WORD: + /* fields: item->u1.str == string associated with this (word). */ + break; + + case PV_MACRO: + /* fields: item->u1.str == name of macro + item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + + item->u3.macro_statements == pval list of statements in macro body. + */ + /* had better not see this */ + if (contains_switch(item->u3.macro_statements)) + return 1; + break; + + case PV_CONTEXT: + /* fields: item->u1.str == name of context + item->u2.statements == pval list of statements in context body + item->u3.abstract == int 1 if an abstract keyword were present + */ + /* had better not see this */ + if (contains_switch(item->u2.statements)) + return 1; + break; + + case PV_MACRO_CALL: + /* fields: item->u1.str == name of macro to call + item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + */ + break; + + case PV_APPLICATION_CALL: + /* fields: item->u1.str == name of application to call + item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user + item->u2.arglist->u1.str == argument + item->u2.arglist->next == next arg + */ + break; + + case PV_CASE: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + /* had better not see this */ + if (contains_switch(item->u2.statements)) + return 1; + break; + + case PV_PATTERN: + /* fields: item->u1.str == value of case + item->u2.statements == pval list of statements under the case + */ + /* had better not see this */ + if (contains_switch(item->u2.statements)) + return 1; + break; + + case PV_DEFAULT: + /* fields: + item->u2.statements == pval list of statements under the case + */ + /* had better not see this */ + if (contains_switch(item->u2.statements)) + return 1; + break; + + case PV_CATCH: + /* fields: item->u1.str == name of extension to catch + item->u2.statements == pval list of statements in context body + */ + /* had better not see this */ + if (contains_switch(item->u2.statements)) + return 1; + break; + + case PV_SWITCHES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + */ + break; + + case PV_ESWITCHES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + */ + break; + + case PV_INCLUDES: + /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list + item->u2.arglist == pval list of 4 PV_WORD elements for time values + */ + break; + + case PV_STATEMENTBLOCK: + /* fields: item->u1.list == pval list of statements in block, one per entry in the list + */ + if (contains_switch(item->u1.list) ) + return 1; + break; + + case PV_VARDEC: + /* fields: item->u1.str == variable name + item->u2.val == variable value to assign + */ + break; + + case PV_GOTO: + /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user. + item->u1.list->u1.str == where the data on a PV_WORD will always be. + */ + break; + + case PV_LABEL: + /* fields: item->u1.str == label name + */ + break; + + case PV_FOR: + /* fields: item->u1.for_init == a string containing the initalizer + item->u2.for_test == a string containing the loop test + item->u3.for_inc == a string containing the loop increment + + item->u4.for_statements == a pval list of statements in the for () + */ + if (contains_switch(item->u4.for_statements)) + return 1; + break; + + case PV_WHILE: + /* fields: item->u1.str == the while conditional, as supplied by user + + item->u2.statements == a pval list of statements in the while () + */ + if (contains_switch(item->u2.statements)) + return 1; + break; + + case PV_BREAK: + /* fields: none + */ + break; + + case PV_RETURN: + /* fields: none + */ + break; + + case PV_CONTINUE: + /* fields: none + */ + break; + + case PV_IFTIME: + /* fields: item->u1.list == there are 4 linked PV_WORDs here. + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + if (contains_switch(item->u2.statements)) + return 1; + if ( item->u3.else_statements ) { + if (contains_switch(item->u3.else_statements)) + return 1; + } + break; + + case PV_RANDOM: + /* fields: item->u1.str == the random number expression, as supplied by user + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + if (contains_switch(item->u2.statements)) + return 1; + if ( item->u3.else_statements ) { + if (contains_switch(item->u3.else_statements)) + return 1; + } + break; + + case PV_IF: + /* fields: item->u1.str == the if conditional, as supplied by user + + item->u2.statements == a pval list of statements in the if () + item->u3.else_statements == a pval list of statements in the else + (could be zero) + */ + if (contains_switch(item->u2.statements)) + return 1; + if ( item->u3.else_statements ) { + if (contains_switch(item->u3.else_statements)) + return 1; + } + break; + + case PV_SWITCH: + /* fields: item->u1.str == the switch expression + + item->u2.statements == a pval list of statements in the switch, + (will be case statements, most likely!) + */ + return 1; /* JACKPOT */ + break; + + case PV_EXTENSION: + /* fields: item->u1.str == the extension name, label, whatever it's called + + item->u2.statements == a pval list of statements in the extension + item->u3.hints == a char * hint argument + item->u4.regexten == an int boolean. non-zero says that regexten was specified + */ + if (contains_switch(item->u2.statements)) + return 1; + break; + + case PV_IGNOREPAT: + /* fields: item->u1.str == the ignorepat data + */ + break; + + case PV_GLOBALS: + /* fields: item->u1.statements == pval list of statements, usually vardecs + */ + break; + } + return 0; +} + +int contains_switch(pval *item) +{ + pval *i; + + for (i=item; i; i=i->next) { + if (find_switch_item(i)) + return 1; + } + return 0; +} + + static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *this_context ) { pval *p,*p2,*p3; @@ -3098,6 +3355,46 @@ static void gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_priority *loop_continue_save; struct ael_extension *switch_case,*switch_null; + if ((mother_exten && !mother_exten->checked_switch) || (exten && !exten->checked_switch)) { + if (contains_switch(statement)) { /* only run contains_switch if you haven't checked before */ + if (mother_exten) { + if (!mother_exten->has_switch) { + switch_set = new_prio(); + switch_set->type = AEL_APPCALL; + switch_set->app = strdup("Set"); + switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}"); + linkprio(exten, switch_set, mother_exten); + mother_exten->has_switch = 1; + mother_exten->checked_switch = 1; + if (exten) { + exten->has_switch = 1; + exten->checked_switch = 1; + } + } + } else if (exten) { + if (!exten->has_switch) { + switch_set = new_prio(); + switch_set->type = AEL_APPCALL; + switch_set->app = strdup("Set"); + switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}"); + linkprio(exten, switch_set, mother_exten); + exten->has_switch = 1; + exten->checked_switch = 1; + if (mother_exten) { + mother_exten->has_switch = 1; + mother_exten->checked_switch = 1; + } + } + } + } else { + if (mother_exten) { + mother_exten->checked_switch = 1; + } + if (exten) { + exten->checked_switch = 1; + } + } + } for (p=statement; p; p=p->next) { switch (p->type) { case PV_VARDEC: @@ -3121,7 +3418,7 @@ static void gen_prios(struct ael_extension *exten, char *label, pval *statement, pr->origin = p; linkprio(exten, pr, mother_exten); break; - + case PV_GOTO: pr = new_prio(); pr->type = AEL_APPCALL; @@ -3344,21 +3641,6 @@ static void gen_prios(struct ael_extension *exten, char *label, pval *statement, loop_break_save = exten->loop_break; /* save them, then restore before leaving */ loop_continue_save = exten->loop_continue; snprintf(new_label,sizeof(new_label),"sw-%s-%d", label, control_statement_count); - if ((mother_exten && !mother_exten->has_switch)) { - switch_set = new_prio(); - switch_set->type = AEL_APPCALL; - switch_set->app = strdup("Set"); - switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}"); - linkprio(exten, switch_set, mother_exten); - mother_exten->has_switch = 1; - } else if ((exten && !exten->has_switch)) { - switch_set = new_prio(); - switch_set->type = AEL_APPCALL; - switch_set->app = strdup("Set"); - switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}"); - linkprio(exten, switch_set, exten); - exten->has_switch = 1; - } switch_test = new_prio(); switch_end = new_prio(); switch_test->type = AEL_APPCALL; @@ -3384,6 +3666,14 @@ static void gen_prios(struct ael_extension *exten, char *label, pval *statement, if (p2->type == PV_CASE) { /* ok, generate a extension and link it in */ switch_case = new_exten(); + if (mother_exten && mother_exten->checked_switch) { + switch_case->has_switch = mother_exten->has_switch; + switch_case->checked_switch = mother_exten->checked_switch; + } + if (exten && exten->checked_switch) { + switch_case->has_switch = exten->has_switch; + switch_case->checked_switch = exten->checked_switch; + } switch_case->context = this_context; switch_case->is_switch = 1; /* the break/continue locations are inherited from parent */ @@ -3448,6 +3738,14 @@ static void gen_prios(struct ael_extension *exten, char *label, pval *statement, } else if (p2->type == PV_PATTERN) { /* ok, generate a extension and link it in */ switch_case = new_exten(); + if (mother_exten && mother_exten->checked_switch) { + switch_case->has_switch = mother_exten->has_switch; + switch_case->checked_switch = mother_exten->checked_switch; + } + if (exten && exten->checked_switch) { + switch_case->has_switch = exten->has_switch; + switch_case->checked_switch = exten->checked_switch; + } switch_case->context = this_context; switch_case->is_switch = 1; /* the break/continue locations are inherited from parent */ @@ -3511,6 +3809,14 @@ static void gen_prios(struct ael_extension *exten, char *label, pval *statement, } else if (p2->type == PV_DEFAULT) { /* ok, generate a extension and link it in */ switch_case = new_exten(); + if (mother_exten && mother_exten->checked_switch) { + switch_case->has_switch = mother_exten->has_switch; + switch_case->checked_switch = mother_exten->checked_switch; + } + if (exten && exten->checked_switch) { + switch_case->has_switch = exten->has_switch; + switch_case->checked_switch = exten->checked_switch; + } switch_case->context = this_context; switch_case->is_switch = 1; @@ -3520,6 +3826,14 @@ static void gen_prios(struct ael_extension *exten, char *label, pval *statement, default_exists++; switch_null = new_exten(); + if (mother_exten && mother_exten->checked_switch) { + switch_null->has_switch = mother_exten->has_switch; + switch_null->checked_switch = mother_exten->checked_switch; + } + if (exten && exten->checked_switch) { + switch_null->has_switch = exten->has_switch; + switch_null->checked_switch = exten->checked_switch; + } switch_null->context = this_context; switch_null->is_switch = 1; switch_empty = new_prio(); @@ -3783,6 +4097,15 @@ static void gen_prios(struct ael_extension *exten, char *label, pval *statement, /* generate an extension with name of catch, put all catch stats into this exten! */ switch_case = new_exten(); + if (mother_exten && mother_exten->checked_switch) { + switch_case->has_switch = mother_exten->has_switch; + switch_case->checked_switch = mother_exten->checked_switch; + } + if (exten && exten->checked_switch) { + switch_case->has_switch = exten->has_switch; + switch_case->checked_switch = exten->checked_switch; + } + switch_case->context = this_context; linkexten(exten,switch_case); switch_case->name = strdup(p->u1.str); -- cgit v1.2.3