don't make expression evaluator allocate a memory buffer for each result
[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 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               ((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, "%ld", (long int) 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[4096];
394         
395         if (ast_expr(argv[1], s, sizeof(s)))
396                 printf("=====%s======\n",s);
397         else
398                 printf("No result\n");
399 }
400
401 #endif
402
403 #undef ast_yyerror
404 #define ast_yyerror(x) ast_yyerror(x, YYLTYPE *yylloc, struct parse_io *parseio)
405
406 /* I put the ast_yyerror func in the flex input file,
407    because it refers to the buffer state. Best to
408    let it access the BUFFER stuff there and not trying
409    define all the structs, macros etc. in this file! */
410
411
412 static struct val *
413 op_or (struct val *a, struct val *b)
414 {
415         if (is_zero_or_null (a)) {
416                 free_value (a);
417                 return (b);
418         } else {
419                 free_value (b);
420                 return (a);
421         }
422 }
423                 
424 static struct val *
425 op_and (struct val *a, struct val *b)
426 {
427         if (is_zero_or_null (a) || is_zero_or_null (b)) {
428                 free_value (a);
429                 free_value (b);
430                 return (make_integer ((quad_t)0));
431         } else {
432                 free_value (b);
433                 return (a);
434         }
435 }
436
437 static struct val *
438 op_eq (struct val *a, struct val *b)
439 {
440         struct val *r; 
441
442         if (isstring (a) || isstring (b)) {
443                 to_string (a);
444                 to_string (b);  
445                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) == 0));
446         } else {
447 #ifdef DEBUG_FOR_CONVERSIONS
448                 char buffer[2000];
449                 sprintf(buffer,"Converting '%s' and '%s' ", a->u.s, b->u.s);
450 #endif
451                 (void)to_integer(a);
452                 (void)to_integer(b);
453 #ifdef DEBUG_FOR_CONVERSIONS
454                 ast_log(LOG_WARNING,"%s to '%lld' and '%lld'\n", buffer, a->u.i, b->u.i);
455 #endif
456                 r = make_integer ((quad_t)(a->u.i == b->u.i));
457         }
458
459         free_value (a);
460         free_value (b);
461         return r;
462 }
463
464 static struct val *
465 op_gt (struct val *a, struct val *b)
466 {
467         struct val *r;
468
469         if (isstring (a) || isstring (b)) {
470                 to_string (a);
471                 to_string (b);
472                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) > 0));
473         } else {
474                 (void)to_integer(a);
475                 (void)to_integer(b);
476                 r = make_integer ((quad_t)(a->u.i > b->u.i));
477         }
478
479         free_value (a);
480         free_value (b);
481         return r;
482 }
483
484 static struct val *
485 op_lt (struct val *a, struct val *b)
486 {
487         struct val *r;
488
489         if (isstring (a) || isstring (b)) {
490                 to_string (a);
491                 to_string (b);
492                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) < 0));
493         } else {
494                 (void)to_integer(a);
495                 (void)to_integer(b);
496                 r = make_integer ((quad_t)(a->u.i < b->u.i));
497         }
498
499         free_value (a);
500         free_value (b);
501         return r;
502 }
503
504 static struct val *
505 op_ge (struct val *a, struct val *b)
506 {
507         struct val *r;
508
509         if (isstring (a) || isstring (b)) {
510                 to_string (a);
511                 to_string (b);
512                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) >= 0));
513         } else {
514                 (void)to_integer(a);
515                 (void)to_integer(b);
516                 r = make_integer ((quad_t)(a->u.i >= b->u.i));
517         }
518
519         free_value (a);
520         free_value (b);
521         return r;
522 }
523
524 static struct val *
525 op_le (struct val *a, struct val *b)
526 {
527         struct val *r;
528
529         if (isstring (a) || isstring (b)) {
530                 to_string (a);
531                 to_string (b);
532                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) <= 0));
533         } else {
534                 (void)to_integer(a);
535                 (void)to_integer(b);
536                 r = make_integer ((quad_t)(a->u.i <= b->u.i));
537         }
538
539         free_value (a);
540         free_value (b);
541         return r;
542 }
543
544 static struct val *
545 op_cond (struct val *a, struct val *b, struct val *c)
546 {
547         struct val *r;
548
549         if( isstring(a) )
550         {
551                 if( strlen(a->u.s) && strcmp(a->u.s, "\"\"") != 0 && strcmp(a->u.s,"0") != 0 )
552                 {
553                         free_value(a);
554                         free_value(c);
555                         r = b;
556                 }
557                 else
558                 {
559                         free_value(a);
560                         free_value(b);
561                         r = c;
562                 }
563         }
564         else
565         {
566                 (void)to_integer(a);
567                 if( a->u.i )
568                 {
569                         free_value(a);
570                         free_value(c);
571                         r = b;
572                 }
573                 else
574                 {
575                         free_value(a);
576                         free_value(b);
577                         r = c;
578                 }
579         }
580         return r;
581 }
582
583 static struct val *
584 op_ne (struct val *a, struct val *b)
585 {
586         struct val *r;
587
588         if (isstring (a) || isstring (b)) {
589                 to_string (a);
590                 to_string (b);
591                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) != 0));
592         } else {
593                 (void)to_integer(a);
594                 (void)to_integer(b);
595                 r = make_integer ((quad_t)(a->u.i != b->u.i));
596         }
597
598         free_value (a);
599         free_value (b);
600         return r;
601 }
602
603 static int
604 chk_plus (quad_t a, quad_t b, quad_t r)
605 {
606         /* sum of two positive numbers must be positive */
607         if (a > 0 && b > 0 && r <= 0)
608                 return 1;
609         /* sum of two negative numbers must be negative */
610         if (a < 0 && b < 0 && r >= 0)
611                 return 1;
612         /* all other cases are OK */
613         return 0;
614 }
615
616 static struct val *
617 op_plus (struct val *a, struct val *b)
618 {
619         struct val *r;
620
621         if (!to_integer (a)) {
622                 ast_log(LOG_WARNING,"non-numeric argument\n");
623                 if (!to_integer (b)) {
624                         free_value(a);
625                         free_value(b);
626                         return make_integer(0);
627                 } else {
628                         free_value(a);
629                         return (b);
630                 }
631         } else if (!to_integer(b)) {
632                 free_value(b);
633                 return (a);
634         }
635
636         r = make_integer (/*(quad_t)*/(a->u.i + b->u.i));
637         if (chk_plus (a->u.i, b->u.i, r->u.i)) {
638                 ast_log(LOG_WARNING,"overflow\n");
639         }
640         free_value (a);
641         free_value (b);
642         return r;
643 }
644
645 static int
646 chk_minus (quad_t a, quad_t b, quad_t r)
647 {
648         /* special case subtraction of QUAD_MIN */
649         if (b == QUAD_MIN) {
650                 if (a >= 0)
651                         return 1;
652                 else
653                         return 0;
654         }
655         /* this is allowed for b != QUAD_MIN */
656         return chk_plus (a, -b, r);
657 }
658
659 static struct val *
660 op_minus (struct val *a, struct val *b)
661 {
662         struct val *r;
663
664         if (!to_integer (a)) {
665                 ast_log(LOG_WARNING, "non-numeric argument\n");
666                 if (!to_integer (b)) {
667                         free_value(a);
668                         free_value(b);
669                         return make_integer(0);
670                 } else {
671                         r = make_integer(0 - b->u.i);
672                         free_value(a);
673                         free_value(b);
674                         return (r);
675                 }
676         } else if (!to_integer(b)) {
677                 ast_log(LOG_WARNING, "non-numeric argument\n");
678                 free_value(b);
679                 return (a);
680         }
681
682         r = make_integer (/*(quad_t)*/(a->u.i - b->u.i));
683         if (chk_minus (a->u.i, b->u.i, r->u.i)) {
684                 ast_log(LOG_WARNING, "overflow\n");
685         }
686         free_value (a);
687         free_value (b);
688         return r;
689 }
690
691 static struct val *
692 op_negate (struct val *a)
693 {
694         struct val *r;
695
696         if (!to_integer (a) ) {
697                 free_value(a);
698                 ast_log(LOG_WARNING, "non-numeric argument\n");
699                 return make_integer(0);
700         }
701
702         r = make_integer (/*(quad_t)*/(- a->u.i));
703         if (chk_minus (0, a->u.i, r->u.i)) {
704                 ast_log(LOG_WARNING, "overflow\n");
705         }
706         free_value (a);
707         return r;
708 }
709
710 static struct val *
711 op_compl (struct val *a)
712 {
713         int v1 = 1;
714         struct val *r;
715         
716         if( !a )
717         {
718                 v1 = 0;
719         }
720         else
721         {
722                 switch( a->type )
723                 {
724                 case AST_EXPR_integer:
725                         if( a->u.i == 0 )
726                                 v1 = 0;
727                         break;
728                         
729                 case AST_EXPR_string:
730                         if( a->u.s == 0 )
731                                 v1 = 0;
732                         else
733                         {
734                                 if( a->u.s[0] == 0 )
735                                         v1 = 0;
736                                 else if (strlen(a->u.s) == 1 && a->u.s[0] == '0' )
737                                         v1 = 0;
738                         }
739                         break;
740                         
741                 case AST_EXPR_numeric_string:
742                         if( a->u.s == 0 )
743                                 v1 = 0;
744                         else
745                         {
746                                 if( a->u.s[0] == 0 )
747                                         v1 = 0;
748                                 else if (strlen(a->u.s) == 1 && a->u.s[0] == '0' )
749                                         v1 = 0;
750                         }
751                         break;
752                 }
753         }
754         
755         r = make_integer (!v1);
756         free_value (a);
757         return r;
758 }
759
760 static int
761 chk_times (quad_t a, quad_t b, quad_t r)
762 {
763         /* special case: first operand is 0, no overflow possible */
764         if (a == 0)
765                 return 0;
766         /* cerify that result of division matches second operand */
767         if (r / a != b)
768                 return 1;
769         return 0;
770 }
771
772 static struct val *
773 op_times (struct val *a, struct val *b)
774 {
775         struct val *r;
776
777         if (!to_integer (a) || !to_integer (b)) {
778                 free_value(a);
779                 free_value(b);
780                 ast_log(LOG_WARNING, "non-numeric argument\n");
781                 return(make_integer(0));
782         }
783
784         r = make_integer (/*(quad_t)*/(a->u.i * b->u.i));
785         if (chk_times (a->u.i, b->u.i, r->u.i)) {
786                 ast_log(LOG_WARNING, "overflow\n");
787         }
788         free_value (a);
789         free_value (b);
790         return (r);
791 }
792
793 static int
794 chk_div (quad_t a, quad_t b)
795 {
796         /* div by zero has been taken care of before */
797         /* only QUAD_MIN / -1 causes overflow */
798         if (a == QUAD_MIN && b == -1)
799                 return 1;
800         /* everything else is OK */
801         return 0;
802 }
803
804 static struct val *
805 op_div (struct val *a, struct val *b)
806 {
807         struct val *r;
808
809         if (!to_integer (a)) {
810                 free_value(a);
811                 free_value(b);
812                 ast_log(LOG_WARNING, "non-numeric argument\n");
813                 return make_integer(0);
814         } else if (!to_integer (b)) {
815                 free_value(a);
816                 free_value(b);
817                 ast_log(LOG_WARNING, "non-numeric argument\n");
818                 return make_integer(INT_MAX);
819         }
820
821         if (b->u.i == 0) {
822                 ast_log(LOG_WARNING, "division by zero\n");             
823                 free_value(a);
824                 free_value(b);
825                 return make_integer(INT_MAX);
826         }
827
828         r = make_integer (/*(quad_t)*/(a->u.i / b->u.i));
829         if (chk_div (a->u.i, b->u.i)) {
830                 ast_log(LOG_WARNING, "overflow\n");
831         }
832         free_value (a);
833         free_value (b);
834         return r;
835 }
836         
837 static struct val *
838 op_rem (struct val *a, struct val *b)
839 {
840         struct val *r;
841
842         if (!to_integer (a) || !to_integer (b)) {
843                 ast_log(LOG_WARNING, "non-numeric argument\n");
844                 free_value(a);
845                 free_value(b);
846                 return make_integer(0);
847         }
848
849         if (b->u.i == 0) {
850                 ast_log(LOG_WARNING, "div by zero\n");
851                 free_value(a);
852                 return(b);
853         }
854
855         r = make_integer (/*(quad_t)*/(a->u.i % b->u.i));
856         /* chk_rem necessary ??? */
857         free_value (a);
858         free_value (b);
859         return r;
860 }
861         
862
863 static struct val *
864 op_colon (struct val *a, struct val *b)
865 {
866         regex_t rp;
867         regmatch_t rm[2];
868         char errbuf[256];
869         int eval;
870         struct val *v;
871
872         /* coerce to both arguments to strings */
873         to_string(a);
874         to_string(b);
875         /* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
876         strip_quotes(a);
877         strip_quotes(b);
878         /* compile regular expression */
879         if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
880                 regerror (eval, &rp, errbuf, sizeof(errbuf));
881                 ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
882                 free_value(a);
883                 free_value(b);
884                 return make_str("");            
885         }
886
887         /* compare string against pattern */
888         /* remember that patterns are anchored to the beginning of the line */
889         if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
890                 if (rm[1].rm_so >= 0) {
891                         *(a->u.s + rm[1].rm_eo) = '\0';
892                         v = make_str (a->u.s + rm[1].rm_so);
893
894                 } else {
895                         v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
896                 }
897         } else {
898                 if (rp.re_nsub == 0) {
899                         v = make_integer ((quad_t)0);
900                 } else {
901                         v = make_str ("");
902                 }
903         }
904
905         /* free arguments and pattern buffer */
906         free_value (a);
907         free_value (b);
908         regfree (&rp);
909
910         return v;
911 }
912         
913
914 static struct val *
915 op_eqtilde (struct val *a, struct val *b)
916 {
917         regex_t rp;
918         regmatch_t rm[2];
919         char errbuf[256];
920         int eval;
921         struct val *v;
922
923         /* coerce to both arguments to strings */
924         to_string(a);
925         to_string(b);
926         /* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
927         strip_quotes(a);
928         strip_quotes(b);
929         /* compile regular expression */
930         if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
931                 regerror (eval, &rp, errbuf, sizeof(errbuf));
932                 ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
933                 free_value(a);
934                 free_value(b);
935                 return make_str("");            
936         }
937
938         /* compare string against pattern */
939         /* remember that patterns are anchored to the beginning of the line */
940         if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 ) {
941                 if (rm[1].rm_so >= 0) {
942                         *(a->u.s + rm[1].rm_eo) = '\0';
943                         v = make_str (a->u.s + rm[1].rm_so);
944
945                 } else {
946                         v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
947                 }
948         } else {
949                 if (rp.re_nsub == 0) {
950                         v = make_integer ((quad_t)0);
951                 } else {
952                         v = make_str ("");
953                 }
954         }
955
956         /* free arguments and pattern buffer */
957         free_value (a);
958         free_value (b);
959         regfree (&rp);
960
961         return v;
962 }