2 * Copyright (c) 1992, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 static char const copyright[] =
39 "@(#) Copyright (c) 1992, 1993, 1994\n\
40 The Regents of the University of California. All rights reserved.\n";
45 static char sccsid[] = "@(#)test.c 8.3 (Berkeley) 4/2/94";
47 static const char rcsid[] =
51 #include <sys/param.h>
63 #include "operators.h"
73 #define IS_BANG(s) (s[0] == '!' && s[1] == '\0')
76 * This structure hold a value. The type keyword specifies the type of
77 * the value, and the union u holds the value. The value of a boolean
78 * is stored in u.num (1 = TRUE, 0 = FALSE).
89 short op; /* Which operator. */
90 short pri; /* Priority of operator. */
94 char *name; /* Name of file. */
95 int rcode; /* Return code from stat. */
96 struct stat stat; /* Status info on file. */
99 static int expr_is_false __P((struct value *));
100 static void expr_operator __P((int, struct value *, struct filestat *));
101 static void get_int __P((char *, long *));
102 static int lookup_op __P((char *, const char *const *));
103 static void overflow __P((void));
104 static int posix_binary_op __P((char **));
105 static int posix_unary_op __P((char **));
106 static void syntax __P((void));
113 struct operator opstack[STACKSIZE];
114 struct operator *opsp;
115 struct value valstack[STACKSIZE + 1];
118 char c, **ap, *opname, *p;
119 int binary, nest, op = 0, pri, ret_val, skipping;
121 if ((p = argv[0]) == NULL)
122 errx(2, "test: argc is zero");
124 if (*p != '\0' && p[strlen(p) - 1] == '[') {
125 if (strcmp(argv[--argc], "]"))
126 errx(2, "missing ]");
133 * Test(1) implements an inherently ambiguous grammer. In order to
134 * assure some degree of consistency, we special case the POSIX 1003.2
135 * requirements to assure correct evaluation for POSIX scripts. The
136 * following special cases comply with POSIX P1003.2/D11.2 Section
143 case 1: /* % test arg */
144 return (argv[1] == NULL || *argv[1] == '\0') ? 1 : 0;
146 case 2: /* % test op arg */
149 return (*argv[2] == '\0') ? 0 : 1;
151 ret_val = posix_unary_op(&argv[1]);
156 case 3: /* % test arg1 op arg2 */
157 if (IS_BANG(argv[1])) {
158 ret_val = posix_unary_op(&argv[1]);
161 } else if (lookup_op(argv[2], andor_op) < 0) {
162 ret_val = posix_binary_op(&argv[1]);
167 case 4: /* % test ! arg1 op arg2 */
168 if (IS_BANG(argv[1]) && lookup_op(argv[3], andor_op) < 0 ) {
169 ret_val = posix_binary_op(&argv[2]);
179 * We use operator precedence parsing, evaluating the expression as
180 * we parse it. Parentheses are handled by bumping up the priority
181 * of operators using the variable "nest." We use the variable
182 * "skipping" to turn off evaluation temporarily for the short
183 * circuit boolean operators. (It is important do the short circuit
184 * evaluation because under NFS a stat operation can take infinitely
187 opsp = opstack + STACKSIZE;
191 valstack[0].type = BOOLEAN;
192 valstack[0].u.num = 0;
199 if (opname[0] == '(' && opname[1] == '\0') {
202 } else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) {
203 if (opsp == &opstack[0])
207 opsp->pri = op_priority[op] + nest;
210 valsp->type = STRING;
211 valsp->u.string = opname;
216 if (opname == NULL) {
222 if (opname[0] != ')' || opname[1] != '\0') {
223 if ((op = lookup_op(opname, binary_op)) < 0)
225 op += FIRST_BINARY_OP;
226 pri = op_priority[op] + nest;
229 if ((nest -= NESTINCR) < 0)
232 while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) {
236 c = op_argflag[opsp->op];
238 if (valsp->type == STRING)
239 get_int(valsp->u.string,
241 valsp->type = INTEGER;
242 } else if (c >= OP_STRING) {
243 /* OP_STRING or OP_FILE */
244 if (valsp->type == INTEGER) {
245 if ((p = malloc(32)) == NULL)
252 "%ld", valsp->u.num);
255 } else if (valsp->type == BOOLEAN) {
260 valsp->u.string = "";
262 valsp->type = STRING;
263 if (c == OP_FILE && (fs.name == NULL ||
264 strcmp(fs.name, valsp->u.string))) {
265 fs.name = valsp->u.string;
267 stat(valsp->u.string,
271 if (binary < FIRST_BINARY_OP)
276 expr_operator(opsp->op, valsp, &fs);
277 else if (opsp->op == AND1 || opsp->op == OR1)
279 valsp++; /* push value */
280 opsp++; /* pop operator */
284 if (opsp == &opstack[0])
286 if (op == AND1 || op == AND2) {
288 if (skipping || expr_is_false(valsp - 1))
291 if (op == OR1 || op == OR2) {
293 if (skipping || !expr_is_false(valsp - 1))
300 done: return (expr_is_false(&valstack[0]));
308 if (val->type == STRING) {
309 if (val->u.string[0] == '\0')
311 } else { /* INTEGER or BOOLEAN */
320 * Execute an operator. Op is the operator. Sp is the stack pointer;
321 * sp[0] refers to the first operand, sp[1] refers to the second operand
322 * (if any), and the result is placed in sp[0]. The operands are converted
323 * to the type expected by the operator before expr_operator is called.
324 * Fs is a pointer to a structure which holds the value of the last call
325 * to stat, to avoid repeated stat calls on the same file.
328 expr_operator(op, sp, fs)
337 sp->u.num = expr_is_false(sp);
342 if (fs == NULL || fs->rcode == -1)
355 i = S_IWOTH|S_IWGRP|S_IWUSR;
360 if (geteuid() != 0) {
362 permission: if (fs->stat.st_uid == geteuid())
365 gid_t grlist[NGROUPS];
368 ngroups = getgroups(NGROUPS, grlist);
369 for (j = 0; j < ngroups; j++)
370 if (fs->stat.st_gid == grlist[j]) {
376 i = S_IXOTH|S_IXGRP|S_IXUSR;
377 goto filebit; /* true if (stat.st_mode & i) != 0 */
392 fs->rcode = lstat(sp->u.string, &fs->stat);
397 filetype: if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0)
400 false: sp->u.num = 0;
411 filebit: if (fs->stat.st_mode & i && fs->rcode >= 0)
415 sp->u.num = fs->rcode >= 0 ? fs->stat.st_size : 0L;
419 sp->u.num = isatty(sp->u.num);
423 if (sp->u.string[0] == '\0')
427 sp->u.num = strlen(sp->u.string);
433 * These operators are mostly handled by the parser. If we
434 * get here it means that both operands were evaluated, so
435 * the value is the value of the second operand.
442 if (!strcmp(sp->u.string, (sp + 1)->u.string))
450 if (sp->u.num == (sp + 1)->u.num)
454 if (sp->u.num != (sp + 1)->u.num)
458 if (sp->u.num > (sp + 1)->u.num)
462 if (sp->u.num < (sp + 1)->u.num)
466 if (sp->u.num <= (sp + 1)->u.num)
470 if (sp->u.num >= (sp + 1)->u.num)
478 lookup_op(name, table)
480 const char *const * table;
482 const char *const * tp;
487 for (tp = table; (p = *tp) != NULL; tp++)
488 if (p[1] == c && !strcmp(p, name))
503 if ((op = lookup_op(opname, unary_op)) < 0)
507 valp.u.string = opname;
510 fs.rcode = stat(opname, &fs.stat);
511 } else if (c != OP_STRING)
514 expr_operator(op, &valp, &fs);
515 return (valp.u.num == 0);
519 posix_binary_op(argv)
527 if ((op = lookup_op(opname, binary_op)) < 0)
529 op += FIRST_BINARY_OP;
533 get_int(argv[0], &v[0].u.num);
534 get_int(argv[2], &v[1].u.num);
536 v[0].u.string = argv[0];
537 v[1].u.string = argv[2];
539 expr_operator(op, v, NULL);
540 return (v[0].u.num == 0);
544 * Integer type checking.
554 for (; *v && isspace(*v); ++v);
561 if (isdigit(*v) || ((*v == '-' || *v == '+') && isdigit(*(v+1)))) {
563 val = strtol(v, &ep, 10);
565 errx(2, "%s: trailing non-numeric characters", v);
566 if (errno == ERANGE) {
568 errx(2, "%s: underflow", v);
570 errx(2, "%s: overflow", v);
575 errx(2, "%s: expected integer", v);
582 errx(2, "syntax error");
589 errx(2, "expression is too complex");