2 * The expr and test commands.
4 * Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
5 * This file is part of ash, which is distributed under the terms specified
6 * by the Ash General Public License. See the file named LICENSE.
11 #include "operators.h"
13 #include <sys/types.h>
29 * This structure hold a value. The type keyword specifies the type of
30 * the value, and the union u holds the value. The value of a boolean
31 * is stored in u.num (1 = TRUE, 0 = FALSE).
44 short op
; /* which operator */
45 short pri
; /* priority of operator */
50 char *name
; /* name of file */
51 int rcode
; /* return code from stat */
52 struct stat stat
; /* status info on file */
56 extern char *match_begin
[10]; /* matched string */
57 extern short match_length
[10]; /* defined in regexp.c */
58 extern short number_parens
; /* number of \( \) pairs */
62 static int expr_is_false(struct value
*);
63 static void expr_operator(int, struct value
*, struct filestat
*);
64 static int lookup_op(char *, char *const*);
66 static int expr_is_false();
67 static void expr_operator();
68 static int lookup_op();
73 exprcmd(argc
, argv
) char **argv
; {
79 int nest
; /* parenthises nesting */
84 struct operator opstack
[STACKSIZE
];
85 struct operator *opsp
;
86 struct value valstack
[STACKSIZE
+ 1];
96 if (! equal(argv
[argc
- 1], "]"))
98 argv
[argc
- 1] = NULL
;
105 * We use operator precedence parsing, evaluating the expression
106 * as we parse it. Parentheses are handled by bumping up the
107 * priority of operators using the variable "nest." We use the
108 * variable "skipping" to turn off evaluation temporarily for the
109 * short circuit boolean operators. (It is important do the short
110 * circuit evaluation because under NFS a stat operation can take
116 opsp
= opstack
+ STACKSIZE
;
119 valstack
[0].type
= BOOLEAN
;
120 valstack
[0].u
.num
= 0;
126 syntax
: error("syntax error");
127 if (opname
[0] == '(' && opname
[1] == '\0') {
130 } else if (*ap
&& (op
= lookup_op(opname
, unary_op
)) >= 0) {
131 if (opsp
== &opstack
[0])
132 overflow
: error("Expression too complex");
135 opsp
->pri
= op_priority
[op
] + nest
;
139 if (opname
[0] == '\'') {
140 for (p
= opname
; *++p
!= '\0' ; );
141 if (--p
> opname
&& *p
== '\'') {
146 valsp
->type
= STRING
;
147 valsp
->u
.string
= opname
;
152 if (opname
== NULL
) {
158 if (opname
[0] != ')' || opname
[1] != '\0') {
159 if ((op
= lookup_op(opname
, binary_op
)) < 0)
161 op
+= FIRST_BINARY_OP
;
162 pri
= op_priority
[op
] + nest
;
165 if ((nest
-= NESTINCR
) < 0)
168 while (opsp
< &opstack
[STACKSIZE
] && opsp
->pri
>= pri
) {
172 c
= op_argflag
[opsp
->op
];
174 if (valsp
->type
== STRING
)
175 valsp
->u
.num
= atol(valsp
->u
.string
);
176 valsp
->type
= INTEGER
;
177 } else if (c
>= OP_STRING
) { /* OP_STRING or OP_FILE */
178 if (valsp
->type
== INTEGER
) {
181 fmtstr(p
, 32, "%d", valsp
->u
.num
);
183 sprintf(p
, "%d", valsp
->u
.num
);
186 } else if (valsp
->type
== BOOLEAN
) {
188 valsp
->u
.string
= "true";
190 valsp
->u
.string
= "";
192 valsp
->type
= STRING
;
195 || ! equal(fs
.name
, valsp
->u
.string
))) {
196 fs
.name
= valsp
->u
.string
;
197 fs
.rcode
= stat(valsp
->u
.string
, &fs
.stat
);
200 if (binary
< FIRST_BINARY_OP
)
205 expr_operator(opsp
->op
, valsp
, &fs
);
206 else if (opsp
->op
== AND1
|| opsp
->op
== OR1
)
208 valsp
++; /* push value */
209 opsp
++; /* pop operator */
213 if (opsp
== &opstack
[0])
215 if (op
== AND1
|| op
== AND2
) {
217 if (skipping
|| expr_is_false(valsp
- 1))
220 if (op
== OR1
|| op
== OR2
) {
222 if (skipping
|| ! expr_is_false(valsp
- 1))
231 if (valstack
[0].type
== STRING
)
232 printf("%s\n", valstack
[0].u
.string
);
233 else if (valstack
[0].type
== INTEGER
)
234 printf("%ld\n", valstack
[0].u
.num
);
235 else if (valstack
[0].u
.num
!= 0)
238 return expr_is_false(&valstack
[0]);
246 if (val
->type
== STRING
) {
247 if (val
->u
.string
[0] == '\0')
249 } else { /* INTEGER or BOOLEAN */
258 * Execute an operator. Op is the operator. Sp is the stack pointer;
259 * sp[0] refers to the first operand, sp[1] refers to the second operand
260 * (if any), and the result is placed in sp[0]. The operands are converted
261 * to the type expected by the operator before expr_operator is called.
262 * Fs is a pointer to a structure which holds the value of the last call
263 * to stat, to avoid repeated stat calls on the same file.
267 expr_operator(op
, sp
, fs
)
273 struct stat st1
, st2
;
279 sp
->u
.num
= expr_is_false(sp
);
283 if (fs
->rcode
>= 0) goto true;
294 if (fs
->stat
.st_uid
== geteuid())
296 else if (fs
->stat
.st_gid
== getegid())
298 goto filebit
; /* true if (stat.st_mode & i) != 0 */
319 if ((fs
->stat
.st_mode
& S_IFMT
) == i
&& fs
->rcode
>= 0) {
337 if (fs
->stat
.st_mode
& i
&& fs
->rcode
>= 0)
341 if (lstat(fs
->name
, &st1
) == -1)
343 if (S_ISLNK(st1
.st_mode
))
347 sp
->u
.num
= fs
->rcode
>= 0? fs
->stat
.st_size
: 0L;
352 if (stat(sp
->u
.string
, &st1
) != 0) {
354 } else if (stat((sp
+ 1)->u
.string
, &st2
) != 0) {
357 int isnewer
= st1
.st_mtime
>= st2
.st_mtime
;
361 sp
->u
.num
= !isnewer
;
366 sp
->u
.num
= isatty(sp
->u
.num
);
370 if (sp
->u
.string
[0] == '\0')
374 sp
->u
.num
= strlen(sp
->u
.string
);
380 * These operators are mostly handled by the parser. If we
381 * get here it means that both operands were evaluated, so
382 * the value is the value of the second operand.
389 if (equal(sp
->u
.string
, (sp
+ 1)->u
.string
))
397 if (sp
->u
.num
== (sp
+ 1)->u
.num
)
401 if (sp
->u
.num
!= (sp
+ 1)->u
.num
)
405 if (sp
->u
.num
> (sp
+ 1)->u
.num
)
409 if (sp
->u
.num
< (sp
+ 1)->u
.num
)
413 if (sp
->u
.num
<= (sp
+ 1)->u
.num
)
417 if (sp
->u
.num
>= (sp
+ 1)->u
.num
)
421 sp
->u
.num
+= (sp
+ 1)->u
.num
;
424 sp
->u
.num
-= (sp
+ 1)->u
.num
;
427 sp
->u
.num
*= (sp
+ 1)->u
.num
;
430 if ((sp
+ 1)->u
.num
== 0)
431 error("Division by zero");
432 sp
->u
.num
/= (sp
+ 1)->u
.num
;
435 if ((sp
+ 1)->u
.num
== 0)
436 error("Division by zero");
437 sp
->u
.num
%= (sp
+ 1)->u
.num
;
441 r
= regcomp(&pat
, (sp
+ 1)->u
.string
, 0);
443 error("Bad regular expression");
444 if (regexec(&pat
, sp
->u
.string
, 2, rm
, 0) == 0 &&
447 if (pat
.re_nsub
> 0) {
448 sp
->u
.string
[rm
[1].rm_eo
] = '\0';
449 sp
->u
.string
= sp
->u
.string
+rm
[1].rm_so
;
451 sp
->u
.num
= rm
[0].rm_eo
;
455 if (pat
.re_nsub
> 0) {
456 sp
->u
.string
[0] = '\0';
469 lookup_op(name
, table
)
473 register char *const*tp
;
474 register char const *p
;
477 for (tp
= table
; (p
= *tp
) != NULL
; tp
++) {
478 if (p
[1] == c
&& equal(p
, name
))