xref: /freebsd/bin/test/test.c (revision 9ea42c8e)
1717a08b6SSheldon Hearn /*	$NetBSD: test.c,v 1.21 1999/04/05 09:48:38 kleink Exp $	*/
2717a08b6SSheldon Hearn 
3717a08b6SSheldon Hearn /*
4717a08b6SSheldon Hearn  * test(1); version 7-like  --  author Erik Baalbergen
5717a08b6SSheldon Hearn  * modified by Eric Gisin to be used as built-in.
6717a08b6SSheldon Hearn  * modified by Arnold Robbins to add SVR3 compatibility
7717a08b6SSheldon Hearn  * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
8717a08b6SSheldon Hearn  * modified by J.T. Conklin for NetBSD.
94b88c807SRodney W. Grimes  *
10717a08b6SSheldon Hearn  * This program is in the Public Domain.
114b88c807SRodney W. Grimes  */
124b88c807SRodney W. Grimes 
134b88c807SRodney W. Grimes #ifndef lint
149ba8bd65SPhilippe Charnier static const char rcsid[] =
152a456239SPeter Wemm   "$FreeBSD$";
164b88c807SRodney W. Grimes #endif /* not lint */
174b88c807SRodney W. Grimes 
18717a08b6SSheldon Hearn #include <sys/types.h>
19007d3350SEivind Eklund #include <sys/stat.h>
204b88c807SRodney W. Grimes 
214b88c807SRodney W. Grimes #include <ctype.h>
224b88c807SRodney W. Grimes #include <err.h>
234b88c807SRodney W. Grimes #include <errno.h>
246dca6515SKris Kennaway #include <limits.h>
2525e04004SAkinori MUSHA #include <stdarg.h>
264b88c807SRodney W. Grimes #include <stdio.h>
274b88c807SRodney W. Grimes #include <stdlib.h>
284b88c807SRodney W. Grimes #include <string.h>
294b88c807SRodney W. Grimes #include <unistd.h>
304b88c807SRodney W. Grimes 
31d90c5c4aSAkinori MUSHA #ifdef SHELL
32d90c5c4aSAkinori MUSHA #define main testcmd
33d90c5c4aSAkinori MUSHA #include "bltin/bltin.h"
34d919a882SAkinori MUSHA #else
35d919a882SAkinori MUSHA static void error(const char *, ...) __attribute__((__noreturn__));
36d919a882SAkinori MUSHA 
37d919a882SAkinori MUSHA static void
38d919a882SAkinori MUSHA #ifdef __STDC__
39d919a882SAkinori MUSHA error(const char *msg, ...)
40d919a882SAkinori MUSHA #else
41d919a882SAkinori MUSHA error(va_alist)
42d919a882SAkinori MUSHA 	va_dcl
43d919a882SAkinori MUSHA #endif
44d919a882SAkinori MUSHA {
45d919a882SAkinori MUSHA 	va_list ap;
46d919a882SAkinori MUSHA #ifndef __STDC__
47d919a882SAkinori MUSHA 	const char *msg;
48d919a882SAkinori MUSHA 
49d919a882SAkinori MUSHA 	va_start(ap);
50d919a882SAkinori MUSHA 	msg = va_arg(ap, const char *);
51d919a882SAkinori MUSHA #else
52d919a882SAkinori MUSHA 	va_start(ap, msg);
53d919a882SAkinori MUSHA #endif
54d919a882SAkinori MUSHA 	verrx(2, msg, ap);
55d919a882SAkinori MUSHA 	/*NOTREACHED*/
56d919a882SAkinori MUSHA 	va_end(ap);
57d919a882SAkinori MUSHA }
58d90c5c4aSAkinori MUSHA #endif
59d90c5c4aSAkinori MUSHA 
60717a08b6SSheldon Hearn /* test(1) accepts the following grammar:
61717a08b6SSheldon Hearn 	oexpr	::= aexpr | aexpr "-o" oexpr ;
62717a08b6SSheldon Hearn 	aexpr	::= nexpr | nexpr "-a" aexpr ;
63717a08b6SSheldon Hearn 	nexpr	::= primary | "!" primary
64717a08b6SSheldon Hearn 	primary	::= unary-operator operand
65717a08b6SSheldon Hearn 		| operand binary-operator operand
66717a08b6SSheldon Hearn 		| operand
67717a08b6SSheldon Hearn 		| "(" oexpr ")"
68717a08b6SSheldon Hearn 		;
69717a08b6SSheldon Hearn 	unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
70717a08b6SSheldon Hearn 		"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
714b88c807SRodney W. Grimes 
72717a08b6SSheldon Hearn 	binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
73717a08b6SSheldon Hearn 			"-nt"|"-ot"|"-ef";
74717a08b6SSheldon Hearn 	operand ::= <any legal UNIX file name>
754b88c807SRodney W. Grimes */
76717a08b6SSheldon Hearn 
77717a08b6SSheldon Hearn enum token {
78717a08b6SSheldon Hearn 	EOI,
79717a08b6SSheldon Hearn 	FILRD,
80717a08b6SSheldon Hearn 	FILWR,
81717a08b6SSheldon Hearn 	FILEX,
82717a08b6SSheldon Hearn 	FILEXIST,
83717a08b6SSheldon Hearn 	FILREG,
84717a08b6SSheldon Hearn 	FILDIR,
85717a08b6SSheldon Hearn 	FILCDEV,
86717a08b6SSheldon Hearn 	FILBDEV,
87717a08b6SSheldon Hearn 	FILFIFO,
88717a08b6SSheldon Hearn 	FILSOCK,
89717a08b6SSheldon Hearn 	FILSYM,
90717a08b6SSheldon Hearn 	FILGZ,
91717a08b6SSheldon Hearn 	FILTT,
92717a08b6SSheldon Hearn 	FILSUID,
93717a08b6SSheldon Hearn 	FILSGID,
94717a08b6SSheldon Hearn 	FILSTCK,
95717a08b6SSheldon Hearn 	FILNT,
96717a08b6SSheldon Hearn 	FILOT,
97717a08b6SSheldon Hearn 	FILEQ,
98717a08b6SSheldon Hearn 	FILUID,
99717a08b6SSheldon Hearn 	FILGID,
100717a08b6SSheldon Hearn 	STREZ,
101717a08b6SSheldon Hearn 	STRNZ,
102717a08b6SSheldon Hearn 	STREQ,
103717a08b6SSheldon Hearn 	STRNE,
104717a08b6SSheldon Hearn 	STRLT,
105717a08b6SSheldon Hearn 	STRGT,
106717a08b6SSheldon Hearn 	INTEQ,
107717a08b6SSheldon Hearn 	INTNE,
108717a08b6SSheldon Hearn 	INTGE,
109717a08b6SSheldon Hearn 	INTGT,
110717a08b6SSheldon Hearn 	INTLE,
111717a08b6SSheldon Hearn 	INTLT,
112717a08b6SSheldon Hearn 	UNOT,
113717a08b6SSheldon Hearn 	BAND,
114717a08b6SSheldon Hearn 	BOR,
115717a08b6SSheldon Hearn 	LPAREN,
116717a08b6SSheldon Hearn 	RPAREN,
117717a08b6SSheldon Hearn 	OPERAND
1184b88c807SRodney W. Grimes };
1194b88c807SRodney W. Grimes 
120717a08b6SSheldon Hearn enum token_types {
121717a08b6SSheldon Hearn 	UNOP,
122717a08b6SSheldon Hearn 	BINOP,
123717a08b6SSheldon Hearn 	BUNOP,
124717a08b6SSheldon Hearn 	BBINOP,
125717a08b6SSheldon Hearn 	PAREN
1264b88c807SRodney W. Grimes };
1274b88c807SRodney W. Grimes 
128717a08b6SSheldon Hearn struct t_op {
129717a08b6SSheldon Hearn 	const char *op_text;
130717a08b6SSheldon Hearn 	short op_num, op_type;
131717a08b6SSheldon Hearn } const ops [] = {
132717a08b6SSheldon Hearn 	{"-r",	FILRD,	UNOP},
133717a08b6SSheldon Hearn 	{"-w",	FILWR,	UNOP},
134717a08b6SSheldon Hearn 	{"-x",	FILEX,	UNOP},
135717a08b6SSheldon Hearn 	{"-e",	FILEXIST,UNOP},
136717a08b6SSheldon Hearn 	{"-f",	FILREG,	UNOP},
137717a08b6SSheldon Hearn 	{"-d",	FILDIR,	UNOP},
138717a08b6SSheldon Hearn 	{"-c",	FILCDEV,UNOP},
139717a08b6SSheldon Hearn 	{"-b",	FILBDEV,UNOP},
140717a08b6SSheldon Hearn 	{"-p",	FILFIFO,UNOP},
141717a08b6SSheldon Hearn 	{"-u",	FILSUID,UNOP},
142717a08b6SSheldon Hearn 	{"-g",	FILSGID,UNOP},
143717a08b6SSheldon Hearn 	{"-k",	FILSTCK,UNOP},
144717a08b6SSheldon Hearn 	{"-s",	FILGZ,	UNOP},
145717a08b6SSheldon Hearn 	{"-t",	FILTT,	UNOP},
146717a08b6SSheldon Hearn 	{"-z",	STREZ,	UNOP},
147717a08b6SSheldon Hearn 	{"-n",	STRNZ,	UNOP},
148717a08b6SSheldon Hearn 	{"-h",	FILSYM,	UNOP},		/* for backwards compat */
149717a08b6SSheldon Hearn 	{"-O",	FILUID,	UNOP},
150717a08b6SSheldon Hearn 	{"-G",	FILGID,	UNOP},
151717a08b6SSheldon Hearn 	{"-L",	FILSYM,	UNOP},
152717a08b6SSheldon Hearn 	{"-S",	FILSOCK,UNOP},
153717a08b6SSheldon Hearn 	{"=",	STREQ,	BINOP},
154717a08b6SSheldon Hearn 	{"!=",	STRNE,	BINOP},
155717a08b6SSheldon Hearn 	{"<",	STRLT,	BINOP},
156717a08b6SSheldon Hearn 	{">",	STRGT,	BINOP},
157717a08b6SSheldon Hearn 	{"-eq",	INTEQ,	BINOP},
158717a08b6SSheldon Hearn 	{"-ne",	INTNE,	BINOP},
159717a08b6SSheldon Hearn 	{"-ge",	INTGE,	BINOP},
160717a08b6SSheldon Hearn 	{"-gt",	INTGT,	BINOP},
161717a08b6SSheldon Hearn 	{"-le",	INTLE,	BINOP},
162717a08b6SSheldon Hearn 	{"-lt",	INTLT,	BINOP},
163717a08b6SSheldon Hearn 	{"-nt",	FILNT,	BINOP},
164717a08b6SSheldon Hearn 	{"-ot",	FILOT,	BINOP},
165717a08b6SSheldon Hearn 	{"-ef",	FILEQ,	BINOP},
166717a08b6SSheldon Hearn 	{"!",	UNOT,	BUNOP},
167717a08b6SSheldon Hearn 	{"-a",	BAND,	BBINOP},
168717a08b6SSheldon Hearn 	{"-o",	BOR,	BBINOP},
169717a08b6SSheldon Hearn 	{"(",	LPAREN,	PAREN},
170717a08b6SSheldon Hearn 	{")",	RPAREN,	PAREN},
171717a08b6SSheldon Hearn 	{0,	0,	0}
1724b88c807SRodney W. Grimes };
1734b88c807SRodney W. Grimes 
174717a08b6SSheldon Hearn struct t_op const *t_wp_op;
175717a08b6SSheldon Hearn char **t_wp;
176717a08b6SSheldon Hearn 
177717a08b6SSheldon Hearn static int	aexpr __P((enum token));
178717a08b6SSheldon Hearn static int	binop __P((void));
1796dca6515SKris Kennaway static int	equalf __P((const char *, const char *));
180717a08b6SSheldon Hearn static int	filstat __P((char *, enum token));
181717a08b6SSheldon Hearn static int	getn __P((const char *));
182de96f240SStefan Eßer static quad_t	getq __P((const char *));
183de96f240SStefan Eßer static int	intcmp __P((const char *, const char *));
1846dca6515SKris Kennaway static int	isoperand __P((void));
1856dca6515SKris Kennaway int		main __P((int, char **));
186717a08b6SSheldon Hearn static int	newerf __P((const char *, const char *));
1876dca6515SKris Kennaway static int	nexpr __P((enum token));
1886dca6515SKris Kennaway static int	oexpr __P((enum token));
189717a08b6SSheldon Hearn static int	olderf __P((const char *, const char *));
1906dca6515SKris Kennaway static int	primary __P((enum token));
1916dca6515SKris Kennaway static void	syntax __P((const char *, const char *));
1926dca6515SKris Kennaway static enum	token t_lex __P((char *));
1934b88c807SRodney W. Grimes 
1944b88c807SRodney W. Grimes int
1954b88c807SRodney W. Grimes main(argc, argv)
1964b88c807SRodney W. Grimes 	int argc;
197717a08b6SSheldon Hearn 	char **argv;
1984b88c807SRodney W. Grimes {
199717a08b6SSheldon Hearn 	int	res;
2009abf3043SSheldon Hearn 	char	*p;
2014b88c807SRodney W. Grimes 
2029abf3043SSheldon Hearn 	if ((p = rindex(argv[0], '/')) == NULL)
2039abf3043SSheldon Hearn 		p = argv[0];
2049abf3043SSheldon Hearn 	else
2059abf3043SSheldon Hearn 		p++;
2069abf3043SSheldon Hearn 	if (strcmp(p, "[") == 0) {
207bd90b9c7SAkinori MUSHA 		if (strcmp(argv[--argc], "]") != 0)
208d919a882SAkinori MUSHA 			error("missing ]");
2094b88c807SRodney W. Grimes 		argv[argc] = NULL;
2104b88c807SRodney W. Grimes 	}
2114b88c807SRodney W. Grimes 
212bd90b9c7SAkinori MUSHA 	/* no expression => false */
213bd90b9c7SAkinori MUSHA 	if (--argc <= 0)
214bd90b9c7SAkinori MUSHA 		return 1;
215bd90b9c7SAkinori MUSHA 
2162a6d85a9SBrian Feldman 	/* XXX work around the absence of an eaccess(2) syscall */
217d2fed466SBrian Feldman 	(void)setgid(getegid());
218d2fed466SBrian Feldman 	(void)setuid(geteuid());
219d2fed466SBrian Feldman 
220717a08b6SSheldon Hearn 	t_wp = &argv[1];
221717a08b6SSheldon Hearn 	res = !oexpr(t_lex(*t_wp));
222717a08b6SSheldon Hearn 
223717a08b6SSheldon Hearn 	if (*t_wp != NULL && *++t_wp != NULL)
224717a08b6SSheldon Hearn 		syntax(*t_wp, "unexpected operator");
225717a08b6SSheldon Hearn 
226717a08b6SSheldon Hearn 	return res;
2274b88c807SRodney W. Grimes }
228717a08b6SSheldon Hearn 
229717a08b6SSheldon Hearn static void
230717a08b6SSheldon Hearn syntax(op, msg)
231717a08b6SSheldon Hearn 	const char	*op;
232717a08b6SSheldon Hearn 	const char	*msg;
233717a08b6SSheldon Hearn {
234717a08b6SSheldon Hearn 
235717a08b6SSheldon Hearn 	if (op && *op)
236d919a882SAkinori MUSHA 		error("%s: %s", op, msg);
237717a08b6SSheldon Hearn 	else
238d919a882SAkinori MUSHA 		error("%s", msg);
2394b88c807SRodney W. Grimes }
240717a08b6SSheldon Hearn 
241717a08b6SSheldon Hearn static int
242717a08b6SSheldon Hearn oexpr(n)
243717a08b6SSheldon Hearn 	enum token n;
244717a08b6SSheldon Hearn {
245717a08b6SSheldon Hearn 	int res;
246717a08b6SSheldon Hearn 
247717a08b6SSheldon Hearn 	res = aexpr(n);
248717a08b6SSheldon Hearn 	if (t_lex(*++t_wp) == BOR)
249717a08b6SSheldon Hearn 		return oexpr(t_lex(*++t_wp)) || res;
250717a08b6SSheldon Hearn 	t_wp--;
251717a08b6SSheldon Hearn 	return res;
2524b88c807SRodney W. Grimes }
253717a08b6SSheldon Hearn 
254717a08b6SSheldon Hearn static int
255717a08b6SSheldon Hearn aexpr(n)
256717a08b6SSheldon Hearn 	enum token n;
257717a08b6SSheldon Hearn {
258717a08b6SSheldon Hearn 	int res;
259717a08b6SSheldon Hearn 
260717a08b6SSheldon Hearn 	res = nexpr(n);
261717a08b6SSheldon Hearn 	if (t_lex(*++t_wp) == BAND)
262717a08b6SSheldon Hearn 		return aexpr(t_lex(*++t_wp)) && res;
263717a08b6SSheldon Hearn 	t_wp--;
264717a08b6SSheldon Hearn 	return res;
265717a08b6SSheldon Hearn }
266717a08b6SSheldon Hearn 
267717a08b6SSheldon Hearn static int
268717a08b6SSheldon Hearn nexpr(n)
269717a08b6SSheldon Hearn 	enum token n;			/* token */
270717a08b6SSheldon Hearn {
271717a08b6SSheldon Hearn 	if (n == UNOT)
272717a08b6SSheldon Hearn 		return !nexpr(t_lex(*++t_wp));
273717a08b6SSheldon Hearn 	return primary(n);
274717a08b6SSheldon Hearn }
275717a08b6SSheldon Hearn 
276717a08b6SSheldon Hearn static int
277717a08b6SSheldon Hearn primary(n)
278717a08b6SSheldon Hearn 	enum token n;
279717a08b6SSheldon Hearn {
280717a08b6SSheldon Hearn 	enum token nn;
281717a08b6SSheldon Hearn 	int res;
282717a08b6SSheldon Hearn 
283717a08b6SSheldon Hearn 	if (n == EOI)
284717a08b6SSheldon Hearn 		return 0;		/* missing expression */
285717a08b6SSheldon Hearn 	if (n == LPAREN) {
286717a08b6SSheldon Hearn 		if ((nn = t_lex(*++t_wp)) == RPAREN)
287717a08b6SSheldon Hearn 			return 0;	/* missing expression */
288717a08b6SSheldon Hearn 		res = oexpr(nn);
289717a08b6SSheldon Hearn 		if (t_lex(*++t_wp) != RPAREN)
290717a08b6SSheldon Hearn 			syntax(NULL, "closing paren expected");
291717a08b6SSheldon Hearn 		return res;
292717a08b6SSheldon Hearn 	}
293717a08b6SSheldon Hearn 	if (t_wp_op && t_wp_op->op_type == UNOP) {
294717a08b6SSheldon Hearn 		/* unary expression */
295717a08b6SSheldon Hearn 		if (*++t_wp == NULL)
296717a08b6SSheldon Hearn 			syntax(t_wp_op->op_text, "argument expected");
297717a08b6SSheldon Hearn 		switch (n) {
298717a08b6SSheldon Hearn 		case STREZ:
299717a08b6SSheldon Hearn 			return strlen(*t_wp) == 0;
300717a08b6SSheldon Hearn 		case STRNZ:
301717a08b6SSheldon Hearn 			return strlen(*t_wp) != 0;
302717a08b6SSheldon Hearn 		case FILTT:
303717a08b6SSheldon Hearn 			return isatty(getn(*t_wp));
3044b88c807SRodney W. Grimes 		default:
305717a08b6SSheldon Hearn 			return filstat(*t_wp, n);
306717a08b6SSheldon Hearn 		}
3074b88c807SRodney W. Grimes 	}
3084b88c807SRodney W. Grimes 
309717a08b6SSheldon Hearn 	if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
310717a08b6SSheldon Hearn 		return binop();
3114b88c807SRodney W. Grimes 	}
312717a08b6SSheldon Hearn 
313717a08b6SSheldon Hearn 	return strlen(*t_wp) > 0;
3144b88c807SRodney W. Grimes }
3154b88c807SRodney W. Grimes 
3164b88c807SRodney W. Grimes static int
317717a08b6SSheldon Hearn binop()
3184b88c807SRodney W. Grimes {
319717a08b6SSheldon Hearn 	const char *opnd1, *opnd2;
320717a08b6SSheldon Hearn 	struct t_op const *op;
3214b88c807SRodney W. Grimes 
322717a08b6SSheldon Hearn 	opnd1 = *t_wp;
323717a08b6SSheldon Hearn 	(void) t_lex(*++t_wp);
324717a08b6SSheldon Hearn 	op = t_wp_op;
3254b88c807SRodney W. Grimes 
326717a08b6SSheldon Hearn 	if ((opnd2 = *++t_wp) == NULL)
327717a08b6SSheldon Hearn 		syntax(op->op_text, "argument expected");
3284b88c807SRodney W. Grimes 
329717a08b6SSheldon Hearn 	switch (op->op_num) {
3304b88c807SRodney W. Grimes 	case STREQ:
331717a08b6SSheldon Hearn 		return strcmp(opnd1, opnd2) == 0;
3324b88c807SRodney W. Grimes 	case STRNE:
333717a08b6SSheldon Hearn 		return strcmp(opnd1, opnd2) != 0;
334717a08b6SSheldon Hearn 	case STRLT:
335717a08b6SSheldon Hearn 		return strcmp(opnd1, opnd2) < 0;
336717a08b6SSheldon Hearn 	case STRGT:
337717a08b6SSheldon Hearn 		return strcmp(opnd1, opnd2) > 0;
338717a08b6SSheldon Hearn 	case INTEQ:
339de96f240SStefan Eßer 		return intcmp(opnd1, opnd2) == 0;
340717a08b6SSheldon Hearn 	case INTNE:
341de96f240SStefan Eßer 		return intcmp(opnd1, opnd2) != 0;
342717a08b6SSheldon Hearn 	case INTGE:
343de96f240SStefan Eßer 		return intcmp(opnd1, opnd2) >= 0;
344717a08b6SSheldon Hearn 	case INTGT:
345de96f240SStefan Eßer 		return intcmp(opnd1, opnd2) > 0;
346717a08b6SSheldon Hearn 	case INTLE:
347de96f240SStefan Eßer 		return intcmp(opnd1, opnd2) <= 0;
348717a08b6SSheldon Hearn 	case INTLT:
349de96f240SStefan Eßer 		return intcmp(opnd1, opnd2) < 0;
350717a08b6SSheldon Hearn 	case FILNT:
351717a08b6SSheldon Hearn 		return newerf (opnd1, opnd2);
352717a08b6SSheldon Hearn 	case FILOT:
353717a08b6SSheldon Hearn 		return olderf (opnd1, opnd2);
354717a08b6SSheldon Hearn 	case FILEQ:
355717a08b6SSheldon Hearn 		return equalf (opnd1, opnd2);
356717a08b6SSheldon Hearn 	default:
357717a08b6SSheldon Hearn 		abort();
358717a08b6SSheldon Hearn 		/* NOTREACHED */
359717a08b6SSheldon Hearn 	}
360717a08b6SSheldon Hearn }
361717a08b6SSheldon Hearn 
362717a08b6SSheldon Hearn static int
363717a08b6SSheldon Hearn filstat(nm, mode)
364717a08b6SSheldon Hearn 	char *nm;
365717a08b6SSheldon Hearn 	enum token mode;
366717a08b6SSheldon Hearn {
367717a08b6SSheldon Hearn 	struct stat s;
368717a08b6SSheldon Hearn 
369717a08b6SSheldon Hearn 	if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
370717a08b6SSheldon Hearn 		return 0;
371717a08b6SSheldon Hearn 
372717a08b6SSheldon Hearn 	switch (mode) {
373717a08b6SSheldon Hearn 	case FILRD:
374717a08b6SSheldon Hearn 		return access(nm, R_OK) == 0;
375717a08b6SSheldon Hearn 	case FILWR:
376717a08b6SSheldon Hearn 		return access(nm, W_OK) == 0;
377717a08b6SSheldon Hearn 	case FILEX:
3782a6d85a9SBrian Feldman 		/* XXX work around access(2) false positives for superuser */
379d2fed466SBrian Feldman 		if (access(nm, X_OK) != 0)
380eb5e5558SBrian Feldman 			return 0;
381d2fed466SBrian Feldman 		if (S_ISDIR(s.st_mode) || getuid() != 0)
382eb5e5558SBrian Feldman 			return 1;
383d2fed466SBrian Feldman 		return (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0;
384717a08b6SSheldon Hearn 	case FILEXIST:
385717a08b6SSheldon Hearn 		return access(nm, F_OK) == 0;
386717a08b6SSheldon Hearn 	case FILREG:
387717a08b6SSheldon Hearn 		return S_ISREG(s.st_mode);
388717a08b6SSheldon Hearn 	case FILDIR:
389717a08b6SSheldon Hearn 		return S_ISDIR(s.st_mode);
390717a08b6SSheldon Hearn 	case FILCDEV:
391717a08b6SSheldon Hearn 		return S_ISCHR(s.st_mode);
392717a08b6SSheldon Hearn 	case FILBDEV:
393717a08b6SSheldon Hearn 		return S_ISBLK(s.st_mode);
394717a08b6SSheldon Hearn 	case FILFIFO:
395717a08b6SSheldon Hearn 		return S_ISFIFO(s.st_mode);
396717a08b6SSheldon Hearn 	case FILSOCK:
397717a08b6SSheldon Hearn 		return S_ISSOCK(s.st_mode);
398717a08b6SSheldon Hearn 	case FILSYM:
399717a08b6SSheldon Hearn 		return S_ISLNK(s.st_mode);
400717a08b6SSheldon Hearn 	case FILSUID:
401717a08b6SSheldon Hearn 		return (s.st_mode & S_ISUID) != 0;
402717a08b6SSheldon Hearn 	case FILSGID:
403717a08b6SSheldon Hearn 		return (s.st_mode & S_ISGID) != 0;
404717a08b6SSheldon Hearn 	case FILSTCK:
405717a08b6SSheldon Hearn 		return (s.st_mode & S_ISVTX) != 0;
406717a08b6SSheldon Hearn 	case FILGZ:
407717a08b6SSheldon Hearn 		return s.st_size > (off_t)0;
408717a08b6SSheldon Hearn 	case FILUID:
409717a08b6SSheldon Hearn 		return s.st_uid == geteuid();
410717a08b6SSheldon Hearn 	case FILGID:
411717a08b6SSheldon Hearn 		return s.st_gid == getegid();
412717a08b6SSheldon Hearn 	default:
413717a08b6SSheldon Hearn 		return 1;
414717a08b6SSheldon Hearn 	}
415717a08b6SSheldon Hearn }
416717a08b6SSheldon Hearn 
417717a08b6SSheldon Hearn static enum token
418717a08b6SSheldon Hearn t_lex(s)
419717a08b6SSheldon Hearn 	char *s;
420717a08b6SSheldon Hearn {
421717a08b6SSheldon Hearn 	struct t_op const *op = ops;
422717a08b6SSheldon Hearn 
423717a08b6SSheldon Hearn 	if (s == 0) {
424717a08b6SSheldon Hearn 		t_wp_op = NULL;
425717a08b6SSheldon Hearn 		return EOI;
426717a08b6SSheldon Hearn 	}
427717a08b6SSheldon Hearn 	while (op->op_text) {
428717a08b6SSheldon Hearn 		if (strcmp(s, op->op_text) == 0) {
429717a08b6SSheldon Hearn 			if ((op->op_type == UNOP && isoperand()) ||
430717a08b6SSheldon Hearn 			    (op->op_num == LPAREN && *(t_wp+1) == 0))
4314b88c807SRodney W. Grimes 				break;
432717a08b6SSheldon Hearn 			t_wp_op = op;
433717a08b6SSheldon Hearn 			return op->op_num;
4344b88c807SRodney W. Grimes 		}
435717a08b6SSheldon Hearn 		op++;
436717a08b6SSheldon Hearn 	}
437717a08b6SSheldon Hearn 	t_wp_op = NULL;
438717a08b6SSheldon Hearn 	return OPERAND;
4394b88c807SRodney W. Grimes }
4404b88c807SRodney W. Grimes 
4414b88c807SRodney W. Grimes static int
442717a08b6SSheldon Hearn isoperand()
4434b88c807SRodney W. Grimes {
444717a08b6SSheldon Hearn 	struct t_op const *op = ops;
445717a08b6SSheldon Hearn 	char *s;
446717a08b6SSheldon Hearn 	char *t;
4474b88c807SRodney W. Grimes 
448717a08b6SSheldon Hearn 	if ((s  = *(t_wp+1)) == 0)
449717a08b6SSheldon Hearn 		return 1;
450717a08b6SSheldon Hearn 	if ((t = *(t_wp+2)) == 0)
451717a08b6SSheldon Hearn 		return 0;
452717a08b6SSheldon Hearn 	while (op->op_text) {
453717a08b6SSheldon Hearn 		if (strcmp(s, op->op_text) == 0)
454717a08b6SSheldon Hearn 			return op->op_type == BINOP &&
455717a08b6SSheldon Hearn 			    (t[0] != ')' || t[1] != '\0');
456717a08b6SSheldon Hearn 		op++;
457717a08b6SSheldon Hearn 	}
458717a08b6SSheldon Hearn 	return 0;
4594b88c807SRodney W. Grimes }
4604b88c807SRodney W. Grimes 
461717a08b6SSheldon Hearn /* atoi with error detection */
4624b88c807SRodney W. Grimes static int
463717a08b6SSheldon Hearn getn(s)
464717a08b6SSheldon Hearn 	const char *s;
4654b88c807SRodney W. Grimes {
466717a08b6SSheldon Hearn 	char *p;
467717a08b6SSheldon Hearn 	long r;
4684b88c807SRodney W. Grimes 
4694b88c807SRodney W. Grimes 	errno = 0;
470717a08b6SSheldon Hearn 	r = strtol(s, &p, 10);
471717a08b6SSheldon Hearn 
472717a08b6SSheldon Hearn 	if (errno != 0)
4739ea42c8eSAndrey A. Chernov 		error((errno == EINVAL) ? "%s: bad number" :
4749ea42c8eSAndrey A. Chernov 					  "%s: out of range", s);
475717a08b6SSheldon Hearn 
476717a08b6SSheldon Hearn 	while (isspace((unsigned char)*p))
477717a08b6SSheldon Hearn 		p++;
478717a08b6SSheldon Hearn 
479717a08b6SSheldon Hearn 	if (*p)
480d919a882SAkinori MUSHA 		error("%s: bad number", s);
481717a08b6SSheldon Hearn 
482717a08b6SSheldon Hearn 	return (int) r;
4834b88c807SRodney W. Grimes }
4844b88c807SRodney W. Grimes 
485de96f240SStefan Eßer /* atoi with error detection and 64 bit range */
486de96f240SStefan Eßer static quad_t
487de96f240SStefan Eßer getq(s)
488de96f240SStefan Eßer 	const char *s;
489de96f240SStefan Eßer {
490de96f240SStefan Eßer 	char *p;
491de96f240SStefan Eßer 	quad_t r;
492de96f240SStefan Eßer 
493de96f240SStefan Eßer 	errno = 0;
494de96f240SStefan Eßer 	r = strtoq(s, &p, 10);
495de96f240SStefan Eßer 
496de96f240SStefan Eßer 	if (errno != 0)
4979ea42c8eSAndrey A. Chernov 		error((errno == EINVAL) ? "%s: bad number" :
4989ea42c8eSAndrey A. Chernov 					  "%s: out of range", s);
499de96f240SStefan Eßer 
500de96f240SStefan Eßer 	while (isspace((unsigned char)*p))
501de96f240SStefan Eßer 		p++;
502de96f240SStefan Eßer 
503de96f240SStefan Eßer 	if (*p)
504d919a882SAkinori MUSHA 		error("%s: bad number", s);
505de96f240SStefan Eßer 
506de96f240SStefan Eßer 	return r;
507de96f240SStefan Eßer }
508de96f240SStefan Eßer 
509de96f240SStefan Eßer static int
510de96f240SStefan Eßer intcmp (s1, s2)
511de96f240SStefan Eßer 	const char *s1, *s2;
512de96f240SStefan Eßer {
513de96f240SStefan Eßer 	quad_t q1, q2;
514de96f240SStefan Eßer 
515de96f240SStefan Eßer 
516de96f240SStefan Eßer 	q1 = getq(s1);
517de96f240SStefan Eßer 	q2 = getq(s2);
518de96f240SStefan Eßer 
519de96f240SStefan Eßer 	if (q1 > q2)
520de96f240SStefan Eßer 		return 1;
521de96f240SStefan Eßer 
522de96f240SStefan Eßer 	if (q1 < q2)
523de96f240SStefan Eßer 		return -1;
524de96f240SStefan Eßer 
525de96f240SStefan Eßer 	return 0;
526de96f240SStefan Eßer }
527de96f240SStefan Eßer 
528717a08b6SSheldon Hearn static int
529717a08b6SSheldon Hearn newerf (f1, f2)
530717a08b6SSheldon Hearn 	const char *f1, *f2;
5314b88c807SRodney W. Grimes {
532717a08b6SSheldon Hearn 	struct stat b1, b2;
5334b88c807SRodney W. Grimes 
534717a08b6SSheldon Hearn 	return (stat (f1, &b1) == 0 &&
535717a08b6SSheldon Hearn 		stat (f2, &b2) == 0 &&
536717a08b6SSheldon Hearn 		b1.st_mtime > b2.st_mtime);
5374b88c807SRodney W. Grimes }
5384b88c807SRodney W. Grimes 
539717a08b6SSheldon Hearn static int
540717a08b6SSheldon Hearn olderf (f1, f2)
541717a08b6SSheldon Hearn 	const char *f1, *f2;
5424b88c807SRodney W. Grimes {
543717a08b6SSheldon Hearn 	struct stat b1, b2;
5444b88c807SRodney W. Grimes 
545717a08b6SSheldon Hearn 	return (stat (f1, &b1) == 0 &&
546717a08b6SSheldon Hearn 		stat (f2, &b2) == 0 &&
547717a08b6SSheldon Hearn 		b1.st_mtime < b2.st_mtime);
548717a08b6SSheldon Hearn }
549717a08b6SSheldon Hearn 
550717a08b6SSheldon Hearn static int
551717a08b6SSheldon Hearn equalf (f1, f2)
552717a08b6SSheldon Hearn 	const char *f1, *f2;
553717a08b6SSheldon Hearn {
554717a08b6SSheldon Hearn 	struct stat b1, b2;
555717a08b6SSheldon Hearn 
556717a08b6SSheldon Hearn 	return (stat (f1, &b1) == 0 &&
557717a08b6SSheldon Hearn 		stat (f2, &b2) == 0 &&
558717a08b6SSheldon Hearn 		b1.st_dev == b2.st_dev &&
559717a08b6SSheldon Hearn 		b1.st_ino == b2.st_ino);
5604b88c807SRodney W. Grimes }
561