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