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