formatting fixes (bug #4736)
[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     (-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               ((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 TOK_COMPL { $$ = 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   { $$ = 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         | expr TOK_COND expr TOK_COLONCOLON expr  { $$ = op_cond ($1, $3, $5); 
221                                 @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
222                                                         @$.first_line=0; @$.last_line=0;}
223         ;
224
225 %%
226
227 static struct val *
228 make_integer (quad_t i)
229 {
230         struct val *vp;
231
232         vp = (struct val *) malloc (sizeof (*vp));
233         if (vp == NULL) {
234                 ast_log(LOG_WARNING, "malloc() failed\n");
235                 return(NULL);
236         }
237
238         vp->type = AST_EXPR_integer;
239         vp->u.i  = i;
240         return vp; 
241 }
242
243 static struct val *
244 make_str (const char *s)
245 {
246         struct val *vp;
247         size_t i;
248         int isint;
249
250         vp = (struct val *) malloc (sizeof (*vp));
251         if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
252                 ast_log(LOG_WARNING,"malloc() failed\n");
253                 return(NULL);
254         }
255
256         for(i = 1, isint = isdigit(s[0]) || s[0] == '-';
257             isint && i < strlen(s);
258             i++)
259         {
260                 if(!isdigit(s[i]))
261                          isint = 0;
262         }
263
264         if (isint)
265                 vp->type = AST_EXPR_numeric_string;
266         else    
267                 vp->type = AST_EXPR_string;
268
269         return vp;
270 }
271
272
273 static void
274 free_value (struct val *vp)
275 {       
276         if (vp==NULL) {
277                 return;
278         }
279         if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string)
280                 free (vp->u.s); 
281 }
282
283
284 static quad_t
285 to_integer (struct val *vp)
286 {
287         quad_t i;
288         
289         if (vp == NULL) {
290                 ast_log(LOG_WARNING,"vp==NULL in to_integer()\n");
291                 return(0);
292         }
293
294         if (vp->type == AST_EXPR_integer)
295                 return 1;
296
297         if (vp->type == AST_EXPR_string)
298                 return 0;
299
300         /* vp->type == AST_EXPR_numeric_string, make it numeric */
301         errno = 0;
302         i  = strtoll(vp->u.s, (char**)NULL, 10);
303         if (errno != 0) {
304                 ast_log(LOG_WARNING,"Conversion of %s to integer under/overflowed!\n", vp->u.s);
305                 free(vp->u.s);
306                 vp->u.s = 0;
307                 return(0);
308         }
309         free (vp->u.s);
310         vp->u.i = i;
311         vp->type = AST_EXPR_integer;
312         return 1;
313 }
314
315 static void
316 strip_quotes(struct val *vp)
317 {
318         if (vp->type != AST_EXPR_string && vp->type != AST_EXPR_numeric_string)
319                 return;
320         
321         if( vp->u.s[0] == '"' && vp->u.s[strlen(vp->u.s)-1] == '"' )
322         {
323                 char *f, *t;
324                 f = vp->u.s;
325                 t = vp->u.s;
326                 
327                 while( *f )
328                 {
329                         if( *f  && *f != '"' )
330                                 *t++ = *f++;
331                         else
332                                 f++;
333                 }
334                 *t = *f;
335         }
336 }
337
338 static void
339 to_string (struct val *vp)
340 {
341         char *tmp;
342
343         if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string)
344                 return;
345
346         tmp = malloc ((size_t)25);
347         if (tmp == NULL) {
348                 ast_log(LOG_WARNING,"malloc() failed\n");
349                 return;
350         }
351
352         sprintf (tmp, "%lld", (long long)vp->u.i);
353         vp->type = AST_EXPR_string;
354         vp->u.s  = tmp;
355 }
356
357
358 static int
359 isstring (struct val *vp)
360 {
361         /* only TRUE if this string is not a valid integer */
362         return (vp->type == AST_EXPR_string);
363 }
364
365
366 static int
367 is_zero_or_null (struct val *vp)
368 {
369         if (vp->type == AST_EXPR_integer) {
370                 return (vp->u.i == 0);
371         } else {
372                 return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
373         }
374         /* NOTREACHED */
375 }
376
377 #ifdef STANDALONE
378
379 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
380 {
381         va_list vars;
382         va_start(vars,fmt);
383         
384         printf("LOG: lev:%d file:%s  line:%d func: %s  ",
385                    level, file, line, function);
386         vprintf(fmt, vars);
387         fflush(stdout);
388         va_end(vars);
389 }
390
391
392 int main(int argc,char **argv) {
393         char *s;
394
395         s=ast_expr(argv[1]);
396
397         printf("=====%s======\n",s);
398 }
399
400 #endif
401
402 #undef ast_yyerror
403 #define ast_yyerror(x) ast_yyerror(x, YYLTYPE *yylloc, struct parse_io *parseio)
404
405 /* I put the ast_yyerror func in the flex input file,
406    because it refers to the buffer state. Best to
407    let it access the BUFFER stuff there and not trying
408    define all the structs, macros etc. in this file! */
409
410
411 static struct val *
412 op_or (struct val *a, struct val *b)
413 {
414         if (is_zero_or_null (a)) {
415                 free_value (a);
416                 return (b);
417         } else {
418                 free_value (b);
419                 return (a);
420         }
421 }
422                 
423 static struct val *
424 op_and (struct val *a, struct val *b)
425 {
426         if (is_zero_or_null (a) || is_zero_or_null (b)) {
427                 free_value (a);
428                 free_value (b);
429                 return (make_integer ((quad_t)0));
430         } else {
431                 free_value (b);
432                 return (a);
433         }
434 }
435
436 static struct val *
437 op_eq (struct val *a, struct val *b)
438 {
439         struct val *r; 
440
441         if (isstring (a) || isstring (b)) {
442                 to_string (a);
443                 to_string (b);  
444                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) == 0));
445         } else {
446 #ifdef DEBUG_FOR_CONVERSIONS
447                 char buffer[2000];
448                 sprintf(buffer,"Converting '%s' and '%s' ", a->u.s, b->u.s);
449 #endif
450                 (void)to_integer(a);
451                 (void)to_integer(b);
452 #ifdef DEBUG_FOR_CONVERSIONS
453                 ast_log(LOG_WARNING,"%s to '%lld' and '%lld'\n", buffer, a->u.i, b->u.i);
454 #endif
455                 r = make_integer ((quad_t)(a->u.i == b->u.i));
456         }
457
458         free_value (a);
459         free_value (b);
460         return r;
461 }
462
463 static struct val *
464 op_gt (struct val *a, struct val *b)
465 {
466         struct val *r;
467
468         if (isstring (a) || isstring (b)) {
469                 to_string (a);
470                 to_string (b);
471                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) > 0));
472         } else {
473                 (void)to_integer(a);
474                 (void)to_integer(b);
475                 r = make_integer ((quad_t)(a->u.i > b->u.i));
476         }
477
478         free_value (a);
479         free_value (b);
480         return r;
481 }
482
483 static struct val *
484 op_lt (struct val *a, struct val *b)
485 {
486         struct val *r;
487
488         if (isstring (a) || isstring (b)) {
489                 to_string (a);
490                 to_string (b);
491                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) < 0));
492         } else {
493                 (void)to_integer(a);
494                 (void)to_integer(b);
495                 r = make_integer ((quad_t)(a->u.i < b->u.i));
496         }
497
498         free_value (a);
499         free_value (b);
500         return r;
501 }
502
503 static struct val *
504 op_ge (struct val *a, struct val *b)
505 {
506         struct val *r;
507
508         if (isstring (a) || isstring (b)) {
509                 to_string (a);
510                 to_string (b);
511                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) >= 0));
512         } else {
513                 (void)to_integer(a);
514                 (void)to_integer(b);
515                 r = make_integer ((quad_t)(a->u.i >= b->u.i));
516         }
517
518         free_value (a);
519         free_value (b);
520         return r;
521 }
522
523 static struct val *
524 op_le (struct val *a, struct val *b)
525 {
526         struct val *r;
527
528         if (isstring (a) || isstring (b)) {
529                 to_string (a);
530                 to_string (b);
531                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) <= 0));
532         } else {
533                 (void)to_integer(a);
534                 (void)to_integer(b);
535                 r = make_integer ((quad_t)(a->u.i <= b->u.i));
536         }
537
538         free_value (a);
539         free_value (b);
540         return r;
541 }
542
543 static struct val *
544 op_cond (struct val *a, struct val *b, struct val *c)
545 {
546         struct val *r;
547
548         if( isstring(a) )
549         {
550                 if( strlen(a->u.s) && strcmp(a->u.s, "\"\"") != 0 && strcmp(a->u.s,"0") != 0 )
551                 {
552                         free_value(a);
553                         free_value(c);
554                         r = b;
555                 }
556                 else
557                 {
558                         free_value(a);
559                         free_value(b);
560                         r = c;
561                 }
562         }
563         else
564         {
565                 (void)to_integer(a);
566                 if( a->u.i )
567                 {
568                         free_value(a);
569                         free_value(c);
570                         r = b;
571                 }
572                 else
573                 {
574                         free_value(a);
575                         free_value(b);
576                         r = c;
577                 }
578         }
579         return r;
580 }
581
582 static struct val *
583 op_ne (struct val *a, struct val *b)
584 {
585         struct val *r;
586
587         if (isstring (a) || isstring (b)) {
588                 to_string (a);
589                 to_string (b);
590                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) != 0));
591         } else {
592                 (void)to_integer(a);
593                 (void)to_integer(b);
594                 r = make_integer ((quad_t)(a->u.i != b->u.i));
595         }
596
597         free_value (a);
598         free_value (b);
599         return r;
600 }
601
602 static int
603 chk_plus (quad_t a, quad_t b, quad_t r)
604 {
605         /* sum of two positive numbers must be positive */
606         if (a > 0 && b > 0 && r <= 0)
607                 return 1;
608         /* sum of two negative numbers must be negative */
609         if (a < 0 && b < 0 && r >= 0)
610                 return 1;
611         /* all other cases are OK */
612         return 0;
613 }
614
615 static struct val *
616 op_plus (struct val *a, struct val *b)
617 {
618         struct val *r;
619
620         if (!to_integer (a)) {
621                 ast_log(LOG_WARNING,"non-numeric argument\n");
622                 if (!to_integer (b)) {
623                         free_value(a);
624                         free_value(b);
625                         return make_integer(0);
626                 } else {
627                         free_value(a);
628                         return (b);
629                 }
630         } else if (!to_integer(b)) {
631                 free_value(b);
632                 return (a);
633         }
634
635         r = make_integer (/*(quad_t)*/(a->u.i + b->u.i));
636         if (chk_plus (a->u.i, b->u.i, r->u.i)) {
637                 ast_log(LOG_WARNING,"overflow\n");
638         }
639         free_value (a);
640         free_value (b);
641         return r;
642 }
643
644 static int
645 chk_minus (quad_t a, quad_t b, quad_t r)
646 {
647         /* special case subtraction of QUAD_MIN */
648         if (b == QUAD_MIN) {
649                 if (a >= 0)
650                         return 1;
651                 else
652                         return 0;
653         }
654         /* this is allowed for b != QUAD_MIN */
655         return chk_plus (a, -b, r);
656 }
657
658 static struct val *
659 op_minus (struct val *a, struct val *b)
660 {
661         struct val *r;
662
663         if (!to_integer (a)) {
664                 ast_log(LOG_WARNING, "non-numeric argument\n");
665                 if (!to_integer (b)) {
666                         free_value(a);
667                         free_value(b);
668                         return make_integer(0);
669                 } else {
670                         r = make_integer(0 - b->u.i);
671                         free_value(a);
672                         free_value(b);
673                         return (r);
674                 }
675         } else if (!to_integer(b)) {
676                 ast_log(LOG_WARNING, "non-numeric argument\n");
677                 free_value(b);
678                 return (a);
679         }
680
681         r = make_integer (/*(quad_t)*/(a->u.i - b->u.i));
682         if (chk_minus (a->u.i, b->u.i, r->u.i)) {
683                 ast_log(LOG_WARNING, "overflow\n");
684         }
685         free_value (a);
686         free_value (b);
687         return r;
688 }
689
690 static struct val *
691 op_negate (struct val *a)
692 {
693         struct val *r;
694
695         if (!to_integer (a) ) {
696                 free_value(a);
697                 ast_log(LOG_WARNING, "non-numeric argument\n");
698                 return make_integer(0);
699         }
700
701         r = make_integer (/*(quad_t)*/(- a->u.i));
702         if (chk_minus (0, a->u.i, r->u.i)) {
703                 ast_log(LOG_WARNING, "overflow\n");
704         }
705         free_value (a);
706         return r;
707 }
708
709 static struct val *
710 op_compl (struct val *a)
711 {
712         int v1 = 1;
713         struct val *r;
714         
715         if( !a )
716         {
717                 v1 = 0;
718         }
719         else
720         {
721                 switch( a->type )
722                 {
723                 case AST_EXPR_integer:
724                         if( a->u.i == 0 )
725                                 v1 = 0;
726                         break;
727                         
728                 case AST_EXPR_string:
729                         if( a->u.s == 0 )
730                                 v1 = 0;
731                         else
732                         {
733                                 if( a->u.s[0] == 0 )
734                                         v1 = 0;
735                                 else if (strlen(a->u.s) == 1 && a->u.s[0] == '0' )
736                                         v1 = 0;
737                         }
738                         break;
739                         
740                 case AST_EXPR_numeric_string:
741                         if( a->u.s == 0 )
742                                 v1 = 0;
743                         else
744                         {
745                                 if( a->u.s[0] == 0 )
746                                         v1 = 0;
747                                 else if (strlen(a->u.s) == 1 && a->u.s[0] == '0' )
748                                         v1 = 0;
749                         }
750                         break;
751                 }
752         }
753         
754         r = make_integer (!v1);
755         free_value (a);
756         return r;
757 }
758
759 static int
760 chk_times (quad_t a, quad_t b, quad_t r)
761 {
762         /* special case: first operand is 0, no overflow possible */
763         if (a == 0)
764                 return 0;
765         /* cerify that result of division matches second operand */
766         if (r / a != b)
767                 return 1;
768         return 0;
769 }
770
771 static struct val *
772 op_times (struct val *a, struct val *b)
773 {
774         struct val *r;
775
776         if (!to_integer (a) || !to_integer (b)) {
777                 free_value(a);
778                 free_value(b);
779                 ast_log(LOG_WARNING, "non-numeric argument\n");
780                 return(make_integer(0));
781         }
782
783         r = make_integer (/*(quad_t)*/(a->u.i * b->u.i));
784         if (chk_times (a->u.i, b->u.i, r->u.i)) {
785                 ast_log(LOG_WARNING, "overflow\n");
786         }
787         free_value (a);
788         free_value (b);
789         return (r);
790 }
791
792 static int
793 chk_div (quad_t a, quad_t b)
794 {
795         /* div by zero has been taken care of before */
796         /* only QUAD_MIN / -1 causes overflow */
797         if (a == QUAD_MIN && b == -1)
798                 return 1;
799         /* everything else is OK */
800         return 0;
801 }
802
803 static struct val *
804 op_div (struct val *a, struct val *b)
805 {
806         struct val *r;
807
808         if (!to_integer (a)) {
809                 free_value(a);
810                 free_value(b);
811                 ast_log(LOG_WARNING, "non-numeric argument\n");
812                 return make_integer(0);
813         } else if (!to_integer (b)) {
814                 free_value(a);
815                 free_value(b);
816                 ast_log(LOG_WARNING, "non-numeric argument\n");
817                 return make_integer(INT_MAX);
818         }
819
820         if (b->u.i == 0) {
821                 ast_log(LOG_WARNING, "division by zero\n");             
822                 free_value(a);
823                 free_value(b);
824                 return make_integer(INT_MAX);
825         }
826
827         r = make_integer (/*(quad_t)*/(a->u.i / b->u.i));
828         if (chk_div (a->u.i, b->u.i)) {
829                 ast_log(LOG_WARNING, "overflow\n");
830         }
831         free_value (a);
832         free_value (b);
833         return r;
834 }
835         
836 static struct val *
837 op_rem (struct val *a, struct val *b)
838 {
839         struct val *r;
840
841         if (!to_integer (a) || !to_integer (b)) {
842                 ast_log(LOG_WARNING, "non-numeric argument\n");
843                 free_value(a);
844                 free_value(b);
845                 return make_integer(0);
846         }
847
848         if (b->u.i == 0) {
849                 ast_log(LOG_WARNING, "div by zero\n");
850                 free_value(a);
851                 return(b);
852         }
853
854         r = make_integer (/*(quad_t)*/(a->u.i % b->u.i));
855         /* chk_rem necessary ??? */
856         free_value (a);
857         free_value (b);
858         return r;
859 }
860         
861
862 static struct val *
863 op_colon (struct val *a, struct val *b)
864 {
865         regex_t rp;
866         regmatch_t rm[2];
867         char errbuf[256];
868         int eval;
869         struct val *v;
870
871         /* coerce to both arguments to strings */
872         to_string(a);
873         to_string(b);
874         /* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
875         strip_quotes(a);
876         strip_quotes(b);
877         /* compile regular expression */
878         if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
879                 regerror (eval, &rp, errbuf, sizeof(errbuf));
880                 ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
881                 free_value(a);
882                 free_value(b);
883                 return make_str("");            
884         }
885
886         /* compare string against pattern */
887         /* remember that patterns are anchored to the beginning of the line */
888         if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
889                 if (rm[1].rm_so >= 0) {
890                         *(a->u.s + rm[1].rm_eo) = '\0';
891                         v = make_str (a->u.s + rm[1].rm_so);
892
893                 } else {
894                         v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
895                 }
896         } else {
897                 if (rp.re_nsub == 0) {
898                         v = make_integer ((quad_t)0);
899                 } else {
900                         v = make_str ("");
901                 }
902         }
903
904         /* free arguments and pattern buffer */
905         free_value (a);
906         free_value (b);
907         regfree (&rp);
908
909         return v;
910 }
911         
912
913 static struct val *
914 op_eqtilde (struct val *a, struct val *b)
915 {
916         regex_t rp;
917         regmatch_t rm[2];
918         char errbuf[256];
919         int eval;
920         struct val *v;
921
922         /* coerce to both arguments to strings */
923         to_string(a);
924         to_string(b);
925         /* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
926         strip_quotes(a);
927         strip_quotes(b);
928         /* compile regular expression */
929         if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
930                 regerror (eval, &rp, errbuf, sizeof(errbuf));
931                 ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
932                 free_value(a);
933                 free_value(b);
934                 return make_str("");            
935         }
936
937         /* compare string against pattern */
938         /* remember that patterns are anchored to the beginning of the line */
939         if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 ) {
940                 if (rm[1].rm_so >= 0) {
941                         *(a->u.s + rm[1].rm_eo) = '\0';
942                         v = make_str (a->u.s + rm[1].rm_so);
943
944                 } else {
945                         v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
946                 }
947         } else {
948                 if (rp.re_nsub == 0) {
949                         v = make_integer ((quad_t)0);
950                 } else {
951                         v = make_str ("");
952                 }
953         }
954
955         /* free arguments and pattern buffer */
956         free_value (a);
957         free_value (b);
958         regfree (&rp);
959
960         return v;
961 }