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