test.c revision 88471
149884Ssheldonh/*	$NetBSD: test.c,v 1.21 1999/04/05 09:48:38 kleink Exp $	*/
249884Ssheldonh
349884Ssheldonh/*
449884Ssheldonh * test(1); version 7-like  --  author Erik Baalbergen
549884Ssheldonh * modified by Eric Gisin to be used as built-in.
649884Ssheldonh * modified by Arnold Robbins to add SVR3 compatibility
749884Ssheldonh * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
849884Ssheldonh * modified by J.T. Conklin for NetBSD.
91556Srgrimes *
1049884Ssheldonh * This program is in the Public Domain.
111556Srgrimes */
121556Srgrimes
131556Srgrimes#ifndef lint
1436152Scharnierstatic const char rcsid[] =
1550471Speter  "$FreeBSD: head/bin/test/test.c 88471 2001-12-25 08:10:34Z ache $";
161556Srgrimes#endif /* not lint */
171556Srgrimes
1849884Ssheldonh#include <sys/types.h>
191556Srgrimes#include <sys/stat.h>
201556Srgrimes
211556Srgrimes#include <ctype.h>
221556Srgrimes#include <err.h>
231556Srgrimes#include <errno.h>
2476883Skris#include <limits.h>
2586619Sknu#include <stdarg.h>
261556Srgrimes#include <stdio.h>
271556Srgrimes#include <stdlib.h>
281556Srgrimes#include <string.h>
291556Srgrimes#include <unistd.h>
301556Srgrimes
3186505Sknu#ifdef SHELL
3286505Sknu#define main testcmd
3386505Sknu#include "bltin/bltin.h"
3486618Sknu#else
3588084Sache#include <locale.h>
3688084Sache
3786618Sknustatic void error(const char *, ...) __attribute__((__noreturn__));
3886618Sknu
3986618Sknustatic void
4086618Sknu#ifdef __STDC__
4186618Sknuerror(const char *msg, ...)
4286618Sknu#else
4386618Sknuerror(va_alist)
4486618Sknu	va_dcl
4586505Sknu#endif
4686618Sknu{
4786618Sknu	va_list ap;
4886618Sknu#ifndef __STDC__
4986618Sknu	const char *msg;
5086505Sknu
5186618Sknu	va_start(ap);
5286618Sknu	msg = va_arg(ap, const char *);
5386618Sknu#else
5486618Sknu	va_start(ap, msg);
5586618Sknu#endif
5686618Sknu	verrx(2, msg, ap);
5786618Sknu	/*NOTREACHED*/
5886618Sknu	va_end(ap);
5986618Sknu}
6086618Sknu#endif
6186618Sknu
6249884Ssheldonh/* test(1) accepts the following grammar:
6349884Ssheldonh	oexpr	::= aexpr | aexpr "-o" oexpr ;
6449884Ssheldonh	aexpr	::= nexpr | nexpr "-a" aexpr ;
6549884Ssheldonh	nexpr	::= primary | "!" primary
6649884Ssheldonh	primary	::= unary-operator operand
6749884Ssheldonh		| operand binary-operator operand
6849884Ssheldonh		| operand
6949884Ssheldonh		| "(" oexpr ")"
7049884Ssheldonh		;
7149884Ssheldonh	unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
7249884Ssheldonh		"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
731556Srgrimes
7449884Ssheldonh	binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
7549884Ssheldonh			"-nt"|"-ot"|"-ef";
7649884Ssheldonh	operand ::= <any legal UNIX file name>
7749884Ssheldonh*/
781556Srgrimes
7949884Ssheldonhenum token {
8049884Ssheldonh	EOI,
8149884Ssheldonh	FILRD,
8249884Ssheldonh	FILWR,
8349884Ssheldonh	FILEX,
8449884Ssheldonh	FILEXIST,
8549884Ssheldonh	FILREG,
8649884Ssheldonh	FILDIR,
8749884Ssheldonh	FILCDEV,
8849884Ssheldonh	FILBDEV,
8949884Ssheldonh	FILFIFO,
9049884Ssheldonh	FILSOCK,
9149884Ssheldonh	FILSYM,
9249884Ssheldonh	FILGZ,
9349884Ssheldonh	FILTT,
9449884Ssheldonh	FILSUID,
9549884Ssheldonh	FILSGID,
9649884Ssheldonh	FILSTCK,
9749884Ssheldonh	FILNT,
9849884Ssheldonh	FILOT,
9949884Ssheldonh	FILEQ,
10049884Ssheldonh	FILUID,
10149884Ssheldonh	FILGID,
10249884Ssheldonh	STREZ,
10349884Ssheldonh	STRNZ,
10449884Ssheldonh	STREQ,
10549884Ssheldonh	STRNE,
10649884Ssheldonh	STRLT,
10749884Ssheldonh	STRGT,
10849884Ssheldonh	INTEQ,
10949884Ssheldonh	INTNE,
11049884Ssheldonh	INTGE,
11149884Ssheldonh	INTGT,
11249884Ssheldonh	INTLE,
11349884Ssheldonh	INTLT,
11449884Ssheldonh	UNOT,
11549884Ssheldonh	BAND,
11649884Ssheldonh	BOR,
11749884Ssheldonh	LPAREN,
11849884Ssheldonh	RPAREN,
11949884Ssheldonh	OPERAND
1201556Srgrimes};
1211556Srgrimes
12249884Ssheldonhenum token_types {
12349884Ssheldonh	UNOP,
12449884Ssheldonh	BINOP,
12549884Ssheldonh	BUNOP,
12649884Ssheldonh	BBINOP,
12749884Ssheldonh	PAREN
1281556Srgrimes};
1291556Srgrimes
13049884Ssheldonhstruct t_op {
13149884Ssheldonh	const char *op_text;
13249884Ssheldonh	short op_num, op_type;
13349884Ssheldonh} const ops [] = {
13449884Ssheldonh	{"-r",	FILRD,	UNOP},
13549884Ssheldonh	{"-w",	FILWR,	UNOP},
13649884Ssheldonh	{"-x",	FILEX,	UNOP},
13749884Ssheldonh	{"-e",	FILEXIST,UNOP},
13849884Ssheldonh	{"-f",	FILREG,	UNOP},
13949884Ssheldonh	{"-d",	FILDIR,	UNOP},
14049884Ssheldonh	{"-c",	FILCDEV,UNOP},
14149884Ssheldonh	{"-b",	FILBDEV,UNOP},
14249884Ssheldonh	{"-p",	FILFIFO,UNOP},
14349884Ssheldonh	{"-u",	FILSUID,UNOP},
14449884Ssheldonh	{"-g",	FILSGID,UNOP},
14549884Ssheldonh	{"-k",	FILSTCK,UNOP},
14649884Ssheldonh	{"-s",	FILGZ,	UNOP},
14749884Ssheldonh	{"-t",	FILTT,	UNOP},
14849884Ssheldonh	{"-z",	STREZ,	UNOP},
14949884Ssheldonh	{"-n",	STRNZ,	UNOP},
15049884Ssheldonh	{"-h",	FILSYM,	UNOP},		/* for backwards compat */
15149884Ssheldonh	{"-O",	FILUID,	UNOP},
15249884Ssheldonh	{"-G",	FILGID,	UNOP},
15349884Ssheldonh	{"-L",	FILSYM,	UNOP},
15449884Ssheldonh	{"-S",	FILSOCK,UNOP},
15549884Ssheldonh	{"=",	STREQ,	BINOP},
15649884Ssheldonh	{"!=",	STRNE,	BINOP},
15749884Ssheldonh	{"<",	STRLT,	BINOP},
15849884Ssheldonh	{">",	STRGT,	BINOP},
15949884Ssheldonh	{"-eq",	INTEQ,	BINOP},
16049884Ssheldonh	{"-ne",	INTNE,	BINOP},
16149884Ssheldonh	{"-ge",	INTGE,	BINOP},
16249884Ssheldonh	{"-gt",	INTGT,	BINOP},
16349884Ssheldonh	{"-le",	INTLE,	BINOP},
16449884Ssheldonh	{"-lt",	INTLT,	BINOP},
16549884Ssheldonh	{"-nt",	FILNT,	BINOP},
16649884Ssheldonh	{"-ot",	FILOT,	BINOP},
16749884Ssheldonh	{"-ef",	FILEQ,	BINOP},
16849884Ssheldonh	{"!",	UNOT,	BUNOP},
16949884Ssheldonh	{"-a",	BAND,	BBINOP},
17049884Ssheldonh	{"-o",	BOR,	BBINOP},
17149884Ssheldonh	{"(",	LPAREN,	PAREN},
17249884Ssheldonh	{")",	RPAREN,	PAREN},
17349884Ssheldonh	{0,	0,	0}
1741556Srgrimes};
1751556Srgrimes
17649884Ssheldonhstruct t_op const *t_wp_op;
17749884Ssheldonhchar **t_wp;
1781556Srgrimes
17976883Skrisstatic int	aexpr __P((enum token));
18076883Skrisstatic int	binop __P((void));
18176883Skrisstatic int	equalf __P((const char *, const char *));
18276883Skrisstatic int	filstat __P((char *, enum token));
18376883Skrisstatic int	getn __P((const char *));
18488471Sachestatic long long	getq __P((const char *));
18576883Skrisstatic int	intcmp __P((const char *, const char *));
18676883Skrisstatic int	isoperand __P((void));
18776883Skrisint		main __P((int, char **));
18876883Skrisstatic int	newerf __P((const char *, const char *));
18976883Skrisstatic int	nexpr __P((enum token));
19076883Skrisstatic int	oexpr __P((enum token));
19176883Skrisstatic int	olderf __P((const char *, const char *));
19276883Skrisstatic int	primary __P((enum token));
19376883Skrisstatic void	syntax __P((const char *, const char *));
19476883Skrisstatic enum	token t_lex __P((char *));
19549884Ssheldonh
1961556Srgrimesint
1971556Srgrimesmain(argc, argv)
1981556Srgrimes	int argc;
19949884Ssheldonh	char **argv;
2001556Srgrimes{
20149884Ssheldonh	int	res;
20255179Ssheldonh	char	*p;
2031556Srgrimes
20455179Ssheldonh	if ((p = rindex(argv[0], '/')) == NULL)
20555179Ssheldonh		p = argv[0];
20655179Ssheldonh	else
20755179Ssheldonh		p++;
20855179Ssheldonh	if (strcmp(p, "[") == 0) {
20986622Sknu		if (strcmp(argv[--argc], "]") != 0)
21086618Sknu			error("missing ]");
2111556Srgrimes		argv[argc] = NULL;
2121556Srgrimes	}
2131556Srgrimes
21486622Sknu	/* no expression => false */
21586622Sknu	if (--argc <= 0)
21686622Sknu		return 1;
21786622Sknu
21888084Sache#ifndef SHELL
21988084Sache	(void)setlocale(LC_CTYPE, "");
22088084Sache#endif
22150302Sgreen	/* XXX work around the absence of an eaccess(2) syscall */
22250087Sgreen	(void)setgid(getegid());
22350087Sgreen	(void)setuid(geteuid());
22450087Sgreen
22549884Ssheldonh	t_wp = &argv[1];
22649884Ssheldonh	res = !oexpr(t_lex(*t_wp));
2271556Srgrimes
22849884Ssheldonh	if (*t_wp != NULL && *++t_wp != NULL)
22949884Ssheldonh		syntax(*t_wp, "unexpected operator");
23049884Ssheldonh
23149884Ssheldonh	return res;
2321556Srgrimes}
2331556Srgrimes
23449884Ssheldonhstatic void
23549884Ssheldonhsyntax(op, msg)
23649884Ssheldonh	const char	*op;
23749884Ssheldonh	const char	*msg;
2381556Srgrimes{
2391556Srgrimes
24049884Ssheldonh	if (op && *op)
24186618Sknu		error("%s: %s", op, msg);
24249884Ssheldonh	else
24386618Sknu		error("%s", msg);
2441556Srgrimes}
2451556Srgrimes
24649884Ssheldonhstatic int
24749884Ssheldonhoexpr(n)
24849884Ssheldonh	enum token n;
2491556Srgrimes{
25049884Ssheldonh	int res;
2511556Srgrimes
25249884Ssheldonh	res = aexpr(n);
25349884Ssheldonh	if (t_lex(*++t_wp) == BOR)
25449884Ssheldonh		return oexpr(t_lex(*++t_wp)) || res;
25549884Ssheldonh	t_wp--;
25649884Ssheldonh	return res;
25749884Ssheldonh}
2584171Sache
25949884Ssheldonhstatic int
26049884Ssheldonhaexpr(n)
26149884Ssheldonh	enum token n;
26249884Ssheldonh{
26349884Ssheldonh	int res;
2641556Srgrimes
26549884Ssheldonh	res = nexpr(n);
26649884Ssheldonh	if (t_lex(*++t_wp) == BAND)
26749884Ssheldonh		return aexpr(t_lex(*++t_wp)) && res;
26849884Ssheldonh	t_wp--;
26949884Ssheldonh	return res;
2701556Srgrimes}
2711556Srgrimes
2721556Srgrimesstatic int
27349884Ssheldonhnexpr(n)
27449884Ssheldonh	enum token n;			/* token */
2751556Srgrimes{
27649884Ssheldonh	if (n == UNOT)
27749884Ssheldonh		return !nexpr(t_lex(*++t_wp));
27849884Ssheldonh	return primary(n);
2791556Srgrimes}
2801556Srgrimes
2811556Srgrimesstatic int
28249884Ssheldonhprimary(n)
28349884Ssheldonh	enum token n;
2841556Srgrimes{
28549884Ssheldonh	enum token nn;
28649884Ssheldonh	int res;
2871556Srgrimes
28849884Ssheldonh	if (n == EOI)
28949884Ssheldonh		return 0;		/* missing expression */
29049884Ssheldonh	if (n == LPAREN) {
29149884Ssheldonh		if ((nn = t_lex(*++t_wp)) == RPAREN)
29249884Ssheldonh			return 0;	/* missing expression */
29349884Ssheldonh		res = oexpr(nn);
29449884Ssheldonh		if (t_lex(*++t_wp) != RPAREN)
29549884Ssheldonh			syntax(NULL, "closing paren expected");
29649884Ssheldonh		return res;
29749884Ssheldonh	}
29849884Ssheldonh	if (t_wp_op && t_wp_op->op_type == UNOP) {
29949884Ssheldonh		/* unary expression */
30049884Ssheldonh		if (*++t_wp == NULL)
30149884Ssheldonh			syntax(t_wp_op->op_text, "argument expected");
30249884Ssheldonh		switch (n) {
30349884Ssheldonh		case STREZ:
30449884Ssheldonh			return strlen(*t_wp) == 0;
30549884Ssheldonh		case STRNZ:
30649884Ssheldonh			return strlen(*t_wp) != 0;
30749884Ssheldonh		case FILTT:
30849884Ssheldonh			return isatty(getn(*t_wp));
30949884Ssheldonh		default:
31049884Ssheldonh			return filstat(*t_wp, n);
31149884Ssheldonh		}
31249884Ssheldonh	}
3131556Srgrimes
31449884Ssheldonh	if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
31549884Ssheldonh		return binop();
31649884Ssheldonh	}
31749884Ssheldonh
31849884Ssheldonh	return strlen(*t_wp) > 0;
3191556Srgrimes}
3201556Srgrimes
3211556Srgrimesstatic int
32249884Ssheldonhbinop()
3231556Srgrimes{
32449884Ssheldonh	const char *opnd1, *opnd2;
32549884Ssheldonh	struct t_op const *op;
3261556Srgrimes
32749884Ssheldonh	opnd1 = *t_wp;
32849884Ssheldonh	(void) t_lex(*++t_wp);
32949884Ssheldonh	op = t_wp_op;
3301556Srgrimes
33149884Ssheldonh	if ((opnd2 = *++t_wp) == NULL)
33249884Ssheldonh		syntax(op->op_text, "argument expected");
33349884Ssheldonh
33449884Ssheldonh	switch (op->op_num) {
33549884Ssheldonh	case STREQ:
33649884Ssheldonh		return strcmp(opnd1, opnd2) == 0;
33749884Ssheldonh	case STRNE:
33849884Ssheldonh		return strcmp(opnd1, opnd2) != 0;
33949884Ssheldonh	case STRLT:
34049884Ssheldonh		return strcmp(opnd1, opnd2) < 0;
34149884Ssheldonh	case STRGT:
34249884Ssheldonh		return strcmp(opnd1, opnd2) > 0;
34349884Ssheldonh	case INTEQ:
34462925Sse		return intcmp(opnd1, opnd2) == 0;
34549884Ssheldonh	case INTNE:
34662925Sse		return intcmp(opnd1, opnd2) != 0;
34749884Ssheldonh	case INTGE:
34862925Sse		return intcmp(opnd1, opnd2) >= 0;
34949884Ssheldonh	case INTGT:
35062925Sse		return intcmp(opnd1, opnd2) > 0;
35149884Ssheldonh	case INTLE:
35262925Sse		return intcmp(opnd1, opnd2) <= 0;
35349884Ssheldonh	case INTLT:
35462925Sse		return intcmp(opnd1, opnd2) < 0;
35549884Ssheldonh	case FILNT:
35649884Ssheldonh		return newerf (opnd1, opnd2);
35749884Ssheldonh	case FILOT:
35849884Ssheldonh		return olderf (opnd1, opnd2);
35949884Ssheldonh	case FILEQ:
36049884Ssheldonh		return equalf (opnd1, opnd2);
36149884Ssheldonh	default:
36249884Ssheldonh		abort();
36349884Ssheldonh		/* NOTREACHED */
3641556Srgrimes	}
3651556Srgrimes}
3661556Srgrimes
36749884Ssheldonhstatic int
36849884Ssheldonhfilstat(nm, mode)
36949884Ssheldonh	char *nm;
37049884Ssheldonh	enum token mode;
3711556Srgrimes{
37249884Ssheldonh	struct stat s;
3731556Srgrimes
37449884Ssheldonh	if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
37549884Ssheldonh		return 0;
3762664Scsgr
37749884Ssheldonh	switch (mode) {
37849884Ssheldonh	case FILRD:
37949884Ssheldonh		return access(nm, R_OK) == 0;
38049884Ssheldonh	case FILWR:
38149884Ssheldonh		return access(nm, W_OK) == 0;
38249884Ssheldonh	case FILEX:
38350302Sgreen		/* XXX work around access(2) false positives for superuser */
38450087Sgreen		if (access(nm, X_OK) != 0)
38550087Sgreen			return 0;
38650087Sgreen		if (S_ISDIR(s.st_mode) || getuid() != 0)
38750087Sgreen			return 1;
38850087Sgreen		return (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0;
38949884Ssheldonh	case FILEXIST:
39049884Ssheldonh		return access(nm, F_OK) == 0;
39149884Ssheldonh	case FILREG:
39249884Ssheldonh		return S_ISREG(s.st_mode);
39349884Ssheldonh	case FILDIR:
39449884Ssheldonh		return S_ISDIR(s.st_mode);
39549884Ssheldonh	case FILCDEV:
39649884Ssheldonh		return S_ISCHR(s.st_mode);
39749884Ssheldonh	case FILBDEV:
39849884Ssheldonh		return S_ISBLK(s.st_mode);
39949884Ssheldonh	case FILFIFO:
40049884Ssheldonh		return S_ISFIFO(s.st_mode);
40149884Ssheldonh	case FILSOCK:
40249884Ssheldonh		return S_ISSOCK(s.st_mode);
40349884Ssheldonh	case FILSYM:
40449884Ssheldonh		return S_ISLNK(s.st_mode);
40549884Ssheldonh	case FILSUID:
40649884Ssheldonh		return (s.st_mode & S_ISUID) != 0;
40749884Ssheldonh	case FILSGID:
40849884Ssheldonh		return (s.st_mode & S_ISGID) != 0;
40949884Ssheldonh	case FILSTCK:
41049884Ssheldonh		return (s.st_mode & S_ISVTX) != 0;
41149884Ssheldonh	case FILGZ:
41249884Ssheldonh		return s.st_size > (off_t)0;
41349884Ssheldonh	case FILUID:
41449884Ssheldonh		return s.st_uid == geteuid();
41549884Ssheldonh	case FILGID:
41649884Ssheldonh		return s.st_gid == getegid();
41749884Ssheldonh	default:
41849884Ssheldonh		return 1;
4192675Scsgr	}
42049884Ssheldonh}
4212675Scsgr
42249884Ssheldonhstatic enum token
42349884Ssheldonht_lex(s)
42449884Ssheldonh	char *s;
42549884Ssheldonh{
42649884Ssheldonh	struct t_op const *op = ops;
42749884Ssheldonh
42849884Ssheldonh	if (s == 0) {
42949884Ssheldonh		t_wp_op = NULL;
43049884Ssheldonh		return EOI;
43149884Ssheldonh	}
43249884Ssheldonh	while (op->op_text) {
43349884Ssheldonh		if (strcmp(s, op->op_text) == 0) {
43449884Ssheldonh			if ((op->op_type == UNOP && isoperand()) ||
43549884Ssheldonh			    (op->op_num == LPAREN && *(t_wp+1) == 0))
43649884Ssheldonh				break;
43749884Ssheldonh			t_wp_op = op;
43849884Ssheldonh			return op->op_num;
4391556Srgrimes		}
44049884Ssheldonh		op++;
4411556Srgrimes	}
44249884Ssheldonh	t_wp_op = NULL;
44349884Ssheldonh	return OPERAND;
4441556Srgrimes}
4451556Srgrimes
44649884Ssheldonhstatic int
44749884Ssheldonhisoperand()
4481556Srgrimes{
44949884Ssheldonh	struct t_op const *op = ops;
45049884Ssheldonh	char *s;
45149884Ssheldonh	char *t;
4521556Srgrimes
45349884Ssheldonh	if ((s  = *(t_wp+1)) == 0)
45449884Ssheldonh		return 1;
45549884Ssheldonh	if ((t = *(t_wp+2)) == 0)
45649884Ssheldonh		return 0;
45749884Ssheldonh	while (op->op_text) {
45849884Ssheldonh		if (strcmp(s, op->op_text) == 0)
45949884Ssheldonh			return op->op_type == BINOP &&
46049884Ssheldonh			    (t[0] != ')' || t[1] != '\0');
46149884Ssheldonh		op++;
46249884Ssheldonh	}
46349884Ssheldonh	return 0;
4641556Srgrimes}
4651556Srgrimes
46649884Ssheldonh/* atoi with error detection */
46749884Ssheldonhstatic int
46849884Ssheldonhgetn(s)
46949884Ssheldonh	const char *s;
4701556Srgrimes{
47149884Ssheldonh	char *p;
47249884Ssheldonh	long r;
4731556Srgrimes
47449884Ssheldonh	errno = 0;
47549884Ssheldonh	r = strtol(s, &p, 10);
47649884Ssheldonh
47788084Sache	if (s == p)
47888084Sache		error("%s: bad number", s);
47988084Sache
48049884Ssheldonh	if (errno != 0)
48187961Sache		error((errno == EINVAL) ? "%s: bad number" :
48287961Sache					  "%s: out of range", s);
48349884Ssheldonh
48449884Ssheldonh	while (isspace((unsigned char)*p))
48586622Sknu		p++;
48649884Ssheldonh
48749884Ssheldonh	if (*p)
48886622Sknu		error("%s: bad number", s);
48949884Ssheldonh
49049884Ssheldonh	return (int) r;
4911556Srgrimes}
49249884Ssheldonh
49362925Sse/* atoi with error detection and 64 bit range */
49488471Sachestatic long long
49562925Ssegetq(s)
49662925Sse	const char *s;
49762925Sse{
49862925Sse	char *p;
49988471Sache	long long r;
50062925Sse
50162925Sse	errno = 0;
50288471Sache	r = strtoll(s, &p, 10);
50362925Sse
50488084Sache	if (s == p)
50588084Sache		error("%s: bad number", s);
50688084Sache
50762925Sse	if (errno != 0)
50887961Sache		error((errno == EINVAL) ? "%s: bad number" :
50987961Sache					  "%s: out of range", s);
51062925Sse
51162925Sse	while (isspace((unsigned char)*p))
51286622Sknu		p++;
51362925Sse
51462925Sse	if (*p)
51586622Sknu		error("%s: bad number", s);
51662925Sse
51762925Sse	return r;
51862925Sse}
51962925Sse
52049884Ssheldonhstatic int
52162925Sseintcmp (s1, s2)
52262925Sse	const char *s1, *s2;
52362925Sse{
52488471Sache	long long q1, q2;
52562925Sse
52662925Sse
52762925Sse	q1 = getq(s1);
52862925Sse	q2 = getq(s2);
52962925Sse
53062925Sse	if (q1 > q2)
53162925Sse		return 1;
53262925Sse
53362925Sse	if (q1 < q2)
53462925Sse		return -1;
53562925Sse
53662925Sse	return 0;
53762925Sse}
53862925Sse
53962925Ssestatic int
54049884Ssheldonhnewerf (f1, f2)
54149884Ssheldonh	const char *f1, *f2;
54249884Ssheldonh{
54349884Ssheldonh	struct stat b1, b2;
54449884Ssheldonh
54549884Ssheldonh	return (stat (f1, &b1) == 0 &&
54649884Ssheldonh		stat (f2, &b2) == 0 &&
54749884Ssheldonh		b1.st_mtime > b2.st_mtime);
54849884Ssheldonh}
54949884Ssheldonh
55049884Ssheldonhstatic int
55149884Ssheldonholderf (f1, f2)
55249884Ssheldonh	const char *f1, *f2;
55349884Ssheldonh{
55449884Ssheldonh	struct stat b1, b2;
55549884Ssheldonh
55649884Ssheldonh	return (stat (f1, &b1) == 0 &&
55749884Ssheldonh		stat (f2, &b2) == 0 &&
55849884Ssheldonh		b1.st_mtime < b2.st_mtime);
55949884Ssheldonh}
56049884Ssheldonh
56149884Ssheldonhstatic int
56249884Ssheldonhequalf (f1, f2)
56349884Ssheldonh	const char *f1, *f2;
56449884Ssheldonh{
56549884Ssheldonh	struct stat b1, b2;
56649884Ssheldonh
56749884Ssheldonh	return (stat (f1, &b1) == 0 &&
56849884Ssheldonh		stat (f2, &b2) == 0 &&
56949884Ssheldonh		b1.st_dev == b2.st_dev &&
57049884Ssheldonh		b1.st_ino == b2.st_ino);
57149884Ssheldonh}
572