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