2 /* Written by Pace Willisson (pace@blitz.com)
3 * and placed in the public domain.
5 * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
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
12 * $FreeBSD: src/bin/expr/expr.y,v 1.16 2000/07/22 10:59:36 se Exp $
18 ASTERISK_FILE_VERSION
(__FILE__
, "$Revision$")
21 #include <sys/types.h>
28 #if !defined(SOLARIS) && !defined(__CYGWIN__)
29 /* #include <err.h> */
31 #define quad_t int64_t
37 #include "asterisk/ast_expr.h"
38 #include "asterisk/logger.h"
40 #if defined(LONG_LONG_MIN) && !defined(QUAD_MIN)
41 #define QUAD_MIN LONG_LONG_MIN
43 #if defined(LONG_LONG_MAX) && !defined(QUAD_MAX)
44 #define QUAD_MAX LONG_LONG_MAX
47 # if ! defined(QUAD_MIN)
48 # define QUAD_MIN (-0x7fffffffffffffffLL-1)
50 # if ! defined(QUAD_MAX)
51 # define QUAD_MAX (0x7fffffffffffffffLL)
54 #define YYPARSE_PARAM parseio
55 #define YYLEX_PARAM ((struct parse_io *)parseio)->scanner
56 #define YYERROR_VERBOSE 1
57 extern
char extra_error_message
[4095];
58 extern
int extra_error_message_supplied
;
61 AST_EXPR_integer
, AST_EXPR_numeric_string
, AST_EXPR_string
65 void ast_log
(int level
, const char *file
, int line
, const char *function
, const char *fmt
, ...
) __attribute__
((format
(printf
,5,6)));
76 typedef
void *yyscan_t
;
85 static int chk_div __P
((quad_t
, quad_t
));
86 static int chk_minus __P
((quad_t
, quad_t
, quad_t
));
87 static int chk_plus __P
((quad_t
, quad_t
, quad_t
));
88 static int chk_times __P
((quad_t
, quad_t
, quad_t
));
89 static void free_value __P
((struct val
*));
90 static int is_zero_or_null __P
((struct val
*));
91 static int isstring __P
((struct val
*));
92 static struct val
*make_integer __P
((quad_t
));
93 static struct val
*make_str __P
((const char *));
94 static struct val
*op_and __P
((struct val
*, struct val
*));
95 static struct val
*op_colon __P
((struct val
*, struct val
*));
96 static struct val
*op_eqtilde __P
((struct val
*, struct val
*));
97 static struct val
*op_div __P
((struct val
*, struct val
*));
98 static struct val
*op_eq __P
((struct val
*, struct val
*));
99 static struct val
*op_ge __P
((struct val
*, struct val
*));
100 static struct val
*op_gt __P
((struct val
*, struct val
*));
101 static struct val
*op_le __P
((struct val
*, struct val
*));
102 static struct val
*op_lt __P
((struct val
*, struct val
*));
103 static struct val
*op_cond __P
((struct val
*, struct val
*, struct val
*));
104 static struct val
*op_minus __P
((struct val
*, struct val
*));
105 static struct val
*op_negate __P
((struct val
*));
106 static struct val
*op_compl __P
((struct val
*));
107 static struct val
*op_ne __P
((struct val
*, struct val
*));
108 static struct val
*op_or __P
((struct val
*, struct val
*));
109 static struct val
*op_plus __P
((struct val
*, struct val
*));
110 static struct val
*op_rem __P
((struct val
*, struct val
*));
111 static struct val
*op_times __P
((struct val
*, struct val
*));
112 static quad_t to_integer __P
((struct val
*));
113 static void to_string __P
((struct val
*));
115 /* uh, if I want to predeclare yylex with a YYLTYPE, I have to predeclare the yyltype... sigh */
116 typedef
struct yyltype
125 # define YYLTYPE yyltype
126 # define YYLTYPE_IS_TRIVIAL 1
128 /* we will get warning about no prototype for yylex! But we can't
129 define it here, we have no definition yet for YYSTYPE. */
131 int ast_yyerror
(const char *,YYLTYPE *, struct parse_io
*);
133 /* I wanted to add args to the yyerror routine, so I could print out
134 some useful info about the error. Not as easy as it looks, but it
136 #define ast_yyerror(x) ast_yyerror(x,&yyloc,parseio)
137 #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);}
142 /* %debug for when you are having big problems */
144 /* %name-prefix="ast_yy" */
152 extern
int ast_yylex __P
((YYSTYPE *, YYLTYPE *, yyscan_t
));
154 %left
<val
> TOK_COND TOK_COLONCOLON
157 %left
<val
> TOK_EQ TOK_GT TOK_LT TOK_GE TOK_LE TOK_NE
158 %left
<val
> TOK_PLUS TOK_MINUS
159 %left
<val
> TOK_MULT TOK_DIV TOK_MOD
160 %right
<val
> TOK_COMPL
161 %left
<val
> TOK_COLON TOK_EQTILDE
162 %left
<val
> TOK_RP TOK_LP
166 %type
<val
> start expr
169 %destructor
{ free_value
($$
); } expr TOKEN TOK_COND TOK_COLONCOLON TOK_OR TOK_AND TOK_EQ
170 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
175 start: expr
{ ((struct parse_io
*)parseio
)->val
= (struct val
*)calloc
(sizeof
(struct val
),1);
176 ((struct parse_io
*)parseio
)->val
->type
= $1->type
;
177 if
( $1->type
== AST_EXPR_integer
)
178 ((struct parse_io
*)parseio
)->val
->u.i
= $1->u.i
;
180 ((struct parse_io
*)parseio
)->val
->u.s
= $1->u.s
;
183 |
{/* nothing */ ((struct parse_io
*)parseio
)->val
= (struct val
*)calloc
(sizeof
(struct val
),1);
184 ((struct parse_io
*)parseio
)->val
->type
= AST_EXPR_string
;
185 ((struct parse_io
*)parseio
)->val
->u.s
= strdup
("");
190 expr: TOKEN
{ $$
= $1;}
191 | TOK_LP expr TOK_RP
{ $$
= $2;
192 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
193 @$.first_line
=0; @$.last_line
=0;
194 DESTROY
($1); DESTROY
($3); }
195 | expr TOK_OR expr
{ $$
= op_or
($1, $3);
197 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
198 @$.first_line
=0; @$.last_line
=0;}
199 | expr TOK_AND expr
{ $$
= op_and
($1, $3);
201 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
202 @$.first_line
=0; @$.last_line
=0;}
203 | expr TOK_EQ expr
{ $$
= op_eq
($1, $3);
205 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
206 @$.first_line
=0; @$.last_line
=0;}
207 | expr TOK_GT expr
{ $$
= op_gt
($1, $3);
209 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
210 @$.first_line
=0; @$.last_line
=0;}
211 | expr TOK_LT expr
{ $$
= op_lt
($1, $3);
213 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
214 @$.first_line
=0; @$.last_line
=0;}
215 | expr TOK_GE expr
{ $$
= op_ge
($1, $3);
217 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
218 @$.first_line
=0; @$.last_line
=0;}
219 | expr TOK_LE expr
{ $$
= op_le
($1, $3);
221 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
222 @$.first_line
=0; @$.last_line
=0;}
223 | expr TOK_NE expr
{ $$
= op_ne
($1, $3);
225 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
226 @$.first_line
=0; @$.last_line
=0;}
227 | expr TOK_PLUS expr
{ $$
= op_plus
($1, $3);
229 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
230 @$.first_line
=0; @$.last_line
=0;}
231 | expr TOK_MINUS expr
{ $$
= op_minus
($1, $3);
233 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
234 @$.first_line
=0; @$.last_line
=0;}
235 | TOK_MINUS expr %prec TOK_COMPL
{ $$
= op_negate
($2);
237 @$.first_column
= @
1.first_column
; @$.last_column
= @
2.last_column
;
238 @$.first_line
=0; @$.last_line
=0;}
239 | TOK_COMPL expr
{ $$
= op_compl
($2);
241 @$.first_column
= @
1.first_column
; @$.last_column
= @
2.last_column
;
242 @$.first_line
=0; @$.last_line
=0;}
243 | expr TOK_MULT expr
{ $$
= op_times
($1, $3);
245 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
246 @$.first_line
=0; @$.last_line
=0;}
247 | expr TOK_DIV expr
{ $$
= op_div
($1, $3);
249 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
250 @$.first_line
=0; @$.last_line
=0;}
251 | expr TOK_MOD expr
{ $$
= op_rem
($1, $3);
253 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
254 @$.first_line
=0; @$.last_line
=0;}
255 | expr TOK_COLON expr
{ $$
= op_colon
($1, $3);
257 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
258 @$.first_line
=0; @$.last_line
=0;}
259 | expr TOK_EQTILDE expr
{ $$
= op_eqtilde
($1, $3);
261 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
262 @$.first_line
=0; @$.last_line
=0;}
263 | expr TOK_COND expr TOK_COLONCOLON expr
{ $$
= op_cond
($1, $3, $5);
266 @$.first_column
= @
1.first_column
; @$.last_column
= @
3.last_column
;
267 @$.first_line
=0; @$.last_line
=0;}
273 make_integer
(quad_t i
)
277 vp
= (struct val
*) malloc
(sizeof
(*vp
));
279 ast_log
(LOG_WARNING
, "malloc() failed\n");
283 vp
->type
= AST_EXPR_integer
;
289 make_str
(const char *s
)
295 vp
= (struct val
*) malloc
(sizeof
(*vp
));
296 if
(vp
== NULL ||
((vp
->u.s
= strdup
(s
)) == NULL
)) {
297 ast_log
(LOG_WARNING
,"malloc() failed\n");
301 for
(i
= 1, isint
= isdigit
(s
[0]) || s
[0] == '-';
302 isint
&& i
< strlen
(s
);
310 vp
->type
= AST_EXPR_numeric_string
;
312 vp
->type
= AST_EXPR_string
;
319 free_value
(struct val
*vp
)
324 if
(vp
->type
== AST_EXPR_string || vp
->type
== AST_EXPR_numeric_string
)
331 to_integer
(struct val
*vp
)
336 ast_log
(LOG_WARNING
,"vp==NULL in to_integer()\n");
340 if
(vp
->type
== AST_EXPR_integer
)
343 if
(vp
->type
== AST_EXPR_string
)
346 /* vp->type == AST_EXPR_numeric_string, make it numeric */
348 i
= strtoll
(vp
->u.s
, (char**)NULL
, 10);
350 ast_log
(LOG_WARNING
,"Conversion of %s to integer under/overflowed!\n", vp
->u.s
);
357 vp
->type
= AST_EXPR_integer
;
362 strip_quotes
(struct val
*vp
)
364 if
(vp
->type
!= AST_EXPR_string
&& vp
->type
!= AST_EXPR_numeric_string
)
367 if
( vp
->u.s
[0] == '"' && vp
->u.s
[strlen
(vp
->u.s
)-1] == '"' )
375 if
( *f
&& *f
!= '"' )
385 to_string
(struct val
*vp
)
389 if
(vp
->type
== AST_EXPR_string || vp
->type
== AST_EXPR_numeric_string
)
392 tmp
= malloc
((size_t)25);
394 ast_log
(LOG_WARNING
,"malloc() failed\n");
398 sprintf
(tmp
, "%ld", (long int) vp
->u.i
);
399 vp
->type
= AST_EXPR_string
;
405 isstring
(struct val
*vp
)
407 /* only TRUE if this string is not a valid integer */
408 return
(vp
->type
== AST_EXPR_string
);
413 is_zero_or_null
(struct val
*vp
)
415 if
(vp
->type
== AST_EXPR_integer
) {
416 return
(vp
->u.i
== 0);
418 return
(*vp
->u.s
== 0 ||
(to_integer
(vp
) && vp
->u.i
== 0));
425 void ast_log
(int level
, const char *file
, int line
, const char *function
, const char *fmt
, ...
)
430 printf
("LOG: lev:%d file:%s line:%d func: %s ",
431 level
, file
, line
, function
);
438 int main
(int argc
,char **argv
) {
446 if
( access
(argv
[1],F_OK
)== 0 )
450 infile
= fopen
(argv
[1],"r");
453 printf
("Sorry, couldn't open %s for reading!\n", argv
[1]);
456 while
( fgets
(s
,sizeof
(s
),infile
) )
458 if
( s
[strlen
(s
)-1] == '\n' )
461 ret
= ast_expr
(s
, out
, sizeof
(out
));
462 printf
("Expression: %s Result: [%d] '%s'\n",
469 if
(ast_expr
(argv
[1], s
, sizeof
(s
)))
470 printf
("=====%s======\n",s
);
472 printf
("No result\n");
479 #define ast_yyerror(x) ast_yyerror(x, YYLTYPE *yylloc, struct parse_io *parseio)
481 /* I put the ast_yyerror func in the flex input file,
482 because it refers to the buffer state. Best to
483 let it access the BUFFER stuff there and not trying
484 define all the structs, macros etc. in this file! */
488 op_or
(struct val
*a
, struct val
*b
)
490 if
(is_zero_or_null
(a
)) {
500 op_and
(struct val
*a
, struct val
*b
)
502 if
(is_zero_or_null
(a
) || is_zero_or_null
(b
)) {
505 return
(make_integer
((quad_t
)0));
513 op_eq
(struct val
*a
, struct val
*b
)
517 if
(isstring
(a
) || isstring
(b
)) {
520 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) == 0));
522 #ifdef DEBUG_FOR_CONVERSIONS
524 sprintf
(buffer
,"Converting '%s' and '%s' ", a
->u.s
, b
->u.s
);
528 #ifdef DEBUG_FOR_CONVERSIONS
529 ast_log
(LOG_WARNING
,"%s to '%lld' and '%lld'\n", buffer
, a
->u.i
, b
->u.i
);
531 r
= make_integer
((quad_t
)(a
->u.i
== b
->u.i
));
540 op_gt
(struct val
*a
, struct val
*b
)
544 if
(isstring
(a
) || isstring
(b
)) {
547 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) > 0));
551 r
= make_integer
((quad_t
)(a
->u.i
> b
->u.i
));
560 op_lt
(struct val
*a
, struct val
*b
)
564 if
(isstring
(a
) || isstring
(b
)) {
567 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) < 0));
571 r
= make_integer
((quad_t
)(a
->u.i
< b
->u.i
));
580 op_ge
(struct val
*a
, struct val
*b
)
584 if
(isstring
(a
) || isstring
(b
)) {
587 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) >= 0));
591 r
= make_integer
((quad_t
)(a
->u.i
>= b
->u.i
));
600 op_le
(struct val
*a
, struct val
*b
)
604 if
(isstring
(a
) || isstring
(b
)) {
607 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) <= 0));
611 r
= make_integer
((quad_t
)(a
->u.i
<= b
->u.i
));
620 op_cond
(struct val
*a
, struct val
*b
, struct val
*c
)
626 if
( strlen
(a
->u.s
) && strcmp
(a
->u.s
, "\"\"") != 0 && strcmp
(a
->u.s
,"0") != 0 )
659 op_ne
(struct val
*a
, struct val
*b
)
663 if
(isstring
(a
) || isstring
(b
)) {
666 r
= make_integer
((quad_t
)(strcoll
(a
->u.s
, b
->u.s
) != 0));
670 r
= make_integer
((quad_t
)(a
->u.i
!= b
->u.i
));
679 chk_plus
(quad_t a
, quad_t b
, quad_t r
)
681 /* sum of two positive numbers must be positive */
682 if
(a
> 0 && b
> 0 && r
<= 0)
684 /* sum of two negative numbers must be negative */
685 if
(a
< 0 && b
< 0 && r
>= 0)
687 /* all other cases are OK */
692 op_plus
(struct val
*a
, struct val
*b
)
696 if
(!to_integer
(a
)) {
697 if
( !extra_error_message_supplied
)
698 ast_log
(LOG_WARNING
,"non-numeric argument\n");
699 if
(!to_integer
(b
)) {
702 return make_integer
(0);
707 } else if
(!to_integer
(b
)) {
712 r
= make_integer
(/*(quad_t)*/(a
->u.i
+ b
->u.i
));
713 if
(chk_plus
(a
->u.i
, b
->u.i
, r
->u.i
)) {
714 ast_log
(LOG_WARNING
,"overflow\n");
722 chk_minus
(quad_t a
, quad_t b
, quad_t r
)
724 /* special case subtraction of QUAD_MIN */
731 /* this is allowed for b != QUAD_MIN */
732 return chk_plus
(a
, -b
, r
);
736 op_minus
(struct val
*a
, struct val
*b
)
740 if
(!to_integer
(a
)) {
741 if
( !extra_error_message_supplied
)
742 ast_log
(LOG_WARNING
, "non-numeric argument\n");
743 if
(!to_integer
(b
)) {
746 return make_integer
(0);
748 r
= make_integer
(0 - b
->u.i
);
753 } else if
(!to_integer
(b
)) {
754 if
( !extra_error_message_supplied
)
755 ast_log
(LOG_WARNING
, "non-numeric argument\n");
760 r
= make_integer
(/*(quad_t)*/(a
->u.i
- b
->u.i
));
761 if
(chk_minus
(a
->u.i
, b
->u.i
, r
->u.i
)) {
762 ast_log
(LOG_WARNING
, "overflow\n");
770 op_negate
(struct val
*a
)
774 if
(!to_integer
(a
) ) {
776 if
( !extra_error_message_supplied
)
777 ast_log
(LOG_WARNING
, "non-numeric argument\n");
778 return make_integer
(0);
781 r
= make_integer
(/*(quad_t)*/(- a
->u.i
));
782 if
(chk_minus
(0, a
->u.i
, r
->u.i
)) {
783 ast_log
(LOG_WARNING
, "overflow\n");
790 op_compl
(struct val
*a
)
803 case AST_EXPR_integer
:
808 case AST_EXPR_string
:
815 else if
(strlen
(a
->u.s
) == 1 && a
->u.s
[0] == '0' )
820 case AST_EXPR_numeric_string
:
827 else if
(strlen
(a
->u.s
) == 1 && a
->u.s
[0] == '0' )
834 r
= make_integer
(!v1
);
840 chk_times
(quad_t a
, quad_t b
, quad_t r
)
842 /* special case: first operand is 0, no overflow possible */
845 /* cerify that result of division matches second operand */
852 op_times
(struct val
*a
, struct val
*b
)
856 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
859 if
( !extra_error_message_supplied
)
860 ast_log
(LOG_WARNING
, "non-numeric argument\n");
861 return
(make_integer
(0));
864 r
= make_integer
(/*(quad_t)*/(a
->u.i
* b
->u.i
));
865 if
(chk_times
(a
->u.i
, b
->u.i
, r
->u.i
)) {
866 ast_log
(LOG_WARNING
, "overflow\n");
874 chk_div
(quad_t a
, quad_t b
)
876 /* div by zero has been taken care of before */
877 /* only QUAD_MIN / -1 causes overflow */
878 if
(a
== QUAD_MIN
&& b
== -1)
880 /* everything else is OK */
885 op_div
(struct val
*a
, struct val
*b
)
889 if
(!to_integer
(a
)) {
892 if
( !extra_error_message_supplied
)
893 ast_log
(LOG_WARNING
, "non-numeric argument\n");
894 return make_integer
(0);
895 } else if
(!to_integer
(b
)) {
898 if
( !extra_error_message_supplied
)
899 ast_log
(LOG_WARNING
, "non-numeric argument\n");
900 return make_integer
(INT_MAX
);
904 ast_log
(LOG_WARNING
, "division by zero\n");
907 return make_integer
(INT_MAX
);
910 r
= make_integer
(/*(quad_t)*/(a
->u.i
/ b
->u.i
));
911 if
(chk_div
(a
->u.i
, b
->u.i
)) {
912 ast_log
(LOG_WARNING
, "overflow\n");
920 op_rem
(struct val
*a
, struct val
*b
)
924 if
(!to_integer
(a
) ||
!to_integer
(b
)) {
925 if
( !extra_error_message_supplied
)
926 ast_log
(LOG_WARNING
, "non-numeric argument\n");
929 return make_integer
(0);
933 ast_log
(LOG_WARNING
, "div by zero\n");
938 r
= make_integer
(/*(quad_t)*/(a
->u.i % b
->u.i
));
939 /* chk_rem necessary ??? */
947 op_colon
(struct val
*a
, struct val
*b
)
955 /* coerce to both arguments to strings */
958 /* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
961 /* compile regular expression */
962 if
((eval
= regcomp
(&rp
, b
->u.s
, REG_EXTENDED
)) != 0) {
963 regerror
(eval
, &rp
, errbuf
, sizeof
(errbuf
));
964 ast_log
(LOG_WARNING
,"regcomp() error : %s",errbuf
);
970 /* compare string against pattern */
971 /* remember that patterns are anchored to the beginning of the line */
972 if
(regexec
(&rp
, a
->u.s
, (size_t)2, rm
, 0) == 0 && rm
[0].rm_so
== 0) {
973 if
(rm
[1].rm_so
>= 0) {
974 *(a
->u.s
+ rm
[1].rm_eo
) = '\0';
975 v
= make_str
(a
->u.s
+ rm
[1].rm_so
);
978 v
= make_integer
((quad_t
)(rm
[0].rm_eo
- rm
[0].rm_so
));
981 if
(rp.re_nsub
== 0) {
982 v
= make_integer
((quad_t
)0);
988 /* free arguments and pattern buffer */
998 op_eqtilde
(struct val
*a
, struct val
*b
)
1006 /* coerce to both arguments to strings */
1009 /* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
1012 /* compile regular expression */
1013 if
((eval
= regcomp
(&rp
, b
->u.s
, REG_EXTENDED
)) != 0) {
1014 regerror
(eval
, &rp
, errbuf
, sizeof
(errbuf
));
1015 ast_log
(LOG_WARNING
,"regcomp() error : %s",errbuf
);
1018 return make_str
("");
1021 /* compare string against pattern */
1022 /* remember that patterns are anchored to the beginning of the line */
1023 if
(regexec
(&rp
, a
->u.s
, (size_t)2, rm
, 0) == 0 ) {
1024 if
(rm
[1].rm_so
>= 0) {
1025 *(a
->u.s
+ rm
[1].rm_eo
) = '\0';
1026 v
= make_str
(a
->u.s
+ rm
[1].rm_so
);
1029 v
= make_integer
((quad_t
)(rm
[0].rm_eo
- rm
[0].rm_so
));
1032 if
(rp.re_nsub
== 0) {
1033 v
= make_integer
((quad_t
)0);
1039 /* free arguments and pattern buffer */