xref: /freebsd/bin/test/test.c (revision 717a08b6)
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[] =
15717a08b6SSheldon Hearn 	"$Id: test.c,v 1.22 1999/08/14 05:38:04 chris Exp $";
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>
244b88c807SRodney W. Grimes #include <stdio.h>
254b88c807SRodney W. Grimes #include <stdlib.h>
264b88c807SRodney W. Grimes #include <string.h>
274b88c807SRodney W. Grimes #include <unistd.h>
284b88c807SRodney W. Grimes 
29717a08b6SSheldon Hearn /* test(1) accepts the following grammar:
30717a08b6SSheldon Hearn 	oexpr	::= aexpr | aexpr "-o" oexpr ;
31717a08b6SSheldon Hearn 	aexpr	::= nexpr | nexpr "-a" aexpr ;
32717a08b6SSheldon Hearn 	nexpr	::= primary | "!" primary
33717a08b6SSheldon Hearn 	primary	::= unary-operator operand
34717a08b6SSheldon Hearn 		| operand binary-operator operand
35717a08b6SSheldon Hearn 		| operand
36717a08b6SSheldon Hearn 		| "(" oexpr ")"
37717a08b6SSheldon Hearn 		;
38717a08b6SSheldon Hearn 	unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
39717a08b6SSheldon Hearn 		"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
404b88c807SRodney W. Grimes 
41717a08b6SSheldon Hearn 	binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
42717a08b6SSheldon Hearn 			"-nt"|"-ot"|"-ef";
43717a08b6SSheldon Hearn 	operand ::= <any legal UNIX file name>
444b88c807SRodney W. Grimes */
45717a08b6SSheldon Hearn 
46717a08b6SSheldon Hearn enum token {
47717a08b6SSheldon Hearn 	EOI,
48717a08b6SSheldon Hearn 	FILRD,
49717a08b6SSheldon Hearn 	FILWR,
50717a08b6SSheldon Hearn 	FILEX,
51717a08b6SSheldon Hearn 	FILEXIST,
52717a08b6SSheldon Hearn 	FILREG,
53717a08b6SSheldon Hearn 	FILDIR,
54717a08b6SSheldon Hearn 	FILCDEV,
55717a08b6SSheldon Hearn 	FILBDEV,
56717a08b6SSheldon Hearn 	FILFIFO,
57717a08b6SSheldon Hearn 	FILSOCK,
58717a08b6SSheldon Hearn 	FILSYM,
59717a08b6SSheldon Hearn 	FILGZ,
60717a08b6SSheldon Hearn 	FILTT,
61717a08b6SSheldon Hearn 	FILSUID,
62717a08b6SSheldon Hearn 	FILSGID,
63717a08b6SSheldon Hearn 	FILSTCK,
64717a08b6SSheldon Hearn 	FILNT,
65717a08b6SSheldon Hearn 	FILOT,
66717a08b6SSheldon Hearn 	FILEQ,
67717a08b6SSheldon Hearn 	FILUID,
68717a08b6SSheldon Hearn 	FILGID,
69717a08b6SSheldon Hearn 	STREZ,
70717a08b6SSheldon Hearn 	STRNZ,
71717a08b6SSheldon Hearn 	STREQ,
72717a08b6SSheldon Hearn 	STRNE,
73717a08b6SSheldon Hearn 	STRLT,
74717a08b6SSheldon Hearn 	STRGT,
75717a08b6SSheldon Hearn 	INTEQ,
76717a08b6SSheldon Hearn 	INTNE,
77717a08b6SSheldon Hearn 	INTGE,
78717a08b6SSheldon Hearn 	INTGT,
79717a08b6SSheldon Hearn 	INTLE,
80717a08b6SSheldon Hearn 	INTLT,
81717a08b6SSheldon Hearn 	UNOT,
82717a08b6SSheldon Hearn 	BAND,
83717a08b6SSheldon Hearn 	BOR,
84717a08b6SSheldon Hearn 	LPAREN,
85717a08b6SSheldon Hearn 	RPAREN,
86717a08b6SSheldon Hearn 	OPERAND
874b88c807SRodney W. Grimes };
884b88c807SRodney W. Grimes 
89717a08b6SSheldon Hearn enum token_types {
90717a08b6SSheldon Hearn 	UNOP,
91717a08b6SSheldon Hearn 	BINOP,
92717a08b6SSheldon Hearn 	BUNOP,
93717a08b6SSheldon Hearn 	BBINOP,
94717a08b6SSheldon Hearn 	PAREN
954b88c807SRodney W. Grimes };
964b88c807SRodney W. Grimes 
97717a08b6SSheldon Hearn struct t_op {
98717a08b6SSheldon Hearn 	const char *op_text;
99717a08b6SSheldon Hearn 	short op_num, op_type;
100717a08b6SSheldon Hearn } const ops [] = {
101717a08b6SSheldon Hearn 	{"-r",	FILRD,	UNOP},
102717a08b6SSheldon Hearn 	{"-w",	FILWR,	UNOP},
103717a08b6SSheldon Hearn 	{"-x",	FILEX,	UNOP},
104717a08b6SSheldon Hearn 	{"-e",	FILEXIST,UNOP},
105717a08b6SSheldon Hearn 	{"-f",	FILREG,	UNOP},
106717a08b6SSheldon Hearn 	{"-d",	FILDIR,	UNOP},
107717a08b6SSheldon Hearn 	{"-c",	FILCDEV,UNOP},
108717a08b6SSheldon Hearn 	{"-b",	FILBDEV,UNOP},
109717a08b6SSheldon Hearn 	{"-p",	FILFIFO,UNOP},
110717a08b6SSheldon Hearn 	{"-u",	FILSUID,UNOP},
111717a08b6SSheldon Hearn 	{"-g",	FILSGID,UNOP},
112717a08b6SSheldon Hearn 	{"-k",	FILSTCK,UNOP},
113717a08b6SSheldon Hearn 	{"-s",	FILGZ,	UNOP},
114717a08b6SSheldon Hearn 	{"-t",	FILTT,	UNOP},
115717a08b6SSheldon Hearn 	{"-z",	STREZ,	UNOP},
116717a08b6SSheldon Hearn 	{"-n",	STRNZ,	UNOP},
117717a08b6SSheldon Hearn 	{"-h",	FILSYM,	UNOP},		/* for backwards compat */
118717a08b6SSheldon Hearn 	{"-O",	FILUID,	UNOP},
119717a08b6SSheldon Hearn 	{"-G",	FILGID,	UNOP},
120717a08b6SSheldon Hearn 	{"-L",	FILSYM,	UNOP},
121717a08b6SSheldon Hearn 	{"-S",	FILSOCK,UNOP},
122717a08b6SSheldon Hearn 	{"=",	STREQ,	BINOP},
123717a08b6SSheldon Hearn 	{"!=",	STRNE,	BINOP},
124717a08b6SSheldon Hearn 	{"<",	STRLT,	BINOP},
125717a08b6SSheldon Hearn 	{">",	STRGT,	BINOP},
126717a08b6SSheldon Hearn 	{"-eq",	INTEQ,	BINOP},
127717a08b6SSheldon Hearn 	{"-ne",	INTNE,	BINOP},
128717a08b6SSheldon Hearn 	{"-ge",	INTGE,	BINOP},
129717a08b6SSheldon Hearn 	{"-gt",	INTGT,	BINOP},
130717a08b6SSheldon Hearn 	{"-le",	INTLE,	BINOP},
131717a08b6SSheldon Hearn 	{"-lt",	INTLT,	BINOP},
132717a08b6SSheldon Hearn 	{"-nt",	FILNT,	BINOP},
133717a08b6SSheldon Hearn 	{"-ot",	FILOT,	BINOP},
134717a08b6SSheldon Hearn 	{"-ef",	FILEQ,	BINOP},
135717a08b6SSheldon Hearn 	{"!",	UNOT,	BUNOP},
136717a08b6SSheldon Hearn 	{"-a",	BAND,	BBINOP},
137717a08b6SSheldon Hearn 	{"-o",	BOR,	BBINOP},
138717a08b6SSheldon Hearn 	{"(",	LPAREN,	PAREN},
139717a08b6SSheldon Hearn 	{")",	RPAREN,	PAREN},
140717a08b6SSheldon Hearn 	{0,	0,	0}
1414b88c807SRodney W. Grimes };
1424b88c807SRodney W. Grimes 
143717a08b6SSheldon Hearn struct t_op const *t_wp_op;
144717a08b6SSheldon Hearn char **t_wp;
145717a08b6SSheldon Hearn 
146717a08b6SSheldon Hearn static void syntax __P((const char *, const char *));
147717a08b6SSheldon Hearn static enum token t_lex __P((char *));
148717a08b6SSheldon Hearn static int oexpr __P((enum token));
149717a08b6SSheldon Hearn static int aexpr __P((enum token));
150717a08b6SSheldon Hearn static int nexpr __P((enum token));
151717a08b6SSheldon Hearn static int primary __P((enum token));
152717a08b6SSheldon Hearn static int binop __P((void));
153717a08b6SSheldon Hearn static int filstat __P((char *, enum token));
154717a08b6SSheldon Hearn static int isoperand __P((void));
155717a08b6SSheldon Hearn static int getn __P((const char *));
156717a08b6SSheldon Hearn static int newerf __P((const char *, const char *));
157717a08b6SSheldon Hearn static int olderf __P((const char *, const char *));
158717a08b6SSheldon Hearn static int equalf __P((const char *, const char *));
1594b88c807SRodney W. Grimes 
1604b88c807SRodney W. Grimes int
1614b88c807SRodney W. Grimes main(argc, argv)
1624b88c807SRodney W. Grimes 	int argc;
163717a08b6SSheldon Hearn 	char **argv;
1644b88c807SRodney W. Grimes {
165717a08b6SSheldon Hearn 	int	res;
1664b88c807SRodney W. Grimes 
167717a08b6SSheldon Hearn 	if (strcmp(argv[0], "[") == 0) {
1684b88c807SRodney W. Grimes 		if (strcmp(argv[--argc], "]"))
1694b88c807SRodney W. Grimes 			errx(2, "missing ]");
1704b88c807SRodney W. Grimes 		argv[argc] = NULL;
1714b88c807SRodney W. Grimes 	}
1724b88c807SRodney W. Grimes 
173717a08b6SSheldon Hearn 	t_wp = &argv[1];
174717a08b6SSheldon Hearn 	res = !oexpr(t_lex(*t_wp));
175717a08b6SSheldon Hearn 
176717a08b6SSheldon Hearn 	if (*t_wp != NULL && *++t_wp != NULL)
177717a08b6SSheldon Hearn 		syntax(*t_wp, "unexpected operator");
178717a08b6SSheldon Hearn 
179717a08b6SSheldon Hearn 	return res;
1804b88c807SRodney W. Grimes }
181717a08b6SSheldon Hearn 
182717a08b6SSheldon Hearn static void
183717a08b6SSheldon Hearn syntax(op, msg)
184717a08b6SSheldon Hearn 	const char	*op;
185717a08b6SSheldon Hearn 	const char	*msg;
186717a08b6SSheldon Hearn {
187717a08b6SSheldon Hearn 
188717a08b6SSheldon Hearn 	if (op && *op)
189717a08b6SSheldon Hearn 		errx(2, "%s: %s", op, msg);
190717a08b6SSheldon Hearn 	else
191717a08b6SSheldon Hearn 		errx(2, "%s", msg);
1924b88c807SRodney W. Grimes }
193717a08b6SSheldon Hearn 
194717a08b6SSheldon Hearn static int
195717a08b6SSheldon Hearn oexpr(n)
196717a08b6SSheldon Hearn 	enum token n;
197717a08b6SSheldon Hearn {
198717a08b6SSheldon Hearn 	int res;
199717a08b6SSheldon Hearn 
200717a08b6SSheldon Hearn 	res = aexpr(n);
201717a08b6SSheldon Hearn 	if (t_lex(*++t_wp) == BOR)
202717a08b6SSheldon Hearn 		return oexpr(t_lex(*++t_wp)) || res;
203717a08b6SSheldon Hearn 	t_wp--;
204717a08b6SSheldon Hearn 	return res;
2054b88c807SRodney W. Grimes }
206717a08b6SSheldon Hearn 
207717a08b6SSheldon Hearn static int
208717a08b6SSheldon Hearn aexpr(n)
209717a08b6SSheldon Hearn 	enum token n;
210717a08b6SSheldon Hearn {
211717a08b6SSheldon Hearn 	int res;
212717a08b6SSheldon Hearn 
213717a08b6SSheldon Hearn 	res = nexpr(n);
214717a08b6SSheldon Hearn 	if (t_lex(*++t_wp) == BAND)
215717a08b6SSheldon Hearn 		return aexpr(t_lex(*++t_wp)) && res;
216717a08b6SSheldon Hearn 	t_wp--;
217717a08b6SSheldon Hearn 	return res;
218717a08b6SSheldon Hearn }
219717a08b6SSheldon Hearn 
220717a08b6SSheldon Hearn static int
221717a08b6SSheldon Hearn nexpr(n)
222717a08b6SSheldon Hearn 	enum token n;			/* token */
223717a08b6SSheldon Hearn {
224717a08b6SSheldon Hearn 	if (n == UNOT)
225717a08b6SSheldon Hearn 		return !nexpr(t_lex(*++t_wp));
226717a08b6SSheldon Hearn 	return primary(n);
227717a08b6SSheldon Hearn }
228717a08b6SSheldon Hearn 
229717a08b6SSheldon Hearn static int
230717a08b6SSheldon Hearn primary(n)
231717a08b6SSheldon Hearn 	enum token n;
232717a08b6SSheldon Hearn {
233717a08b6SSheldon Hearn 	enum token nn;
234717a08b6SSheldon Hearn 	int res;
235717a08b6SSheldon Hearn 
236717a08b6SSheldon Hearn 	if (n == EOI)
237717a08b6SSheldon Hearn 		return 0;		/* missing expression */
238717a08b6SSheldon Hearn 	if (n == LPAREN) {
239717a08b6SSheldon Hearn 		if ((nn = t_lex(*++t_wp)) == RPAREN)
240717a08b6SSheldon Hearn 			return 0;	/* missing expression */
241717a08b6SSheldon Hearn 		res = oexpr(nn);
242717a08b6SSheldon Hearn 		if (t_lex(*++t_wp) != RPAREN)
243717a08b6SSheldon Hearn 			syntax(NULL, "closing paren expected");
244717a08b6SSheldon Hearn 		return res;
245717a08b6SSheldon Hearn 	}
246717a08b6SSheldon Hearn 	if (t_wp_op && t_wp_op->op_type == UNOP) {
247717a08b6SSheldon Hearn 		/* unary expression */
248717a08b6SSheldon Hearn 		if (*++t_wp == NULL)
249717a08b6SSheldon Hearn 			syntax(t_wp_op->op_text, "argument expected");
250717a08b6SSheldon Hearn 		switch (n) {
251717a08b6SSheldon Hearn 		case STREZ:
252717a08b6SSheldon Hearn 			return strlen(*t_wp) == 0;
253717a08b6SSheldon Hearn 		case STRNZ:
254717a08b6SSheldon Hearn 			return strlen(*t_wp) != 0;
255717a08b6SSheldon Hearn 		case FILTT:
256717a08b6SSheldon Hearn 			return isatty(getn(*t_wp));
2574b88c807SRodney W. Grimes 		default:
258717a08b6SSheldon Hearn 			return filstat(*t_wp, n);
259717a08b6SSheldon Hearn 		}
2604b88c807SRodney W. Grimes 	}
2614b88c807SRodney W. Grimes 
262717a08b6SSheldon Hearn 	if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
263717a08b6SSheldon Hearn 		return binop();
2644b88c807SRodney W. Grimes 	}
265717a08b6SSheldon Hearn 
266717a08b6SSheldon Hearn 	return strlen(*t_wp) > 0;
2674b88c807SRodney W. Grimes }
2684b88c807SRodney W. Grimes 
2694b88c807SRodney W. Grimes static int
270717a08b6SSheldon Hearn binop()
2714b88c807SRodney W. Grimes {
272717a08b6SSheldon Hearn 	const char *opnd1, *opnd2;
273717a08b6SSheldon Hearn 	struct t_op const *op;
2744b88c807SRodney W. Grimes 
275717a08b6SSheldon Hearn 	opnd1 = *t_wp;
276717a08b6SSheldon Hearn 	(void) t_lex(*++t_wp);
277717a08b6SSheldon Hearn 	op = t_wp_op;
2784b88c807SRodney W. Grimes 
279717a08b6SSheldon Hearn 	if ((opnd2 = *++t_wp) == NULL)
280717a08b6SSheldon Hearn 		syntax(op->op_text, "argument expected");
2814b88c807SRodney W. Grimes 
282717a08b6SSheldon Hearn 	switch (op->op_num) {
2834b88c807SRodney W. Grimes 	case STREQ:
284717a08b6SSheldon Hearn 		return strcmp(opnd1, opnd2) == 0;
2854b88c807SRodney W. Grimes 	case STRNE:
286717a08b6SSheldon Hearn 		return strcmp(opnd1, opnd2) != 0;
287717a08b6SSheldon Hearn 	case STRLT:
288717a08b6SSheldon Hearn 		return strcmp(opnd1, opnd2) < 0;
289717a08b6SSheldon Hearn 	case STRGT:
290717a08b6SSheldon Hearn 		return strcmp(opnd1, opnd2) > 0;
291717a08b6SSheldon Hearn 	case INTEQ:
292717a08b6SSheldon Hearn 		return getn(opnd1) == getn(opnd2);
293717a08b6SSheldon Hearn 	case INTNE:
294717a08b6SSheldon Hearn 		return getn(opnd1) != getn(opnd2);
295717a08b6SSheldon Hearn 	case INTGE:
296717a08b6SSheldon Hearn 		return getn(opnd1) >= getn(opnd2);
297717a08b6SSheldon Hearn 	case INTGT:
298717a08b6SSheldon Hearn 		return getn(opnd1) > getn(opnd2);
299717a08b6SSheldon Hearn 	case INTLE:
300717a08b6SSheldon Hearn 		return getn(opnd1) <= getn(opnd2);
301717a08b6SSheldon Hearn 	case INTLT:
302717a08b6SSheldon Hearn 		return getn(opnd1) < getn(opnd2);
303717a08b6SSheldon Hearn 	case FILNT:
304717a08b6SSheldon Hearn 		return newerf (opnd1, opnd2);
305717a08b6SSheldon Hearn 	case FILOT:
306717a08b6SSheldon Hearn 		return olderf (opnd1, opnd2);
307717a08b6SSheldon Hearn 	case FILEQ:
308717a08b6SSheldon Hearn 		return equalf (opnd1, opnd2);
309717a08b6SSheldon Hearn 	default:
310717a08b6SSheldon Hearn 		abort();
311717a08b6SSheldon Hearn 		/* NOTREACHED */
312717a08b6SSheldon Hearn 	}
313717a08b6SSheldon Hearn }
314717a08b6SSheldon Hearn 
315717a08b6SSheldon Hearn static int
316717a08b6SSheldon Hearn filstat(nm, mode)
317717a08b6SSheldon Hearn 	char *nm;
318717a08b6SSheldon Hearn 	enum token mode;
319717a08b6SSheldon Hearn {
320717a08b6SSheldon Hearn 	struct stat s;
321717a08b6SSheldon Hearn 
322717a08b6SSheldon Hearn 	if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
323717a08b6SSheldon Hearn 		return 0;
324717a08b6SSheldon Hearn 
325717a08b6SSheldon Hearn 	switch (mode) {
326717a08b6SSheldon Hearn 	case FILRD:
327717a08b6SSheldon Hearn 		return access(nm, R_OK) == 0;
328717a08b6SSheldon Hearn 	case FILWR:
329717a08b6SSheldon Hearn 		return access(nm, W_OK) == 0;
330717a08b6SSheldon Hearn 	case FILEX:
331717a08b6SSheldon Hearn 		return access(nm, X_OK) == 0;
332717a08b6SSheldon Hearn 	case FILEXIST:
333717a08b6SSheldon Hearn 		return access(nm, F_OK) == 0;
334717a08b6SSheldon Hearn 	case FILREG:
335717a08b6SSheldon Hearn 		return S_ISREG(s.st_mode);
336717a08b6SSheldon Hearn 	case FILDIR:
337717a08b6SSheldon Hearn 		return S_ISDIR(s.st_mode);
338717a08b6SSheldon Hearn 	case FILCDEV:
339717a08b6SSheldon Hearn 		return S_ISCHR(s.st_mode);
340717a08b6SSheldon Hearn 	case FILBDEV:
341717a08b6SSheldon Hearn 		return S_ISBLK(s.st_mode);
342717a08b6SSheldon Hearn 	case FILFIFO:
343717a08b6SSheldon Hearn 		return S_ISFIFO(s.st_mode);
344717a08b6SSheldon Hearn 	case FILSOCK:
345717a08b6SSheldon Hearn 		return S_ISSOCK(s.st_mode);
346717a08b6SSheldon Hearn 	case FILSYM:
347717a08b6SSheldon Hearn 		return S_ISLNK(s.st_mode);
348717a08b6SSheldon Hearn 	case FILSUID:
349717a08b6SSheldon Hearn 		return (s.st_mode & S_ISUID) != 0;
350717a08b6SSheldon Hearn 	case FILSGID:
351717a08b6SSheldon Hearn 		return (s.st_mode & S_ISGID) != 0;
352717a08b6SSheldon Hearn 	case FILSTCK:
353717a08b6SSheldon Hearn 		return (s.st_mode & S_ISVTX) != 0;
354717a08b6SSheldon Hearn 	case FILGZ:
355717a08b6SSheldon Hearn 		return s.st_size > (off_t)0;
356717a08b6SSheldon Hearn 	case FILUID:
357717a08b6SSheldon Hearn 		return s.st_uid == geteuid();
358717a08b6SSheldon Hearn 	case FILGID:
359717a08b6SSheldon Hearn 		return s.st_gid == getegid();
360717a08b6SSheldon Hearn 	default:
361717a08b6SSheldon Hearn 		return 1;
362717a08b6SSheldon Hearn 	}
363717a08b6SSheldon Hearn }
364717a08b6SSheldon Hearn 
365717a08b6SSheldon Hearn static enum token
366717a08b6SSheldon Hearn t_lex(s)
367717a08b6SSheldon Hearn 	char *s;
368717a08b6SSheldon Hearn {
369717a08b6SSheldon Hearn 	struct t_op const *op = ops;
370717a08b6SSheldon Hearn 
371717a08b6SSheldon Hearn 	if (s == 0) {
372717a08b6SSheldon Hearn 		t_wp_op = NULL;
373717a08b6SSheldon Hearn 		return EOI;
374717a08b6SSheldon Hearn 	}
375717a08b6SSheldon Hearn 	while (op->op_text) {
376717a08b6SSheldon Hearn 		if (strcmp(s, op->op_text) == 0) {
377717a08b6SSheldon Hearn 			if ((op->op_type == UNOP && isoperand()) ||
378717a08b6SSheldon Hearn 			    (op->op_num == LPAREN && *(t_wp+1) == 0))
3794b88c807SRodney W. Grimes 				break;
380717a08b6SSheldon Hearn 			t_wp_op = op;
381717a08b6SSheldon Hearn 			return op->op_num;
3824b88c807SRodney W. Grimes 		}
383717a08b6SSheldon Hearn 		op++;
384717a08b6SSheldon Hearn 	}
385717a08b6SSheldon Hearn 	t_wp_op = NULL;
386717a08b6SSheldon Hearn 	return OPERAND;
3874b88c807SRodney W. Grimes }
3884b88c807SRodney W. Grimes 
3894b88c807SRodney W. Grimes static int
390717a08b6SSheldon Hearn isoperand()
3914b88c807SRodney W. Grimes {
392717a08b6SSheldon Hearn 	struct t_op const *op = ops;
393717a08b6SSheldon Hearn 	char *s;
394717a08b6SSheldon Hearn 	char *t;
3954b88c807SRodney W. Grimes 
396717a08b6SSheldon Hearn 	if ((s  = *(t_wp+1)) == 0)
397717a08b6SSheldon Hearn 		return 1;
398717a08b6SSheldon Hearn 	if ((t = *(t_wp+2)) == 0)
399717a08b6SSheldon Hearn 		return 0;
400717a08b6SSheldon Hearn 	while (op->op_text) {
401717a08b6SSheldon Hearn 		if (strcmp(s, op->op_text) == 0)
402717a08b6SSheldon Hearn 			return op->op_type == BINOP &&
403717a08b6SSheldon Hearn 			    (t[0] != ')' || t[1] != '\0');
404717a08b6SSheldon Hearn 		op++;
405717a08b6SSheldon Hearn 	}
406717a08b6SSheldon Hearn 	return 0;
4074b88c807SRodney W. Grimes }
4084b88c807SRodney W. Grimes 
409717a08b6SSheldon Hearn /* atoi with error detection */
4104b88c807SRodney W. Grimes static int
411717a08b6SSheldon Hearn getn(s)
412717a08b6SSheldon Hearn 	const char *s;
4134b88c807SRodney W. Grimes {
414717a08b6SSheldon Hearn 	char *p;
415717a08b6SSheldon Hearn 	long r;
4164b88c807SRodney W. Grimes 
4174b88c807SRodney W. Grimes 	errno = 0;
418717a08b6SSheldon Hearn 	r = strtol(s, &p, 10);
419717a08b6SSheldon Hearn 
420717a08b6SSheldon Hearn 	if (errno != 0)
421717a08b6SSheldon Hearn 	  errx(2, "%s: out of range", s);
422717a08b6SSheldon Hearn 
423717a08b6SSheldon Hearn 	while (isspace((unsigned char)*p))
424717a08b6SSheldon Hearn 	  p++;
425717a08b6SSheldon Hearn 
426717a08b6SSheldon Hearn 	if (*p)
427717a08b6SSheldon Hearn 	  errx(2, "%s: bad number", s);
428717a08b6SSheldon Hearn 
429717a08b6SSheldon Hearn 	return (int) r;
4304b88c807SRodney W. Grimes }
4314b88c807SRodney W. Grimes 
432717a08b6SSheldon Hearn static int
433717a08b6SSheldon Hearn newerf (f1, f2)
434717a08b6SSheldon Hearn 	const char *f1, *f2;
4354b88c807SRodney W. Grimes {
436717a08b6SSheldon Hearn 	struct stat b1, b2;
4374b88c807SRodney W. Grimes 
438717a08b6SSheldon Hearn 	return (stat (f1, &b1) == 0 &&
439717a08b6SSheldon Hearn 		stat (f2, &b2) == 0 &&
440717a08b6SSheldon Hearn 		b1.st_mtime > b2.st_mtime);
4414b88c807SRodney W. Grimes }
4424b88c807SRodney W. Grimes 
443717a08b6SSheldon Hearn static int
444717a08b6SSheldon Hearn olderf (f1, f2)
445717a08b6SSheldon Hearn 	const char *f1, *f2;
4464b88c807SRodney W. Grimes {
447717a08b6SSheldon Hearn 	struct stat b1, b2;
4484b88c807SRodney W. Grimes 
449717a08b6SSheldon Hearn 	return (stat (f1, &b1) == 0 &&
450717a08b6SSheldon Hearn 		stat (f2, &b2) == 0 &&
451717a08b6SSheldon Hearn 		b1.st_mtime < b2.st_mtime);
452717a08b6SSheldon Hearn }
453717a08b6SSheldon Hearn 
454717a08b6SSheldon Hearn static int
455717a08b6SSheldon Hearn equalf (f1, f2)
456717a08b6SSheldon Hearn 	const char *f1, *f2;
457717a08b6SSheldon Hearn {
458717a08b6SSheldon Hearn 	struct stat b1, b2;
459717a08b6SSheldon Hearn 
460717a08b6SSheldon Hearn 	return (stat (f1, &b1) == 0 &&
461717a08b6SSheldon Hearn 		stat (f2, &b2) == 0 &&
462717a08b6SSheldon Hearn 		b1.st_dev == b2.st_dev &&
463717a08b6SSheldon Hearn 		b1.st_ino == b2.st_ino);
4644b88c807SRodney W. Grimes }
465