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