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