parser: some more const-correctness for the other functions in msg_parser.[c,h]
[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         struct action** def_jmp_bm;
162         int* cond;
163         struct action*** jmp_bm;
164         int default_found;
165         int first, last, start, end, hits, best_hits;
166         struct rval_expr* sw_rve;
167         
168         ret=E_BUG;
169         cond=0;
170         jmp_bm=0;
171         def_jmp_bm=0;
172         default_found=0;
173         /* check if string switch (first case is string or RE) */
174         for (c=(struct case_stms*)t->val[1].u.data; c && c->is_default; c=c->next);
175         if (c && (c->type==MATCH_STR || c->type==MATCH_RE))
176                 return fix_match(t);
177         
178         sw_rve=(struct rval_expr*)t->val[0].u.data;
179         /*  handle null actions: optimize away if no
180            sideffects */
181         if (t->val[1].u.data==0){
182                 if (!rve_has_side_effects(sw_rve)){
183                         t->type=BLOCK_T;
184                         rve_destroy(sw_rve);
185                         t->val[0].type=BLOCK_ST;
186                         t->val[0].u.data=0;
187                         DBG("SWITCH: null switch optimized away\n");
188                 }else{
189                         t->type=EVAL_T;
190                         t->val[0].type=RVE_ST;
191                         DBG("SWITCH: null switch turned to EVAL_T\n");
192                 }
193                 return 0;
194         }
195         def_a=0;
196         n=0;
197         for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
198                 if (c->ct_rve){
199                         if (c->type!=MATCH_INT){
200                                 LOG(L_ERR, "ERROR: fix_switch: wrong case type %d (int"
201                                                         "expected)\n", c->type);
202                                 return E_UNSPEC;
203                         }
204                         if (!rve_is_constant(c->ct_rve)){
205                                 LOG(L_ERR, "ERROR: fix_switch: non constant "
206                                                 "expression in case\n");
207                                 return E_BUG;
208                         }
209                         if (rval_expr_eval_int(0, 0,  &c->label.match_int, c->ct_rve)
210                                         <0){
211                                 LOG(L_ERR, "ERROR: fix_switch: case expression"
212                                                 " (%d,%d) has non-interger type\n",
213                                                 c->ct_rve->fpos.s_line,
214                                                 c->ct_rve->fpos.s_col);
215                                 return E_BUG;
216                         }
217                         c->is_default=0;
218                         n++; /* count only non-default cases */
219                 }else{
220                         if (default_found){
221                                 LOG(L_ERR, "ERROR: fix_switch: more then one \"default\"");
222                                 return E_UNSPEC;
223                         }
224                         default_found=1;
225                         c->label.match_int=-1;
226                         c->is_default=1;
227                         def_a=c->actions;
228                 }
229                 if ( c->actions && ((ret=fix_actions(c->actions))<0))
230                         goto error;
231         }
232         DBG("SWITCH: %d cases, %d default\n", n, default_found);
233         /*: handle n==0 (no case only a default:) */
234         if (n==0){
235                 if (default_found){
236                         if (!rve_has_side_effects(sw_rve)){
237                                 t->type=BLOCK_T;
238                                 rve_destroy(sw_rve);
239                                 destroy_case_stms(t->val[1].u.data);
240                                 t->val[0].type=BLOCK_ST;
241                                 t->val[0].u.data=def_a;
242                                 t->val[1].type=0;
243                                 t->val[1].u.data=0;
244                                 DBG("SWITCH: default only switch optimized away (BLOCK_T)\n");
245                                 return 0;
246                         }
247                         DBG("SWITCH: default only switch with side-effect...\n");
248                 }else{
249                         LOG(L_CRIT, "BUG: fix_switch: empty switch not expected at this"
250                                         " point\n");
251                         ret=E_BUG;
252                         goto error;
253                 }
254         }
255         cond=pkg_malloc(sizeof(cond[0])*n);
256         jmp_bm=pkg_malloc(sizeof(jmp_bm[0])*n);
257         if (cond==0 || jmp_bm==0){
258                 LOG(L_ERR, "ERROR: fix_switch: memory allocation failure\n");
259                 ret=E_OUT_OF_MEM;
260                 goto error;
261         }
262         
263         /* fill condition table and jump point bookmarks and "flatten" the action 
264            lists (transform them into a single list for the entire switch, rather
265             then one block per case ) */
266         n=0;
267         action_lst=0;
268         tail=&action_lst;
269         for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
270                 a=c->actions;
271                 if (a){
272                         for (; a->next; a=a->next);
273                         if (action_lst==0)
274                                 action_lst=c->actions;
275                         else
276                                 *tail=c->actions;
277                 }
278                 if (c->is_default){
279                         def_jmp_bm=tail;
280                 } else {
281                         for (j=0; j<n; j++){
282                                 if (cond[j]==c->label.match_int){
283                                         LOG(L_ERR, "ERROR: fix_switch: duplicate case (%d,%d)\n",
284                                                         c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col);
285                                         ret=E_UNSPEC;
286                                         goto error;
287                                 }
288                         }
289                         cond[n]=c->label.match_int;
290                         jmp_bm[n]=tail;
291                         n++;
292                 }
293                 if (c->actions)
294                         tail=&a->next;
295         }
296         /* handle constant rve w/ no side-effects: replace the whole case 
297            with the case rve block */
298         if ( (scr_opt_lev>=2) &&
299                         !rve_has_side_effects(sw_rve) && rve_is_constant(sw_rve)){
300                 if (rval_expr_eval_int(0, 0,  &val, sw_rve) <0){
301                         LOG(L_ERR, "ERROR: fix_switch: wrong type for switch(...) "
302                                         "expression (%d,%d)\n", 
303                                         sw_rve->fpos.s_line, sw_rve->fpos.s_col);
304                         ret=E_UNSPEC;
305                         goto error;
306                 }
307                 /* start with the "default:" value in case nothing is found */
308                 block=def_jmp_bm?*def_jmp_bm:0;
309                 for (i=0; i<n; i++){
310                         if (cond[i]==val){
311                                 block=*jmp_bm[i];
312                                 break;
313                         }
314                 }
315                 t->type=BLOCK_T;
316                 rve_destroy(sw_rve);
317                 t->val[0].type=BLOCK_ST;
318                 t->val[0].u.data=block;
319                 destroy_case_stms(t->val[1].u.data);
320                 t->val[1].type=0;
321                 t->val[1].u.data=0;
322                 ret=0;
323                 DBG("SWITCH: constant switch(%d) with %d cases optimized away to case "
324                                 " %d \n", val, n, i);
325                 goto end;
326         }
327         /* try to create a jumptable */
328         /* cost: 2 cmp & table lookup
329            => makes sense for more then 3 cases
330            & if size< MAX_JT_SIZE
331         */
332         best_hits=3; /* more then 3 hits needed */
333         start=end=0;
334         for (i=0; i<n; i++){
335                 last=first=cond[i];
336                 hits=1;
337                 for (j=0; j<n; j++){
338                         if ((i==j) || (cond[j]<=first)) continue;
339                         if (cond[j]<last)
340                                 hits++;
341                         else if ((cond[j]-first)<MAX_JT_SIZE){
342                                 last=cond[j];
343                                 hits++;
344                         }
345                 }
346                 if (hits>best_hits){
347                         best_hits=hits;
348                         start=first;
349                         end=last;
350                         if (hits==n) break;
351                 }
352         }
353         if (start!=end){
354                 /* build jumptable: end-start entries and
355                  with a n-best_hits normal switch table */
356                 jmp=mk_switch_jmp_table(end-start+1, n-best_hits);
357                 if (jmp==0){
358                         LOG(L_ERR, "ERROR: fix_switch: memory allocation error\n");
359                         ret=E_OUT_OF_MEM;
360                         goto error;
361                 }
362                 jmp->first=start;
363                 jmp->last=end;
364                 jmp->rest.n=n-best_hits;
365                 jmp->rest.def=def_jmp_bm?*def_jmp_bm:0;
366                 /* fill it with default values */
367                 for (i=0; i<=(end-start); i++)
368                         jmp->tbl[i]=jmp->rest.def;
369                 for (i=0, j=0; i<n; i++){
370                         if (cond[i]>=start && cond[i]<=end){
371                                 jmp->tbl[cond[i]-start]=*jmp_bm[i];
372                         }else{
373                                 jmp->rest.cond[j]=cond[i];
374                                 jmp->rest.jump[j]=*jmp_bm[i];
375                                 j++;
376                         }
377                 }
378                 t->type=SWITCH_JT_T;
379                 t->val[1].type=JUMPTABLE_ST;
380                 t->val[1].u.data=jmp;
381                 ret=0;
382                 DBG("SWITCH: optimized to jumptable [%d, %d] and %d condtable,"
383                                 "default: %s\n ",
384                                 jmp->first, jmp->last, jmp->rest.n, jmp->rest.def?"yes":"no");
385         }else{
386                 sct=mk_switch_cond_table(n);
387                 if (sct==0){
388                         LOG(L_ERR, "ERROR: fix_switch: memory allocation error\n");
389                         ret=E_OUT_OF_MEM;
390                         goto error;
391                 }
392                 sct->n=n;
393                 for (i=0; i<n; i++){
394                         sct->cond[i]=cond[i];
395                         sct->jump[i]=*jmp_bm[i];
396                 }
397                 sct->def=def_jmp_bm?*def_jmp_bm:0;
398                 t->type=SWITCH_COND_T;
399                 t->val[1].type=CONDTABLE_ST;
400                 t->val[1].u.data=sct;
401                 DBG("SWITCH: optimized to condtable (%d) default: %s\n ",
402                                 sct->n, sct->def?"yes":"no");
403                 ret=0;
404         }
405 end:
406 error:
407         if (cond) pkg_free(cond);
408         if (jmp_bm) pkg_free(jmp_bm);
409         return ret;
410 }
411
412
413
414 /** fixup function for MATCH_T actions.
415  * can produce 3 different action types:
416  *  - BLOCK_T (actions) - actions grouped in a block, break ends the block
417  *    execution.
418  *  - EVAL_T (cond)  - null switch block, but the condition has to be
419  *                       evaluated due to possible side-effects.
420  *  - MATCH_COND_T(cond, jumps) - condition table
421  */
422 static int fix_match(struct action* t)
423 {
424         struct case_stms* c;
425         int n, i, j, ret;
426         struct action* a;
427         struct action* block;
428         struct action* def_a;
429         struct action* action_lst;
430         struct action** tail;
431         struct match_cond_table* mct;
432         struct action** def_jmp_bm;
433         struct match_str* match;
434         struct action*** jmp_bm;
435         int default_found;
436         struct rval_expr* m_rve;
437         struct rvalue* rv;
438         regex_t* regex;
439         str s;
440         
441         ret=E_BUG;
442         match=0;
443         jmp_bm=0;
444         def_jmp_bm=0;
445         default_found=0;
446         rv=0;
447         s.s=0;
448         s.len=0;
449         m_rve=(struct rval_expr*)t->val[0].u.data;
450         /*  handle null actions: optimize away if no
451            sideffects */
452         if (t->val[1].u.data==0){
453                 if (!rve_has_side_effects(m_rve)){
454                         t->type=BLOCK_T;
455                         rve_destroy(m_rve);
456                         t->val[0].type=BLOCK_ST;
457                         t->val[0].u.data=0;
458                         DBG("MATCH: null switch optimized away\n");
459                 }else{
460                         t->type=EVAL_T;
461                         t->val[0].type=RVE_ST;
462                         DBG("MATCH: null switch turned to EVAL_T\n");
463                 }
464                 return 0;
465         }
466         def_a=0;
467         n=0;
468         for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
469                 if (c->ct_rve){
470                         if (c->type!=MATCH_STR && c->type!=MATCH_RE){
471                                 LOG(L_ERR, "ERROR: fix_match: wrong case type %d (string"
472                                                         "or RE expected)\n", c->type);
473                                 return E_UNSPEC;
474                         }
475                         if (!rve_is_constant(c->ct_rve)){
476                                 LOG(L_ERR, "ERROR: fix_match: non constant "
477                                                 "expression in case\n");
478                                 ret=E_BUG;
479                                 goto error;
480                         }
481                         if ((rv=rval_expr_eval(0, 0, c->ct_rve)) == 0 ){
482                                 LOG(L_ERR, "ERROR: fix_match: bad case expression"
483                                                 " (%d,%d)\n",
484                                                 c->ct_rve->fpos.s_line,
485                                                 c->ct_rve->fpos.s_col);
486                                 ret=E_BUG;
487                                 goto error;
488                         }
489                         if (rval_get_str(0, 0, &s, rv, 0)<0){
490                                 LOG(L_ERR, "ERROR: fix_match (%d,%d): out of memory?\n",
491                                                 c->ct_rve->fpos.s_line,
492                                                 c->ct_rve->fpos.s_col);
493                                 ret=E_BUG;
494                                 goto error;
495                         }
496                         if (c->type==MATCH_RE){
497                                 if ((regex=pkg_malloc(sizeof(regex_t))) == 0){
498                                         LOG(L_ERR, "ERROR: fix_match: out of memory\n");
499                                         ret=E_OUT_OF_MEM;
500                                         goto error;
501                                 }
502                                 if (regcomp(regex, s.s, 
503                                                         REG_EXTENDED | REG_NOSUB | c->re_flags) !=0){
504                                         pkg_free(regex);
505                                         regex=0;
506                                         LOG(L_ERR, "ERROR: fix_match (%d, %d): bad regular"
507                                                                 " expression %.*s\n",
508                                                         c->ct_rve->fpos.s_line,
509                                                         c->ct_rve->fpos.s_col,
510                                                         s.len, ZSW(s.s));
511                                         ret=E_UNSPEC;
512                                         goto error;
513                                 }
514                                 c->label.match_re=regex;
515                                 regex=0;
516                         }else if (c->type==MATCH_STR){
517                                 c->label.match_str=s;
518                                 s.s=0;
519                                 s.len=0;
520                         }else{
521                                 LOG(L_CRIT, "BUG: fix_match (%d,%d): wrong case type %d\n",
522                                                 c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col,
523                                                 c->type);
524                                 ret=E_BUG;
525                                 goto error;
526                         }
527                         c->is_default=0;
528                         n++; /* count only non-default cases */
529                         /* cleanup */
530                         rval_destroy(rv);
531                         rv=0;
532                         if (s.s){
533                                 pkg_free(s.s);
534                                 s.s=0;
535                                 s.len=0;
536                         }
537                 }else{
538                         if (default_found){
539                                 LOG(L_ERR, "ERROR: fix_match: more then one \"default\""
540                                                 " label found (%d, %d)\n",
541                                                 c->ct_rve->fpos.s_line,
542                                                 c->ct_rve->fpos.s_col);
543                                 ret=E_UNSPEC;
544                                 goto error;
545                         }
546                         default_found=1;
547                         c->is_default=1;
548                         def_a=c->actions;
549                 }
550                 if ( c->actions && ((ret=fix_actions(c->actions))<0))
551                         goto error;
552         }
553         DBG("MATCH: %d cases, %d default\n", n, default_found);
554         /*: handle n==0 (no case only a default:) */
555         if (n==0){
556                 if (default_found){
557                         if (!rve_has_side_effects(m_rve)){
558                                 t->type=BLOCK_T;
559                                 rve_destroy(m_rve);
560                                 destroy_case_stms(t->val[1].u.data);
561                                 t->val[0].type=BLOCK_ST;
562                                 t->val[0].u.data=def_a;
563                                 t->val[1].type=0;
564                                 t->val[1].u.data=0;
565                                 DBG("MATCH: default only switch optimized away (BLOCK_T)\n");
566                                 return 0;
567                         }
568                         DBG("MATCH: default only switch with side-effect...\n");
569                 }else{
570                         LOG(L_CRIT, "BUG: fix_match: empty switch not expected at this"
571                                         " point\n");
572                         ret=E_BUG;
573                         goto error;
574                 }
575         }
576         /* n is the number of labels here */
577         match=pkg_malloc(sizeof(match[0])*n);
578         jmp_bm=pkg_malloc(sizeof(jmp_bm[0])*n);
579         if (match==0 || jmp_bm==0){
580                 LOG(L_ERR, "ERROR: fix_match: memory allocation failure\n");
581                 ret=E_OUT_OF_MEM;
582                 goto error;
583         }
584         
585         /* fill condition table and jump point bookmarks and "flatten" the action 
586            lists (transform them into a single list for the entire switch, rather
587             then one block per case ) */
588         n=0;
589         action_lst=0;
590         tail=&action_lst;
591         for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
592                 a=c->actions;
593                 if (a){
594                         for (; a->next; a=a->next);
595                         if (action_lst==0)
596                                 action_lst=c->actions;
597                         else
598                                 *tail=c->actions;
599                 }
600                 if (c->is_default){
601                         def_jmp_bm=tail;
602                 } else{
603                         match[n].type=c->type;
604                         if (match[n].type == MATCH_STR){
605                                 for (j=0; j<n; j++){
606                                         if ( match[j].type == c->type &&
607                                                  match[j].l.s.len ==  c->label.match_str.len &&
608                                                  memcmp(match[j].l.s.s, c->label.match_str.s,
609                                                                         match[j].l.s.len) == 0 ){
610                                                 LOG(L_ERR, "ERROR: fix_match: duplicate case"
611                                                                 " (%d,%d)\n", c->ct_rve->fpos.s_line,
612                                                                 c->ct_rve->fpos.s_col);
613                                                 ret=E_UNSPEC;
614                                                 goto error;
615                                         }
616                                 }
617                                 match[n].flags=0;
618                                 match[n].l.s=c->label.match_str;
619                                 c->label.match_str.s=0; /* prevent s being freed */
620                                 c->label.match_str.len=0;
621                         } else {
622                                 match[n].flags=c->re_flags | REG_EXTENDED | REG_NOSUB;
623                                 match[n].l.regex=c->label.match_re;
624                                 c->label.match_re=0;
625                         }
626                         jmp_bm[n]=tail;
627                         n++;
628                 }
629                 if (c->actions)
630                         tail=&a->next;
631         }
632         /* handle constant rve w/ no side-effects: replace the whole case 
633            with the case rve block */
634         if ( (scr_opt_lev>=2) &&
635                         !rve_has_side_effects(m_rve) && rve_is_constant(m_rve)){
636                 if ((rv=rval_expr_eval(0, 0, m_rve)) == 0){
637                         LOG(L_ERR, "ERROR: fix_match: bad expression (%d,%d)\n", 
638                                         m_rve->fpos.s_line, m_rve->fpos.s_col);
639                         ret=E_UNSPEC;
640                         goto error;
641                 }
642                 if (rval_get_str(0, 0, &s, rv, 0) < 0 ){
643                                 LOG(L_ERR, "ERROR: fix_match (%d,%d): bad string expression\n",
644                                                 m_rve->fpos.s_line,
645                                                 m_rve->fpos.s_col);
646                         ret=E_UNSPEC;
647                         goto error;
648                 }
649                 /* start with the "default:" value in case nothing is found */
650                 block=def_jmp_bm?*def_jmp_bm:0;
651                 for (i=0; i<n; i++){
652                         if (((match[i].type == MATCH_STR) && (match[i].l.s.len == s.len) &&
653                                         (memcmp(match[i].l.s.s, s.s, s.len) == 0)) ||
654                                 ((match[i].type == MATCH_RE) && 
655                                         regexec(match[i].l.regex, s.s, 0, 0, 0) == 0) ) {
656                                 block=*jmp_bm[i];
657                                 break;
658                         }
659                 }
660                 DBG("MATCH: constant switch(\"%.*s\") with %d cases optimized away"
661                                 " to case no. %d\n", s.len, ZSW(s.s), n, i);
662                 /* cleanup */
663                 rval_destroy(rv);
664                 rv=0;
665                 pkg_free(s.s);
666                 s.s=0;
667                 s.len=0;
668                 ret=0;
669                 /* replace with BLOCK_ST */
670                 rve_destroy(m_rve);
671                 destroy_case_stms(t->val[1].u.data);
672                 t->type=BLOCK_T;
673                 t->val[0].type=BLOCK_ST;
674                 t->val[0].u.data=block;
675                 t->val[1].type=0;
676                 t->val[1].u.data=0;
677                 goto end;
678         }
679         mct=mk_match_cond_table(n);
680         if (mct==0){
681                 LOG(L_ERR, "ERROR: fix_match: memory allocation error\n");
682                 ret=E_OUT_OF_MEM;
683                 goto error;
684         }
685         mct->n=n;
686         for (i=0; i<n; i++){
687                 mct->match[i]=match[i];
688                 mct->jump[i]=*jmp_bm[i];
689         }
690         mct->def=def_jmp_bm?*def_jmp_bm:0;
691         t->type=MATCH_COND_T;
692         t->val[1].type=MATCH_CONDTABLE_ST;
693         t->val[1].u.data=mct;
694         DBG("MATCH: optimized to match condtable (%d) default: %s\n ",
695                                 mct->n, mct->def?"yes":"no");
696                 ret=0;
697 end:
698 error:
699         if (match) pkg_free(match);
700         if (jmp_bm) pkg_free(jmp_bm);
701         /* cleanup rv & s*/
702         if (rv) rval_destroy(rv);
703         if (s.s) pkg_free(s.s);
704         return ret;
705 }
706 /* vi: set ts=4 sw=4 tw=79:ai:cindent: */