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