Restore EXP2 and LOG2 functions, by providing mathematical identify functions, when...
[asterisk/asterisk.git] / main / ast_expr2.y
1 %{
2 /* Written by Pace Willisson (pace@blitz.com) 
3  * and placed in the public domain.
4  *
5  * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
6  *
7  * And then overhauled twice by Steve Murphy (murf@digium.com)
8  * to add double-quoted strings, allow mult. spaces, improve
9  * error messages, and then to fold in a flex scanner for the 
10  * yylex operation.
11  *
12  * $FreeBSD: src/bin/expr/expr.y,v 1.16 2000/07/22 10:59:36 se Exp $
13  */
14
15 #include <sys/types.h>
16 #include <stdio.h>
17
18 #ifdef STANDALONE /* I guess somewhere, the feature is set in the asterisk includes */
19 #ifndef __USE_ISOC99
20 #define __USE_ISOC99 1
21 #endif
22 #endif
23
24 #ifdef __USE_ISOC99
25 #define FP___PRINTF "%.18Lg"
26 #define FP___FMOD   fmodl
27 #define FP___STRTOD  strtold
28 #define FP___TYPE    long double
29 #define FUNC_COS     cosl
30 #define FUNC_SIN     sinl
31 #define FUNC_TAN     tanl
32 #define FUNC_ACOS     acosl
33 #define FUNC_ASIN     asinl
34 #define FUNC_ATAN     atanl
35 #define FUNC_ATAN2     atan2l
36 #define FUNC_POW       powl
37 #define FUNC_SQRT       sqrtl
38 #define FUNC_FLOOR      floorl
39 #define FUNC_CEIL      ceill
40 #define FUNC_ROUND     roundl
41 #define FUNC_RINT     rintl
42 #define FUNC_TRUNC     truncl
43 #define FUNC_EXP       expl
44 #ifdef HAVE_EXP2L
45 #define FUNC_EXP2       exp2l
46 #else
47 #define FUNC_EXP2(x)    expl((x) * logl(2))
48 #endif
49 #ifdef HAVE_EXP10L
50 #define FUNC_EXP10       exp10l
51 #else
52 #define FUNC_EXP10(x)   expl((x) * logl(10))
53 #endif
54 #define FUNC_LOG       logl
55 #ifdef HAVE_LOG2L
56 #define FUNC_LOG2       log2l
57 #else
58 #define FUNC_LOG2(x)    (logl(x) / logl(2))
59 #endif
60 #ifdef HAVE_LOG10L
61 #define FUNC_LOG10       log10l
62 #else
63 #define FUNC_LOG10(x)   (logl(x) / logl(10))
64 #endif
65 #define FUNC_REMAINDER       remainderl
66 #else
67 #define FP___PRINTF "%.16g"
68 #define FP___FMOD   fmod
69 #define FP___STRTOD  strtod
70 #define FP___TYPE    double
71 #define FUNC_COS     cos
72 #define FUNC_SIN     sin
73 #define FUNC_TAN     tan
74 #define FUNC_ACOS     acos
75 #define FUNC_ASIN     asin
76 #define FUNC_ATAN     atan
77 #define FUNC_ATAN2     atan2
78 #define FUNC_POW       pow
79 #define FUNC_SQRT       sqrt
80 #define FUNC_FLOOR      floor
81 #define FUNC_CEIL      ceil
82 #define FUNC_ROUND     round
83 #define FUNC_RINT     rint
84 #define FUNC_TRUNC     trunc
85 #define FUNC_EXP       exp
86 #ifdef HAVE_EXP2
87 #define FUNC_EXP2       exp2
88 #else
89 #define FUNC_EXP2(x)    exp((x) * log(2))
90 #endif
91 #ifdef HAVE_EXP10
92 #define FUNC_EXP10       exp10
93 #else
94 #define FUNC_EXP10(x)   exp((x) * log(10))
95 #endif
96 #define FUNC_LOG       log
97 #ifdef HAVE_LOG2
98 #define FUNC_LOG2       log2
99 #else
100 #define FUNC_LOG2(x)    (log(x) / log(2))
101 #endif
102 #ifdef HAVE_LOG10
103 #define FUNC_LOG10       log10
104 #else
105 #define FUNC_LOG10(x)   (log(x) / log(10))
106 #endif
107 #define FUNC_REMAINDER       remainder
108 #endif
109
110 #include <stdlib.h>
111 #ifndef _GNU_SOURCE
112 #define _GNU_SOURCE
113 #endif
114 #include <string.h>
115 #include <math.h>
116 #include <locale.h>
117 #include <unistd.h>
118 #include <ctype.h>
119 #if !defined(SOLARIS) && !defined(__CYGWIN__)
120         /* #include <err.h> */
121 #else
122 #define quad_t int64_t
123 #endif
124 #include <errno.h>
125 #include <regex.h>
126 #include <limits.h>
127
128 #include "asterisk.h"
129 #include "asterisk/ast_expr.h"
130 #include "asterisk/logger.h"
131 #ifndef STANDALONE
132 #include "asterisk/pbx.h"
133 #endif
134
135 #if defined(LONG_LONG_MIN) && !defined(QUAD_MIN)
136 #define QUAD_MIN LONG_LONG_MIN
137 #endif
138 #if defined(LONG_LONG_MAX) && !defined(QUAD_MAX)
139 #define QUAD_MAX LONG_LONG_MAX
140 #endif
141
142 #  if ! defined(QUAD_MIN)
143 #   define QUAD_MIN     (-0x7fffffffffffffffLL-1)
144 #  endif
145 #  if ! defined(QUAD_MAX)
146 #   define QUAD_MAX     (0x7fffffffffffffffLL)
147 #  endif
148 #define YYENABLE_NLS 0
149 #define YYPARSE_PARAM parseio
150 #define YYLEX_PARAM ((struct parse_io *)parseio)->scanner
151 #define YYERROR_VERBOSE 1
152 extern char extra_error_message[4095];
153 extern int extra_error_message_supplied;
154
155 enum valtype {
156         AST_EXPR_number, AST_EXPR_numeric_string, AST_EXPR_string
157 } ;
158
159 #ifdef STANDALONE
160 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__ ((format (printf,5,6)));
161 #endif
162
163 struct val {
164         enum valtype type;
165         union {
166                 char *s;
167                 FP___TYPE i; /* either long double, or just double, on a bad day */
168         } u;
169 } ;
170
171 enum node_type {
172         AST_EXPR_NODE_COMMA, AST_EXPR_NODE_STRING, AST_EXPR_NODE_VAL
173 } ;
174
175 struct expr_node 
176 {
177         enum node_type type;
178         struct val *val;
179         struct expr_node *left;
180         struct expr_node *right;
181 };
182
183
184 typedef void *yyscan_t;
185
186 struct parse_io
187 {
188         char *string;
189         struct val *val;
190         yyscan_t scanner;
191         struct ast_channel *chan;
192 };
193  
194 static int              chk_div __P((FP___TYPE, FP___TYPE));
195 static int              chk_minus __P((FP___TYPE, FP___TYPE, FP___TYPE));
196 static int              chk_plus __P((FP___TYPE, FP___TYPE, FP___TYPE));
197 static int              chk_times __P((FP___TYPE, FP___TYPE, FP___TYPE));
198 static void             free_value __P((struct val *));
199 static int              is_zero_or_null __P((struct val *));
200 static int              isstring __P((struct val *));
201 static struct val       *make_number __P((FP___TYPE));
202 static struct val       *make_str __P((const char *));
203 static struct val       *op_and __P((struct val *, struct val *));
204 static struct val       *op_colon __P((struct val *, struct val *));
205 static struct val       *op_eqtilde __P((struct val *, struct val *));
206 static struct val       *op_div __P((struct val *, struct val *));
207 static struct val       *op_eq __P((struct val *, struct val *));
208 static struct val       *op_ge __P((struct val *, struct val *));
209 static struct val       *op_gt __P((struct val *, struct val *));
210 static struct val       *op_le __P((struct val *, struct val *));
211 static struct val       *op_lt __P((struct val *, struct val *));
212 static struct val       *op_cond __P((struct val *, struct val *, struct val *));
213 static struct val       *op_minus __P((struct val *, struct val *));
214 static struct val       *op_negate __P((struct val *));
215 static struct val       *op_compl __P((struct val *));
216 static struct val       *op_ne __P((struct val *, struct val *));
217 static struct val       *op_or __P((struct val *, struct val *));
218 static struct val       *op_plus __P((struct val *, struct val *));
219 static struct val       *op_rem __P((struct val *, struct val *));
220 static struct val       *op_times __P((struct val *, struct val *));
221 static struct val   *op_func(struct val *funcname, struct expr_node *arglist, struct ast_channel *chan);
222 static int              to_number __P((struct val *));
223 static void             to_string __P((struct val *));
224 static struct expr_node *alloc_expr_node(enum node_type);
225 static void destroy_arglist(struct expr_node *arglist);
226 static int is_really_num(char *str);
227
228 /* uh, if I want to predeclare yylex with a YYLTYPE, I have to predeclare the yyltype... sigh */
229 typedef struct yyltype
230 {
231   int first_line;
232   int first_column;
233
234   int last_line;
235   int last_column;
236 } yyltype;
237
238 # define YYLTYPE yyltype
239 # define YYLTYPE_IS_TRIVIAL 1
240
241 /* we will get warning about no prototype for yylex! But we can't
242    define it here, we have no definition yet for YYSTYPE. */
243
244 int             ast_yyerror(const char *,YYLTYPE *, struct parse_io *);
245  
246 /* I wanted to add args to the yyerror routine, so I could print out
247    some useful info about the error. Not as easy as it looks, but it
248    is possible. */
249 #define ast_yyerror(x) ast_yyerror(x,&yyloc,parseio)
250 #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);}
251 %}
252  
253 %pure-parser
254 %locations
255 /* %debug  for when you are having big problems */
256
257 /* %name-prefix="ast_yy" */
258
259 %union
260 {
261         struct val *val;
262         struct expr_node *arglist;
263 }
264
265 %{
266 extern int              ast_yylex __P((YYSTYPE *, YYLTYPE *, yyscan_t));
267 %}
268 %left <val> TOK_COMMA
269 %left <val> TOK_COND TOK_COLONCOLON
270 %left <val> TOK_OR
271 %left <val> TOK_AND
272 %left <val> TOK_EQ TOK_GT TOK_LT TOK_GE TOK_LE TOK_NE
273 %left <val> TOK_PLUS TOK_MINUS
274 %left <val> TOK_MULT TOK_DIV TOK_MOD 
275 %right <val> TOK_COMPL
276 %left <val> TOK_COLON TOK_EQTILDE
277 %left <val> TOK_RP TOK_LP
278
279
280 %token <val> TOKEN
281 %type <arglist> arglist
282 %type <val> start expr
283
284
285 %destructor {  free_value($$); }  expr TOKEN TOK_COND TOK_COLONCOLON TOK_OR TOK_AND TOK_EQ 
286                                  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 
287                                  TOK_RP TOK_LP
288
289 %%
290
291 start: expr { ((struct parse_io *)parseio)->val = (struct val *)calloc(sizeof(struct val),1);
292               ((struct parse_io *)parseio)->val->type = $1->type;
293               if( $1->type == AST_EXPR_number )
294                                   ((struct parse_io *)parseio)->val->u.i = $1->u.i;
295               else
296                                   ((struct parse_io *)parseio)->val->u.s = $1->u.s; 
297                           free($1);
298                         }
299         | {/* nothing */ ((struct parse_io *)parseio)->val = (struct val *)calloc(sizeof(struct val),1);
300               ((struct parse_io *)parseio)->val->type = AST_EXPR_string;
301                           ((struct parse_io *)parseio)->val->u.s = strdup(""); 
302                         }
303
304         ;
305
306 arglist: expr { $$ = alloc_expr_node(AST_EXPR_NODE_VAL); $$->val = $1;}
307        | arglist TOK_COMMA expr %prec TOK_RP{struct expr_node *x = alloc_expr_node(AST_EXPR_NODE_VAL);
308                                  struct expr_node *t;
309                                                                  DESTROY($2);
310                                  for (t=$1;t->right;t=t->right)
311                                                                   ;
312                                  $$ = $1; t->right = x; x->val = $3;}
313        ;
314
315 expr: 
316       TOKEN TOK_LP arglist TOK_RP { $$ = op_func($1,$3, ((struct parse_io *)parseio)->chan);
317                                             DESTROY($2);
318                                                                         DESTROY($4);
319                                                                         DESTROY($1);
320                                                                         destroy_arglist($3);
321                                   }
322     | TOKEN {$$ = $1;}
323         | TOK_LP expr TOK_RP { $$ = $2;
324                                @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
325                                                    @$.first_line=0; @$.last_line=0;
326                                                         DESTROY($1); DESTROY($3); }
327         | expr TOK_OR expr { $$ = op_or ($1, $3);
328                                                 DESTROY($2);    
329                          @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
330                                                  @$.first_line=0; @$.last_line=0;}
331         | expr TOK_AND expr { $$ = op_and ($1, $3); 
332                                                 DESTROY($2);    
333                               @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
334                           @$.first_line=0; @$.last_line=0;}
335         | expr TOK_EQ expr { $$ = op_eq ($1, $3);
336                                                 DESTROY($2);    
337                              @$.first_column = @1.first_column; @$.last_column = @3.last_column;
338                                                  @$.first_line=0; @$.last_line=0;}
339         | expr TOK_GT expr { $$ = op_gt ($1, $3);
340                                                 DESTROY($2);    
341                          @$.first_column = @1.first_column; @$.last_column = @3.last_column;
342                                                  @$.first_line=0; @$.last_line=0;}
343         | expr TOK_LT expr { $$ = op_lt ($1, $3); 
344                                                 DESTROY($2);    
345                              @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
346                                                  @$.first_line=0; @$.last_line=0;}
347         | expr TOK_GE expr  { $$ = op_ge ($1, $3); 
348                                                 DESTROY($2);    
349                               @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
350                                                   @$.first_line=0; @$.last_line=0;}
351         | expr TOK_LE expr  { $$ = op_le ($1, $3); 
352                                                 DESTROY($2);    
353                               @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
354                                                   @$.first_line=0; @$.last_line=0;}
355         | expr TOK_NE expr  { $$ = op_ne ($1, $3); 
356                                                 DESTROY($2);    
357                               @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
358                                                   @$.first_line=0; @$.last_line=0;}
359         | expr TOK_PLUS expr { $$ = op_plus ($1, $3); 
360                                                 DESTROY($2);    
361                                @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
362                                                    @$.first_line=0; @$.last_line=0;}
363         | expr TOK_MINUS expr { $$ = op_minus ($1, $3); 
364                                                 DESTROY($2);    
365                                 @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
366                                                         @$.first_line=0; @$.last_line=0;}
367         | TOK_MINUS expr %prec TOK_COMPL { $$ = op_negate ($2); 
368                                                 DESTROY($1);    
369                                 @$.first_column = @1.first_column; @$.last_column = @2.last_column; 
370                                                         @$.first_line=0; @$.last_line=0;}
371         | TOK_COMPL expr   { $$ = op_compl ($2); 
372                                                 DESTROY($1);    
373                                 @$.first_column = @1.first_column; @$.last_column = @2.last_column; 
374                                                         @$.first_line=0; @$.last_line=0;}
375         | expr TOK_MULT expr { $$ = op_times ($1, $3); 
376                                                 DESTROY($2);    
377                                @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
378                                                    @$.first_line=0; @$.last_line=0;}
379         | expr TOK_DIV expr { $$ = op_div ($1, $3); 
380                                                 DESTROY($2);    
381                               @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
382                                                   @$.first_line=0; @$.last_line=0;}
383         | expr TOK_MOD expr { $$ = op_rem ($1, $3); 
384                                                 DESTROY($2);    
385                               @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
386                                                   @$.first_line=0; @$.last_line=0;}
387         | expr TOK_COLON expr { $$ = op_colon ($1, $3); 
388                                                 DESTROY($2);    
389                                 @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
390                                                         @$.first_line=0; @$.last_line=0;}
391         | expr TOK_EQTILDE expr { $$ = op_eqtilde ($1, $3); 
392                                                 DESTROY($2);    
393                                 @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
394                                                         @$.first_line=0; @$.last_line=0;}
395         | expr TOK_COND expr TOK_COLONCOLON expr  { $$ = op_cond ($1, $3, $5); 
396                                                 DESTROY($2);    
397                                                 DESTROY($4);    
398                                 @$.first_column = @1.first_column; @$.last_column = @3.last_column; 
399                                                         @$.first_line=0; @$.last_line=0;}
400         ;
401
402 %%
403
404 static struct expr_node *alloc_expr_node(enum node_type nt)
405 {
406         struct expr_node *x = calloc(1,sizeof(struct expr_node));
407         if (!x) {
408                 ast_log(LOG_ERROR, "Allocation for expr_node FAILED!!\n");
409                 return 0;
410         }
411         x->type = nt;
412         return x;
413 }
414
415
416
417 static struct val *
418 make_number (FP___TYPE i)
419 {
420         struct val *vp;
421
422         vp = (struct val *) malloc (sizeof (*vp));
423         if (vp == NULL) {
424                 ast_log(LOG_WARNING, "malloc() failed\n");
425                 return(NULL);
426         }
427
428         vp->type = AST_EXPR_number;
429         vp->u.i  = i;
430         return vp; 
431 }
432
433 static struct val *
434 make_str (const char *s)
435 {
436         struct val *vp;
437         size_t i;
438         int isint; /* this started out being a test for an integer, but then ended up being a test for a float */
439
440         vp = (struct val *) malloc (sizeof (*vp));
441         if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
442                 ast_log(LOG_WARNING,"malloc() failed\n");
443                 return(NULL);
444         }
445
446         for (i = 0, isint = (isdigit(s[0]) || s[0] == '-' || s[0]=='.'); isint && i < strlen(s); i++)
447         {
448                 if (!isdigit(s[i]) && s[i] != '.') {
449                         isint = 0;
450                         break;
451                 }
452         }
453         if (isint)
454                 vp->type = AST_EXPR_numeric_string;
455         else    
456                 vp->type = AST_EXPR_string;
457
458         return vp;
459 }
460
461
462 static void
463 free_value (struct val *vp)
464 {       
465         if (vp==NULL) {
466                 return;
467         }
468         if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string)
469                 free (vp->u.s); 
470         free(vp);
471 }
472
473
474 static int
475 to_number (struct val *vp)
476 {
477         FP___TYPE i;
478         
479         if (vp == NULL) {
480                 ast_log(LOG_WARNING,"vp==NULL in to_number()\n");
481                 return(0);
482         }
483
484         if (vp->type == AST_EXPR_number)
485                 return 1;
486
487         if (vp->type == AST_EXPR_string)
488                 return 0;
489
490         /* vp->type == AST_EXPR_numeric_string, make it numeric */
491         errno = 0;
492         i  = FP___STRTOD(vp->u.s, (char**)0); /* either strtod, or strtold on a good day */
493         if (errno != 0) {
494                 ast_log(LOG_WARNING,"Conversion of %s to number under/overflowed!\n", vp->u.s);
495                 free(vp->u.s);
496                 vp->u.s = 0;
497                 return(0);
498         }
499         free (vp->u.s);
500         vp->u.i = i;
501         vp->type = AST_EXPR_number;
502         return 1;
503 }
504
505 static void
506 strip_quotes(struct val *vp)
507 {
508         if (vp->type != AST_EXPR_string && vp->type != AST_EXPR_numeric_string)
509                 return;
510         
511         if( vp->u.s[0] == '"' && vp->u.s[strlen(vp->u.s)-1] == '"' )
512         {
513                 char *f, *t;
514                 f = vp->u.s;
515                 t = vp->u.s;
516                 
517                 while( *f )
518                 {
519                         if( *f  && *f != '"' )
520                                 *t++ = *f++;
521                         else
522                                 f++;
523                 }
524                 *t = *f;
525         }
526 }
527
528 static void
529 to_string (struct val *vp)
530 {
531         char *tmp;
532
533         if (vp->type == AST_EXPR_string || vp->type == AST_EXPR_numeric_string)
534                 return;
535
536         tmp = malloc ((size_t)25);
537         if (tmp == NULL) {
538                 ast_log(LOG_WARNING,"malloc() failed\n");
539                 return;
540         }
541
542         sprintf(tmp, FP___PRINTF, vp->u.i);
543         vp->type = AST_EXPR_string;
544         vp->u.s  = tmp;
545 }
546
547
548 static int
549 isstring (struct val *vp)
550 {
551         /* only TRUE if this string is not a valid number */
552         return (vp->type == AST_EXPR_string);
553 }
554
555
556 static int
557 is_zero_or_null (struct val *vp)
558 {
559         if (vp->type == AST_EXPR_number) {
560                 return (vp->u.i == 0);
561         } else {
562                 return (*vp->u.s == 0 || (to_number(vp) && vp->u.i == 0));
563         }
564         /* NOTREACHED */
565 }
566
567 #ifdef STANDALONE
568
569 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
570 {
571         va_list vars;
572         va_start(vars,fmt);
573         
574         printf("LOG: lev:%d file:%s  line:%d func: %s  ",
575                    level, file, line, function);
576         vprintf(fmt, vars);
577         fflush(stdout);
578         va_end(vars);
579 }
580
581
582 int main(int argc,char **argv) {
583         char s[4096];
584         char out[4096];
585         FILE *infile;
586         
587         if( !argv[1] )
588                 exit(20);
589         
590         if( access(argv[1],F_OK)== 0 )
591         {
592                 int ret;
593                 
594                 infile = fopen(argv[1],"r");
595                 if( !infile )
596                 {
597                         printf("Sorry, couldn't open %s for reading!\n", argv[1]);
598                         exit(10);
599                 }
600                 while( fgets(s,sizeof(s),infile) )
601                 {
602                         if( s[strlen(s)-1] == '\n' )
603                                 s[strlen(s)-1] = 0;
604                         
605                         ret = ast_expr(s, out, sizeof(out),NULL);
606                         printf("Expression: %s    Result: [%d] '%s'\n",
607                                    s, ret, out);
608                 }
609                 fclose(infile);
610         }
611         else
612         {
613                 if (ast_expr(argv[1], s, sizeof(s), NULL))
614                         printf("=====%s======\n",s);
615                 else
616                         printf("No result\n");
617         }
618 }
619
620 #endif
621
622 #undef ast_yyerror
623 #define ast_yyerror(x) ast_yyerror(x, YYLTYPE *yylloc, struct parse_io *parseio)
624
625 /* I put the ast_yyerror func in the flex input file,
626    because it refers to the buffer state. Best to
627    let it access the BUFFER stuff there and not trying
628    define all the structs, macros etc. in this file! */
629
630 static void destroy_arglist(struct expr_node *arglist)
631 {
632         struct expr_node *arglist_next;
633         
634         while (arglist)
635         {
636                 arglist_next = arglist->right;
637                 if (arglist->val)
638                         free_value(arglist->val);
639                 arglist->val = 0;
640                 arglist->right = 0;
641                 free(arglist);
642                 arglist = arglist_next;
643         }
644 }
645
646 static char *compose_func_args(struct expr_node *arglist)
647 {
648         struct expr_node *t = arglist;
649         char *argbuf;
650         int total_len = 0;
651         
652         while (t) {
653                 if (t != arglist)
654                         total_len += 1; /* for the sep */
655                 if (t->val) {
656                         if (t->val->type == AST_EXPR_number)
657                                 total_len += 25; /* worst case */
658                         else
659                                 total_len += strlen(t->val->u.s);
660                 }
661                 
662                 t = t->right;
663         }
664         total_len++; /* for the null */
665         ast_log(LOG_NOTICE,"argbuf allocated %d bytes;\n", total_len);
666         argbuf = malloc(total_len);
667         argbuf[0] = 0;
668         t = arglist;
669         while (t) {
670                 char numbuf[30];
671                 
672                 if (t != arglist)
673                         strcat(argbuf,"|");
674                 
675                 if (t->val) {
676                         if (t->val->type == AST_EXPR_number) {
677                                 sprintf(numbuf,FP___PRINTF,t->val->u.i);
678                                 strcat(argbuf,numbuf);
679                         } else
680                                 strcat(argbuf,t->val->u.s);
681                 }
682                 t = t->right;
683         }
684         ast_log(LOG_NOTICE,"argbuf uses %d bytes;\n", (int) strlen(argbuf));
685         return argbuf;
686 }
687
688 static int is_really_num(char *str)
689 {
690         if ( strspn(str,"-0123456789.   ") == strlen(str))
691                 return 1;
692         else
693                 return 0;
694 }
695
696
697 static struct val *op_func(struct val *funcname, struct expr_node *arglist, struct ast_channel *chan)
698 {
699         if (strspn(funcname->u.s,"ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789") == strlen(funcname->u.s))
700         {
701                 struct val *result;
702                 
703                 if (strcmp(funcname->u.s,"COS") == 0) {
704                         if (arglist && !arglist->right && arglist->val){
705                                 to_number(arglist->val);
706                                 result = make_number(FUNC_COS(arglist->val->u.i));
707                                 return result;
708                         } else {
709                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
710                                 return make_number(0.0);
711                         }
712                 } else if (strcmp(funcname->u.s,"SIN") == 0) {
713                         if (arglist && !arglist->right && arglist->val){
714                                 to_number(arglist->val);
715                                 result = make_number(FUNC_SIN(arglist->val->u.i));
716                                 return result;
717                         } else {
718                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
719                                 return make_number(0.0);
720                         }
721                 } else if (strcmp(funcname->u.s,"TAN") == 0) {
722                         if (arglist && !arglist->right && arglist->val){
723                                 to_number(arglist->val);
724                                 result = make_number(FUNC_TAN(arglist->val->u.i));
725                                 return result;
726                         } else {
727                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
728                                 return make_number(0.0);
729                         }
730                 } else if (strcmp(funcname->u.s,"ACOS") == 0) {
731                         if (arglist && !arglist->right && arglist->val){
732                                 to_number(arglist->val);
733                                 result = make_number(FUNC_ACOS(arglist->val->u.i));
734                                 return result;
735                         } else {
736                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
737                                 return make_number(0.0);
738                         }
739                 } else if (strcmp(funcname->u.s,"ASIN") == 0) {
740                         if (arglist && !arglist->right && arglist->val){
741                                 to_number(arglist->val);
742                                 result = make_number(FUNC_ASIN(arglist->val->u.i));
743                                 return result;
744                         } else {
745                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
746                                 return make_number(0.0);
747                         }
748                 } else if (strcmp(funcname->u.s,"ATAN") == 0) {
749                         if (arglist && !arglist->right && arglist->val){
750                                 to_number(arglist->val);
751                                 result = make_number(FUNC_ATAN(arglist->val->u.i));
752                                 return result;
753                         } else {
754                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
755                                 return make_number(0.0);
756                         }
757                 } else if (strcmp(funcname->u.s,"ATAN2") == 0) {
758                         if (arglist && arglist->right && !arglist->right->right && arglist->val && arglist->right->val){
759                                 to_number(arglist->val);
760                                 to_number(arglist->right->val);
761                                 result = make_number(FUNC_ATAN2(arglist->val->u.i, arglist->right->val->u.i));
762                                 return result;
763                         } else {
764                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
765                                 return make_number(0.0);
766                         }
767                 } else if (strcmp(funcname->u.s,"POW") == 0) {
768                         if (arglist && arglist->right && !arglist->right->right && arglist->val && arglist->right->val){
769                                 to_number(arglist->val);
770                                 to_number(arglist->right->val);
771                                 result = make_number(FUNC_POW(arglist->val->u.i, arglist->right->val->u.i));
772                                 return result;
773                         } else {
774                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
775                                 return make_number(0.0);
776                         }
777                 } else if (strcmp(funcname->u.s,"SQRT") == 0) {
778                         if (arglist && !arglist->right && arglist->val){
779                                 to_number(arglist->val);
780                                 result = make_number(FUNC_SQRT(arglist->val->u.i));
781                                 return result;
782                         } else {
783                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
784                                 return make_number(0.0);
785                         }
786                 } else if (strcmp(funcname->u.s,"FLOOR") == 0) {
787                         if (arglist && !arglist->right && arglist->val){
788                                 to_number(arglist->val);
789                                 result = make_number(FUNC_FLOOR(arglist->val->u.i));
790                                 return result;
791                         } else {
792                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
793                                 return make_number(0.0);
794                         }
795                 } else if (strcmp(funcname->u.s,"CEIL") == 0) {
796                         if (arglist && !arglist->right && arglist->val){
797                                 to_number(arglist->val);
798                                 result = make_number(FUNC_CEIL(arglist->val->u.i));
799                                 return result;
800                         } else {
801                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
802                                 return make_number(0.0);
803                         }
804                 } else if (strcmp(funcname->u.s,"ROUND") == 0) {
805                         if (arglist && !arglist->right && arglist->val){
806                                 to_number(arglist->val);
807                                 result = make_number(FUNC_ROUND(arglist->val->u.i));
808                                 return result;
809                         } else {
810                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
811                                 return make_number(0.0);
812                         }
813                 } else if (strcmp(funcname->u.s,"RINT") == 0) {
814                         if (arglist && !arglist->right && arglist->val){
815                                 to_number(arglist->val);
816                                 result = make_number(FUNC_RINT(arglist->val->u.i));
817                                 return result;
818                         } else {
819                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
820                                 return make_number(0.0);
821                         }
822                 } else if (strcmp(funcname->u.s,"TRUNC") == 0) {
823                         if (arglist && !arglist->right && arglist->val){
824                                 to_number(arglist->val);
825                                 result = make_number(FUNC_TRUNC(arglist->val->u.i));
826                                 return result;
827                         } else {
828                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
829                                 return make_number(0.0);
830                         }
831                 } else if (strcmp(funcname->u.s,"EXP") == 0) {
832                         if (arglist && !arglist->right && arglist->val){
833                                 to_number(arglist->val);
834                                 result = make_number(FUNC_EXP(arglist->val->u.i));
835                                 return result;
836                         } else {
837                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
838                                 return make_number(0.0);
839                         }
840                 } else if (strcmp(funcname->u.s,"EXP2") == 0) {
841                         if (arglist && !arglist->right && arglist->val){
842                                 to_number(arglist->val);
843                                 result = make_number(FUNC_EXP2(arglist->val->u.i));
844                                 return result;
845                         } else {
846                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
847                                 return make_number(0.0);
848                         }
849                 } else if (strcmp(funcname->u.s,"EXP10") == 0) {
850                         if (arglist && !arglist->right && arglist->val){
851                                 to_number(arglist->val);
852                                 result = make_number(FUNC_EXP10(arglist->val->u.i));
853                                 return result;
854                         } else {
855                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
856                                 return make_number(0.0);
857                         }
858                 } else if (strcmp(funcname->u.s,"LOG") == 0) {
859                         if (arglist && !arglist->right && arglist->val){
860                                 to_number(arglist->val);
861                                 result = make_number(FUNC_LOG(arglist->val->u.i));
862                                 return result;
863                         } else {
864                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
865                                 return make_number(0.0);
866                         }
867                 } else if (strcmp(funcname->u.s,"LOG2") == 0) {
868                         if (arglist && !arglist->right && arglist->val){
869                                 to_number(arglist->val);
870                                 result = make_number(FUNC_LOG2(arglist->val->u.i));
871                                 return result;
872                         } else {
873                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
874                                 return make_number(0.0);
875                         }
876                 } else if (strcmp(funcname->u.s,"LOG10") == 0) {
877                         if (arglist && !arglist->right && arglist->val){
878                                 to_number(arglist->val);
879                                 result = make_number(FUNC_LOG10(arglist->val->u.i));
880                                 return result;
881                         } else {
882                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
883                                 return make_number(0.0);
884                         }
885                 } else if (strcmp(funcname->u.s,"REMAINDER") == 0) {
886                         if (arglist && arglist->right && !arglist->right->right && arglist->val && arglist->right->val){
887                                 to_number(arglist->val);
888                                 to_number(arglist->right->val);
889                                 result = make_number(FUNC_REMAINDER(arglist->val->u.i, arglist->right->val->u.i));
890                                 return result;
891                         } else {
892                                 ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
893                                 return make_number(0.0);
894                         }
895                 } else {
896                         /* is this a custom function we should execute and collect the results of? */
897 #ifndef STANDALONE
898                         struct ast_custom_function *f = ast_custom_function_find(funcname->u.s);
899                         if (!chan)
900                                 ast_log(LOG_WARNING,"Hey! chan is NULL.\n");
901                         if (!f)
902                                 ast_log(LOG_WARNING,"Hey! could not find func %s.\n", funcname->u.s);
903                         
904                         if (f && chan) {
905                                 if (f->read) {
906                                         char workspace[512];
907                                         char *argbuf = compose_func_args(arglist);
908                                         f->read(chan, funcname->u.s, argbuf, workspace, sizeof(workspace));
909                                         free(argbuf);
910                                         if (is_really_num(workspace))
911                                                 return make_number(FP___STRTOD(workspace,(char **)NULL));
912                                         else
913                                                 return make_str(workspace);
914                                 } else {
915                                         ast_log(LOG_ERROR,"Error! Function '%s' cannot be read!\n", funcname->u.s);
916                                         return (make_number ((FP___TYPE)0.0));
917                                 }
918                                 
919                         } else {
920                                 ast_log(LOG_ERROR,"Error! '%s' doesn't appear to be an available function!", funcname->u.s);
921                                 return (make_number ((FP___TYPE)0.0));
922                         }
923 #else
924                         ast_log(LOG_ERROR,"Error! '%s' is not available in the standalone version!", funcname->u.s);
925                         return (make_number ((FP___TYPE)0.0));
926 #endif
927                 }
928         }
929         else
930         {
931                 ast_log(LOG_ERROR,"Error! '%s' is not possibly a function name!", funcname->u.s);
932                 return (make_number ((FP___TYPE)0.0));
933         }
934         return (make_number ((FP___TYPE)0.0));
935 }
936
937
938 static struct val *
939 op_or (struct val *a, struct val *b)
940 {
941         if (is_zero_or_null (a)) {
942                 free_value (a);
943                 return (b);
944         } else {
945                 free_value (b);
946                 return (a);
947         }
948 }
949                 
950 static struct val *
951 op_and (struct val *a, struct val *b)
952 {
953         if (is_zero_or_null (a) || is_zero_or_null (b)) {
954                 free_value (a);
955                 free_value (b);
956                 return (make_number ((FP___TYPE)0.0));
957         } else {
958                 free_value (b);
959                 return (a);
960         }
961 }
962
963 static struct val *
964 op_eq (struct val *a, struct val *b)
965 {
966         struct val *r; 
967
968         if (isstring (a) || isstring (b)) {
969                 to_string (a);
970                 to_string (b);  
971                 r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) == 0));
972         } else {
973 #ifdef DEBUG_FOR_CONVERSIONS
974                 char buffer[2000];
975                 sprintf(buffer,"Converting '%s' and '%s' ", a->u.s, b->u.s);
976 #endif
977                 (void)to_number(a);
978                 (void)to_number(b);
979 #ifdef DEBUG_FOR_CONVERSIONS
980                 ast_log(LOG_WARNING,"%s to '%lld' and '%lld'\n", buffer, a->u.i, b->u.i);
981 #endif
982                 r = make_number ((FP___TYPE)(a->u.i == b->u.i));
983         }
984
985         free_value (a);
986         free_value (b);
987         return r;
988 }
989
990 static struct val *
991 op_gt (struct val *a, struct val *b)
992 {
993         struct val *r;
994
995         if (isstring (a) || isstring (b)) {
996                 to_string (a);
997                 to_string (b);
998                 r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) > 0));
999         } else {
1000                 (void)to_number(a);
1001                 (void)to_number(b);
1002                 r = make_number ((FP___TYPE)(a->u.i > b->u.i));
1003         }
1004
1005         free_value (a);
1006         free_value (b);
1007         return r;
1008 }
1009
1010 static struct val *
1011 op_lt (struct val *a, struct val *b)
1012 {
1013         struct val *r;
1014
1015         if (isstring (a) || isstring (b)) {
1016                 to_string (a);
1017                 to_string (b);
1018                 r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) < 0));
1019         } else {
1020                 (void)to_number(a);
1021                 (void)to_number(b);
1022                 r = make_number ((FP___TYPE)(a->u.i < b->u.i));
1023         }
1024
1025         free_value (a);
1026         free_value (b);
1027         return r;
1028 }
1029
1030 static struct val *
1031 op_ge (struct val *a, struct val *b)
1032 {
1033         struct val *r;
1034
1035         if (isstring (a) || isstring (b)) {
1036                 to_string (a);
1037                 to_string (b);
1038                 r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) >= 0));
1039         } else {
1040                 (void)to_number(a);
1041                 (void)to_number(b);
1042                 r = make_number ((FP___TYPE)(a->u.i >= b->u.i));
1043         }
1044
1045         free_value (a);
1046         free_value (b);
1047         return r;
1048 }
1049
1050 static struct val *
1051 op_le (struct val *a, struct val *b)
1052 {
1053         struct val *r;
1054
1055         if (isstring (a) || isstring (b)) {
1056                 to_string (a);
1057                 to_string (b);
1058                 r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) <= 0));
1059         } else {
1060                 (void)to_number(a);
1061                 (void)to_number(b);
1062                 r = make_number ((FP___TYPE)(a->u.i <= b->u.i));
1063         }
1064
1065         free_value (a);
1066         free_value (b);
1067         return r;
1068 }
1069
1070 static struct val *
1071 op_cond (struct val *a, struct val *b, struct val *c)
1072 {
1073         struct val *r;
1074
1075         if( isstring(a) )
1076         {
1077                 if( strlen(a->u.s) && strcmp(a->u.s, "\"\"") != 0 && strcmp(a->u.s,"0") != 0 )
1078                 {
1079                         free_value(a);
1080                         free_value(c);
1081                         r = b;
1082                 }
1083                 else
1084                 {
1085                         free_value(a);
1086                         free_value(b);
1087                         r = c;
1088                 }
1089         }
1090         else
1091         {
1092                 (void)to_number(a);
1093                 if( a->u.i )
1094                 {
1095                         free_value(a);
1096                         free_value(c);
1097                         r = b;
1098                 }
1099                 else
1100                 {
1101                         free_value(a);
1102                         free_value(b);
1103                         r = c;
1104                 }
1105         }
1106         return r;
1107 }
1108
1109 static struct val *
1110 op_ne (struct val *a, struct val *b)
1111 {
1112         struct val *r;
1113
1114         if (isstring (a) || isstring (b)) {
1115                 to_string (a);
1116                 to_string (b);
1117                 r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) != 0));
1118         } else {
1119                 (void)to_number(a);
1120                 (void)to_number(b);
1121                 r = make_number ((FP___TYPE)(a->u.i != b->u.i));
1122         }
1123
1124         free_value (a);
1125         free_value (b);
1126         return r;
1127 }
1128
1129 static int
1130 chk_plus (FP___TYPE a, FP___TYPE b, FP___TYPE r)
1131 {
1132         /* sum of two positive numbers must be positive */
1133         if (a > 0 && b > 0 && r <= 0)
1134                 return 1;
1135         /* sum of two negative numbers must be negative */
1136         if (a < 0 && b < 0 && r >= 0)
1137                 return 1;
1138         /* all other cases are OK */
1139         return 0;
1140 }
1141
1142 static struct val *
1143 op_plus (struct val *a, struct val *b)
1144 {
1145         struct val *r;
1146
1147         if (!to_number (a)) {
1148                 if( !extra_error_message_supplied )
1149                         ast_log(LOG_WARNING,"non-numeric argument\n");
1150                 if (!to_number (b)) {
1151                         free_value(a);
1152                         free_value(b);
1153                         return make_number(0);
1154                 } else {
1155                         free_value(a);
1156                         return (b);
1157                 }
1158         } else if (!to_number(b)) {
1159                 free_value(b);
1160                 return (a);
1161         }
1162
1163         r = make_number (a->u.i + b->u.i);
1164         if (chk_plus (a->u.i, b->u.i, r->u.i)) {
1165                 ast_log(LOG_WARNING,"overflow\n");
1166         }
1167         free_value (a);
1168         free_value (b);
1169         return r;
1170 }
1171
1172 static int
1173 chk_minus (FP___TYPE a, FP___TYPE b, FP___TYPE r)
1174 {
1175         /* special case subtraction of QUAD_MIN */
1176         if (b == QUAD_MIN) {
1177                 if (a >= 0)
1178                         return 1;
1179                 else
1180                         return 0;
1181         }
1182         /* this is allowed for b != QUAD_MIN */
1183         return chk_plus (a, -b, r);
1184 }
1185
1186 static struct val *
1187 op_minus (struct val *a, struct val *b)
1188 {
1189         struct val *r;
1190
1191         if (!to_number (a)) {
1192                 if( !extra_error_message_supplied )
1193                         ast_log(LOG_WARNING, "non-numeric argument\n");
1194                 if (!to_number (b)) {
1195                         free_value(a);
1196                         free_value(b);
1197                         return make_number(0);
1198                 } else {
1199                         r = make_number(0 - b->u.i);
1200                         free_value(a);
1201                         free_value(b);
1202                         return (r);
1203                 }
1204         } else if (!to_number(b)) {
1205                 if( !extra_error_message_supplied )
1206                         ast_log(LOG_WARNING, "non-numeric argument\n");
1207                 free_value(b);
1208                 return (a);
1209         }
1210
1211         r = make_number (a->u.i - b->u.i);
1212         if (chk_minus (a->u.i, b->u.i, r->u.i)) {
1213                 ast_log(LOG_WARNING, "overflow\n");
1214         }
1215         free_value (a);
1216         free_value (b);
1217         return r;
1218 }
1219
1220 static struct val *
1221 op_negate (struct val *a)
1222 {
1223         struct val *r;
1224
1225         if (!to_number (a) ) {
1226                 free_value(a);
1227                 if( !extra_error_message_supplied )
1228                         ast_log(LOG_WARNING, "non-numeric argument\n");
1229                 return make_number(0);
1230         }
1231
1232         r = make_number (- a->u.i);
1233         if (chk_minus (0, a->u.i, r->u.i)) {
1234                 ast_log(LOG_WARNING, "overflow\n");
1235         }
1236         free_value (a);
1237         return r;
1238 }
1239
1240 static struct val *
1241 op_compl (struct val *a)
1242 {
1243         int v1 = 1;
1244         struct val *r;
1245         
1246         if( !a )
1247         {
1248                 v1 = 0;
1249         }
1250         else
1251         {
1252                 switch( a->type )
1253                 {
1254                 case AST_EXPR_number:
1255                         if( a->u.i == 0 )
1256                                 v1 = 0;
1257                         break;
1258                         
1259                 case AST_EXPR_string:
1260                         if( a->u.s == 0 )
1261                                 v1 = 0;
1262                         else
1263                         {
1264                                 if( a->u.s[0] == 0 )
1265                                         v1 = 0;
1266                                 else if (strlen(a->u.s) == 1 && a->u.s[0] == '0' )
1267                                         v1 = 0;
1268                         }
1269                         break;
1270                         
1271                 case AST_EXPR_numeric_string:
1272                         if( a->u.s == 0 )
1273                                 v1 = 0;
1274                         else
1275                         {
1276                                 if( a->u.s[0] == 0 )
1277                                         v1 = 0;
1278                                 else if (strlen(a->u.s) == 1 && a->u.s[0] == '0' )
1279                                         v1 = 0;
1280                         }
1281                         break;
1282                 }
1283         }
1284         
1285         r = make_number (!v1);
1286         free_value (a);
1287         return r;
1288 }
1289
1290 static int
1291 chk_times (FP___TYPE a, FP___TYPE b, FP___TYPE r)
1292 {
1293         /* special case: first operand is 0, no overflow possible */
1294         if (a == 0)
1295                 return 0;
1296         /* cerify that result of division matches second operand */
1297         if (r / a != b)
1298                 return 1;
1299         return 0;
1300 }
1301
1302 static struct val *
1303 op_times (struct val *a, struct val *b)
1304 {
1305         struct val *r;
1306
1307         if (!to_number (a) || !to_number (b)) {
1308                 free_value(a);
1309                 free_value(b);
1310                 if( !extra_error_message_supplied )
1311                         ast_log(LOG_WARNING, "non-numeric argument\n");
1312                 return(make_number(0));
1313         }
1314
1315         r = make_number (a->u.i * b->u.i);
1316         if (chk_times (a->u.i, b->u.i, r->u.i)) {
1317                 ast_log(LOG_WARNING, "overflow\n");
1318         }
1319         free_value (a);
1320         free_value (b);
1321         return (r);
1322 }
1323
1324 static int
1325 chk_div (FP___TYPE a, FP___TYPE b)
1326 {
1327         /* div by zero has been taken care of before */
1328         /* only QUAD_MIN / -1 causes overflow */
1329         if (a == QUAD_MIN && b == -1)
1330                 return 1;
1331         /* everything else is OK */
1332         return 0;
1333 }
1334
1335 static struct val *
1336 op_div (struct val *a, struct val *b)
1337 {
1338         struct val *r;
1339
1340         if (!to_number (a)) {
1341                 free_value(a);
1342                 free_value(b);
1343                 if( !extra_error_message_supplied )
1344                         ast_log(LOG_WARNING, "non-numeric argument\n");
1345                 return make_number(0);
1346         } else if (!to_number (b)) {
1347                 free_value(a);
1348                 free_value(b);
1349                 if( !extra_error_message_supplied )
1350                         ast_log(LOG_WARNING, "non-numeric argument\n");
1351                 return make_number(INT_MAX);
1352         }
1353
1354         if (b->u.i == 0) {
1355                 ast_log(LOG_WARNING, "division by zero\n");             
1356                 free_value(a);
1357                 free_value(b);
1358                 return make_number(INT_MAX);
1359         }
1360
1361         r = make_number (a->u.i / b->u.i);
1362         if (chk_div (a->u.i, b->u.i)) {
1363                 ast_log(LOG_WARNING, "overflow\n");
1364         }
1365         free_value (a);
1366         free_value (b);
1367         return r;
1368 }
1369         
1370 static struct val *
1371 op_rem (struct val *a, struct val *b)
1372 {
1373         struct val *r;
1374
1375         if (!to_number (a) || !to_number (b)) {
1376                 if( !extra_error_message_supplied )
1377                         ast_log(LOG_WARNING, "non-numeric argument\n");
1378                 free_value(a);
1379                 free_value(b);
1380                 return make_number(0);
1381         }
1382
1383         if (b->u.i == 0) {
1384                 ast_log(LOG_WARNING, "div by zero\n");
1385                 free_value(a);
1386                 return(b);
1387         }
1388
1389         r = make_number (FP___FMOD(a->u.i, b->u.i)); /* either fmod or fmodl if FP___TYPE is available */
1390         /* chk_rem necessary ??? */
1391         free_value (a);
1392         free_value (b);
1393         return r;
1394 }
1395         
1396
1397 static struct val *
1398 op_colon (struct val *a, struct val *b)
1399 {
1400         regex_t rp;
1401         regmatch_t rm[2];
1402         char errbuf[256];
1403         int eval;
1404         struct val *v;
1405
1406         /* coerce to both arguments to strings */
1407         to_string(a);
1408         to_string(b);
1409         /* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
1410         strip_quotes(a);
1411         strip_quotes(b);
1412         /* compile regular expression */
1413         if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
1414                 regerror (eval, &rp, errbuf, sizeof(errbuf));
1415                 ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
1416                 free_value(a);
1417                 free_value(b);
1418                 return make_str("");            
1419         }
1420
1421         /* compare string against pattern */
1422         /* remember that patterns are anchored to the beginning of the line */
1423         if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
1424                 if (rm[1].rm_so >= 0) {
1425                         *(a->u.s + rm[1].rm_eo) = '\0';
1426                         v = make_str (a->u.s + rm[1].rm_so);
1427
1428                 } else {
1429                         v = make_number ((FP___TYPE)(rm[0].rm_eo - rm[0].rm_so));
1430                 }
1431         } else {
1432                 if (rp.re_nsub == 0) {
1433                         v = make_number ((FP___TYPE)0);
1434                 } else {
1435                         v = make_str ("");
1436                 }
1437         }
1438
1439         /* free arguments and pattern buffer */
1440         free_value (a);
1441         free_value (b);
1442         regfree (&rp);
1443
1444         return v;
1445 }
1446         
1447
1448 static struct val *
1449 op_eqtilde (struct val *a, struct val *b)
1450 {
1451         regex_t rp;
1452         regmatch_t rm[2];
1453         char errbuf[256];
1454         int eval;
1455         struct val *v;
1456
1457         /* coerce to both arguments to strings */
1458         to_string(a);
1459         to_string(b);
1460         /* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
1461         strip_quotes(a);
1462         strip_quotes(b);
1463         /* compile regular expression */
1464         if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
1465                 regerror (eval, &rp, errbuf, sizeof(errbuf));
1466                 ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
1467                 free_value(a);
1468                 free_value(b);
1469                 return make_str("");            
1470         }
1471
1472         /* compare string against pattern */
1473         /* remember that patterns are anchored to the beginning of the line */
1474         if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 ) {
1475                 if (rm[1].rm_so >= 0) {
1476                         *(a->u.s + rm[1].rm_eo) = '\0';
1477                         v = make_str (a->u.s + rm[1].rm_so);
1478
1479                 } else {
1480                         v = make_number ((FP___TYPE)(rm[0].rm_eo - rm[0].rm_so));
1481                 }
1482         } else {
1483                 if (rp.re_nsub == 0) {
1484                         v = make_number ((FP___TYPE)0.0);
1485                 } else {
1486                         v = make_str ("");
1487                 }
1488         }
1489
1490         /* free arguments and pattern buffer */
1491         free_value (a);
1492         free_value (b);
1493         regfree (&rp);
1494
1495         return v;
1496 }