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