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