67b56fdd894c199e373911d84f3350d7ac3f589d
[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
280         if (karoto->firsttoken==1) {
281                 t1 = karoto->argv;
282                 karoto->firsttoken = 0;
283         } else {
284                 t1 = karoto->ptrptr;
285         }
286         
287         while(*t1 && *t1 == ' ' )  /* we can remove worries about leading/multiple spaces being present */
288                 t1++;
289         karoto->ptrptr = t1;
290         yylloc->first_column = t1 - karoto->argv;
291         
292         while( *t1 && *t1 != ' ' && *t1 != '"') /* find the next space or quote */
293                 t1++;
294         if( *t1 == ' ' )
295         {
296                 *t1 = 0;
297                 p = karoto->ptrptr;
298                 karoto->ptrptr = t1+1;
299                 yylloc->last_column = t1 - karoto->argv;
300         }
301         else if (*t1 == '"' )
302         {
303                 /* opening quote. find the closing quote */
304                 char *t2=t1+1;
305                 while( *t2 && *t2 != '"')
306                         t2++;
307                 if( *t2 == '"' )
308                 {
309                         *t2 = 0;
310                         karoto->ptrptr = t2+1;
311                         p = t1+1;
312                 }
313                 else
314                 {
315                         /* NOT GOOD -- no closing quote! */
316                         p = t1;
317                         karoto->ptrptr = t2;
318                 }
319                 yylloc->last_column = t2 - karoto->argv;
320         }
321         else if( *t1 == 0 )
322         {
323                 /* we are done. That was quick */
324                 p = karoto->ptrptr;
325                 yylloc->last_column = t1 - karoto->argv;
326         }
327         if( *p == 0 )
328                 p = 0;
329         
330         if (p==NULL) {
331                 return (0);
332         }
333
334
335         if (strlen (p) == 1) {
336                 if (strchr ("|&=<>+-*/%:()", *p))
337                         return (*p);
338         } else if (strlen (p) == 2 && p[1] == '=') {
339                 switch (*p) {
340                 case '>': return (GE);
341                 case '<': return (LE);
342                 case '!': return (NE);
343                 }
344         }
345
346         lvalp->val = make_str (p);
347         return (TOKEN);
348 }
349
350 static int
351 is_zero_or_null (vp)
352 struct val *vp;
353 {
354         if (vp->type == integer) {
355                 return (vp->u.i == 0);
356         } else {
357                 return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
358         }
359         /* NOTREACHED */
360 }
361
362 char *ast_expr (char *arg)
363 {
364         struct parser_control karoto;
365
366         char *kota;
367         char *pirouni;
368         
369         kota=strdup(arg);
370         karoto.result = NULL;
371         karoto.firsttoken=1;
372         karoto.argv=kota;
373         karoto.arg_orig = arg;
374         /* ast_yydebug = 1; */
375         
376         ast_yyparse ((void *)&karoto);
377
378         free(kota);
379
380         if (karoto.result==NULL) {
381                 pirouni=strdup("0");
382                 return(pirouni);
383         } else {
384                 if (karoto.result->type == integer) {
385                         pirouni=malloc(256);
386                         sprintf (pirouni,"%lld", (long long)karoto.result->u.i);
387                 }
388                 else {
389                         pirouni=strdup(karoto.result->u.s);
390                 }
391                 free(karoto.result);
392         }
393         return(pirouni);
394 }
395
396 #ifdef STANDALONE
397
398 int main(int argc,char **argv) {
399         char *s;
400
401         s=ast_expr(argv[1]);
402
403         printf("=====%s======\n",s);
404 }
405
406 #endif
407
408 #undef ast_yyerror
409 #define ast_yyerror(x) ast_yyerror(x, YYLTYPE *yylloc, struct parser_control *karoto)
410
411 static int
412 ast_yyerror (const char *s)
413 {       
414         char spacebuf[8000]; /* best safe than sorry */
415         char spacebuf2[8000]; /* best safe than sorry */
416         int i=0;
417         spacebuf[0] = 0;
418         
419         if( yylloc->first_column > 7990 ) /* if things get out of whack, why crash? */
420                 yylloc->first_column = 7990;
421         if( yylloc->last_column > 7990 )
422                 yylloc->last_column = 7990;
423         for(i=0;i<yylloc->first_column;i++) spacebuf[i] = ' ';
424         for(   ;i<yylloc->last_column;i++) spacebuf[i] = '^';
425         spacebuf[i] = 0;
426
427         for(i=0;i<karoto->ptrptr-karoto->argv;i++) spacebuf2[i] = ' ';
428         spacebuf2[i++]='^';
429         spacebuf2[i]= 0;
430
431         ast_log(LOG_WARNING,"ast_yyerror(): syntax error: %s; Input:\n%s\n%s\n%s\n",s, 
432                         karoto->arg_orig,spacebuf,spacebuf2);
433         return(0);
434 }
435
436
437 static struct val *
438 op_or (a, b)
439 struct val *a, *b;
440 {
441         if (is_zero_or_null (a)) {
442                 free_value (a);
443                 return (b);
444         } else {
445                 free_value (b);
446                 return (a);
447         }
448 }
449                 
450 static struct val *
451 op_and (a, b)
452 struct val *a, *b;
453 {
454         if (is_zero_or_null (a) || is_zero_or_null (b)) {
455                 free_value (a);
456                 free_value (b);
457                 return (make_integer ((quad_t)0));
458         } else {
459                 free_value (b);
460                 return (a);
461         }
462 }
463
464 static struct val *
465 op_eq (a, b)
466 struct val *a, *b;
467 {
468         struct val *r; 
469
470         if (isstring (a) || isstring (b)) {
471                 to_string (a);
472                 to_string (b);  
473                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) == 0));
474         } else {
475                 (void)to_integer(a);
476                 (void)to_integer(b);
477                 r = make_integer ((quad_t)(a->u.i == b->u.i));
478         }
479
480         free_value (a);
481         free_value (b);
482         return r;
483 }
484
485 static struct val *
486 op_gt (a, b)
487 struct val *a, *b;
488 {
489         struct val *r;
490
491         if (isstring (a) || isstring (b)) {
492                 to_string (a);
493                 to_string (b);
494                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) > 0));
495         } else {
496                 (void)to_integer(a);
497                 (void)to_integer(b);
498                 r = make_integer ((quad_t)(a->u.i > b->u.i));
499         }
500
501         free_value (a);
502         free_value (b);
503         return r;
504 }
505
506 static struct val *
507 op_lt (a, b)
508 struct val *a, *b;
509 {
510         struct val *r;
511
512         if (isstring (a) || isstring (b)) {
513                 to_string (a);
514                 to_string (b);
515                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) < 0));
516         } else {
517                 (void)to_integer(a);
518                 (void)to_integer(b);
519                 r = make_integer ((quad_t)(a->u.i < b->u.i));
520         }
521
522         free_value (a);
523         free_value (b);
524         return r;
525 }
526
527 static struct val *
528 op_ge (a, b)
529 struct val *a, *b;
530 {
531         struct val *r;
532
533         if (isstring (a) || isstring (b)) {
534                 to_string (a);
535                 to_string (b);
536                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) >= 0));
537         } else {
538                 (void)to_integer(a);
539                 (void)to_integer(b);
540                 r = make_integer ((quad_t)(a->u.i >= b->u.i));
541         }
542
543         free_value (a);
544         free_value (b);
545         return r;
546 }
547
548 static struct val *
549 op_le (a, b)
550 struct val *a, *b;
551 {
552         struct val *r;
553
554         if (isstring (a) || isstring (b)) {
555                 to_string (a);
556                 to_string (b);
557                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) <= 0));
558         } else {
559                 (void)to_integer(a);
560                 (void)to_integer(b);
561                 r = make_integer ((quad_t)(a->u.i <= b->u.i));
562         }
563
564         free_value (a);
565         free_value (b);
566         return r;
567 }
568
569 static struct val *
570 op_ne (a, b)
571 struct val *a, *b;
572 {
573         struct val *r;
574
575         if (isstring (a) || isstring (b)) {
576                 to_string (a);
577                 to_string (b);
578                 r = make_integer ((quad_t)(strcoll (a->u.s, b->u.s) != 0));
579         } else {
580                 (void)to_integer(a);
581                 (void)to_integer(b);
582                 r = make_integer ((quad_t)(a->u.i != b->u.i));
583         }
584
585         free_value (a);
586         free_value (b);
587         return r;
588 }
589
590 static int
591 chk_plus (a, b, r)
592 quad_t a, b, r;
593 {
594         /* sum of two positive numbers must be positive */
595         if (a > 0 && b > 0 && r <= 0)
596                 return 1;
597         /* sum of two negative numbers must be negative */
598         if (a < 0 && b < 0 && r >= 0)
599                 return 1;
600         /* all other cases are OK */
601         return 0;
602 }
603
604 static struct val *
605 op_plus (a, b)
606 struct val *a, *b;
607 {
608         struct val *r;
609
610         if (!to_integer (a) || !to_integer (b)) {
611                 ast_log(LOG_WARNING,"non-numeric argument\n");
612                 free_value(a);
613                 free_value(b);
614                 return(NULL);
615         }
616
617         r = make_integer (/*(quad_t)*/(a->u.i + b->u.i));
618         if (chk_plus (a->u.i, b->u.i, r->u.i)) {
619                 ast_log(LOG_WARNING,"overflow\n");
620                 free_value(a);
621                 free_value(b);
622                 return(NULL);
623         }
624         free_value (a);
625         free_value (b);
626         return r;
627 }
628
629 static int
630 chk_minus (a, b, r)
631 quad_t a, b, r;
632 {
633         /* special case subtraction of QUAD_MIN */
634         if (b == QUAD_MIN) {
635                 if (a >= 0)
636                         return 1;
637                 else
638                         return 0;
639         }
640         /* this is allowed for b != QUAD_MIN */
641         return chk_plus (a, -b, r);
642 }
643
644 static struct val *
645 op_minus (a, b)
646 struct val *a, *b;
647 {
648         struct val *r;
649
650         if (!to_integer (a) || !to_integer (b)) {
651                 free_value(a);
652                 free_value(b);
653                 ast_log(LOG_WARNING, "non-numeric argument\n");
654                 return(NULL);
655         }
656
657         r = make_integer (/*(quad_t)*/(a->u.i - b->u.i));
658         if (chk_minus (a->u.i, b->u.i, r->u.i)) {
659                 free_value(a);
660                 free_value(b);
661                 ast_log(LOG_WARNING, "overload\n");
662                 return(NULL);
663         }
664         free_value (a);
665         free_value (b);
666         return r;
667 }
668
669 static int
670 chk_times (a, b, r)
671 quad_t a, b, r;
672 {
673         /* special case: first operand is 0, no overflow possible */
674         if (a == 0)
675                 return 0;
676         /* cerify that result of division matches second operand */
677         if (r / a != b)
678                 return 1;
679         return 0;
680 }
681
682 static struct val *
683 op_times (a, b)
684 struct val *a, *b;
685 {
686         struct val *r;
687
688         if (!to_integer (a) || !to_integer (b)) {
689                 free_value(a);
690                 free_value(b);
691                 ast_log(LOG_WARNING, "non-numeric argument\n");
692                 return(NULL);
693         }
694
695         r = make_integer (/*(quad_t)*/(a->u.i * b->u.i));
696         if (chk_times (a->u.i, b->u.i, r->u.i)) {
697                 ast_log(LOG_WARNING, "overflow\n");
698                 free_value(a);
699                 free_value(b);
700                 return(NULL);
701         }
702         free_value (a);
703         free_value (b);
704         return (r);
705 }
706
707 static int
708 chk_div (a, b)
709 quad_t a, b;
710 {
711         /* div by zero has been taken care of before */
712         /* only QUAD_MIN / -1 causes overflow */
713         if (a == QUAD_MIN && b == -1)
714                 return 1;
715         /* everything else is OK */
716         return 0;
717 }
718
719 static struct val *
720 op_div (a, b)
721 struct val *a, *b;
722 {
723         struct val *r;
724
725         if (!to_integer (a) || !to_integer (b)) {
726                 free_value(a);
727                 free_value(b);
728                 ast_log(LOG_WARNING, "non-numeric argument\n");
729                 return(NULL);
730         }
731
732         if (b->u.i == 0) {
733                 ast_log(LOG_WARNING, "division by zero\n");             
734                 free_value(a);
735                 free_value(b);
736                 return(NULL);
737         }
738
739         r = make_integer (/*(quad_t)*/(a->u.i / b->u.i));
740         if (chk_div (a->u.i, b->u.i)) {
741                 ast_log(LOG_WARNING, "overflow\n");
742                 free_value(a);
743                 free_value(b);
744                 return(NULL);
745         }
746         free_value (a);
747         free_value (b);
748         return r;
749 }
750         
751 static struct val *
752 op_rem (a, b)
753 struct val *a, *b;
754 {
755         struct val *r;
756
757         if (!to_integer (a) || !to_integer (b)) {
758                 ast_log(LOG_WARNING, "non-numeric argument\n");
759                 free_value(a);
760                 free_value(b);
761                 return(NULL);
762         }
763
764         if (b->u.i == 0) {
765                 ast_log(LOG_WARNING, "div by zero\n");
766                 free_value(a);
767                 free_value(b);
768                 return(NULL);
769         }
770
771         r = make_integer (/*(quad_t)*/(a->u.i % b->u.i));
772         /* chk_rem necessary ??? */
773         free_value (a);
774         free_value (b);
775         return r;
776 }
777         
778 static struct val *
779 op_colon (a, b)
780 struct val *a, *b;
781 {
782         regex_t rp;
783         regmatch_t rm[2];
784         char errbuf[256];
785         int eval;
786         struct val *v;
787
788         /* coerce to both arguments to strings */
789         to_string(a);
790         to_string(b);
791
792         /* compile regular expression */
793         if ((eval = regcomp (&rp, b->u.s, 0)) != 0) {
794                 regerror (eval, &rp, errbuf, sizeof(errbuf));
795                 ast_log(LOG_WARNING,"regcomp() error : %s",errbuf);
796                 free_value(a);
797                 free_value(b);
798                 return(NULL);           
799         }
800
801         /* compare string against pattern */
802         /* remember that patterns are anchored to the beginning of the line */
803         if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
804                 if (rm[1].rm_so >= 0) {
805                         *(a->u.s + rm[1].rm_eo) = '\0';
806                         v = make_str (a->u.s + rm[1].rm_so);
807
808                 } else {
809                         v = make_integer ((quad_t)(rm[0].rm_eo - rm[0].rm_so));
810                 }
811         } else {
812                 if (rp.re_nsub == 0) {
813                         v = make_integer ((quad_t)0);
814                 } else {
815                         v = make_str ("");
816                 }
817         }
818
819         /* free arguments and pattern buffer */
820         free_value (a);
821         free_value (b);
822         regfree (&rp);
823
824         return v;
825 }