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