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