various minor portability fixes (mostly from tholo for OpenBSD)
[asterisk-bristuff.git] / ast_expr2.y
blob61a3142efbc18919d15644a0ef882a283f086ba4
1 %{
2 /* Written by Pace Willisson (pace@blitz.com)
3 * and placed in the public domain.
5 * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
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.
12 * $FreeBSD: src/bin/expr/expr.y,v 1.16 2000/07/22 10:59:36 se Exp $
15 #include "asterisk.h"
17 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
19 #include <sys/types.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <locale.h>
24 #include <unistd.h>
25 #include <ctype.h>
26 #if !defined(SOLARIS) && !defined(__CYGWIN__)
27 #include <err.h>
28 #else
29 #define quad_t int64_t
30 #endif
31 #include <errno.h>
32 #include <regex.h>
33 #include <limits.h>
35 #include "asterisk/ast_expr.h"
36 #include "asterisk/logger.h"
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
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
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;
58 enum valtype {
59 AST_EXPR_integer, AST_EXPR_numeric_string, AST_EXPR_string
60 } ;
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
66 struct val {
67 enum valtype type;
68 union {
69 char *s;
70 quad_t i;
71 } u;
72 } ;
74 typedef void *yyscan_t;
76 struct parse_io
78 char *string;
79 struct val *val;
80 yyscan_t scanner;
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 *));
113 /* uh, if I want to predeclare yylex with a YYLTYPE, I have to predeclare the yyltype... sigh */
114 typedef struct yyltype
116 int first_line;
117 int first_column;
119 int last_line;
120 int last_column;
121 } yyltype;
123 # define YYLTYPE yyltype
124 # define YYLTYPE_IS_TRIVIAL 1
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. */
129 int ast_yyerror(const char *,YYLTYPE *, struct parse_io *);
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);}
138 %pure-parser
139 %locations
140 /* %debug for when you are having big problems */
142 /* %name-prefix="ast_yy" */
144 %union
146 struct val *val;
150 extern int ast_yylex __P((YYSTYPE *, YYLTYPE *, yyscan_t));
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
163 %token <val> TOKEN
164 %type <val> start expr
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
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);
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("");
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;}
270 static struct val *
271 make_integer (quad_t i)
273 struct val *vp;
275 vp = (struct val *) malloc (sizeof (*vp));
276 if (vp == NULL) {
277 ast_log(LOG_WARNING, "malloc() failed\n");
278 return(NULL);
281 vp->type = AST_EXPR_integer;
282 vp->u.i = i;
283 return vp;
286 static struct val *
287 make_str (const char *s)
289 struct val *vp;
290 size_t i;
291 int isint;
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);
299 for(i = 1, isint = isdigit(s[0]) || s[0] == '-';
300 isint && i < strlen(s);
301 i++)
303 if(!isdigit(s[i]))
304 isint = 0;
307 if (isint)
308 vp->type = AST_EXPR_numeric_string;
309 else
310 vp->type = AST_EXPR_string;
312 return vp;
316 static void
317 free_value (struct val *vp)
319 if (vp==NULL) {
320 return;
322 if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string)
323 free (vp->u.s);
324 free(vp);
328 static quad_t
329 to_integer (struct val *vp)
331 quad_t i;
333 if (vp == NULL) {
334 ast_log(LOG_WARNING,"vp==NULL in to_integer()\n");
335 return(0);
338 if (vp->type == AST_EXPR_integer)
339 return 1;
341 if (vp->type == AST_EXPR_string)
342 return 0;
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);
353 free (vp->u.s);
354 vp->u.i = i;
355 vp->type = AST_EXPR_integer;
356 return 1;
359 static void
360 strip_quotes(struct val *vp)
362 if (vp->type != AST_EXPR_string && vp->type != AST_EXPR_numeric_string)
363 return;
365 if( vp->u.s[0] == '"' && vp->u.s[strlen(vp->u.s)-1] == '"' )
367 char *f, *t;
368 f = vp->u.s;
369 t = vp->u.s;
371 while( *f )
373 if( *f && *f != '"' )
374 *t++ = *f++;
375 else
376 f++;
378 *t = *f;
382 static void
383 to_string (struct val *vp)
385 char *tmp;
387 if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string)
388 return;
390 tmp = malloc ((size_t)25);
391 if (tmp == NULL) {
392 ast_log(LOG_WARNING,"malloc() failed\n");
393 return;
396 sprintf(tmp, "%ld", (long int) vp->u.i);
397 vp->type = AST_EXPR_string;
398 vp->u.s = tmp;
402 static int
403 isstring (struct val *vp)
405 /* only TRUE if this string is not a valid integer */
406 return (vp->type == AST_EXPR_string);
410 static int
411 is_zero_or_null (struct val *vp)
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));
418 /* NOTREACHED */
421 #ifdef STANDALONE
423 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
425 va_list vars;
426 va_start(vars,fmt);
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);
436 int main(int argc,char **argv) {
437 char s[4096];
438 char out[4096];
439 FILE *infile;
441 if( !argv[1] )
442 exit(20);
444 if( access(argv[1],F_OK)== 0 )
446 int ret;
448 infile = fopen(argv[1],"r");
449 if( !infile )
451 printf("Sorry, couldn't open %s for reading!\n", argv[1]);
452 exit(10);
454 while( fgets(s,sizeof(s),infile) )
456 if( s[strlen(s)-1] == '\n' )
457 s[strlen(s)-1] = 0;
459 ret = ast_expr(s, out, sizeof(out));
460 printf("Expression: %s Result: [%d] '%s'\n",
461 s, ret, out);
463 fclose(infile);
465 else
467 if (ast_expr(argv[1], s, sizeof(s)))
468 printf("=====%s======\n",s);
469 else
470 printf("No result\n");
474 #endif
476 #undef ast_yyerror
477 #define ast_yyerror(x) ast_yyerror(x, YYLTYPE *yylloc, struct parse_io *parseio)
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! */
485 static struct val *
486 op_or (struct val *a, struct val *b)
488 if (is_zero_or_null (a)) {
489 free_value (a);
490 return (b);
491 } else {
492 free_value (b);
493 return (a);
497 static struct val *
498 op_and (struct val *a, struct val *b)
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);
510 static struct val *
511 op_eq (struct val *a, struct val *b)
513 struct val *r;
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));
532 free_value (a);
533 free_value (b);
534 return r;
537 static struct val *
538 op_gt (struct val *a, struct val *b)
540 struct val *r;
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));
552 free_value (a);
553 free_value (b);
554 return r;
557 static struct val *
558 op_lt (struct val *a, struct val *b)
560 struct val *r;
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));
572 free_value (a);
573 free_value (b);
574 return r;
577 static struct val *
578 op_ge (struct val *a, struct val *b)
580 struct val *r;
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));
592 free_value (a);
593 free_value (b);
594 return r;
597 static struct val *
598 op_le (struct val *a, struct val *b)
600 struct val *r;
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));
612 free_value (a);
613 free_value (b);
614 return r;
617 static struct val *
618 op_cond (struct val *a, struct val *b, struct val *c)
620 struct val *r;
622 if( isstring(a) )
624 if( strlen(a->u.s) && strcmp(a->u.s, "\"\"") != 0 && strcmp(a->u.s,"0") != 0 )
626 free_value(a);
627 free_value(c);
628 r = b;
630 else
632 free_value(a);
633 free_value(b);
634 r = c;
637 else
639 (void)to_integer(a);
640 if( a->u.i )
642 free_value(a);
643 free_value(c);
644 r = b;
646 else
648 free_value(a);
649 free_value(b);
650 r = c;
653 return r;
656 static struct val *
657 op_ne (struct val *a, struct val *b)
659 struct val *r;
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));
671 free_value (a);
672 free_value (b);
673 return r;
676 static int
677 chk_plus (quad_t a, quad_t b, quad_t r)
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;
689 static struct val *
690 op_plus (struct val *a, struct val *b)
692 struct val *r;
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);
705 } else if (!to_integer(b)) {
706 free_value(b);
707 return (a);
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");
714 free_value (a);
715 free_value (b);
716 return r;
719 static int
720 chk_minus (quad_t a, quad_t b, quad_t r)
722 /* special case subtraction of QUAD_MIN */
723 if (b == QUAD_MIN) {
724 if (a >= 0)
725 return 1;
726 else
727 return 0;
729 /* this is allowed for b != QUAD_MIN */
730 return chk_plus (a, -b, r);
733 static struct val *
734 op_minus (struct val *a, struct val *b)
736 struct val *r;
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);
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);
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");
762 free_value (a);
763 free_value (b);
764 return r;
767 static struct val *
768 op_negate (struct val *a)
770 struct val *r;
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);
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");
783 free_value (a);
784 return r;
787 static struct val *
788 op_compl (struct val *a)
790 int v1 = 1;
791 struct val *r;
793 if( !a )
795 v1 = 0;
797 else
799 switch( a->type )
801 case AST_EXPR_integer:
802 if( a->u.i == 0 )
803 v1 = 0;
804 break;
806 case AST_EXPR_string:
807 if( a->u.s == 0 )
808 v1 = 0;
809 else
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;
816 break;
818 case AST_EXPR_numeric_string:
819 if( a->u.s == 0 )
820 v1 = 0;
821 else
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;
828 break;
832 r = make_integer (!v1);
833 free_value (a);
834 return r;
837 static int
838 chk_times (quad_t a, quad_t b, quad_t r)
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;
849 static struct val *
850 op_times (struct val *a, struct val *b)
852 struct val *r;
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));
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");
866 free_value (a);
867 free_value (b);
868 return (r);
871 static int
872 chk_div (quad_t a, quad_t b)
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;
882 static struct val *
883 op_div (struct val *a, struct val *b)
885 struct val *r;
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);
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);
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");
912 free_value (a);
913 free_value (b);
914 return r;
917 static struct val *
918 op_rem (struct val *a, struct val *b)
920 struct val *r;
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);
930 if (b->u.i == 0) {
931 ast_log(LOG_WARNING, "div by zero\n");
932 free_value(a);
933 return(b);
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;
944 static struct val *
945 op_colon (struct val *a, struct val *b)
947 regex_t rp;
948 regmatch_t rm[2];
949 char errbuf[256];
950 int eval;
951 struct val *v;
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("");
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);
975 } else {
976 v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
978 } else {
979 if (rp.re_nsub == 0) {
980 v = make_integer ((quad_t)0);
981 } else {
982 v = make_str ("");
986 /* free arguments and pattern buffer */
987 free_value (a);
988 free_value (b);
989 regfree (&rp);
991 return v;
995 static struct val *
996 op_eqtilde (struct val *a, struct val *b)
998 regex_t rp;
999 regmatch_t rm[2];
1000 char errbuf[256];
1001 int eval;
1002 struct val *v;
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("");
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);
1026 } else {
1027 v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
1029 } else {
1030 if (rp.re_nsub == 0) {
1031 v = make_integer ((quad_t)0);
1032 } else {
1033 v = make_str ("");
1037 /* free arguments and pattern buffer */
1038 free_value (a);
1039 free_value (b);
1040 regfree (&rp);
1042 return v;