Module: sip-router Branch: andrei/switch Commit: a29a8b6ddba24b8e71faaf78e7426aa7f85c19b5 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=a29a8b6d...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Wed Feb 4 20:44:26 2009 +0100
script parsing: C style switch() & case support
- support for parsing C style switch() & case, e.g.: switch($var){ case 1: log(1, "1\n"); break; case 2: case 3: default: log(1, "default\n"); } (note: this is different from kamailio/openser switch())
---
cfg.lex | 7 +++ cfg.y | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- route_struct.h | 8 +++- switch.h | 60 +++++++++++++++++++++++++++ 4 files changed, 194 insertions(+), 3 deletions(-)
diff --git a/cfg.lex b/cfg.lex index fc9eecb..13767b1 100644 --- a/cfg.lex +++ b/cfg.lex @@ -187,6 +187,9 @@ ELSE "else" SET_ADV_ADDRESS "set_advertised_address" SET_ADV_PORT "set_advertised_port" FORCE_SEND_SOCKET "force_send_socket" +SWITCH "switch" +CASE "case" +DEFAULT "default"
/*ACTION LVALUES*/ URIHOST "uri:host" @@ -495,6 +498,10 @@ EAT_ABLE [\ \t\b\r] return SET_ADV_PORT; } <INITIAL>{FORCE_SEND_SOCKET} { count(); yylval.strval=yytext; return FORCE_SEND_SOCKET; } +<INITIAL>{SWITCH} { count(); yylval.strval=yytext; return SWITCH; } +<INITIAL>{CASE} { count(); yylval.strval=yytext; return CASE; } +<INITIAL>{DEFAULT} { count(); yylval.strval=yytext; return DEFAULT; } +
<INITIAL>{URIHOST} { count(); yylval.strval=yytext; return URIHOST; } <INITIAL>{URIPORT} { count(); yylval.strval=yytext; return URIPORT; } diff --git a/cfg.y b/cfg.y index 63c9eb4..431054d 100644 --- a/cfg.y +++ b/cfg.y @@ -93,6 +93,7 @@ * lval=rval_expr, where lval=avp|pvar (andrei) * 2007-12-06 expression are now evaluated in terms of rvalues; * NUMBER is now always positive; cleanup (andrei) + * 2009-01-26 case/switch() support (andrei) */
%{ @@ -109,6 +110,7 @@ #include "route_struct.h" #include "globals.h" #include "route.h" +#include "switch.h" #include "dprint.h" #include "sr_module.h" #include "modparam.h" @@ -211,6 +213,8 @@ static struct socket_id* mk_listen_id2(struct name_lst*, int, int); static void free_name_lst(struct name_lst* lst); static void free_socket_id_lst(struct socket_id* i);
+static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a); + %}
%union { @@ -219,6 +223,7 @@ static void free_socket_id_lst(struct socket_id* i); char* strval; struct expr* expr; struct action* action; + struct case_stms* case_stms; struct net* ipnet; struct ip_addr* ipaddr; struct socket_id* sockid; @@ -272,6 +277,9 @@ static void free_socket_id_lst(struct socket_id* i); %token SET_ADV_ADDRESS %token SET_ADV_PORT %token FORCE_SEND_SOCKET +%token SWITCH +%token CASE +%token DEFAULT %token URIHOST %token URIPORT %token MAX_LEN @@ -493,6 +501,8 @@ static void free_socket_id_lst(struct socket_id* i); %type <intval> intno eint_op eint_op_onsend %type <intval> eip_op eip_op_onsend %type <action> action actions cmd fcmd if_cmd stm /*exp_stm*/ assign_action +%type <action> switch_cmd +%type <case_stms> single_case case_stms %type <ipaddr> ipv4 ipv6 ipv6addr ip %type <ipnet> ipnet %type <strval> host @@ -514,7 +524,7 @@ static void free_socket_id_lst(struct socket_id* i); %type <attr> attr_id_any_str %type <pvar> pvar %type <lval> lval -%type <rv_expr> rval rval_expr +%type <rv_expr> rval rval_expr ct_rval %type <lval> avp_pvar /* %type <intval> class_id */ %type <intval> assign_op @@ -1762,6 +1772,7 @@ actions: action: fcmd SEMICOLON {$$=$1;} | if_cmd {$$=$1;} + | switch_cmd {$$=$1;} | assign_action SEMICOLON {$$=$1;} | SEMICOLON /* null action */ {$$=0;} | fcmd error { $$=0; yyerror("bad command: missing ';'?"); } @@ -1770,6 +1781,98 @@ if_cmd: IF exp stm { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, NOSUBTYPE, 0); } | IF exp stm ELSE stm { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, ACTIONS_ST, $5); } ; + +ct_rval: rval_expr { + $$=0; + if (!rve_is_constant($1)){ + yyerror("constant expected"); + }else if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){ + yyerror("invalid expression (bad type)"); + }else if (i_tmp!=RV_INT){ + yyerror("invalid expression type, int expected\n"); + }else + $$=$1; + } +; +single_case: + CASE ct_rval COLON actions { + $$=0; + if ($2==0) yyerror ("bad case label"); + else if (($$=mk_case_stm($2, $4))==0){ + yyerror("internal error: memory allocation failure"); + YYABORT; + } + } + | CASE ct_rval COLON { + $$=0; + if ($2==0) yyerror ("bad case label"); + else if (($$=mk_case_stm($2, 0))==0){ + yyerror("internal error: memory allocation failure"); + YYABORT; + } + } + | DEFAULT COLON actions { + if (($$=mk_case_stm(0, $3))==0){ + yyerror("internal error: memory allocation failure"); + YYABORT; + } + } + | DEFAULT COLON { + if (($$=mk_case_stm(0, 0))==0){ + yyerror("internal error: memory allocation failure"); + YYABORT; + } + } + | CASE error { $$=0; yyerror("bad case label"); } + | CASE ct_rval COLON error { $$=0; yyerror ("bad case body"); } +; +case_stms: + case_stms single_case { + $$=$1; + if ($2==0) yyerror ("bad case"); + if ($$){ + *($$->append)=$2; + if (*($$->append)!=0) + $$->append=&((*($$->append))->next); + } + } + | single_case { + $$=$1; + if ($1==0) yyerror ("bad case"); + else $$->append=&($$->next); + } +; +switch_cmd: + SWITCH rval_expr LBRACE case_stms RBRACE { + $$=0; + if ($2==0) yyerror("bad expression in switch(...)"); + else if ($4==0) yyerror ("bad switch body"); + else{ + $$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, $4); + if ($$==0) { + yyerror("internal error"); + YYABORT; + } + } + } + | SWITCH rval_expr LBRACE RBRACE { + $$=0; + warn("empty switch()"); + if ($2==0) yyerror("bad expression in switch(...)"); + else{ + /* it might have sideffects, so leave it for the optimizer */ + $$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, 0); + if ($$==0) { + yyerror("internal error"); + YYABORT; + } + } + } + | SWITCH error { $$=0; yyerror ("bad expression in switch(...)"); } + | SWITCH rval_expr LBRACE error RBRACE + {$$=0; yyerror ("bad switch body"); } +; + /* class_id: LBRACK ATTR_USER RBRACK { $$ = AVP_CLASS_USER; } | LBRACK ATTR_DOMAIN RBRACK { $$ = AVP_CLASS_DOMAIN; } @@ -2763,6 +2866,23 @@ static void free_socket_id_lst(struct socket_id* lst) } }
+ +static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a) +{ + struct case_stms* s; + s=pkg_malloc(sizeof(*s)); + if (s==0) { + LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n"); + } else { + memset(s, 0, sizeof(*s)); + s->ct_rve=ct; + s->actions=a; + s->next=0; + s->append=0; + } + return s; +} + /* int main(int argc, char ** argv) { diff --git a/route_struct.h b/route_struct.h index 76aac25..e87b2d0 100644 --- a/route_struct.h +++ b/route_struct.h @@ -70,7 +70,9 @@ enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O, enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T, SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T, - IF_T, MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T, + IF_T, SWITCH_T /* only until fixup*/, + BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T, + MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T, SETFLAG_T, RESETFLAG_T, ISFLAGSET_T , AVPFLAG_OPER_T, LEN_GT_T, PREFIX_T, STRIP_T,STRIP_TAIL_T, @@ -96,7 +98,9 @@ enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST, MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST, ACTION_ST, AVP_ST, SELECT_ST, PVAR_ST, LVAL_ST, RVE_ST, - RETCODE_ST}; + RETCODE_ST, CASE_ST, + BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST +};
/* run flags */ #define EXIT_R_F 1 diff --git a/switch.h b/switch.h new file mode 100644 index 0000000..4c9f78b --- /dev/null +++ b/switch.h @@ -0,0 +1,60 @@ +/* + * $Id$ + * + * Copyright (C) 2009 iptelorg GmbH + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * /home/andrei/sr.git/switch.h + */ +/* + * History: + * -------- + * 2009-02-02 initial version (andrei) +*/ + +#ifndef __switch_h +#define __switch_h + +#include "route_struct.h" + +struct case_stms{ + struct rval_expr* ct_rve; + struct action* actions; + struct case_stms* next; + struct case_stms** append; + int int_label; + int is_default; +}; + + +struct switch_cond_table{ + int n; /**< size */ + int* cond; /**< int labels array */ + struct action** jump; /**< jump points array */ + struct action* def; /**< default jump */ +}; + + +struct switch_jmp_table{ + int first; /**< first int label in the jump table */ + int last; /**< last int label in the jump table */ + struct action** tbl; /**< jmp table [v-first] iff first<=v<=last */ + struct switch_cond_table rest; /**< normal cond. table for the rest */ +}; + + +#endif /*__switch_h*/ + +/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
Hi Andrei,
does the switch support only integers?
Apart of return code from functions, most of the switches I have seen are for strings (e.g., matching dialed number/address, user IDs, etc...).
Cheers, Daniel
On 02/04/2009 09:50 PM, Andrei Pelinescu-Onciul wrote:
Module: sip-router Branch: andrei/switch Commit: a29a8b6ddba24b8e71faaf78e7426aa7f85c19b5 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=a29a8b6d...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Wed Feb 4 20:44:26 2009 +0100
script parsing: C style switch() & case support
- support for parsing C style switch() & case, e.g.: switch($var){ case 1: log(1, "1\n"); break; case 2: case 3: default: log(1, "default\n"); } (note: this is different from kamailio/openser switch())
cfg.lex | 7 +++ cfg.y | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- route_struct.h | 8 +++- switch.h | 60 +++++++++++++++++++++++++++ 4 files changed, 194 insertions(+), 3 deletions(-)
diff --git a/cfg.lex b/cfg.lex index fc9eecb..13767b1 100644 --- a/cfg.lex +++ b/cfg.lex @@ -187,6 +187,9 @@ ELSE "else" SET_ADV_ADDRESS "set_advertised_address" SET_ADV_PORT "set_advertised_port" FORCE_SEND_SOCKET "force_send_socket" +SWITCH "switch" +CASE "case" +DEFAULT "default"
/*ACTION LVALUES*/ URIHOST "uri:host" @@ -495,6 +498,10 @@ EAT_ABLE [\ \t\b\r] return SET_ADV_PORT; } <INITIAL>{FORCE_SEND_SOCKET} { count(); yylval.strval=yytext; return FORCE_SEND_SOCKET; } +<INITIAL>{SWITCH} { count(); yylval.strval=yytext; return SWITCH; } +<INITIAL>{CASE} { count(); yylval.strval=yytext; return CASE; } +<INITIAL>{DEFAULT} { count(); yylval.strval=yytext; return DEFAULT; }
<INITIAL>{URIHOST} { count(); yylval.strval=yytext; return URIHOST; } <INITIAL>{URIPORT} { count(); yylval.strval=yytext; return URIPORT; } diff --git a/cfg.y b/cfg.y index 63c9eb4..431054d 100644 --- a/cfg.y +++ b/cfg.y @@ -93,6 +93,7 @@
lval=rval_expr, where lval=avp|pvar (andrei)
- 2007-12-06 expression are now evaluated in terms of rvalues;
NUMBER is now always positive; cleanup (andrei)
- 2009-01-26 case/switch() support (andrei)
*/
%{ @@ -109,6 +110,7 @@ #include "route_struct.h" #include "globals.h" #include "route.h" +#include "switch.h" #include "dprint.h" #include "sr_module.h" #include "modparam.h" @@ -211,6 +213,8 @@ static struct socket_id* mk_listen_id2(struct name_lst*, int, int); static void free_name_lst(struct name_lst* lst); static void free_socket_id_lst(struct socket_id* i);
+static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a);
%}
%union { @@ -219,6 +223,7 @@ static void free_socket_id_lst(struct socket_id* i); char* strval; struct expr* expr; struct action* action;
- struct case_stms* case_stms; struct net* ipnet; struct ip_addr* ipaddr; struct socket_id* sockid;
@@ -272,6 +277,9 @@ static void free_socket_id_lst(struct socket_id* i); %token SET_ADV_ADDRESS %token SET_ADV_PORT %token FORCE_SEND_SOCKET +%token SWITCH +%token CASE +%token DEFAULT %token URIHOST %token URIPORT %token MAX_LEN @@ -493,6 +501,8 @@ static void free_socket_id_lst(struct socket_id* i); %type <intval> intno eint_op eint_op_onsend %type <intval> eip_op eip_op_onsend %type <action> action actions cmd fcmd if_cmd stm /*exp_stm*/ assign_action +%type <action> switch_cmd +%type <case_stms> single_case case_stms %type <ipaddr> ipv4 ipv6 ipv6addr ip %type <ipnet> ipnet %type <strval> host @@ -514,7 +524,7 @@ static void free_socket_id_lst(struct socket_id* i); %type <attr> attr_id_any_str %type <pvar> pvar %type <lval> lval -%type <rv_expr> rval rval_expr +%type <rv_expr> rval rval_expr ct_rval %type <lval> avp_pvar /* %type <intval> class_id */ %type <intval> assign_op @@ -1762,6 +1772,7 @@ actions: action: fcmd SEMICOLON {$$=$1;} | if_cmd {$$=$1;}
- | switch_cmd {$$=$1;} | assign_action SEMICOLON {$$=$1;} | SEMICOLON /* null action */ {$$=0;} | fcmd error { $$=0; yyerror("bad command: missing ';'?"); }
@@ -1770,6 +1781,98 @@ if_cmd: IF exp stm { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, NOSUBTYPE, 0); } | IF exp stm ELSE stm { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, ACTIONS_ST, $5); } ;
+ct_rval: rval_expr {
$$=0;
if (!rve_is_constant($1)){
yyerror("constant expected");
}else if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){
yyerror("invalid expression (bad type)");
}else if (i_tmp!=RV_INT){
yyerror("invalid expression type, int expected\n");
}else
$$=$1;
}
+; +single_case:
- CASE ct_rval COLON actions {
$$=0;
if ($2==0) yyerror ("bad case label");
else if (($$=mk_case_stm($2, $4))==0){
yyerror("internal error: memory allocation failure");
YYABORT;
}
- }
- | CASE ct_rval COLON {
$$=0;
if ($2==0) yyerror ("bad case label");
else if (($$=mk_case_stm($2, 0))==0){
yyerror("internal error: memory allocation failure");
YYABORT;
}
- }
- | DEFAULT COLON actions {
if (($$=mk_case_stm(0, $3))==0){
yyerror("internal error: memory allocation failure");
YYABORT;
}
- }
- | DEFAULT COLON {
if (($$=mk_case_stm(0, 0))==0){
yyerror("internal error: memory allocation failure");
YYABORT;
}
- }
- | CASE error { $$=0; yyerror("bad case label"); }
- | CASE ct_rval COLON error { $$=0; yyerror ("bad case body"); }
+; +case_stms:
- case_stms single_case {
$$=$1;
if ($2==0) yyerror ("bad case");
if ($$){
*($$->append)=$2;
if (*($$->append)!=0)
$$->append=&((*($$->append))->next);
}
- }
- | single_case {
$$=$1;
if ($1==0) yyerror ("bad case");
else $$->append=&($$->next);
- }
+; +switch_cmd:
SWITCH rval_expr LBRACE case_stms RBRACE {
$$=0;
if ($2==0) yyerror("bad expression in switch(...)");
else if ($4==0) yyerror ("bad switch body");
else{
$$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, $4);
if ($$==0) {
yyerror("internal error");
YYABORT;
}
}
- }
- | SWITCH rval_expr LBRACE RBRACE {
$$=0;
warn("empty switch()");
if ($2==0) yyerror("bad expression in switch(...)");
else{
/* it might have sideffects, so leave it for the optimizer */
$$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, 0);
if ($$==0) {
yyerror("internal error");
YYABORT;
}
}
- }
- | SWITCH error { $$=0; yyerror ("bad expression in switch(...)"); }
- | SWITCH rval_expr LBRACE error RBRACE
{$$=0; yyerror ("bad switch body"); }
+;
/* class_id: LBRACK ATTR_USER RBRACK { $$ = AVP_CLASS_USER; } | LBRACK ATTR_DOMAIN RBRACK { $$ = AVP_CLASS_DOMAIN; } @@ -2763,6 +2866,23 @@ static void free_socket_id_lst(struct socket_id* lst) } }
+static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a) +{
- struct case_stms* s;
- s=pkg_malloc(sizeof(*s));
- if (s==0) {
LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
- } else {
memset(s, 0, sizeof(*s));
s->ct_rve=ct;
s->actions=a;
s->next=0;
s->append=0;
- }
- return s;
+}
/* int main(int argc, char ** argv) { diff --git a/route_struct.h b/route_struct.h index 76aac25..e87b2d0 100644 --- a/route_struct.h +++ b/route_struct.h @@ -70,7 +70,9 @@ enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O, enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T, SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T,
IF_T, MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
IF_T, SWITCH_T /* only until fixup*/,
BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T,
SETFLAG_T, RESETFLAG_T, ISFLAGSET_T , AVPFLAG_OPER_T, LEN_GT_T, PREFIX_T, STRIP_T,STRIP_TAIL_T,MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
@@ -96,7 +98,9 @@ enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST, MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST, ACTION_ST, AVP_ST, SELECT_ST, PVAR_ST, LVAL_ST, RVE_ST,
RETCODE_ST};
RETCODE_ST, CASE_ST,
BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST
+};
/* run flags */ #define EXIT_R_F 1 diff --git a/switch.h b/switch.h new file mode 100644 index 0000000..4c9f78b --- /dev/null +++ b/switch.h @@ -0,0 +1,60 @@ +/*
- $Id$
- Copyright (C) 2009 iptelorg GmbH
- Permission to use, copy, modify, and distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
+/*
- /home/andrei/sr.git/switch.h
- */
+/*
- History:
- 2009-02-02 initial version (andrei)
+*/
+#ifndef __switch_h +#define __switch_h
+#include "route_struct.h"
+struct case_stms{
- struct rval_expr* ct_rve;
- struct action* actions;
- struct case_stms* next;
- struct case_stms** append;
- int int_label;
- int is_default;
+};
+struct switch_cond_table{
- int n; /**< size */
- int* cond; /**< int labels array */
- struct action** jump; /**< jump points array */
- struct action* def; /**< default jump */
+};
+struct switch_jmp_table{
- int first; /**< first int label in the jump table */
- int last; /**< last int label in the jump table */
- struct action** tbl; /**< jmp table [v-first] iff first<=v<=last */
- struct switch_cond_table rest; /**< normal cond. table for the rest */
+};
+#endif /*__switch_h*/
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
sr-dev mailing list sr-dev@lists.sip-router.org http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
On Feb 04, 2009 at 22:29, Daniel-Constantin Mierla miconda@gmail.com wrote:
Hi Andrei,
does the switch support only integers?
Apart of return code from functions, most of the switches I have seen are for strings (e.g., matching dialed number/address, user IDs, etc...).
Yes, it's only for integers.
For strings, ifs should be used, since the switch wouldn't bring any advantage.
Andrei
On 02/04/2009 09:50 PM, Andrei Pelinescu-Onciul wrote:
Module: sip-router Branch: andrei/switch Commit: a29a8b6ddba24b8e71faaf78e7426aa7f85c19b5 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=a29a8b6d...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Wed Feb 4 20:44:26 2009 +0100
script parsing: C style switch() & case support
- support for parsing C style switch() & case, e.g.:
switch($var){ case 1: log(1, "1\n"); break; case 2: case 3: default: log(1, "default\n"); } (note: this is different from kamailio/openser switch())
cfg.lex | 7 +++ cfg.y | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- route_struct.h | 8 +++- switch.h | 60 +++++++++++++++++++++++++++ 4 files changed, 194 insertions(+), 3 deletions(-)
diff --git a/cfg.lex b/cfg.lex index fc9eecb..13767b1 100644 --- a/cfg.lex +++ b/cfg.lex @@ -187,6 +187,9 @@ ELSE "else" SET_ADV_ADDRESS "set_advertised_address" SET_ADV_PORT "set_advertised_port" FORCE_SEND_SOCKET "force_send_socket" +SWITCH "switch" +CASE "case" +DEFAULT "default"
/*ACTION LVALUES*/ URIHOST "uri:host" @@ -495,6 +498,10 @@ EAT_ABLE [\ \t\b\r] return SET_ADV_PORT; } <INITIAL>{FORCE_SEND_SOCKET} { count(); yylval.strval=yytext; return FORCE_SEND_SOCKET; } +<INITIAL>{SWITCH} { count(); yylval.strval=yytext; return SWITCH; } +<INITIAL>{CASE} { count(); yylval.strval=yytext; return CASE; } +<INITIAL>{DEFAULT} { count(); yylval.strval=yytext; return DEFAULT; }
<INITIAL>{URIHOST} { count(); yylval.strval=yytext; return URIHOST; } <INITIAL>{URIPORT} { count(); yylval.strval=yytext; return URIPORT; } diff --git a/cfg.y b/cfg.y index 63c9eb4..431054d 100644 --- a/cfg.y +++ b/cfg.y @@ -93,6 +93,7 @@
lval=rval_expr, where lval=avp|pvar (andrei)
- 2007-12-06 expression are now evaluated in terms of rvalues;
NUMBER is now always positive; cleanup (andrei)
- 2009-01-26 case/switch() support (andrei)
*/
%{ @@ -109,6 +110,7 @@ #include "route_struct.h" #include "globals.h" #include "route.h" +#include "switch.h" #include "dprint.h" #include "sr_module.h" #include "modparam.h" @@ -211,6 +213,8 @@ static struct socket_id* mk_listen_id2(struct name_lst*, int, int); static void free_name_lst(struct name_lst* lst); static void free_socket_id_lst(struct socket_id* i);
+static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a);
%}
%union { @@ -219,6 +223,7 @@ static void free_socket_id_lst(struct socket_id* i); char* strval; struct expr* expr; struct action* action;
- struct case_stms* case_stms; struct net* ipnet; struct ip_addr* ipaddr; struct socket_id* sockid;
@@ -272,6 +277,9 @@ static void free_socket_id_lst(struct socket_id* i); %token SET_ADV_ADDRESS %token SET_ADV_PORT %token FORCE_SEND_SOCKET +%token SWITCH +%token CASE +%token DEFAULT %token URIHOST %token URIPORT %token MAX_LEN @@ -493,6 +501,8 @@ static void free_socket_id_lst(struct socket_id* i); %type <intval> intno eint_op eint_op_onsend %type <intval> eip_op eip_op_onsend %type <action> action actions cmd fcmd if_cmd stm /*exp_stm*/ assign_action +%type <action> switch_cmd +%type <case_stms> single_case case_stms %type <ipaddr> ipv4 ipv6 ipv6addr ip %type <ipnet> ipnet %type <strval> host @@ -514,7 +524,7 @@ static void free_socket_id_lst(struct socket_id* i); %type <attr> attr_id_any_str %type <pvar> pvar %type <lval> lval -%type <rv_expr> rval rval_expr +%type <rv_expr> rval rval_expr ct_rval %type <lval> avp_pvar /* %type <intval> class_id */ %type <intval> assign_op @@ -1762,6 +1772,7 @@ actions: action: fcmd SEMICOLON {$$=$1;} | if_cmd {$$=$1;}
- | switch_cmd {$$=$1;} | assign_action SEMICOLON {$$=$1;} | SEMICOLON /* null action */ {$$=0;} | fcmd error { $$=0; yyerror("bad command: missing ';'?"); }
@@ -1770,6 +1781,98 @@ if_cmd: IF exp stm { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, NOSUBTYPE, 0); } | IF exp stm ELSE stm { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, ACTIONS_ST, $5); } ;
+ct_rval: rval_expr {
$$=0;
if (!rve_is_constant($1)){
yyerror("constant expected");
}else if (!rve_check_type((enum rval_type*)&i_tmp,
$1, 0, 0 ,0)){
yyerror("invalid expression (bad type)");
}else if (i_tmp!=RV_INT){
yyerror("invalid expression type, int
expected\n");
}else
$$=$1;
}
+; +single_case:
- CASE ct_rval COLON actions {
$$=0;
if ($2==0) yyerror ("bad case label");
else if (($$=mk_case_stm($2, $4))==0){
yyerror("internal error: memory allocation
failure");
YYABORT;
}
- }
- | CASE ct_rval COLON {
$$=0;
if ($2==0) yyerror ("bad case label");
else if (($$=mk_case_stm($2, 0))==0){
yyerror("internal error: memory allocation
failure");
YYABORT;
}
- }
- | DEFAULT COLON actions {
if (($$=mk_case_stm(0, $3))==0){
yyerror("internal error: memory allocation
failure");
YYABORT;
}
- }
- | DEFAULT COLON {
if (($$=mk_case_stm(0, 0))==0){
yyerror("internal error: memory allocation
failure");
YYABORT;
}
- }
- | CASE error { $$=0; yyerror("bad case label"); }
- | CASE ct_rval COLON error { $$=0; yyerror ("bad case body"); }
+; +case_stms:
- case_stms single_case {
$$=$1;
if ($2==0) yyerror ("bad case");
if ($$){
*($$->append)=$2;
if (*($$->append)!=0)
$$->append=&((*($$->append))->next);
}
- }
- | single_case {
$$=$1;
if ($1==0) yyerror ("bad case");
else $$->append=&($$->next);
- }
+; +switch_cmd:
SWITCH rval_expr LBRACE case_stms RBRACE {
$$=0;
if ($2==0) yyerror("bad expression in switch(...)");
else if ($4==0) yyerror ("bad switch body");
else{
$$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, $4);
if ($$==0) {
yyerror("internal error");
YYABORT;
}
}
- }
- | SWITCH rval_expr LBRACE RBRACE {
$$=0;
warn("empty switch()");
if ($2==0) yyerror("bad expression in switch(...)");
else{
/* it might have sideffects, so leave it for the
optimizer */
$$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, 0);
if ($$==0) {
yyerror("internal error");
YYABORT;
}
}
- }
- | SWITCH error { $$=0; yyerror ("bad expression in switch(...)"); }
- | SWITCH rval_expr LBRACE error RBRACE
{$$=0; yyerror ("bad switch body"); }
+;
/* class_id: LBRACK ATTR_USER RBRACK { $$ = AVP_CLASS_USER; } | LBRACK ATTR_DOMAIN RBRACK { $$ = AVP_CLASS_DOMAIN; } @@ -2763,6 +2866,23 @@ static void free_socket_id_lst(struct socket_id* lst) } }
+static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a) +{
- struct case_stms* s;
- s=pkg_malloc(sizeof(*s));
- if (s==0) {
LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
- } else {
memset(s, 0, sizeof(*s));
s->ct_rve=ct;
s->actions=a;
s->next=0;
s->append=0;
- }
- return s;
+}
/* int main(int argc, char ** argv) { diff --git a/route_struct.h b/route_struct.h index 76aac25..e87b2d0 100644 --- a/route_struct.h +++ b/route_struct.h @@ -70,7 +70,9 @@ enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O, enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T, SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T,
IF_T, MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T,
MODULEX_T,
IF_T, SWITCH_T /* only until fixup*/,
BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T,
MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T,
MODULEX_T, SETFLAG_T, RESETFLAG_T, ISFLAGSET_T , AVPFLAG_OPER_T, LEN_GT_T, PREFIX_T, STRIP_T,STRIP_TAIL_T, @@ -96,7 +98,9 @@ enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST, MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST, ACTION_ST, AVP_ST, SELECT_ST, PVAR_ST, LVAL_ST, RVE_ST,
RETCODE_ST};
RETCODE_ST, CASE_ST,
BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST
+};
/* run flags */ #define EXIT_R_F 1 diff --git a/switch.h b/switch.h new file mode 100644 index 0000000..4c9f78b --- /dev/null +++ b/switch.h @@ -0,0 +1,60 @@ +/*
- $Id$
- Copyright (C) 2009 iptelorg GmbH
- Permission to use, copy, modify, and distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
+/*
- /home/andrei/sr.git/switch.h
- */
+/*
- History:
- 2009-02-02 initial version (andrei)
+*/
+#ifndef __switch_h +#define __switch_h
+#include "route_struct.h"
+struct case_stms{
- struct rval_expr* ct_rve;
- struct action* actions;
- struct case_stms* next;
- struct case_stms** append;
- int int_label;
- int is_default;
+};
+struct switch_cond_table{
- int n; /**< size */
- int* cond; /**< int labels array */
- struct action** jump; /**< jump points array */
- struct action* def; /**< default jump */
+};
+struct switch_jmp_table{
- int first; /**< first int label in the jump table */
- int last; /**< last int label in the jump table */
- struct action** tbl; /**< jmp table [v-first] iff first<=v<=last
*/
- struct switch_cond_table rest; /**< normal cond. table for the rest
*/ +};
+#endif /*__switch_h*/
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
sr-dev mailing list sr-dev@lists.sip-router.org http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
-- Daniel-Constantin Mierla http://www.asipto.com
On 02/04/2009 10:58 PM, Andrei Pelinescu-Onciul wrote:
On Feb 04, 2009 at 22:29, Daniel-Constantin Mierla miconda@gmail.com wrote:
Hi Andrei,
does the switch support only integers?
Apart of return code from functions, most of the switches I have seen are for strings (e.g., matching dialed number/address, user IDs, etc...).
Yes, it's only for integers.
For strings, ifs should be used, since the switch wouldn't bring any advantage.
There are couple of advantages: 1) config clarity - instead of a long if (a==... || a==...) you have
switch(a) { case ...: case ...: }
2) it can shorten the script and save some ifs:
switch(a) { case v1: something; case v2: something else; break; }
This is equivalent of: if(a==v1) { something; } if(a==v1 || a==v2){ something; something else; }
or
if(a==v1) { something; something else; } if(a==v2){ something else; }
3) although not implemented yet in kamailio/openser (but planned), inside 'break' can make code cleaner switch(a) { case v1: ... if(...) { break; } ... break; }
4) traditionally, as I could learn, pstn switching/old telco school guys feel more confortable with line oriented routing rules, where they had something like:
extension match "1234": call emergency;
It could be a sswitch (although I would prefer single name to avoid confusions) if breaks logic for integer optimizations.
Cheers, Daniel
Andrei
On 02/04/2009 09:50 PM, Andrei Pelinescu-Onciul wrote:
Module: sip-router Branch: andrei/switch Commit: a29a8b6ddba24b8e71faaf78e7426aa7f85c19b5 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=a29a8b6d...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Wed Feb 4 20:44:26 2009 +0100
script parsing: C style switch() & case support
- support for parsing C style switch() & case, e.g.:
switch($var){ case 1: log(1, "1\n"); break; case 2: case 3: default: log(1, "default\n"); } (note: this is different from kamailio/openser switch())
cfg.lex | 7 +++ cfg.y | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- route_struct.h | 8 +++- switch.h | 60 +++++++++++++++++++++++++++ 4 files changed, 194 insertions(+), 3 deletions(-)
diff --git a/cfg.lex b/cfg.lex index fc9eecb..13767b1 100644 --- a/cfg.lex +++ b/cfg.lex @@ -187,6 +187,9 @@ ELSE "else" SET_ADV_ADDRESS "set_advertised_address" SET_ADV_PORT "set_advertised_port" FORCE_SEND_SOCKET "force_send_socket" +SWITCH "switch" +CASE "case" +DEFAULT "default"
/*ACTION LVALUES*/ URIHOST "uri:host" @@ -495,6 +498,10 @@ EAT_ABLE [\ \t\b\r] return SET_ADV_PORT; } <INITIAL>{FORCE_SEND_SOCKET} { count(); yylval.strval=yytext; return FORCE_SEND_SOCKET; } +<INITIAL>{SWITCH} { count(); yylval.strval=yytext; return SWITCH; } +<INITIAL>{CASE} { count(); yylval.strval=yytext; return CASE; } +<INITIAL>{DEFAULT} { count(); yylval.strval=yytext; return DEFAULT; }
<INITIAL>{URIHOST} { count(); yylval.strval=yytext; return URIHOST; } <INITIAL>{URIPORT} { count(); yylval.strval=yytext; return URIPORT; } diff --git a/cfg.y b/cfg.y index 63c9eb4..431054d 100644 --- a/cfg.y +++ b/cfg.y @@ -93,6 +93,7 @@
lval=rval_expr, where lval=avp|pvar (andrei)
- 2007-12-06 expression are now evaluated in terms of rvalues;
NUMBER is now always positive; cleanup (andrei)
- 2009-01-26 case/switch() support (andrei)
*/
%{ @@ -109,6 +110,7 @@ #include "route_struct.h" #include "globals.h" #include "route.h" +#include "switch.h" #include "dprint.h" #include "sr_module.h" #include "modparam.h" @@ -211,6 +213,8 @@ static struct socket_id* mk_listen_id2(struct name_lst*, int, int); static void free_name_lst(struct name_lst* lst); static void free_socket_id_lst(struct socket_id* i);
+static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a);
%}
%union { @@ -219,6 +223,7 @@ static void free_socket_id_lst(struct socket_id* i); char* strval; struct expr* expr; struct action* action;
- struct case_stms* case_stms; struct net* ipnet; struct ip_addr* ipaddr; struct socket_id* sockid;
@@ -272,6 +277,9 @@ static void free_socket_id_lst(struct socket_id* i); %token SET_ADV_ADDRESS %token SET_ADV_PORT %token FORCE_SEND_SOCKET +%token SWITCH +%token CASE +%token DEFAULT %token URIHOST %token URIPORT %token MAX_LEN @@ -493,6 +501,8 @@ static void free_socket_id_lst(struct socket_id* i); %type <intval> intno eint_op eint_op_onsend %type <intval> eip_op eip_op_onsend %type <action> action actions cmd fcmd if_cmd stm /*exp_stm*/ assign_action +%type <action> switch_cmd +%type <case_stms> single_case case_stms %type <ipaddr> ipv4 ipv6 ipv6addr ip %type <ipnet> ipnet %type <strval> host @@ -514,7 +524,7 @@ static void free_socket_id_lst(struct socket_id* i); %type <attr> attr_id_any_str %type <pvar> pvar %type <lval> lval -%type <rv_expr> rval rval_expr +%type <rv_expr> rval rval_expr ct_rval %type <lval> avp_pvar /* %type <intval> class_id */ %type <intval> assign_op @@ -1762,6 +1772,7 @@ actions: action: fcmd SEMICOLON {$$=$1;} | if_cmd {$$=$1;}
- | switch_cmd {$$=$1;} | assign_action SEMICOLON {$$=$1;} | SEMICOLON /* null action */ {$$=0;} | fcmd error { $$=0; yyerror("bad command: missing ';'?"); }
@@ -1770,6 +1781,98 @@ if_cmd: IF exp stm { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, NOSUBTYPE, 0); } | IF exp stm ELSE stm { $$=mk_action( IF_T, 3, EXPR_ST, $2, ACTIONS_ST, $3, ACTIONS_ST, $5); } ;
+ct_rval: rval_expr {
$$=0;
if (!rve_is_constant($1)){
yyerror("constant expected");
}else if (!rve_check_type((enum rval_type*)&i_tmp,
$1, 0, 0 ,0)){
yyerror("invalid expression (bad type)");
}else if (i_tmp!=RV_INT){
yyerror("invalid expression type, int
expected\n");
}else
$$=$1;
}
+; +single_case:
- CASE ct_rval COLON actions {
$$=0;
if ($2==0) yyerror ("bad case label");
else if (($$=mk_case_stm($2, $4))==0){
yyerror("internal error: memory allocation
failure");
YYABORT;
}
- }
- | CASE ct_rval COLON {
$$=0;
if ($2==0) yyerror ("bad case label");
else if (($$=mk_case_stm($2, 0))==0){
yyerror("internal error: memory allocation
failure");
YYABORT;
}
- }
- | DEFAULT COLON actions {
if (($$=mk_case_stm(0, $3))==0){
yyerror("internal error: memory allocation
failure");
YYABORT;
}
- }
- | DEFAULT COLON {
if (($$=mk_case_stm(0, 0))==0){
yyerror("internal error: memory allocation
failure");
YYABORT;
}
- }
- | CASE error { $$=0; yyerror("bad case label"); }
- | CASE ct_rval COLON error { $$=0; yyerror ("bad case body"); }
+; +case_stms:
- case_stms single_case {
$$=$1;
if ($2==0) yyerror ("bad case");
if ($$){
*($$->append)=$2;
if (*($$->append)!=0)
$$->append=&((*($$->append))->next);
}
- }
- | single_case {
$$=$1;
if ($1==0) yyerror ("bad case");
else $$->append=&($$->next);
- }
+; +switch_cmd:
SWITCH rval_expr LBRACE case_stms RBRACE {
$$=0;
if ($2==0) yyerror("bad expression in switch(...)");
else if ($4==0) yyerror ("bad switch body");
else{
$$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, $4);
if ($$==0) {
yyerror("internal error");
YYABORT;
}
}
- }
- | SWITCH rval_expr LBRACE RBRACE {
$$=0;
warn("empty switch()");
if ($2==0) yyerror("bad expression in switch(...)");
else{
/* it might have sideffects, so leave it for the
optimizer */
$$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, 0);
if ($$==0) {
yyerror("internal error");
YYABORT;
}
}
- }
- | SWITCH error { $$=0; yyerror ("bad expression in switch(...)"); }
- | SWITCH rval_expr LBRACE error RBRACE
{$$=0; yyerror ("bad switch body"); }
+;
/* class_id: LBRACK ATTR_USER RBRACK { $$ = AVP_CLASS_USER; } | LBRACK ATTR_DOMAIN RBRACK { $$ = AVP_CLASS_DOMAIN; } @@ -2763,6 +2866,23 @@ static void free_socket_id_lst(struct socket_id* lst) } }
+static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a) +{
- struct case_stms* s;
- s=pkg_malloc(sizeof(*s));
- if (s==0) {
LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
- } else {
memset(s, 0, sizeof(*s));
s->ct_rve=ct;
s->actions=a;
s->next=0;
s->append=0;
- }
- return s;
+}
/* int main(int argc, char ** argv) { diff --git a/route_struct.h b/route_struct.h index 76aac25..e87b2d0 100644 --- a/route_struct.h +++ b/route_struct.h @@ -70,7 +70,9 @@ enum { METHOD_O=1, URI_O, FROM_URI_O, TO_URI_O, SRCIP_O, SRCPORT_O, enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T, SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T, SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T,
IF_T, MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T,
MODULEX_T,
IF_T, SWITCH_T /* only until fixup*/,
BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T,
MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T,
MODULEX_T, SETFLAG_T, RESETFLAG_T, ISFLAGSET_T , AVPFLAG_OPER_T, LEN_GT_T, PREFIX_T, STRIP_T,STRIP_TAIL_T, @@ -96,7 +98,9 @@ enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST, MYSELF_ST, STR_ST, SOCKID_ST, SOCKETINFO_ST, ACTION_ST, AVP_ST, SELECT_ST, PVAR_ST, LVAL_ST, RVE_ST,
RETCODE_ST};
RETCODE_ST, CASE_ST,
BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST
+};
/* run flags */ #define EXIT_R_F 1 diff --git a/switch.h b/switch.h new file mode 100644 index 0000000..4c9f78b --- /dev/null +++ b/switch.h @@ -0,0 +1,60 @@ +/*
- $Id$
- Copyright (C) 2009 iptelorg GmbH
- Permission to use, copy, modify, and distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
+/*
- /home/andrei/sr.git/switch.h
- */
+/*
- History:
- 2009-02-02 initial version (andrei)
+*/
+#ifndef __switch_h +#define __switch_h
+#include "route_struct.h"
+struct case_stms{
- struct rval_expr* ct_rve;
- struct action* actions;
- struct case_stms* next;
- struct case_stms** append;
- int int_label;
- int is_default;
+};
+struct switch_cond_table{
- int n; /**< size */
- int* cond; /**< int labels array */
- struct action** jump; /**< jump points array */
- struct action* def; /**< default jump */
+};
+struct switch_jmp_table{
- int first; /**< first int label in the jump table */
- int last; /**< last int label in the jump table */
- struct action** tbl; /**< jmp table [v-first] iff first<=v<=last
*/
- struct switch_cond_table rest; /**< normal cond. table for the rest
*/ +};
+#endif /*__switch_h*/
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
sr-dev mailing list sr-dev@lists.sip-router.org http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
-- Daniel-Constantin Mierla http://www.asipto.com
On 02/04/2009 11:18 PM, Daniel-Constantin Mierla wrote:
On 02/04/2009 10:58 PM, Andrei Pelinescu-Onciul wrote:
On Feb 04, 2009 at 22:29, Daniel-Constantin Mierla miconda@gmail.com wrote:
Hi Andrei,
does the switch support only integers?
Apart of return code from functions, most of the switches I have seen are for strings (e.g., matching dialed number/address, user IDs, etc...).
Yes, it's only for integers.
For strings, ifs should be used, since the switch wouldn't bring any advantage.
There are couple of advantages:
- config clarity - instead of a long
if (a==... || a==...) you have
switch(a) { case ...: case ...: }
- it can shorten the script and save some ifs:
switch(a) { case v1: something; case v2: something else; break; }
This is equivalent of: if(a==v1) { something; } if(a==v1 || a==v2){ something; something else; }
or
if(a==v1) { something; something else; } if(a==v2){ something else; }
- although not implemented yet in kamailio/openser (but planned),
inside 'break' can make code cleaner switch(a) { case v1: ... if(...) { break; } ... break; }
- traditionally, as I could learn, pstn switching/old telco school guys
feel more confortable with line oriented routing rules, where they had something like:
extension match "1234": call emergency;
It could be a sswitch (although I would prefer single name to avoid confusions) if breaks logic for integer optimizations.
and btw, as the case values are constant, we probably optimize by creating a hash value at start up from it, so there can be some jumpers and linkers of the the actions crossing cases without breaks.
Cheers, Daniel
On Wednesday 04 February 2009, Daniel-Constantin Mierla wrote:
- it can shorten the script and save some ifs:
switch(a) { case v1: something; case v2: something else; break; }
Hi all,
this is also a big advantage for me, as if your script gets too long its much harder to debug and understand.
It could be a sswitch (although I would prefer single name to avoid confusions) if breaks logic for integer optimizations.
Having two different switch statements is IMHO really confusing.
Cheers,
Henning
On Feb 05, 2009 at 10:48, Henning Westerholt henning.westerholt@1und1.de wrote:
On Wednesday 04 February 2009, Daniel-Constantin Mierla wrote:
- it can shorten the script and save some ifs:
switch(a) { case v1: something; case v2: something else; break; }
Hi all,
this is also a big advantage for me, as if your script gets too long its much harder to debug and understand.
It could be a sswitch (although I would prefer single name to avoid confusions) if breaks logic for integer optimizations.
Having two different switch statements is IMHO really confusing.
It's like the operators: we either have different switch() for strings and integers or we have typed variables. Without this restrictions one cannot optimize (IMO we should have both since that would allow for much better type checking at startup -> a lot of possible script errors can be easily indentified => more user friendly).
How about using match() for sswitch()? Also should we use only strings or REs too, e.g.:
match($v){ case "foo": case /[0-9]+/: ... }
Andrei
On 02/05/2009 05:52 PM, Andrei Pelinescu-Onciul wrote:
On Feb 05, 2009 at 10:48, Henning Westerholt henning.westerholt@1und1.de wrote:
On Wednesday 04 February 2009, Daniel-Constantin Mierla wrote:
- it can shorten the script and save some ifs:
switch(a) { case v1: something; case v2: something else; break; }
Hi all,
this is also a big advantage for me, as if your script gets too long its much harder to debug and understand.
It could be a sswitch (although I would prefer single name to avoid confusions) if breaks logic for integer optimizations.
Having two different switch statements is IMHO really confusing.
It's like the operators: we either have different switch() for strings and integers or we have typed variables. Without this restrictions one cannot optimize (IMO we should have both since that would allow for much better type checking at startup -> a lot of possible script errors can be easily indentified => more user friendly).
What if we decide what type of case value is by the first 'case'? If first one is integer, then all should be integers and the 'switch' will have integer optimizations. If not integer, then expect only strings or regular expressions (which will be an useful addition) with the main benefit of a nice-looking config file.
Cheers, Daniel
How about using match() for sswitch()? Also should we use only strings or REs too, e.g.:
match($v){ case "foo": case /[0-9]+/: ... }
Andrei
sr-dev mailing list sr-dev@lists.sip-router.org http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
El Jueves, 5 de Febrero de 2009, Daniel-Constantin Mierla escribió:
What if we decide what type of case value is by the first 'case'? If first one is integer, then all should be integers and the 'switch' will have integer optimizations. If not integer, then expect only strings or regular expressions (which will be an useful addition) with the main benefit of a nice-looking config file.
What about if the first case value is a pseudo-variable whose value could be an integer or string dynamically? (BTW I'm not sure now if Kamailio allows pseudo-variables as case value).
On 02/05/2009 09:22 PM, Iñaki Baz Castillo wrote:
El Jueves, 5 de Febrero de 2009, Daniel-Constantin Mierla escribió:
What if we decide what type of case value is by the first 'case'? If first one is integer, then all should be integers and the 'switch' will have integer optimizations. If not integer, then expect only strings or regular expressions (which will be an useful addition) with the main benefit of a nice-looking config file.
What about if the first case value is a pseudo-variable whose value could be an integer or string dynamically? (BTW I'm not sure now if Kamailio allows pseudo-variables as case value).
It is not in Kamailio - it does support integer or strings in same switch, but both static values -- not sure if this is needed or of any use (I mean string and int in same switch).
I see switch useful with static values, and regexp will be a good addition. Main usage is to map static extensions, e.g.: 112, 911, voicemail menu, announcement services...
Cheers, Daniel
El Miércoles, 4 de Febrero de 2009, Andrei Pelinescu-Onciul escribió:
Yes, it's only for integers.
For strings, ifs should be used, since the switch wouldn't bring any advantage.
*SER scripting language is a domain specific language. I expect it offers higher level syntax than C provides. If not, which is the purpose of using a DSL?
Kamailio now allows integers and strings (static or pseudo-varaibles) into the 'switch' stament. It would be great also allowing regular expressions:
switch($rU) { case "101": log("destination number is 101\n"); break; case /^102/: log("destination number begins with 102\n"); break; default: log("unknown destination number\n"); }
Perhaps this is too much, but allowing just integers (and just static?) is not very useful IMHO. If so, it would be useful only to inspect some functions return code or SIP response codes.
Just my opinion. Best regards.