core, lib, modules: restructured source code tree
[sip-router] / src / core / switch.c
1 /* 
2  * Copyright (C) 2009 iptelorg GmbH
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 /*!
18  * \file
19  * \brief Kamailio core :: 
20  * \ingroup core
21  * Module: \ref core
22  */
23
24 #include "switch.h"
25 #include "rvalue.h"
26 #include "route.h"
27 #include "mem/mem.h"
28 #include "error.h"
29
30 #define MAX_JT_SIZE 100  /* maximum jump table size */
31
32
33 /** create a cond table structure (pkg_malloc'ed).
34  * @return 0 on error, pointer on success
35  */
36 static struct switch_cond_table* mk_switch_cond_table(int n)
37 {
38         struct switch_cond_table* sct;
39         
40         /* allocate everything in a single block, better for cache locality */
41         sct=pkg_malloc(ROUND_INT(sizeof(*sct))+
42                                         ROUND_POINTER(n*sizeof(sct->cond[0]))+
43                                         n*sizeof(sct->jump[0]));
44         if (sct==0) return 0;
45         sct->n=n;
46         sct->cond=(int*)((char*)sct+ROUND_INT(sizeof(*sct)));
47         sct->jump=(struct action**)
48                                 ((char*)sct->cond+ROUND_POINTER(n*sizeof(sct->cond[0])));
49         sct->def=0;
50         return sct;
51 }
52
53
54
55 /** create a jump table structure (pkg_malloc'ed).
56  * @param jmp_size - size of the jump table
57  * @param rest - size of the fallback condition table
58  * @return 0 on error, pointer on success
59  */
60 static struct switch_jmp_table* mk_switch_jmp_table(int jmp_size, int rest)
61 {
62         struct switch_jmp_table* jt;
63         int size;
64         
65         /* alloc everything in a block */
66         size =  ROUND_POINTER(sizeof(*jt))+
67                         ROUND_INT(jmp_size*sizeof(jt->tbl[0]))+
68                         ROUND_POINTER(rest*sizeof(jt->rest.cond[0]))+
69                         rest*sizeof(jt->rest.jump[0]);
70         jt=pkg_malloc(size);
71         if (jt == 0) return 0;
72         memset(jt, 0, size);
73         jt->tbl = (struct action**)((char*) jt + ROUND_POINTER(sizeof(*jt)));
74         jt->rest.cond = (int*)
75                                         ((char*) jt->tbl + ROUND_INT(jmp_size*sizeof(jt->tbl[0])));
76         jt->rest.jump = (struct action**) ((char*) jt->rest.cond + 
77                                                                 ROUND_POINTER(rest*sizeof(jt->rest.cond[0])));
78         jt->rest.n=rest;
79         return jt;
80 }
81
82
83
84 /** create a match cond table structure (pkg_malloc'ed).
85  * @return 0 on error, pointer on success
86  */
87 static struct match_cond_table* mk_match_cond_table(int n)
88 {
89         struct match_cond_table* mct;
90         
91         /* allocate everything in a single block, better for cache locality */
92         mct=pkg_malloc(ROUND_POINTER(sizeof(*mct))+
93                                         ROUND_POINTER(n*sizeof(mct->match[0]))+
94                                         n*sizeof(mct->jump[0]));
95         if (mct==0) return 0;
96         mct->n=n;
97         mct->match=(struct match_str*)((char*)mct+ROUND_POINTER(sizeof(*mct)));
98         mct->jump=(struct action**)
99                                 ((char*)mct->match+ROUND_POINTER(n*sizeof(mct->match[0])));
100         mct->def=0;
101         return mct;
102 }
103
104
105
106 static int fix_match(struct action* t);
107
108
109
110 void destroy_case_stms(struct case_stms *lst)
111 {
112         struct case_stms* l;
113         struct case_stms* n;
114         
115         for (l=lst; l; l=n){
116                 n=l->next;
117                 rve_destroy(l->ct_rve);
118                 /* TODO: the action list is not freed (missing destroy_action() and
119                    there are some case when we need at least part of the action list
120                 */
121                 pkg_free(l);
122         }
123 }
124
125
126
127 /** fixup function for SWITCH_T actions.
128  * can produce 4 different action types:
129  *  - BLOCK_T (actions) - actions grouped in a block, break ends the block
130  *    execution.
131  *  - EVAL_T (cond)  - null switch block, but the condition has to be
132  *                       evaluated due to possible side-effects.
133  *  - SWITCH_COND_T(cond, jumps) - condition table
134  *  - SWITCH_JT_T(cond, jumptable) - jumptable + condition table
135  * TODO: external optimizers that would "flatten" BLOCK_T w/no breaks or
136  * breaks at the end.
137  * 
138  */
139 int fix_switch(struct action* t)
140 {
141         struct case_stms* c;
142         int n, i, j, ret, val;
143         struct action* a;
144         struct action* block;
145         struct action* def_a;
146         struct action* action_lst;
147         struct action** tail;
148         struct switch_jmp_table* jmp;
149         struct switch_cond_table* sct;
150         struct action** def_jmp_bm;
151         int* cond;
152         struct action*** jmp_bm;
153         int default_found;
154         int first, last, start, end, hits, best_hits;
155         struct rval_expr* sw_rve;
156         
157         ret=E_BUG;
158         cond=0;
159         jmp_bm=0;
160         def_jmp_bm=0;
161         default_found=0;
162         /* check if string switch (first case is string or RE) */
163         for (c=(struct case_stms*)t->val[1].u.data; c && c->is_default; c=c->next);
164         if (c && (c->type==MATCH_STR || c->type==MATCH_RE))
165                 return fix_match(t);
166         
167         sw_rve=(struct rval_expr*)t->val[0].u.data;
168         /*  handle null actions: optimize away if no
169            sideffects */
170         if (t->val[1].u.data==0){
171                 if (!rve_has_side_effects(sw_rve)){
172                         t->type=BLOCK_T;
173                         rve_destroy(sw_rve);
174                         t->val[0].type=BLOCK_ST;
175                         t->val[0].u.data=0;
176                         LM_DBG("null switch optimized away\n");
177                 }else{
178                         t->type=EVAL_T;
179                         t->val[0].type=RVE_ST;
180                         LM_DBG("null switch turned to EVAL_T\n");
181                 }
182                 return 0;
183         }
184         def_a=0;
185         n=0;
186         for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
187                 if (c->ct_rve){
188                         if (c->type!=MATCH_INT){
189                                 LM_ERR("wrong case type %d (int expected)\n", c->type);
190                                 return E_UNSPEC;
191                         }
192                         if (!rve_is_constant(c->ct_rve)){
193                                 LM_ERR("non constant expression in case\n");
194                                 return E_BUG;
195                         }
196                         if (rval_expr_eval_int(0, 0,  &c->label.match_int, c->ct_rve)
197                                         <0){
198                                 LM_ERR("case expression (%d,%d) has non-interger type\n",
199                                                 c->ct_rve->fpos.s_line,
200                                                 c->ct_rve->fpos.s_col);
201                                 return E_BUG;
202                         }
203                         c->is_default=0;
204                         n++; /* count only non-default cases */
205                 }else{
206                         if (default_found){
207                                 LM_ERR("more then one \"default\"");
208                                 return E_UNSPEC;
209                         }
210                         default_found=1;
211                         c->label.match_int=-1;
212                         c->is_default=1;
213                         def_a=c->actions;
214                 }
215                 if ( c->actions && ((ret=fix_actions(c->actions))<0))
216                         goto error;
217         }
218         LM_DBG("%d cases, %d default\n", n, default_found);
219         /*: handle n==0 (no case only a default:) */
220         if (n==0){
221                 if (default_found){
222                         if (!rve_has_side_effects(sw_rve)){
223                                 t->type=BLOCK_T;
224                                 rve_destroy(sw_rve);
225                                 destroy_case_stms(t->val[1].u.data);
226                                 t->val[0].type=BLOCK_ST;
227                                 t->val[0].u.data=def_a;
228                                 t->val[1].type=0;
229                                 t->val[1].u.data=0;
230                                 LM_DBG("default only switch optimized away (BLOCK_T)\n");
231                                 return 0;
232                         }
233                         LM_CRIT("default only switch with side-effect not expected at this point\n");
234                         ret=E_BUG;
235                         goto error;
236                 }else{
237                         LM_CRIT("empty switch not expected at this point\n");
238                         ret=E_BUG;
239                         goto error;
240                 }
241         }
242         cond=pkg_malloc(sizeof(cond[0])*n);
243         jmp_bm=pkg_malloc(sizeof(jmp_bm[0])*n);
244         if (cond==0 || jmp_bm==0){
245                 LM_ERR("memory allocation failure\n");
246                 ret=E_OUT_OF_MEM;
247                 goto error;
248         }
249         
250         /* fill condition table and jump point bookmarks and "flatten" the action 
251            lists (transform them into a single list for the entire switch, rather
252             then one block per case ) */
253         n=0;
254         action_lst=0;
255         tail=&action_lst;
256         for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
257                 a=c->actions;
258                 if (a){
259                         for (; a->next; a=a->next);
260                         if (action_lst==0)
261                                 action_lst=c->actions;
262                         else
263                                 *tail=c->actions;
264                 }
265                 if (c->is_default){
266                         def_jmp_bm=tail;
267                 } else {
268                         for (j=0; j<n; j++){
269                                 if (cond[j]==c->label.match_int){
270                                         LM_ERR("duplicate case (%d,%d)\n",
271                                                         c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col);
272                                         ret=E_UNSPEC;
273                                         goto error;
274                                 }
275                         }
276                         cond[n]=c->label.match_int;
277                         jmp_bm[n]=tail;
278                         n++;
279                 }
280                 if (c->actions)
281                         tail=&a->next;
282         }
283         /* handle constant rve w/ no side-effects: replace the whole case 
284            with the case rve block */
285         if ( (scr_opt_lev>=2) &&
286                         !rve_has_side_effects(sw_rve) && rve_is_constant(sw_rve)){
287                 if (rval_expr_eval_int(0, 0,  &val, sw_rve) <0){
288                         LM_ERR("wrong type for switch(...) expression (%d,%d)\n", 
289                                         sw_rve->fpos.s_line, sw_rve->fpos.s_col);
290                         ret=E_UNSPEC;
291                         goto error;
292                 }
293                 /* start with the "default:" value in case nothing is found */
294                 block=def_jmp_bm?*def_jmp_bm:0;
295                 for (i=0; i<n; i++){
296                         if (cond[i]==val){
297                                 block=*jmp_bm[i];
298                                 break;
299                         }
300                 }
301                 t->type=BLOCK_T;
302                 rve_destroy(sw_rve);
303                 t->val[0].type=BLOCK_ST;
304                 t->val[0].u.data=block;
305                 destroy_case_stms(t->val[1].u.data);
306                 t->val[1].type=0;
307                 t->val[1].u.data=0;
308                 ret=0;
309                 LM_DBG("constant switch(%d) with %d cases optimized away to case"
310                                 " %d \n", val, n, i);
311                 goto end;
312         }
313         /* try to create a jumptable */
314         /* cost: 2 cmp & table lookup
315            => makes sense for more then 3 cases
316            & if size< MAX_JT_SIZE
317         */
318         best_hits=3; /* more then 3 hits needed */
319         start=end=0;
320         for (i=0; i<n; i++){
321                 last=first=cond[i];
322                 hits=1;
323                 for (j=0; j<n; j++){
324                         if ((i==j) || (cond[j]<=first)) continue;
325                         if (cond[j]<last)
326                                 hits++;
327                         else if ((cond[j]-first)<MAX_JT_SIZE){
328                                 last=cond[j];
329                                 hits++;
330                         }
331                 }
332                 if (hits>best_hits){
333                         best_hits=hits;
334                         start=first;
335                         end=last;
336                         if (hits==n) break;
337                 }
338         }
339         if (start!=end){
340                 /* build jumptable: end-start entries and
341                  with a n-best_hits normal switch table */
342                 jmp=mk_switch_jmp_table(end-start+1, n-best_hits);
343                 if (jmp==0){
344                         LM_ERR("memory allocation error\n");
345                         ret=E_OUT_OF_MEM;
346                         goto error;
347                 }
348                 jmp->first=start;
349                 jmp->last=end;
350                 jmp->rest.n=n-best_hits;
351                 jmp->rest.def=def_jmp_bm?*def_jmp_bm:0;
352                 /* fill it with default values */
353                 for (i=0; i<=(end-start); i++)
354                         jmp->tbl[i]=jmp->rest.def;
355                 for (i=0, j=0; i<n; i++){
356                         if (cond[i]>=start && cond[i]<=end){
357                                 jmp->tbl[cond[i]-start]=*jmp_bm[i];
358                         }else{
359                                 jmp->rest.cond[j]=cond[i];
360                                 jmp->rest.jump[j]=*jmp_bm[i];
361                                 j++;
362                         }
363                 }
364                 t->type=SWITCH_JT_T;
365                 t->val[1].type=JUMPTABLE_ST;
366                 t->val[1].u.data=jmp;
367                 ret=0;
368                 LM_DBG("optimized to jumptable [%d, %d] and %d condtable,"
369                                 " default: %s\n ",
370                                 jmp->first, jmp->last, jmp->rest.n, jmp->rest.def?"yes":"no");
371         }else{
372                 sct=mk_switch_cond_table(n);
373                 if (sct==0){
374                         LM_ERR("memory allocation error\n");
375                         ret=E_OUT_OF_MEM;
376                         goto error;
377                 }
378                 sct->n=n;
379                 for (i=0; i<n; i++){
380                         sct->cond[i]=cond[i];
381                         sct->jump[i]=*jmp_bm[i];
382                 }
383                 sct->def=def_jmp_bm?*def_jmp_bm:0;
384                 t->type=SWITCH_COND_T;
385                 t->val[1].type=CONDTABLE_ST;
386                 t->val[1].u.data=sct;
387                 LM_DBG("optimized to condtable (%d) default: %s\n",
388                                 sct->n, sct->def?"yes":"no");
389                 ret=0;
390         }
391 end:
392 error:
393         if (cond) pkg_free(cond);
394         if (jmp_bm) pkg_free(jmp_bm);
395         return ret;
396 }
397
398
399
400 /** fixup function for MATCH_T actions.
401  * can produce 3 different action types:
402  *  - BLOCK_T (actions) - actions grouped in a block, break ends the block
403  *    execution.
404  *  - EVAL_T (cond)  - null switch block, but the condition has to be
405  *                       evaluated due to possible side-effects.
406  *  - MATCH_COND_T(cond, jumps) - condition table
407  */
408 static int fix_match(struct action* t)
409 {
410         struct case_stms* c;
411         int n, i, j, ret;
412         struct action* a;
413         struct action* block;
414         struct action* def_a;
415         struct action* action_lst;
416         struct action** tail;
417         struct match_cond_table* mct;
418         struct action** def_jmp_bm;
419         struct match_str* match;
420         struct action*** jmp_bm;
421         int default_found;
422         struct rval_expr* m_rve;
423         struct rvalue* rv;
424         regex_t* regex;
425         str s;
426         
427         ret=E_BUG;
428         match=0;
429         jmp_bm=0;
430         def_jmp_bm=0;
431         default_found=0;
432         rv=0;
433         s.s=0;
434         s.len=0;
435         m_rve=(struct rval_expr*)t->val[0].u.data;
436         /*  handle null actions: optimize away if no
437            sideffects */
438         if (t->val[1].u.data==0){
439                 if (!rve_has_side_effects(m_rve)){
440                         t->type=BLOCK_T;
441                         rve_destroy(m_rve);
442                         t->val[0].type=BLOCK_ST;
443                         t->val[0].u.data=0;
444                         LM_DBG("null switch optimized away\n");
445                 }else{
446                         t->type=EVAL_T;
447                         t->val[0].type=RVE_ST;
448                         LM_DBG("null switch turned to EVAL_T\n");
449                 }
450                 return 0;
451         }
452         def_a=0;
453         n=0;
454         for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
455                 if (c->ct_rve){
456                         if (c->type!=MATCH_STR && c->type!=MATCH_RE){
457                                 LM_ERR("wrong case type %d (string"
458                                                         "or RE expected)\n", c->type);
459                                 return E_UNSPEC;
460                         }
461                         if (!rve_is_constant(c->ct_rve)){
462                                 LM_ERR("non constant expression in case\n");
463                                 ret=E_BUG;
464                                 goto error;
465                         }
466                         if ((rv=rval_expr_eval(0, 0, c->ct_rve)) == 0 ){
467                                 LM_ERR("bad case expression (%d,%d)\n",
468                                                 c->ct_rve->fpos.s_line,
469                                                 c->ct_rve->fpos.s_col);
470                                 ret=E_BUG;
471                                 goto error;
472                         }
473                         if (rval_get_str(0, 0, &s, rv, 0)<0){
474                                 LM_ERR("(%d,%d): out of memory?\n",
475                                                 c->ct_rve->fpos.s_line,
476                                                 c->ct_rve->fpos.s_col);
477                                 ret=E_BUG;
478                                 goto error;
479                         }
480                         if (c->type==MATCH_RE){
481                                 if ((regex=pkg_malloc(sizeof(regex_t))) == 0){
482                                         LM_ERR("out of memory\n");
483                                         ret=E_OUT_OF_MEM;
484                                         goto error;
485                                 }
486                                 if (regcomp(regex, s.s, 
487                                                         REG_EXTENDED | REG_NOSUB | c->re_flags) !=0){
488                                         pkg_free(regex);
489                                         regex=0;
490                                         LM_ERR("(%d, %d): bad regular expression %.*s\n",
491                                                         c->ct_rve->fpos.s_line,
492                                                         c->ct_rve->fpos.s_col,
493                                                         s.len, ZSW(s.s));
494                                         ret=E_UNSPEC;
495                                         goto error;
496                                 }
497                                 c->label.match_re=regex;
498                                 regex=0;
499                         }else if (c->type==MATCH_STR){
500                                 c->label.match_str=s;
501                                 s.s=0;
502                                 s.len=0;
503                         }else{
504                                 LM_CRIT("(%d,%d): wrong case type %d\n",
505                                                 c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col,
506                                                 c->type);
507                                 ret=E_BUG;
508                                 goto error;
509                         }
510                         c->is_default=0;
511                         n++; /* count only non-default cases */
512                         /* cleanup */
513                         rval_destroy(rv);
514                         rv=0;
515                         if (s.s){
516                                 pkg_free(s.s);
517                                 s.s=0;
518                                 s.len=0;
519                         }
520                 }else{
521                         if (default_found){
522                                 LM_ERR("more then one \"default\" label found (%d, %d)\n",
523                                                 (c->ct_rve)?c->ct_rve->fpos.s_line:0,
524                                                 (c->ct_rve)?c->ct_rve->fpos.s_col:0);
525                                 ret=E_UNSPEC;
526                                 goto error;
527                         }
528                         default_found=1;
529                         c->is_default=1;
530                         def_a=c->actions;
531                 }
532                 if ( c->actions && ((ret=fix_actions(c->actions))<0))
533                         goto error;
534         }
535         LM_DBG("%d cases, %d default\n", n, default_found);
536         /*: handle n==0 (no case only a default:) */
537         if (n==0){
538                 if (default_found){
539                         if (!rve_has_side_effects(m_rve)){
540                                 t->type=BLOCK_T;
541                                 rve_destroy(m_rve);
542                                 destroy_case_stms(t->val[1].u.data);
543                                 t->val[0].type=BLOCK_ST;
544                                 t->val[0].u.data=def_a;
545                                 t->val[1].type=0;
546                                 t->val[1].u.data=0;
547                                 LM_DBG("default only switch optimized away (BLOCK_T)\n");
548                                 return 0;
549                         }
550                         LM_CRIT("default only switch with side-effect not expected at this point\n");
551                         ret=E_BUG;
552                         goto error;
553                 }else{
554                         LM_CRIT("empty switch not expected at this point\n");
555                         ret=E_BUG;
556                         goto error;
557                 }
558         }
559         /* n is the number of labels here */
560         match=pkg_malloc(sizeof(match[0])*n);
561         jmp_bm=pkg_malloc(sizeof(jmp_bm[0])*n);
562         if (match==0 || jmp_bm==0){
563                 LM_ERR("memory allocation failure\n");
564                 ret=E_OUT_OF_MEM;
565                 goto error;
566         }
567         
568         /* fill condition table and jump point bookmarks and "flatten" the action 
569            lists (transform them into a single list for the entire switch, rather
570             then one block per case ) */
571         n=0;
572         action_lst=0;
573         tail=&action_lst;
574         for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
575                 a=c->actions;
576                 if (a){
577                         for (; a->next; a=a->next);
578                         if (action_lst==0)
579                                 action_lst=c->actions;
580                         else
581                                 *tail=c->actions;
582                 }
583                 if (c->is_default){
584                         def_jmp_bm=tail;
585                 } else{
586                         match[n].type=c->type;
587                         if (match[n].type == MATCH_STR){
588                                 for (j=0; j<n; j++){
589                                         if ( match[j].type == c->type &&
590                                                  match[j].l.s.len ==  c->label.match_str.len &&
591                                                  memcmp(match[j].l.s.s, c->label.match_str.s,
592                                                                         match[j].l.s.len) == 0 ){
593                                                 LM_ERR("duplicate case (%d,%d)\n",
594                                                                 c->ct_rve->fpos.s_line,
595                                                                 c->ct_rve->fpos.s_col);
596                                                 ret=E_UNSPEC;
597                                                 goto error;
598                                         }
599                                 }
600                                 match[n].flags=0;
601                                 match[n].l.s=c->label.match_str;
602                                 c->label.match_str.s=0; /* prevent s being freed */
603                                 c->label.match_str.len=0;
604                         } else {
605                                 match[n].flags=c->re_flags | REG_EXTENDED | REG_NOSUB;
606                                 match[n].l.regex=c->label.match_re;
607                                 c->label.match_re=0;
608                         }
609                         jmp_bm[n]=tail;
610                         n++;
611                 }
612                 if (c->actions)
613                         tail=&a->next;
614         }
615         /* handle constant rve w/ no side-effects: replace the whole case 
616            with the case rve block */
617         if ( (scr_opt_lev>=2) &&
618                         !rve_has_side_effects(m_rve) && rve_is_constant(m_rve)){
619                 if ((rv=rval_expr_eval(0, 0, m_rve)) == 0){
620                         LM_ERR("bad expression (%d,%d)\n", 
621                                         m_rve->fpos.s_line, m_rve->fpos.s_col);
622                         ret=E_UNSPEC;
623                         goto error;
624                 }
625                 if (rval_get_str(0, 0, &s, rv, 0) < 0 ){
626                                 LM_ERR("(%d,%d): bad string expression\n",
627                                                 m_rve->fpos.s_line,
628                                                 m_rve->fpos.s_col);
629                         ret=E_UNSPEC;
630                         goto error;
631                 }
632                 /* start with the "default:" value in case nothing is found */
633                 block=def_jmp_bm?*def_jmp_bm:0;
634                 for (i=0; i<n; i++){
635                         if (((match[i].type == MATCH_STR) && (match[i].l.s.len == s.len) &&
636                                         (memcmp(match[i].l.s.s, s.s, s.len) == 0)) ||
637                                 ((match[i].type == MATCH_RE) && 
638                                         regexec(match[i].l.regex, s.s, 0, 0, 0) == 0) ) {
639                                 block=*jmp_bm[i];
640                                 break;
641                         }
642                 }
643                 LM_DBG("constant switch(\"%.*s\") with %d cases optimized away"
644                                 " to case no. %d\n", s.len, ZSW(s.s), n, i);
645                 /* cleanup */
646                 rval_destroy(rv);
647                 rv=0;
648                 pkg_free(s.s);
649                 s.s=0;
650                 s.len=0;
651                 ret=0;
652                 /* replace with BLOCK_ST */
653                 rve_destroy(m_rve);
654                 destroy_case_stms(t->val[1].u.data);
655                 t->type=BLOCK_T;
656                 t->val[0].type=BLOCK_ST;
657                 t->val[0].u.data=block;
658                 t->val[1].type=0;
659                 t->val[1].u.data=0;
660                 goto end;
661         }
662         mct=mk_match_cond_table(n);
663         if (mct==0){
664                 LM_ERR("memory allocation error\n");
665                 ret=E_OUT_OF_MEM;
666                 goto error;
667         }
668         mct->n=n;
669         for (i=0; i<n; i++){
670                 mct->match[i]=match[i];
671                 mct->jump[i]=*jmp_bm[i];
672         }
673         mct->def=def_jmp_bm?*def_jmp_bm:0;
674         t->type=MATCH_COND_T;
675         t->val[1].type=MATCH_CONDTABLE_ST;
676         t->val[1].u.data=mct;
677         LM_DBG("optimized to match condtable (%d) default: %s\n",
678                                 mct->n, mct->def?"yes":"no");
679                 ret=0;
680 end:
681 error:
682         if (match) pkg_free(match);
683         if (jmp_bm) pkg_free(jmp_bm);
684         /* cleanup rv & s*/
685         if (rv) rval_destroy(rv);
686         if (s.s) pkg_free(s.s);
687         return ret;
688 }
689 /* vi: set ts=4 sw=4 tw=79:ai:cindent: */