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