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