]>
git.saurik.com Git - apple/shell_cmds.git/blob - expr/expr.c
1 /* $NetBSD: expr.c,v 1.9 1998/07/28 11:41:48 mycroft Exp $ */
4 * Written by J.T. Conklin <jtc@netbsd.org>.
18 OR
, AND
, EQ
, LT
, GT
, ADD
, SUB
, MUL
, DIV
, MOD
, MATCH
, RP
, LP
,
19 NE
, LE
, GE
, OPERAND
, EOI
38 struct val
*make_int
__P((int64_t));
39 struct val
*make_str
__P((char *));
40 void free_value
__P((struct val
*));
41 int is_integer
__P((struct val
*, int64_t *));
42 int to_integer
__P((struct val
*));
43 void to_string
__P((struct val
*));
44 int is_null
__P((struct val
*));
45 int is_zero_or_null
__P((struct val
*));
46 void nexttoken
__P((void));
47 void error
__P((void)) __attribute__((__noreturn__
));
48 struct val
*eval6
__P((void));
49 struct val
*eval5
__P((void));
50 struct val
*eval4
__P((void));
51 struct val
*eval3
__P((void));
52 struct val
*eval2
__P((void));
53 struct val
*eval1
__P((void));
54 struct val
*eval0
__P((void));
55 int main
__P((int, char **));
64 vp
= (struct val
*) malloc(sizeof(*vp
));
80 vp
= (struct val
*) malloc(sizeof(*vp
));
81 if (vp
== NULL
|| ((vp
->u
.s
= strdup(s
)) == NULL
)) {
93 if (vp
->type
== string
)
99 /* determine if vp is an integer; if so, return it's value in *r */
109 if (vp
->type
== integer
) {
115 * POSIX.2 defines an "integer" as an optional unary minus
116 * followed by digits.
124 /* the optional unary minus *must* be followed by digits to
125 * be considered an integer. A '-' alone is not an integer.
149 /* coerce to vp to an integer */
156 if (vp
->type
== integer
)
159 if (is_integer(vp
, &r
)) {
170 /* coerce to vp to an string */
177 if (vp
->type
== string
)
184 (void)snprintf(tmp
, 100, "%lld", vp
->u
.i
);
192 if ((vp
->type
!= integer
) && (*vp
->u
.s
== 0))
201 if (vp
->type
== integer
)
202 return (vp
->u
.i
== 0);
204 return (*vp
->u
.s
== 0 || (to_integer(vp
) && vp
->u
.i
== 0));
213 if ((p
= *av
) == NULL
) {
221 const char *x
= "|&=<>+-*/%:()";
224 if ((i
= strchr(x
, *p
)) != NULL
) {
228 } else if (p
[1] == '=' && p
[2] == '\0') {
242 tokval
= make_str(p
);
250 errx(2, "syntax error");
259 if (token
== OPERAND
) {
263 } else if (token
== RP
) {
277 /* Parse and evaluate match (regex) expressions */
289 while (token
== MATCH
) {
293 /* coerce to both arguments to strings */
297 /* compile regular expression */
298 if ((eval
= regcomp(&rp
, r
->u
.s
, 0)) != 0) {
299 (void)regerror(eval
, &rp
, errbuf
, sizeof(errbuf
));
300 errx(2, "%s", errbuf
);
303 /* compare string against pattern -- remember that patterns
304 are anchored to the beginning of the line */
305 if (regexec(&rp
, l
->u
.s
, 2, rm
, 0) == 0 && rm
[0].rm_so
== 0) {
306 if (rm
[1].rm_so
>= 0) {
307 *(l
->u
.s
+ rm
[1].rm_eo
) = '\0';
308 v
= make_str(l
->u
.s
+ rm
[1].rm_so
);
311 v
= make_int((int)(rm
[0].rm_eo
- rm
[0].rm_so
));
314 if (rp
.re_nsub
== 0) {
321 /* free arguments and pattern buffer */
332 /* Parse and evaluate multiplication and division expressions */
340 while ((op
= token
) == MUL
|| op
== DIV
|| op
== MOD
) {
344 if (!to_integer(l
) || !to_integer(r
)) {
345 errx(2, "non-numeric argument");
352 errx(2, "division by zero");
367 /* Parse and evaluate addition and subtraction expressions */
375 while ((op
= token
) == ADD
|| op
== SUB
) {
379 if (!to_integer(l
) || !to_integer(r
)) {
380 errx(2, "non-numeric argument");
395 /* Parse and evaluate comparison expressions */
401 int v
= 0; /* pacify gcc */
405 while ((op
= token
) == EQ
|| op
== NE
|| op
== LT
|| op
== GT
|| op
== LE
|| op
== GE
) {
409 if (is_integer(l
, &li
) && is_integer(r
, &ri
)) {
451 v
= (strcoll(l
->u
.s
, r
->u
.s
) > 0);
454 v
= (strcoll(l
->u
.s
, r
->u
.s
) >= 0);
457 v
= (strcoll(l
->u
.s
, r
->u
.s
) < 0);
460 v
= (strcoll(l
->u
.s
, r
->u
.s
) <= 0);
463 v
= (strcoll(l
->u
.s
, r
->u
.s
) == 0);
466 v
= (strcoll(l
->u
.s
, r
->u
.s
) != 0);
494 /* Parse and evaluate & expressions */
501 while (token
== AND
) {
505 if (is_zero_or_null(l
) || is_zero_or_null(r
)) {
517 /* Parse and evaluate | expressions */
524 while (token
== OR
) {
528 if (is_zero_or_null(l
)) {
551 (void) setlocale(LC_ALL
, "");
553 if (!strcmp(*av
, "--"))
560 if (vp
->type
== string
&& vp
->u
.s
[0])
561 to_integer(vp
); /* -0 is not a string */
562 if (vp
->type
== integer
)
563 (void)printf("%lld\n", vp
->u
.i
);
565 (void)printf("%s\n", vp
->u
.s
);
567 exit(is_zero_or_null(vp
));