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