On Feb 04, 2009 at 22:29, Daniel-Constantin Mierla
<miconda(a)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=a29a8b6…
>>
>> Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
>> Committer: Andrei Pelinescu-Onciul <andrei(a)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(a)lists.sip-router.org
>>
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev
>>
>>
> --
> Daniel-Constantin Mierla
>
http://www.asipto.com
>