Let's also include aclocal.m4
[asterisk-bristuff.git] / main / ast_expr2.y
blobb2faf374d02b3e637ae9a6101eee9d77a331589c
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@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.
12 * $FreeBSD: src/bin/expr/expr.y,v 1.16 2000/07/22 10:59:36 se Exp $
15 #include "asterisk.h"
17 #if !defined(STANDALONE_AEL)
18 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
19 #endif
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>
37 #include "asterisk/ast_expr.h"
38 #include "asterisk/logger.h"
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
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
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;
60 enum valtype {
61 AST_EXPR_integer, AST_EXPR_numeric_string, AST_EXPR_string
62 } ;
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
68 struct val {
69 enum valtype type;
70 union {
71 char *s;
72 quad_t i;
73 } u;
74 } ;
76 typedef void *yyscan_t;
78 struct parse_io
80 char *string;
81 struct val *val;
82 yyscan_t scanner;
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 *));
115 /* uh, if I want to predeclare yylex with a YYLTYPE, I have to predeclare the yyltype... sigh */
116 typedef struct yyltype
118 int first_line;
119 int first_column;
121 int last_line;
122 int last_column;
123 } yyltype;
125 # define YYLTYPE yyltype
126 # define YYLTYPE_IS_TRIVIAL 1
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. */
131 int ast_yyerror(const char *,YYLTYPE *, struct parse_io *);
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);}
140 %pure-parser
141 %locations
142 /* %debug for when you are having big problems */
144 /* %name-prefix="ast_yy" */
146 %union
148 struct val *val;
152 extern int ast_yylex __P((YYSTYPE *, YYLTYPE *, yyscan_t));
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
165 %token <val> TOKEN
166 %type <val> start expr
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
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);
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("");
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;}
272 static struct val *
273 make_integer (quad_t i)
275 struct val *vp;
277 vp = (struct val *) malloc (sizeof (*vp));
278 if (vp == NULL) {
279 ast_log(LOG_WARNING, "malloc() failed\n");
280 return(NULL);
283 vp->type = AST_EXPR_integer;
284 vp->u.i = i;
285 return vp;
288 static struct val *
289 make_str (const char *s)
291 struct val *vp;
292 size_t i;
293 int isint;
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);
301 for(i = 1, isint = isdigit(s[0]) || s[0] == '-';
302 isint && i < strlen(s);
303 i++)
305 if(!isdigit(s[i]))
306 isint = 0;
309 if (isint)
310 vp->type = AST_EXPR_numeric_string;
311 else
312 vp->type = AST_EXPR_string;
314 return vp;
318 static void
319 free_value (struct val *vp)
321 if (vp==NULL) {
322 return;
324 if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string)
325 free (vp->u.s);
326 free(vp);
330 static quad_t
331 to_integer (struct val *vp)
333 quad_t i;
335 if (vp == NULL) {
336 ast_log(LOG_WARNING,"vp==NULL in to_integer()\n");
337 return(0);
340 if (vp->type == AST_EXPR_integer)
341 return 1;
343 if (vp->type == AST_EXPR_string)
344 return 0;
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);
355 free (vp->u.s);
356 vp->u.i = i;
357 vp->type = AST_EXPR_integer;
358 return 1;
361 static void
362 strip_quotes(struct val *vp)
364 if (vp->type != AST_EXPR_string && vp->type != AST_EXPR_numeric_string)
365 return;
367 if( vp->u.s[0] == '"' && vp->u.s[strlen(vp->u.s)-1] == '"' )
369 char *f, *t;
370 f = vp->u.s;
371 t = vp->u.s;
373 while( *f )
375 if( *f && *f != '"' )
376 *t++ = *f++;
377 else
378 f++;
380 *t = *f;
384 static void
385 to_string (struct val *vp)
387 char *tmp;
389 if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string)
390 return;
392 tmp = malloc ((size_t)25);
393 if (tmp == NULL) {
394 ast_log(LOG_WARNING,"malloc() failed\n");
395 return;
398 sprintf(tmp, "%ld", (long int) vp->u.i);
399 vp->type = AST_EXPR_string;
400 vp->u.s = tmp;
404 static int
405 isstring (struct val *vp)
407 /* only TRUE if this string is not a valid integer */
408 return (vp->type == AST_EXPR_string);
412 static int
413 is_zero_or_null (struct val *vp)
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));
420 /* NOTREACHED */
423 #ifdef STANDALONE
425 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
427 va_list vars;
428 va_start(vars,fmt);
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);
438 int main(int argc,char **argv) {
439 char s[4096];
440 char out[4096];
441 FILE *infile;
443 if( !argv[1] )
444 exit(20);
446 if( access(argv[1],F_OK)== 0 )
448 int ret;
450 infile = fopen(argv[1],"r");
451 if( !infile )
453 printf("Sorry, couldn't open %s for reading!\n", argv[1]);
454 exit(10);
456 while( fgets(s,sizeof(s),infile) )
458 if( s[strlen(s)-1] == '\n' )
459 s[strlen(s)-1] = 0;
461 ret = ast_expr(s, out, sizeof(out));
462 printf("Expression: %s Result: [%d] '%s'\n",
463 s, ret, out);
465 fclose(infile);
467 else
469 if (ast_expr(argv[1], s, sizeof(s)))
470 printf("=====%s======\n",s);
471 else
472 printf("No result\n");
476 #endif
478 #undef ast_yyerror
479 #define ast_yyerror(x) ast_yyerror(x, YYLTYPE *yylloc, struct parse_io *parseio)
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! */
487 static struct val *
488 op_or (struct val *a, struct val *b)
490 if (is_zero_or_null (a)) {
491 free_value (a);
492 return (b);
493 } else {
494 free_value (b);
495 return (a);
499 static struct val *
500 op_and (struct val *a, struct val *b)
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);
512 static struct val *
513 op_eq (struct val *a, struct val *b)
515 struct val *r;
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));
534 free_value (a);
535 free_value (b);
536 return r;
539 static struct val *
540 op_gt (struct val *a, struct val *b)
542 struct val *r;
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));
554 free_value (a);
555 free_value (b);
556 return r;
559 static struct val *
560 op_lt (struct val *a, struct val *b)
562 struct val *r;
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));
574 free_value (a);
575 free_value (b);
576 return r;
579 static struct val *
580 op_ge (struct val *a, struct val *b)
582 struct val *r;
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));
594 free_value (a);
595 free_value (b);
596 return r;
599 static struct val *
600 op_le (struct val *a, struct val *b)
602 struct val *r;
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));
614 free_value (a);
615 free_value (b);
616 return r;
619 static struct val *
620 op_cond (struct val *a, struct val *b, struct val *c)
622 struct val *r;
624 if( isstring(a) )
626 if( strlen(a->u.s) && strcmp(a->u.s, "\"\"") != 0 && strcmp(a->u.s,"0") != 0 )
628 free_value(a);
629 free_value(c);
630 r = b;
632 else
634 free_value(a);
635 free_value(b);
636 r = c;
639 else
641 (void)to_integer(a);
642 if( a->u.i )
644 free_value(a);
645 free_value(c);
646 r = b;
648 else
650 free_value(a);
651 free_value(b);
652 r = c;
655 return r;
658 static struct val *
659 op_ne (struct val *a, struct val *b)
661 struct val *r;
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));
673 free_value (a);
674 free_value (b);
675 return r;
678 static int
679 chk_plus (quad_t a, quad_t b, quad_t r)
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;
691 static struct val *
692 op_plus (struct val *a, struct val *b)
694 struct val *r;
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);
707 } else if (!to_integer(b)) {
708 free_value(b);
709 return (a);
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");
716 free_value (a);
717 free_value (b);
718 return r;
721 static int
722 chk_minus (quad_t a, quad_t b, quad_t r)
724 /* special case subtraction of QUAD_MIN */
725 if (b == QUAD_MIN) {
726 if (a >= 0)
727 return 1;
728 else
729 return 0;
731 /* this is allowed for b != QUAD_MIN */
732 return chk_plus (a, -b, r);
735 static struct val *
736 op_minus (struct val *a, struct val *b)
738 struct val *r;
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);
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);
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");
764 free_value (a);
765 free_value (b);
766 return r;
769 static struct val *
770 op_negate (struct val *a)
772 struct val *r;
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);
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");
785 free_value (a);
786 return r;
789 static struct val *
790 op_compl (struct val *a)
792 int v1 = 1;
793 struct val *r;
795 if( !a )
797 v1 = 0;
799 else
801 switch( a->type )
803 case AST_EXPR_integer:
804 if( a->u.i == 0 )
805 v1 = 0;
806 break;
808 case AST_EXPR_string:
809 if( a->u.s == 0 )
810 v1 = 0;
811 else
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;
818 break;
820 case AST_EXPR_numeric_string:
821 if( a->u.s == 0 )
822 v1 = 0;
823 else
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;
830 break;
834 r = make_integer (!v1);
835 free_value (a);
836 return r;
839 static int
840 chk_times (quad_t a, quad_t b, quad_t r)
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;
851 static struct val *
852 op_times (struct val *a, struct val *b)
854 struct val *r;
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));
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");
868 free_value (a);
869 free_value (b);
870 return (r);
873 static int
874 chk_div (quad_t a, quad_t b)
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;
884 static struct val *
885 op_div (struct val *a, struct val *b)
887 struct val *r;
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);
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);
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");
914 free_value (a);
915 free_value (b);
916 return r;
919 static struct val *
920 op_rem (struct val *a, struct val *b)
922 struct val *r;
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);
932 if (b->u.i == 0) {
933 ast_log(LOG_WARNING, "div by zero\n");
934 free_value(a);
935 return(b);
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;
946 static struct val *
947 op_colon (struct val *a, struct val *b)
949 regex_t rp;
950 regmatch_t rm[2];
951 char errbuf[256];
952 int eval;
953 struct val *v;
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("");
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);
977 } else {
978 v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
980 } else {
981 if (rp.re_nsub == 0) {
982 v = make_integer ((quad_t)0);
983 } else {
984 v = make_str ("");
988 /* free arguments and pattern buffer */
989 free_value (a);
990 free_value (b);
991 regfree (&rp);
993 return v;
997 static struct val *
998 op_eqtilde (struct val *a, struct val *b)
1000 regex_t rp;
1001 regmatch_t rm[2];
1002 char errbuf[256];
1003 int eval;
1004 struct val *v;
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("");
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);
1028 } else {
1029 v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
1031 } else {
1032 if (rp.re_nsub == 0) {
1033 v = make_integer ((quad_t)0);
1034 } else {
1035 v = make_str ("");
1039 /* free arguments and pattern buffer */
1040 free_value (a);
1041 free_value (b);
1042 regfree (&rp);
1044 return v;