Update chanelog
[asterisk/asterisk.git] / ast_expr.y
1 %{
2 /* Written by Pace Willisson (pace@blitz.com) 
3  * and placed in the public domain.
4  *
5  * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
6  *
7  * $FreeBSD: src/bin/expr/expr.y,v 1.16 2000/07/22 10:59:36 se Exp $
8  */
9
10 #include <sys/types.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <locale.h>
15 #include <ctype.h>
16 #include <err.h>
17 #include <errno.h>
18 #include <regex.h>
19 #include <limits.h>
20 #include <asterisk/ast_expr.h>
21 #include <asterisk/logger.h>
22
23 #ifdef LONG_LONG_MIN
24 #define QUAD_MIN LONG_LONG_MIN
25 #endif
26 #ifdef LONG_LONG_MAX
27 #define QUAD_MAX LONG_LONG_MAX
28 #endif
29
30 #  if ! defined(QUAD_MIN)
31 #   define QUAD_MIN     (-0x7fffffffffffffffL-1)
32 #  endif
33 #  if ! defined(QUAD_MAX)
34 #   define QUAD_MAX     (0x7fffffffffffffffL)
35 #  endif
36
37 #define YYPARSE_PARAM kota
38 #define YYLEX_PARAM kota
39
40 /* #define ast_log fprintf
41 #define LOG_WARNING stderr */
42   
43 enum valtype {
44         integer, numeric_string, string
45 } ;
46
47 struct val {
48         enum valtype type;
49         union {
50                 char *s;
51                 quad_t i;
52         } u;
53 } ;
54
55 struct parser_control {
56         struct val *result;
57         int pipa;
58         char *arg_orig;
59         char *argv;
60         char *ptrptr;
61         int firsttoken;
62 } ;
63
64 static int              chk_div __P((quad_t, quad_t));
65 static int              chk_minus __P((quad_t, quad_t, quad_t));
66 static int              chk_plus __P((quad_t, quad_t, quad_t));
67 static int              chk_times __P((quad_t, quad_t, quad_t));
68 static void             free_value __P((struct val *));
69 static int              is_zero_or_null __P((struct val *));
70 static int              isstring __P((struct val *));
71 static struct val       *make_integer __P((quad_t));
72 static struct val       *make_str __P((const char *));
73 static struct val       *op_and __P((struct val *, struct val *));
74 static struct val       *op_colon __P((struct val *, struct val *));
75 static struct val       *op_div __P((struct val *, struct val *));
76 static struct val       *op_eq __P((struct val *, struct val *));
77 static struct val       *op_ge __P((struct val *, struct val *));
78 static struct val       *op_gt __P((struct val *, struct val *));
79 static struct val       *op_le __P((struct val *, struct val *));
80 static struct val       *op_lt __P((struct val *, struct val *));
81 static struct val       *op_minus __P((struct val *, struct val *));
82 static struct val       *op_ne __P((struct val *, struct val *));
83 static struct val       *op_or __P((struct val *, struct val *));
84 static struct val       *op_plus __P((struct val *, struct val *));
85 static struct val       *op_rem __P((struct val *, struct val *));
86 static struct val       *op_times __P((struct val *, struct val *));
87 static quad_t           to_integer __P((struct val *));
88 static void             to_string __P((struct val *));
89
90 /* uh, if I want to predeclare yylex with a YYLTYPE, I have to predeclare the yyltype... sigh */
91 typedef struct yyltype
92 {
93   int first_line;
94   int first_column;
95
96   int last_line;
97   int last_column;
98 } yyltype;
99
100 # define YYLTYPE yyltype
101 # define YYLTYPE_IS_TRIVIAL 1
102
103 static int              ast_yyerror __P((const char *,YYLTYPE *, struct parser_control *));
104
105 #define ast_yyerror(x) ast_yyerror(x,&yyloc,kota)
106
107 %}
108
109 %pure-parser
110 %locations
111 /* %debug  for when you are having big problems */
112
113 /* %name-prefix="ast_yy" */
114
115 %union
116 {
117         struct val *val;
118 }
119
120 %{
121 static int              ast_yylex __P((YYSTYPE *, YYLTYPE *, struct parser_control *));
122 %}
123
124
125 %left <val> '|'
126 %left <val> '&'
127 %left <val> '=' '>' '<' GE LE NE
128 %left <val> '+' '-'
129 %left <val> '*' '/' '%'
130 %left <val> ':'
131
132 %token <val> TOKEN
133 %type <val> start expr
134
135 %%
136
137 start: expr { ((struct parser_control *)kota)->result = $$; }
138         ;
139
140 expr:   TOKEN
141         | '(' expr ')' { $$ = $2; @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
142         | expr '|' expr { $$ = op_or ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
143         | expr '&' expr { $$ = op_and ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
144         | expr '=' expr { $$ = op_eq ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
145         | expr '>' expr { $$ = op_gt ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
146         | expr '<' expr { $$ = op_lt ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
147         | expr GE expr  { $$ = op_ge ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
148         | expr LE expr  { $$ = op_le ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
149         | expr NE expr  { $$ = op_ne ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
150         | expr '+' expr { $$ = op_plus ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
151         | expr '-' expr { $$ = op_minus ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
152         | expr '*' expr { $$ = op_times ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
153         | expr '/' expr { $$ = op_div ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
154         | expr '%' expr { $$ = op_rem ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
155         | expr ':' expr { $$ = op_colon ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
156         ;
157
158
159 %%
160
161 static struct val *
162 make_integer (i)
163 quad_t i;
164 {
165         struct val *vp;
166
167         vp = (struct val *) malloc (sizeof (*vp));
168         if (vp == NULL) {
169                 ast_log(LOG_WARNING, "malloc() failed\n");
170                 return(NULL);
171         }
172
173         vp->type = integer;
174         vp->u.i  = i;
175         return vp; 
176 }
177
178 static struct val *
179 make_str (s)
180 const char *s;
181 {
182         struct val *vp;
183         size_t i;
184         int isint;
185
186         vp = (struct val *) malloc (sizeof (*vp));
187         if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
188                 ast_log(LOG_WARNING,"malloc() failed\n");
189                 return(NULL);
190         }
191
192         for(i = 1, isint = isdigit(s[0]) || s[0] == '-';
193             isint && i < strlen(s);
194             i++)
195         {
196                 if(!isdigit(s[i]))
197                          isint = 0;
198         }
199
200         if (isint)
201                 vp->type = numeric_string;
202         else    
203                 vp->type = string;
204
205         return vp;
206 }
207
208
209 static void
210 free_value (vp)
211 struct val *vp;
212 {       
213         if (vp==NULL) {
214                 return;
215         }
216         if (vp->type == string || vp->type == numeric_string)
217                 free (vp->u.s); 
218 }
219
220
221 static quad_t
222 to_integer (vp)
223 struct val *vp;
224 {
225         quad_t i;
226
227         if (vp == NULL) {
228                 ast_log(LOG_WARNING,"vp==NULL in to_integer()\n");
229                 return(0);
230         }
231
232         if (vp->type == integer)
233                 return 1;
234
235         if (vp->type == string)
236                 return 0;
237
238         /* vp->type == numeric_string, make it numeric */
239         errno = 0;
240         i  = strtoq(vp->u.s, (char**)NULL, 10);
241         if (errno != 0) {
242                 free(vp->u.s);
243                 ast_log(LOG_WARNING,"overflow\n");
244                 return(0);
245         }
246         free (vp->u.s);
247         vp->u.i = i;
248         vp->type = integer;
249         return 1;
250 }
251
252 static void
253 to_string (vp)
254 struct val *vp;
255 {
256         char *tmp;
257
258         if (vp->type == string || vp->type == numeric_string)
259                 return;
260
261         tmp = malloc ((size_t)25);
262         if (tmp == NULL) {
263                 ast_log(LOG_WARNING,"malloc() failed\n");
264                 return;
265         }
266
267         sprintf (tmp, "%lld", (long long)vp->u.i);
268         vp->type = string;
269         vp->u.s  = tmp;
270 }
271
272
273 static int
274 isstring (vp)
275 struct val *vp;
276 {
277         /* only TRUE if this string is not a valid integer */
278         return (vp->type == string);
279 }
280
281 static int
282 ast_yylex (YYSTYPE *lvalp, YYLTYPE *yylloc, struct parser_control *karoto)
283 {
284         char *p=0;
285         char *t1=0;
286         char savep = 0;
287         char *savepp = 0;
288         
289         if (karoto->firsttoken==1) {
290                 t1 = karoto->argv;
291                 karoto->firsttoken = 0;
292         } else {
293                 t1 = karoto->ptrptr;
294         }
295         
296         while(*t1 && *t1 == ' ' )  /* we can remove worries about leading/multiple spaces being present */
297                 t1++;
298         karoto->ptrptr = t1;
299         yylloc->first_column = t1 - karoto->argv;
300         
301         while( *t1 && *t1 != ' ' && *t1 != '"') /* find the next space or quote */
302                 t1++;
303         if( *t1 == ' ' )
304         {
305                 *t1 = 0;
306                 p = karoto->ptrptr;
307                 karoto->ptrptr = t1+1;
308                 yylloc->last_column = t1 - karoto->argv;
309         }
310         else if (*t1 == '"' )
311         {
312                 /* opening quote. find the closing quote */
313                 char *t2=t1+1;
314                 while( *t2 && *t2 != '"')
315                         t2++;
316                 if( *t2 == '"' )
317                 {
318                         if( *(t2+1) == ' ' || *(t2+1) == 0 )
319                         {
320                                 if( *(t2+1) )
321                                 {
322                                         *(t2+1) = 0;
323                                         karoto->ptrptr = t2+2;
324                                 }
325                                 else
326                                 {
327                                         karoto->ptrptr = t2+1;
328                                 }
329                         }
330                         else
331                         {
332                                 /* hmmm. what if another token is here? */
333                                 /* maybe we can insert a space? */
334                                 savep = *(t2+1);
335                                 savepp = t2+1;
336                                 *(t2+1) = 0;
337                                 karoto->ptrptr = t2+1;
338                         }
339                         p = t1;
340                 }
341                 else
342                 {
343                         /* NOT GOOD -- no closing quote! */
344                         p = t1;
345                         karoto->ptrptr = t2;
346                 }
347                 yylloc->last_column = t2 - karoto->argv;
348         }
349         else if( *t1 == 0 )
350         {
351                 if( t1 != karoto->ptrptr )
352                 {
353                         /* this is the last token */
354                         p = karoto->ptrptr;
355                         karoto->ptrptr = t1;
356                 }
357                 else
358                 {
359                         /* we are done. That was quick */
360                         p = karoto->ptrptr;
361                         yylloc->last_column = t1 - karoto->argv;
362                 }
363         }
364         if( *p == 0 )
365                 p = 0;
366         
367         if (p==NULL) {
368                 return (0);
369         }
370
371
372         if (strlen (p) == 1) {
373                 if (strchr ("|&=<>+-*/%:()", *p))
374                         return (*p);
375         } else if (strlen (p) == 2 && p[1] == '=') {
376                 switch (*p) {
377                 case '>': return (GE);
378                 case '<': return (LE);
379                 case '!': return (NE);
380                 }
381         }
382
383         lvalp->val = make_str (p);
384         if( savep )
385         {
386                 *savepp = savep; /* restore the null terminated string */
387                 savepp = 0;
388                 savep = 0;
389         }
390         return (TOKEN);
391 }
392
393 static int
394 is_zero_or_null (vp)
395 struct val *vp;
396 {
397         if (vp->type == integer) {
398                 return (vp->u.i == 0);
399         } else {
400                 return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
401         }
402         /* NOTREACHED */
403 }
404
405 char *ast_expr (char *arg)
406 {
407         struct parser_control karoto;
408
409         char *kota;
410         char *pirouni;
411         
412         kota=strdup(arg);
413         karoto.result = NULL;
414         karoto.firsttoken=1;
415         karoto.argv=kota;
416         karoto.arg_orig = arg;
417         /* ast_yydebug = 1; */
418         
419         ast_yyparse ((void *)&karoto);
420
421         free(kota);
422
423         if (karoto.result==NULL) {
424                 pirouni=strdup("0");
425                 return(pirouni);
426         } else {
427                 if (karoto.result->type == integer) {
428                         pirouni=malloc(256);
429                         sprintf (pirouni,"%lld", (long long)karoto.result->u.i);
430                 }
431                 else {
432                         pirouni=strdup(karoto.result->u.s);
433                 }
434                 free(karoto.result);
435         }
436         return(pirouni);
437 }
438
439 #ifdef STANDALONE
440
441 int main(int argc,char **argv) {
442         char *s;
443
444         s=ast_expr(argv[1]);
445
446         printf("=====%s======\n",s);
447 }
448
449 #endif
450
451 #undef ast_yyerror
452 #define ast_yyerror(x) ast_yyerror(x, YYLTYPE *yylloc, struct parser_control *karoto)
453
454 static int
455 ast_yyerror (const char *s)
456 {       
457         char spacebuf[8000]; /* best safe than sorry */
458         char spacebuf2[8000]; /* best safe than sorry */
459         int i=0;
460         spacebuf[0] = 0;
461         
462         if( yylloc->first_column > 7990 ) /* if things get out of whack, why crash? */
463                 yylloc->first_column = 7990;
464         if( yylloc->last_column > 7990 )
465                 yylloc->last_column = 7990;
466         for(i=0;i<yylloc->first_column;i++) spacebuf[i] = ' ';
467         for(   ;i<yylloc->last_column;i++) spacebuf[i] = '^';
468         spacebuf[i] = 0;
469
470         for(i=0;i<karoto->ptrptr-karoto->argv;i++) spacebuf2[i] = ' ';
471         spacebuf2[i++]='^';
472         spacebuf2[i]= 0;
473
474         ast_log(LOG_WARNING,"ast_yyerror(): syntax error: %s; Input:\n%s\n%s\n%s\n",s, 
475                         karoto->arg_orig,spacebuf,spacebuf2);
476         return(0);
477 }
478
479
480 static struct val *
481 op_or (a, b)
482 struct val *a, *b;
483 {
484         if (is_zero_or_null (a)) {
485                 free_value (a);
486                 return (b);
487         } else {
488                 free_value (b);
489                 return (a);
490         }
491 }
492                 
493 static struct val *
494 op_and (a, b)
495 struct val *a, *b;
496 {
497         if (is_zero_or_null (a) || is_zero_or_null (b)) {
498                 free_value (a);
499                 free_value (b);
500                 return (make_integer ((quad_t)0));
501         } else {
502                 free_value (b);
503                 return (a);
504         }
505 }
506
507 static struct val *
508 op_eq (a, b)
509 struct val *a, *b;
510 {
511         struct val *r; 
512
513         if (isstring (a) || isstring (b)) {
514                 to_string (a);
515                 to_string (b);  
516                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) == 0));
517         } else {
518                 (void)to_integer(a);
519                 (void)to_integer(b);
520                 r = make_integer ((quad_t)(a->u.i == b->u.i));
521         }
522
523         free_value (a);
524         free_value (b);
525         return r;
526 }
527
528 static struct val *
529 op_gt (a, b)
530 struct val *a, *b;
531 {
532         struct val *r;
533
534         if (isstring (a) || isstring (b)) {
535                 to_string (a);
536                 to_string (b);
537                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) > 0));
538         } else {
539                 (void)to_integer(a);
540                 (void)to_integer(b);
541                 r = make_integer ((quad_t)(a->u.i > b->u.i));
542         }
543
544         free_value (a);
545         free_value (b);
546         return r;
547 }
548
549 static struct val *
550 op_lt (a, b)
551 struct val *a, *b;
552 {
553         struct val *r;
554
555         if (isstring (a) || isstring (b)) {
556                 to_string (a);
557                 to_string (b);
558                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) < 0));
559         } else {
560                 (void)to_integer(a);
561                 (void)to_integer(b);
562                 r = make_integer ((quad_t)(a->u.i < b->u.i));
563         }
564
565         free_value (a);
566         free_value (b);
567         return r;
568 }
569
570 static struct val *
571 op_ge (a, b)
572 struct val *a, *b;
573 {
574         struct val *r;
575
576         if (isstring (a) || isstring (b)) {
577                 to_string (a);
578                 to_string (b);
579                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) >= 0));
580         } else {
581                 (void)to_integer(a);
582                 (void)to_integer(b);
583                 r = make_integer ((quad_t)(a->u.i >= b->u.i));
584         }
585
586         free_value (a);
587         free_value (b);
588         return r;
589 }
590
591 static struct val *
592 op_le (a, b)
593 struct val *a, *b;
594 {
595         struct val *r;
596
597         if (isstring (a) || isstring (b)) {
598                 to_string (a);
599                 to_string (b);
600                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) <= 0));
601         } else {
602                 (void)to_integer(a);
603                 (void)to_integer(b);
604                 r = make_integer ((quad_t)(a->u.i <= b->u.i));
605         }
606
607         free_value (a);
608         free_value (b);
609         return r;
610 }
611
612 static struct val *
613 op_ne (a, b)
614 struct val *a, *b;
615 {
616         struct val *r;
617
618         if (isstring (a) || isstring (b)) {
619                 to_string (a);
620                 to_string (b);
621                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) != 0));
622         } else {
623                 (void)to_integer(a);
624                 (void)to_integer(b);
625                 r = make_integer ((quad_t)(a->u.i != b->u.i));
626         }
627
628         free_value (a);
629         free_value (b);
630         return r;
631 }
632
633 static int
634 chk_plus (a, b, r)
635 quad_t a, b, r;
636 {
637         /* sum of two positive numbers must be positive */
638         if (a > 0 && b > 0 && r <= 0)
639                 return 1;
640         /* sum of two negative numbers must be negative */
641         if (a < 0 && b < 0 && r >= 0)
642                 return 1;
643         /* all other cases are OK */
644         return 0;
645 }
646
647 static struct val *
648 op_plus (a, b)
649 struct val *a, *b;
650 {
651         struct val *r;
652
653         if (!to_integer (a) || !to_integer (b)) {
654                 ast_log(LOG_WARNING,"non-numeric argument\n");
655                 free_value(a);
656                 free_value(b);
657                 return(NULL);
658         }
659
660         r = make_integer (/*(quad_t)*/(a->u.i + b->u.i));
661         if (chk_plus (a->u.i, b->u.i, r->u.i)) {
662                 ast_log(LOG_WARNING,"overflow\n");
663                 free_value(a);
664                 free_value(b);
665                 return(NULL);
666         }
667         free_value (a);
668         free_value (b);
669         return r;
670 }
671
672 static int
673 chk_minus (a, b, r)
674 quad_t a, b, r;
675 {
676         /* special case subtraction of QUAD_MIN */
677         if (b == QUAD_MIN) {
678                 if (a >= 0)
679                         return 1;
680                 else
681                         return 0;
682         }
683         /* this is allowed for b != QUAD_MIN */
684         return chk_plus (a, -b, r);
685 }
686
687 static struct val *
688 op_minus (a, b)
689 struct val *a, *b;
690 {
691         struct val *r;
692
693         if (!to_integer (a) || !to_integer (b)) {
694                 free_value(a);
695                 free_value(b);
696                 ast_log(LOG_WARNING, "non-numeric argument\n");
697                 return(NULL);
698         }
699
700         r = make_integer (/*(quad_t)*/(a->u.i - b->u.i));
701         if (chk_minus (a->u.i, b->u.i, r->u.i)) {
702                 free_value(a);
703                 free_value(b);
704                 ast_log(LOG_WARNING, "overload\n");
705                 return(NULL);
706         }
707         free_value (a);
708         free_value (b);
709         return r;
710 }
711
712 static int
713 chk_times (a, b, r)
714 quad_t a, b, r;
715 {
716         /* special case: first operand is 0, no overflow possible */
717         if (a == 0)
718                 return 0;
719         /* cerify that result of division matches second operand */
720         if (r / a != b)
721                 return 1;
722         return 0;
723 }
724
725 static struct val *
726 op_times (a, b)
727 struct val *a, *b;
728 {
729         struct val *r;
730
731         if (!to_integer (a) || !to_integer (b)) {
732                 free_value(a);
733                 free_value(b);
734                 ast_log(LOG_WARNING, "non-numeric argument\n");
735                 return(NULL);
736         }
737
738         r = make_integer (/*(quad_t)*/(a->u.i * b->u.i));
739         if (chk_times (a->u.i, b->u.i, r->u.i)) {
740                 ast_log(LOG_WARNING, "overflow\n");
741                 free_value(a);
742                 free_value(b);
743                 return(NULL);
744         }
745         free_value (a);
746         free_value (b);
747         return (r);
748 }
749
750 static int
751 chk_div (a, b)
752 quad_t a, b;
753 {
754         /* div by zero has been taken care of before */
755         /* only QUAD_MIN / -1 causes overflow */
756         if (a == QUAD_MIN && b == -1)
757                 return 1;
758         /* everything else is OK */
759         return 0;
760 }
761
762 static struct val *
763 op_div (a, b)
764 struct val *a, *b;
765 {
766         struct val *r;
767
768         if (!to_integer (a) || !to_integer (b)) {
769                 free_value(a);
770                 free_value(b);
771                 ast_log(LOG_WARNING, "non-numeric argument\n");
772                 return(NULL);
773         }
774
775         if (b->u.i == 0) {
776                 ast_log(LOG_WARNING, "division by zero\n");             
777                 free_value(a);
778                 free_value(b);
779                 return(NULL);
780         }
781
782         r = make_integer (/*(quad_t)*/(a->u.i / b->u.i));
783         if (chk_div (a->u.i, b->u.i)) {
784                 ast_log(LOG_WARNING, "overflow\n");
785                 free_value(a);
786                 free_value(b);
787                 return(NULL);
788         }
789         free_value (a);
790         free_value (b);
791         return r;
792 }
793         
794 static struct val *
795 op_rem (a, b)
796 struct val *a, *b;
797 {
798         struct val *r;
799
800         if (!to_integer (a) || !to_integer (b)) {
801                 ast_log(LOG_WARNING, "non-numeric argument\n");
802                 free_value(a);
803                 free_value(b);
804                 return(NULL);
805         }
806
807         if (b->u.i == 0) {
808                 ast_log(LOG_WARNING, "div by zero\n");
809                 free_value(a);
810                 free_value(b);
811                 return(NULL);
812         }
813
814         r = make_integer (/*(quad_t)*/(a->u.i % b->u.i));
815         /* chk_rem necessary ??? */
816         free_value (a);
817         free_value (b);
818         return r;
819 }
820         
821 static struct val *
822 op_colon (a, b)
823 struct val *a, *b;
824 {
825         regex_t rp;
826         regmatch_t rm[2];
827         char errbuf[256];
828         int eval;
829         struct val *v;
830
831         /* coerce to both arguments to strings */
832         to_string(a);
833         to_string(b);
834
835         /* compile regular expression */
836         if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
837                 regerror (eval, &rp, errbuf, sizeof(errbuf));
838                 ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
839                 free_value(a);
840                 free_value(b);
841                 return(NULL);           
842         }
843
844         /* compare string against pattern */
845         /* remember that patterns are anchored to the beginning of the line */
846         if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
847                 if (rm[1].rm_so >= 0) {
848                         *(a->u.s + rm[1].rm_eo) = '\0';
849                         v = make_str (a->u.s + rm[1].rm_so);
850
851                 } else {
852                         v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
853                 }
854         } else {
855                 if (rp.re_nsub == 0) {
856                         v = make_integer ((quad_t)0);
857                 } else {
858                         v = make_str ("");
859                 }
860         }
861
862         /* free arguments and pattern buffer */
863         free_value (a);
864         free_value (b);
865         regfree (&rp);
866
867         return v;
868 }