1 /* $OpenBSD: expr.c,v 1.18 2013/03/28 08:40:31 nicm Exp $ */
2 /* $NetBSD: expr.c,v 1.3.6.1 1996/06/04 20:41:47 cgd Exp $ */
5 * Written by J.T. Conklin <jtc@netbsd.org>.
18 struct val
*make_int(int);
19 struct val
*make_str(char *);
20 void free_value(struct val
*);
21 int is_integer(struct val
*, int *);
22 int to_integer(struct val
*);
23 void to_string(struct val
*);
24 int is_zero_or_null(struct val
*);
26 __dead
void error(void);
27 struct val
*eval6(void);
28 struct val
*eval5(void);
29 struct val
*eval4(void);
30 struct val
*eval3(void);
31 struct val
*eval2(void);
32 struct val
*eval1(void);
33 struct val
*eval0(void);
36 OR
, AND
, EQ
, LT
, GT
, ADD
, SUB
, MUL
, DIV
, MOD
, MATCH
, RP
, LP
,
37 NE
, LE
, GE
, OPERAND
, EOI
61 vp
= (struct val
*) malloc(sizeof(*vp
));
76 vp
= (struct val
*) malloc(sizeof(*vp
));
77 if (vp
== NULL
|| ((vp
->u
.s
= strdup(s
)) == NULL
)) {
86 free_value(struct val
*vp
)
88 if (vp
->type
== string
)
94 /* determine if vp is an integer; if so, return it's value in *r */
96 is_integer(struct val
*vp
, int *r
)
102 if (vp
->type
== integer
) {
108 * POSIX.2 defines an "integer" as an optional unary minus
109 * followed by digits.
136 /* coerce to vp to an integer */
138 to_integer(struct val
*vp
)
142 if (vp
->type
== integer
)
145 if (is_integer(vp
, &r
)) {
156 /* coerce to vp to an string */
158 to_string(struct val
*vp
)
162 if (vp
->type
== string
)
165 if (asprintf(&tmp
, "%d", vp
->u
.i
) == -1)
173 is_zero_or_null(struct val
*vp
)
175 if (vp
->type
== integer
) {
176 return (vp
->u
.i
== 0);
178 return (*vp
->u
.s
== 0 || (to_integer(vp
) && vp
->u
.i
== 0));
188 if ((p
= *av
) == NULL
) {
195 if (pat
== 0 && p
[0] != '\0') {
197 const char *x
= "|&=<>+-*/%:()";
200 if ((i
= strchr(x
, *p
)) != NULL
) {
204 } else if (p
[1] == '=' && p
[2] == '\0') {
218 tokval
= make_str(p
);
226 errx(2, "syntax error");
235 if (token
== OPERAND
) {
239 } else if (token
== RP
) {
255 /* Parse and evaluate match (regex) expressions */
267 while (token
== MATCH
) {
271 /* coerce to both arguments to strings */
275 /* compile regular expression */
276 if ((eval
= regcomp(&rp
, r
->u
.s
, 0)) != 0) {
277 regerror(eval
, &rp
, errbuf
, sizeof(errbuf
));
278 errx(2, "%s", errbuf
);
281 /* compare string against pattern -- remember that patterns
282 are anchored to the beginning of the line */
283 if (regexec(&rp
, l
->u
.s
, 2, rm
, 0) == 0 && rm
[0].rm_so
== 0) {
284 if (rm
[1].rm_so
>= 0) {
285 *(l
->u
.s
+ rm
[1].rm_eo
) = '\0';
286 v
= make_str(l
->u
.s
+ rm
[1].rm_so
);
289 v
= make_int((int)(rm
[0].rm_eo
- rm
[0].rm_so
));
292 if (rp
.re_nsub
== 0) {
299 /* free arguments and pattern buffer */
310 /* Parse and evaluate multiplication and division expressions */
318 while ((op
= token
) == MUL
|| op
== DIV
|| op
== MOD
) {
322 if (!to_integer(l
) || !to_integer(r
)) {
323 errx(2, "non-numeric argument");
330 errx(2, "division by zero");
333 if (l
->u
.i
!= INT_MIN
|| r
->u
.i
!= -1)
336 if (l
->u
.i
!= INT_MIN
|| r
->u
.i
!= -1)
349 /* Parse and evaluate addition and subtraction expressions */
357 while ((op
= token
) == ADD
|| op
== SUB
) {
361 if (!to_integer(l
) || !to_integer(r
)) {
362 errx(2, "non-numeric argument");
377 /* Parse and evaluate comparison expressions */
386 while ((op
= token
) == EQ
|| op
== NE
|| op
== LT
|| op
== GT
||
387 op
== LE
|| op
== GE
) {
391 if (is_integer(l
, &li
) && is_integer(r
, &ri
)) {
420 v
= (strcoll(l
->u
.s
, r
->u
.s
) > 0);
423 v
= (strcoll(l
->u
.s
, r
->u
.s
) >= 0);
426 v
= (strcoll(l
->u
.s
, r
->u
.s
) < 0);
429 v
= (strcoll(l
->u
.s
, r
->u
.s
) <= 0);
432 v
= (strcoll(l
->u
.s
, r
->u
.s
) == 0);
435 v
= (strcoll(l
->u
.s
, r
->u
.s
) != 0);
450 /* Parse and evaluate & expressions */
457 while (token
== AND
) {
461 if (is_zero_or_null(l
) || is_zero_or_null(r
)) {
473 /* Parse and evaluate | expressions */
480 while (token
== OR
) {
484 if (is_zero_or_null(l
)) {
497 main(int argc
, char *argv
[])
501 (void) setlocale(LC_ALL
, "");
503 if (argc
> 1 && !strcmp(argv
[1], "--"))
516 if (vp
->type
== integer
)
517 printf("%d\n", vp
->u
.i
);
519 printf("%s\n", vp
->u
.s
);
521 exit(is_zero_or_null(vp
));