make app_queue 1.2 jump compliant (issue #5580)
[asterisk/asterisk.git] / ast_expr.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  * $FreeBSD: src/bin/expr/expr.y,v 1.16 2000/07/22 10:59:36 se Exp $
8  */
9
10 #include <sys/types.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <locale.h>
15 #include <ctype.h>
16 #ifndef SOLARIS
17 #include <err.h>
18 #else
19 #define quad_t uint64_t
20 #endif
21 #include <errno.h>
22 #include <regex.h>
23 #include <limits.h>
24
25 #include "asterisk/ast_expr.h"
26 #include "asterisk/logger.h"
27
28 #ifndef QUAD_MIN
29 #ifdef LONG_LONG_MIN
30 #define QUAD_MIN LONG_LONG_MIN
31 #else /* LONG_LONG_MIN */
32 #define QUAD_MIN (-0x7fffffffffffffffL-1)
33 #endif /* LONG_LONG_MIN */
34 #endif /* QUAD_MIN */
35
36 #ifndef QUAD_MAX
37 #ifdef LONG_LONG_MAX
38 #define QUAD_MAX LONG_LONG_MAX
39 #else /* LONG_LONG_MAX */
40 #define QUAD_MAX (0x7fffffffffffffffL)
41 #endif /* LONG_LONG_MAX */
42 #endif /* QUAD_MAX */
43
44 #define YYPARSE_PARAM kota
45 #define YYLEX_PARAM kota
46
47 /* #define ast_log fprintf
48 #define LOG_WARNING stderr */
49
50 #ifdef SOLARIS
51 #define __P(p) p
52 #endif
53   
54 enum valtype {
55         integer, numeric_string, string
56 } ;
57
58 struct val {
59         enum valtype type;
60         union {
61                 char *s;
62                 quad_t i;
63         } u;
64 } ;
65
66 struct parser_control {
67         struct val *result;
68         int pipa;
69         char *arg_orig;
70         char *argv;
71         char *ptrptr;
72         int firsttoken;
73 } ;
74
75 static int              chk_div __P((quad_t, quad_t));
76 static int              chk_minus __P((quad_t, quad_t, quad_t));
77 static int              chk_plus __P((quad_t, quad_t, quad_t));
78 static int              chk_times __P((quad_t, quad_t, quad_t));
79 static void             free_value __P((struct val *));
80 static int              is_zero_or_null __P((struct val *));
81 static int              isstring __P((struct val *));
82 static struct val       *make_integer __P((quad_t));
83 static struct val       *make_str __P((const char *));
84 static struct val       *op_and __P((struct val *, struct val *));
85 static struct val       *op_colon __P((struct val *, struct val *));
86 static struct val       *op_div __P((struct val *, struct val *));
87 static struct val       *op_eq __P((struct val *, struct val *));
88 static struct val       *op_ge __P((struct val *, struct val *));
89 static struct val       *op_gt __P((struct val *, struct val *));
90 static struct val       *op_le __P((struct val *, struct val *));
91 static struct val       *op_lt __P((struct val *, struct val *));
92 static struct val       *op_minus __P((struct val *, struct val *));
93 static struct val       *op_ne __P((struct val *, struct val *));
94 static struct val       *op_or __P((struct val *, struct val *));
95 static struct val       *op_plus __P((struct val *, struct val *));
96 static struct val       *op_rem __P((struct val *, struct val *));
97 static struct val       *op_times __P((struct val *, struct val *));
98 static quad_t           to_integer __P((struct val *));
99 static void             to_string __P((struct val *));
100
101 /* uh, if I want to predeclare yylex with a YYLTYPE, I have to predeclare the yyltype... sigh */
102 typedef struct yyltype
103 {
104   int first_line;
105   int first_column;
106
107   int last_line;
108   int last_column;
109 } yyltype;
110
111 # define YYLTYPE yyltype
112 # define YYLTYPE_IS_TRIVIAL 1
113
114 static int              ast_yyerror __P((const char *,YYLTYPE *, struct parser_control *));
115
116 #define ast_yyerror(x) ast_yyerror(x,&yyloc,kota)
117
118 %}
119
120 %pure-parser
121 %locations
122 /* %debug  for when you are having big problems */
123
124 /* %name-prefix="ast_yy" */
125
126 %union
127 {
128         struct val *val;
129 }
130
131 %{
132 static int              ast_yylex __P((YYSTYPE *, YYLTYPE *, struct parser_control *));
133 %}
134
135
136 %left <val> '|'
137 %left <val> '&'
138 %left <val> '=' '>' '<' GE LE NE
139 %left <val> '+' '-'
140 %left <val> '*' '/' '%'
141 %left <val> ':'
142
143 %token <val> TOKEN
144 %type <val> start expr
145
146 %%
147
148 start: expr { ((struct parser_control *)kota)->result = $$; }
149         ;
150
151 expr:   TOKEN
152         | '(' expr ')' { $$ = $2; @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
153         | expr '|' expr { $$ = op_or ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
154         | expr '&' expr { $$ = op_and ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
155         | expr '=' expr { $$ = op_eq ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
156         | expr '>' expr { $$ = op_gt ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
157         | expr '<' expr { $$ = op_lt ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
158         | expr GE expr  { $$ = op_ge ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
159         | expr LE expr  { $$ = op_le ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
160         | expr NE expr  { $$ = op_ne ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
161         | expr '+' expr { $$ = op_plus ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
162         | expr '-' expr { $$ = op_minus ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
163         | expr '*' expr { $$ = op_times ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
164         | expr '/' expr { $$ = op_div ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
165         | expr '%' expr { $$ = op_rem ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
166         | expr ':' expr { $$ = op_colon ($1, $3); @$.first_column = @1.first_column; @$.last_column = @3.last_column; @$.first_line=0; @$.last_line=0;}
167         ;
168
169
170 %%
171
172 static struct val *
173 make_integer (i)
174 quad_t i;
175 {
176         struct val *vp;
177
178         vp = (struct val *) malloc (sizeof (*vp));
179         if (vp == NULL) {
180                 ast_log(LOG_WARNING, "malloc() failed\n");
181                 return(NULL);
182         }
183
184         vp->type = integer;
185         vp->u.i  = i;
186         return vp; 
187 }
188
189 static struct val *
190 make_str (s)
191 const char *s;
192 {
193         struct val *vp;
194         size_t i;
195         int isint;
196
197         vp = (struct val *) malloc (sizeof (*vp));
198         if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
199                 ast_log(LOG_WARNING,"malloc() failed\n");
200                 return(NULL);
201         }
202
203         for(i = 1, isint = isdigit(s[0]) || s[0] == '-';
204             isint && i < strlen(s);
205             i++)
206         {
207                 if(!isdigit(s[i]))
208                          isint = 0;
209         }
210
211         if (isint)
212                 vp->type = numeric_string;
213         else    
214                 vp->type = string;
215
216         return vp;
217 }
218
219
220 static void
221 free_value (vp)
222 struct val *vp;
223 {       
224         if (vp==NULL) {
225                 return;
226         }
227         if (vp->type == string || vp->type == numeric_string)
228                 free (vp->u.s); 
229         free (vp);
230 }
231
232
233 static quad_t
234 to_integer (vp)
235 struct val *vp;
236 {
237         quad_t i;
238
239         if (vp == NULL) {
240                 ast_log(LOG_WARNING,"vp==NULL in to_integer()\n");
241                 return(0);
242         }
243
244         if (vp->type == integer)
245                 return 1;
246
247         if (vp->type == string)
248                 return 0;
249
250         /* vp->type == numeric_string, make it numeric */
251         errno = 0;
252         i  = strtoq(vp->u.s, (char**)NULL, 10);
253         if (errno != 0) {
254                 free(vp->u.s);
255                 ast_log(LOG_WARNING,"overflow\n");
256                 return(0);
257         }
258         free (vp->u.s);
259         vp->u.i = i;
260         vp->type = integer;
261         return 1;
262 }
263
264 static void
265 to_string (vp)
266 struct val *vp;
267 {
268         char *tmp;
269
270         if (vp->type == string || vp->type == numeric_string)
271                 return;
272
273         tmp = malloc ((size_t)25);
274         if (tmp == NULL) {
275                 ast_log(LOG_WARNING,"malloc() failed\n");
276                 return;
277         }
278
279         sprintf (tmp, "%lld", (long long)vp->u.i);
280         vp->type = string;
281         vp->u.s  = tmp;
282 }
283
284
285 static int
286 isstring (vp)
287 struct val *vp;
288 {
289         /* only TRUE if this string is not a valid integer */
290         return (vp->type == string);
291 }
292
293 static int
294 ast_yylex (YYSTYPE *lvalp, YYLTYPE *yylloc, struct parser_control *karoto)
295 {
296         char *p=0;
297         char *t1=0;
298         char savep = 0;
299         char *savepp = 0;
300         
301         if (karoto->firsttoken==1) {
302                 t1 = karoto->argv;
303                 karoto->firsttoken = 0;
304         } else {
305                 t1 = karoto->ptrptr;
306         }
307         
308         while(*t1 && *t1 == ' ' )  /* we can remove worries about leading/multiple spaces being present */
309                 t1++;
310         karoto->ptrptr = t1;
311         yylloc->first_column = t1 - karoto->argv;
312         
313         while( *t1 && *t1 != ' ' && *t1 != '"') /* find the next space or quote */
314                 t1++;
315         if( *t1 == ' ' )
316         {
317                 *t1 = 0;
318                 p = karoto->ptrptr;
319                 karoto->ptrptr = t1+1;
320                 yylloc->last_column = t1 - karoto->argv;
321         }
322         else if (*t1 == '"' )
323         {
324                 /* opening quote. find the closing quote */
325                 char *t2=t1+1;
326                 while( *t2 && *t2 != '"')
327                         t2++;
328                 if( *t2 == '"' )
329                 {
330                         if( *(t2+1) == ' ' || *(t2+1) == 0 )
331                         {
332                                 if( *(t2+1) )
333                                 {
334                                         *(t2+1) = 0;
335                                         karoto->ptrptr = t2+2;
336                                 }
337                                 else
338                                 {
339                                         karoto->ptrptr = t2+1;
340                                 }
341                         }
342                         else
343                         {
344                                 /* hmmm. what if another token is here? */
345                                 /* maybe we can insert a space? */
346                                 savep = *(t2+1);
347                                 savepp = t2+1;
348                                 *(t2+1) = 0;
349                                 karoto->ptrptr = t2+1;
350                         }
351                         p = t1;
352                 }
353                 else
354                 {
355                         /* NOT GOOD -- no closing quote! */
356                         p = t1;
357                         karoto->ptrptr = t2;
358                 }
359                 yylloc->last_column = t2 - karoto->argv;
360         }
361         else if( *t1 == 0 )
362         {
363                 if( t1 != karoto->ptrptr )
364                 {
365                         /* this is the last token */
366                         p = karoto->ptrptr;
367                         karoto->ptrptr = t1;
368                 }
369                 else
370                 {
371                         /* we are done. That was quick */
372                         p = karoto->ptrptr;
373                         yylloc->last_column = t1 - karoto->argv;
374                 }
375         }
376         if( *p == 0 )
377                 p = 0;
378         
379         if (p==NULL) {
380                 return (0);
381         }
382
383
384         if (strlen (p) == 1) {
385                 if (strchr ("|&=<>+-*/%:()", *p))
386                         return (*p);
387         } else if (strlen (p) == 2 && p[1] == '=') {
388                 switch (*p) {
389                 case '>': return (GE);
390                 case '<': return (LE);
391                 case '!': return (NE);
392                 }
393         }
394
395         lvalp->val = make_str (p);
396         if( savep )
397         {
398                 *savepp = savep; /* restore the null terminated string */
399                 savepp = 0;
400                 savep = 0;
401         }
402         return (TOKEN);
403 }
404
405 static int
406 is_zero_or_null (vp)
407 struct val *vp;
408 {
409         if (vp->type == integer) {
410                 return (vp->u.i == 0);
411         } else {
412                 return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
413         }
414         /* NOTREACHED */
415 }
416
417 char *ast_expr (char *arg)
418 {
419         struct parser_control karoto;
420
421         char *kota;
422         char *pirouni;
423         
424         kota=strdup(arg);
425         karoto.result = NULL;
426         karoto.firsttoken=1;
427         karoto.argv=kota;
428         karoto.arg_orig = arg;
429         /* ast_yydebug = 1; */
430         
431         ast_yyparse ((void *)&karoto);
432
433         free(kota);
434
435         if (karoto.result==NULL) {
436                 pirouni=strdup("0");
437                 return(pirouni);
438         } else {
439                 if (karoto.result->type == integer) {
440                         pirouni=malloc(256);
441                         sprintf (pirouni,"%lld", (long long)karoto.result->u.i);
442                 }
443                 else {
444                         pirouni=strdup(karoto.result->u.s);
445                 }
446                 free(karoto.result);
447         }
448         return(pirouni);
449 }
450
451 #ifdef STANDALONE
452
453 int main(int argc,char **argv) {
454         char *s;
455
456         s=ast_expr(argv[1]);
457
458         printf("=====%s======\n",s);
459 }
460
461 #endif
462
463 #undef ast_yyerror
464 #define ast_yyerror(x) ast_yyerror(x, YYLTYPE *yylloc, struct parser_control *karoto)
465
466 static int
467 ast_yyerror (const char *s)
468 {       
469         char spacebuf[8000]; /* best safe than sorry */
470         char spacebuf2[8000]; /* best safe than sorry */
471         int i=0;
472         spacebuf[0] = 0;
473         
474         if( yylloc->first_column > 7990 ) /* if things get out of whack, why crash? */
475                 yylloc->first_column = 7990;
476         if( yylloc->last_column > 7990 )
477                 yylloc->last_column = 7990;
478         for(i=0;i<yylloc->first_column;i++) spacebuf[i] = ' ';
479         for(   ;i<yylloc->last_column;i++) spacebuf[i] = '^';
480         spacebuf[i] = 0;
481
482         for(i=0;i<karoto->ptrptr-karoto->argv;i++) spacebuf2[i] = ' ';
483         spacebuf2[i++]='^';
484         spacebuf2[i]= 0;
485
486         ast_log(LOG_WARNING,"ast_yyerror(): syntax error: %s; Input:\n%s\n%s\n%s\n",s, 
487                         karoto->arg_orig,spacebuf,spacebuf2);
488         return(0);
489 }
490
491
492 static struct val *
493 op_or (a, b)
494 struct val *a, *b;
495 {
496         if (is_zero_or_null (a)) {
497                 free_value (a);
498                 return (b);
499         } else {
500                 free_value (b);
501                 return (a);
502         }
503 }
504                 
505 static struct val *
506 op_and (a, b)
507 struct val *a, *b;
508 {
509         if (is_zero_or_null (a) || is_zero_or_null (b)) {
510                 free_value (a);
511                 free_value (b);
512                 return (make_integer ((quad_t)0));
513         } else {
514                 free_value (b);
515                 return (a);
516         }
517 }
518
519 static struct val *
520 op_eq (a, b)
521 struct val *a, *b;
522 {
523         struct val *r; 
524
525         if (isstring (a) || isstring (b)) {
526                 to_string (a);
527                 to_string (b);  
528                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) == 0));
529         } else {
530                 (void)to_integer(a);
531                 (void)to_integer(b);
532                 r = make_integer ((quad_t)(a->u.i == b->u.i));
533         }
534
535         free_value (a);
536         free_value (b);
537         return r;
538 }
539
540 static struct val *
541 op_gt (a, b)
542 struct val *a, *b;
543 {
544         struct val *r;
545
546         if (isstring (a) || isstring (b)) {
547                 to_string (a);
548                 to_string (b);
549                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) > 0));
550         } else {
551                 (void)to_integer(a);
552                 (void)to_integer(b);
553                 r = make_integer ((quad_t)(a->u.i > b->u.i));
554         }
555
556         free_value (a);
557         free_value (b);
558         return r;
559 }
560
561 static struct val *
562 op_lt (a, b)
563 struct val *a, *b;
564 {
565         struct val *r;
566
567         if (isstring (a) || isstring (b)) {
568                 to_string (a);
569                 to_string (b);
570                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) < 0));
571         } else {
572                 (void)to_integer(a);
573                 (void)to_integer(b);
574                 r = make_integer ((quad_t)(a->u.i < b->u.i));
575         }
576
577         free_value (a);
578         free_value (b);
579         return r;
580 }
581
582 static struct val *
583 op_ge (a, b)
584 struct val *a, *b;
585 {
586         struct val *r;
587
588         if (isstring (a) || isstring (b)) {
589                 to_string (a);
590                 to_string (b);
591                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) >= 0));
592         } else {
593                 (void)to_integer(a);
594                 (void)to_integer(b);
595                 r = make_integer ((quad_t)(a->u.i >= b->u.i));
596         }
597
598         free_value (a);
599         free_value (b);
600         return r;
601 }
602
603 static struct val *
604 op_le (a, b)
605 struct val *a, *b;
606 {
607         struct val *r;
608
609         if (isstring (a) || isstring (b)) {
610                 to_string (a);
611                 to_string (b);
612                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) <= 0));
613         } else {
614                 (void)to_integer(a);
615                 (void)to_integer(b);
616                 r = make_integer ((quad_t)(a->u.i <= b->u.i));
617         }
618
619         free_value (a);
620         free_value (b);
621         return r;
622 }
623
624 static struct val *
625 op_ne (a, b)
626 struct val *a, *b;
627 {
628         struct val *r;
629
630         if (isstring (a) || isstring (b)) {
631                 to_string (a);
632                 to_string (b);
633                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) != 0));
634         } else {
635                 (void)to_integer(a);
636                 (void)to_integer(b);
637                 r = make_integer ((quad_t)(a->u.i != b->u.i));
638         }
639
640         free_value (a);
641         free_value (b);
642         return r;
643 }
644
645 static int
646 chk_plus (a, b, r)
647 quad_t a, b, r;
648 {
649         /* sum of two positive numbers must be positive */
650         if (a > 0 && b > 0 && r <= 0)
651                 return 1;
652         /* sum of two negative numbers must be negative */
653         if (a < 0 && b < 0 && r >= 0)
654                 return 1;
655         /* all other cases are OK */
656         return 0;
657 }
658
659 static struct val *
660 op_plus (a, b)
661 struct val *a, *b;
662 {
663         struct val *r;
664
665         if (!to_integer (a)) {
666                 ast_log(LOG_WARNING,"non-numeric argument\n");
667                 if (!to_integer (b)) {
668                         free_value(a);
669                         free_value(b);
670                         return make_integer(0);
671                 } else {
672                         free_value(a);
673                         return (b);
674                 }
675         } else if (!to_integer(b)) {
676                 free_value(b);
677                 return (a);
678         }
679
680         r = make_integer (/*(quad_t)*/(a->u.i + b->u.i));
681         if (chk_plus (a->u.i, b->u.i, r->u.i)) {
682                 ast_log(LOG_WARNING,"overflow\n");
683         }
684         free_value (a);
685         free_value (b);
686         return r;
687 }
688
689 static int
690 chk_minus (a, b, r)
691 quad_t a, b, r;
692 {
693         /* special case subtraction of QUAD_MIN */
694         if (b == QUAD_MIN) {
695                 if (a >= 0)
696                         return 1;
697                 else
698                         return 0;
699         }
700         /* this is allowed for b != QUAD_MIN */
701         return chk_plus (a, -b, r);
702 }
703
704 static struct val *
705 op_minus (a, b)
706 struct val *a, *b;
707 {
708         struct val *r;
709
710         if (!to_integer (a)) {
711                 ast_log(LOG_WARNING, "non-numeric argument\n");
712                 if (!to_integer (b)) {
713                         free_value(a);
714                         free_value(b);
715                         return make_integer(0);
716                 } else {
717                         r = make_integer(0 - b->u.i);
718                         free_value(a);
719                         free_value(b);
720                         return (r);
721                 }
722         } else if (!to_integer(b)) {
723                 ast_log(LOG_WARNING, "non-numeric argument\n");
724                 free_value(b);
725                 return (a);
726         }
727
728         r = make_integer (/*(quad_t)*/(a->u.i - b->u.i));
729         if (chk_minus (a->u.i, b->u.i, r->u.i)) {
730                 ast_log(LOG_WARNING, "overflow\n");
731         }
732         free_value (a);
733         free_value (b);
734         return r;
735 }
736
737 static int
738 chk_times (a, b, r)
739 quad_t a, b, r;
740 {
741         /* special case: first operand is 0, no overflow possible */
742         if (a == 0)
743                 return 0;
744         /* cerify that result of division matches second operand */
745         if (r / a != b)
746                 return 1;
747         return 0;
748 }
749
750 static struct val *
751 op_times (a, b)
752 struct val *a, *b;
753 {
754         struct val *r;
755
756         if (!to_integer (a) || !to_integer (b)) {
757                 free_value(a);
758                 free_value(b);
759                 ast_log(LOG_WARNING, "non-numeric argument\n");
760                 return(make_integer(0));
761         }
762
763         r = make_integer (/*(quad_t)*/(a->u.i * b->u.i));
764         if (chk_times (a->u.i, b->u.i, r->u.i)) {
765                 ast_log(LOG_WARNING, "overflow\n");
766         }
767         free_value (a);
768         free_value (b);
769         return (r);
770 }
771
772 static int
773 chk_div (a, b)
774 quad_t a, b;
775 {
776         /* div by zero has been taken care of before */
777         /* only QUAD_MIN / -1 causes overflow */
778         if (a == QUAD_MIN && b == -1)
779                 return 1;
780         /* everything else is OK */
781         return 0;
782 }
783
784 static struct val *
785 op_div (a, b)
786 struct val *a, *b;
787 {
788         struct val *r;
789
790         if (!to_integer (a)) {
791                 free_value(a);
792                 free_value(b);
793                 ast_log(LOG_WARNING, "non-numeric argument\n");
794                 return make_integer(0);
795         } else if (!to_integer (b)) {
796                 free_value(a);
797                 free_value(b);
798                 ast_log(LOG_WARNING, "non-numeric argument\n");
799                 return make_integer(INT_MAX);
800         }
801
802         if (b->u.i == 0) {
803                 ast_log(LOG_WARNING, "division by zero\n");             
804                 free_value(a);
805                 free_value(b);
806                 return make_integer(INT_MAX);
807         }
808
809         r = make_integer (/*(quad_t)*/(a->u.i / b->u.i));
810         if (chk_div (a->u.i, b->u.i)) {
811                 ast_log(LOG_WARNING, "overflow\n");
812         }
813         free_value (a);
814         free_value (b);
815         return r;
816 }
817         
818 static struct val *
819 op_rem (a, b)
820 struct val *a, *b;
821 {
822         struct val *r;
823
824         if (!to_integer (a) || !to_integer (b)) {
825                 ast_log(LOG_WARNING, "non-numeric argument\n");
826                 free_value(a);
827                 free_value(b);
828                 return make_integer(0);
829         }
830
831         if (b->u.i == 0) {
832                 ast_log(LOG_WARNING, "div by zero\n");
833                 free_value(a);
834                 return (b);
835         }
836
837         r = make_integer (/*(quad_t)*/(a->u.i % b->u.i));
838         /* chk_rem necessary ??? */
839         free_value (a);
840         free_value (b);
841         return r;
842 }
843         
844 static struct val *
845 op_colon (a, b)
846 struct val *a, *b;
847 {
848         regex_t rp;
849         regmatch_t rm[2];
850         char errbuf[256];
851         int eval;
852         struct val *v;
853
854         /* coerce to both arguments to strings */
855         to_string(a);
856         to_string(b);
857
858         /* compile regular expression */
859         if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
860                 regerror (eval, &rp, errbuf, sizeof(errbuf));
861                 ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
862                 free_value(a);
863                 free_value(b);
864                 return make_str("");            
865         }
866
867         /* compare string against pattern */
868         /* remember that patterns are anchored to the beginning of the line */
869         if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
870                 if (rm[1].rm_so >= 0) {
871                         *(a->u.s + rm[1].rm_eo) = '\0';
872                         v = make_str (a->u.s + rm[1].rm_so);
873
874                 } else {
875                         v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
876                 }
877         } else {
878                 if (rp.re_nsub == 0) {
879                         v = make_integer ((quad_t)0);
880                 } else {
881                         v = make_str ("");
882                 }
883         }
884
885         /* free arguments and pattern buffer */
886         free_value (a);
887         free_value (b);
888         regfree (&rp);
889
890         return v;
891 }