1216Sakaplan /*
2216Sakaplan * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3216Sakaplan * Use is subject to license terms.
4216Sakaplan */
5216Sakaplan
60Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
70Sstevel@tonic-gate /* All Rights Reserved */
80Sstevel@tonic-gate
9*319Sgbrunett /*
10*319Sgbrunett * Copyright (c) 1980 Regents of the University of California.
110Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement
120Sstevel@tonic-gate * specifies the terms and conditions for redistribution.
130Sstevel@tonic-gate */
140Sstevel@tonic-gate
15216Sakaplan #pragma ident "%Z%%M% %I% %E% SMI"
160Sstevel@tonic-gate
170Sstevel@tonic-gate /*
180Sstevel@tonic-gate * test expression
190Sstevel@tonic-gate * [ expression ]
200Sstevel@tonic-gate */
210Sstevel@tonic-gate
220Sstevel@tonic-gate #include <stdio.h>
23*319Sgbrunett #include <stdlib.h>
24*319Sgbrunett #include <unistd.h>
250Sstevel@tonic-gate #include <sys/types.h>
260Sstevel@tonic-gate #include <sys/stat.h>
27*319Sgbrunett #include <string.h>
280Sstevel@tonic-gate
29*319Sgbrunett #define EQ(a, b) ((strcmp(a, b) == 0))
300Sstevel@tonic-gate
31*319Sgbrunett static char *nxtarg(int mt);
32*319Sgbrunett static int exp(void);
33*319Sgbrunett static int e1(void);
34*319Sgbrunett static int e2(void);
35*319Sgbrunett static int e3(void);
36*319Sgbrunett static int tio(char *a, int f);
37*319Sgbrunett static int ftype(char *f, int field);
38*319Sgbrunett static int filtyp(char *f, int field);
39*319Sgbrunett static int fsizep(char *f);
40*319Sgbrunett static void synbad(char *s1, char *s2);
41*319Sgbrunett
42*319Sgbrunett static int ap;
43*319Sgbrunett static int ac;
44*319Sgbrunett static char **av;
450Sstevel@tonic-gate
46216Sakaplan int
main(int argc,char * argv[])47216Sakaplan main(int argc, char *argv[])
480Sstevel@tonic-gate {
490Sstevel@tonic-gate int status;
500Sstevel@tonic-gate
510Sstevel@tonic-gate ac = argc; av = argv; ap = 1;
52*319Sgbrunett if (EQ(argv[0], "[")) {
53*319Sgbrunett if (!EQ(argv[--ac], "]"))
54*319Sgbrunett synbad("] missing", "");
550Sstevel@tonic-gate }
560Sstevel@tonic-gate argv[ac] = 0;
57*319Sgbrunett if (ac <= 1)
58*319Sgbrunett exit(1);
59*319Sgbrunett status = (exp() ? 0 : 1);
60*319Sgbrunett if (nxtarg(1) != 0)
61*319Sgbrunett synbad("too many arguments", "");
62216Sakaplan return (status);
630Sstevel@tonic-gate }
640Sstevel@tonic-gate
65*319Sgbrunett static char *
nxtarg(int mt)66216Sakaplan nxtarg(int mt)
67216Sakaplan {
68*319Sgbrunett if (ap >= ac) {
69*319Sgbrunett if (mt) {
700Sstevel@tonic-gate ap++;
71*319Sgbrunett return (0);
720Sstevel@tonic-gate }
73*319Sgbrunett synbad("argument expected", "");
740Sstevel@tonic-gate }
75*319Sgbrunett return (av[ap++]);
760Sstevel@tonic-gate }
770Sstevel@tonic-gate
78*319Sgbrunett static int
exp(void)79216Sakaplan exp(void)
80216Sakaplan {
810Sstevel@tonic-gate int p1;
820Sstevel@tonic-gate char *p2;
830Sstevel@tonic-gate
840Sstevel@tonic-gate p1 = e1();
850Sstevel@tonic-gate p2 = nxtarg(1);
860Sstevel@tonic-gate if (p2 != 0) {
870Sstevel@tonic-gate if (EQ(p2, "-o"))
88*319Sgbrunett return (p1 | exp());
890Sstevel@tonic-gate if (EQ(p2, "]"))
90*319Sgbrunett synbad("syntax error", "");
910Sstevel@tonic-gate }
920Sstevel@tonic-gate ap--;
93*319Sgbrunett return (p1);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate
96*319Sgbrunett static int
e1(void)97216Sakaplan e1(void)
98216Sakaplan {
990Sstevel@tonic-gate int p1;
1000Sstevel@tonic-gate char *p2;
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate p1 = e2();
1030Sstevel@tonic-gate p2 = nxtarg(1);
1040Sstevel@tonic-gate if ((p2 != 0) && EQ(p2, "-a"))
105*319Sgbrunett return (p1 & e1());
1060Sstevel@tonic-gate ap--;
107*319Sgbrunett return (p1);
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate
110*319Sgbrunett static int
e2(void)111216Sakaplan e2(void)
112216Sakaplan {
1130Sstevel@tonic-gate if (EQ(nxtarg(0), "!"))
114*319Sgbrunett return (!e3());
1150Sstevel@tonic-gate ap--;
116*319Sgbrunett return (e3());
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate
119*319Sgbrunett static int
e3(void)120216Sakaplan e3(void)
121216Sakaplan {
1220Sstevel@tonic-gate int p1;
123216Sakaplan char *a;
1240Sstevel@tonic-gate char *p2;
1250Sstevel@tonic-gate int int1, int2;
1260Sstevel@tonic-gate
127*319Sgbrunett a = nxtarg(0);
128*319Sgbrunett if (EQ(a, "(")) {
1290Sstevel@tonic-gate p1 = exp();
130*319Sgbrunett if (!EQ(nxtarg(0), ")")) synbad(") expected", "");
131*319Sgbrunett return (p1);
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate p2 = nxtarg(1);
1340Sstevel@tonic-gate ap--;
1350Sstevel@tonic-gate if ((p2 == 0) || (!EQ(p2, "=") && !EQ(p2, "!="))) {
136*319Sgbrunett if (EQ(a, "-r"))
137*319Sgbrunett return (tio(nxtarg(0), 4));
1380Sstevel@tonic-gate
139*319Sgbrunett if (EQ(a, "-w"))
140*319Sgbrunett return (tio(nxtarg(0), 2));
1410Sstevel@tonic-gate
142*319Sgbrunett if (EQ(a, "-x"))
143*319Sgbrunett return (tio(nxtarg(0), 1));
1440Sstevel@tonic-gate
145*319Sgbrunett if (EQ(a, "-d"))
146*319Sgbrunett return (filtyp(nxtarg(0), S_IFDIR));
1470Sstevel@tonic-gate
148*319Sgbrunett if (EQ(a, "-c"))
149*319Sgbrunett return (filtyp(nxtarg(0), S_IFCHR));
1500Sstevel@tonic-gate
151*319Sgbrunett if (EQ(a, "-b"))
152*319Sgbrunett return (filtyp(nxtarg(0), S_IFBLK));
1530Sstevel@tonic-gate
154*319Sgbrunett if (EQ(a, "-f")) {
1550Sstevel@tonic-gate struct stat statb;
1560Sstevel@tonic-gate
157*319Sgbrunett return (stat(nxtarg(0), &statb) >= 0 &&
1580Sstevel@tonic-gate (statb.st_mode & S_IFMT) != S_IFDIR);
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate
161*319Sgbrunett if (EQ(a, "-h"))
162*319Sgbrunett return (filtyp(nxtarg(0), S_IFLNK));
1630Sstevel@tonic-gate
164*319Sgbrunett if (EQ(a, "-u"))
165*319Sgbrunett return (ftype(nxtarg(0), S_ISUID));
1660Sstevel@tonic-gate
167*319Sgbrunett if (EQ(a, "-g"))
168*319Sgbrunett return (ftype(nxtarg(0), S_ISGID));
1690Sstevel@tonic-gate
170*319Sgbrunett if (EQ(a, "-k"))
171*319Sgbrunett return (ftype(nxtarg(0), S_ISVTX));
1720Sstevel@tonic-gate
173*319Sgbrunett if (EQ(a, "-p"))
1740Sstevel@tonic-gate #ifdef S_IFIFO
175*319Sgbrunett return (filtyp(nxtarg(0), S_IFIFO));
1760Sstevel@tonic-gate #else
177*319Sgbrunett return (nxtarg(0), 0);
1780Sstevel@tonic-gate #endif
1790Sstevel@tonic-gate
180*319Sgbrunett if (EQ(a, "-s"))
181*319Sgbrunett return (fsizep(nxtarg(0)));
1820Sstevel@tonic-gate
183*319Sgbrunett if (EQ(a, "-t"))
184*319Sgbrunett if (ap >= ac)
185*319Sgbrunett return (isatty(1));
1860Sstevel@tonic-gate else if (EQ((a = nxtarg(0)), "-a") || EQ(a, "-o")) {
1870Sstevel@tonic-gate ap--;
188*319Sgbrunett return (isatty(1));
1890Sstevel@tonic-gate } else
190*319Sgbrunett return (isatty(atoi(a)));
1910Sstevel@tonic-gate
192*319Sgbrunett if (EQ(a, "-n"))
193*319Sgbrunett return (!EQ(nxtarg(0), ""));
194*319Sgbrunett if (EQ(a, "-z"))
195*319Sgbrunett return (EQ(nxtarg(0), ""));
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate p2 = nxtarg(1);
199*319Sgbrunett if (p2 == 0)
200*319Sgbrunett return (!EQ(a, ""));
2010Sstevel@tonic-gate if (EQ(p2, "-a") || EQ(p2, "-o")) {
2020Sstevel@tonic-gate ap--;
203*319Sgbrunett return (!EQ(a, ""));
2040Sstevel@tonic-gate }
205*319Sgbrunett if (EQ(p2, "="))
206*319Sgbrunett return (EQ(nxtarg(0), a));
2070Sstevel@tonic-gate
208*319Sgbrunett if (EQ(p2, "!="))
209*319Sgbrunett return (!EQ(nxtarg(0), a));
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate int1 = atoi(a);
2120Sstevel@tonic-gate int2 = atoi(nxtarg(0));
213*319Sgbrunett if (EQ(p2, "-eq"))
214*319Sgbrunett return (int1 == int2);
215*319Sgbrunett if (EQ(p2, "-ne"))
216*319Sgbrunett return (int1 != int2);
217*319Sgbrunett if (EQ(p2, "-gt"))
218*319Sgbrunett return (int1 > int2);
219*319Sgbrunett if (EQ(p2, "-lt"))
220*319Sgbrunett return (int1 < int2);
221*319Sgbrunett if (EQ(p2, "-ge"))
222*319Sgbrunett return (int1 >= int2);
223*319Sgbrunett if (EQ(p2, "-le"))
224*319Sgbrunett return (int1 <= int2);
2250Sstevel@tonic-gate
226*319Sgbrunett synbad("unknown operator ", p2);
2270Sstevel@tonic-gate /* NOTREACHED */
228216Sakaplan return (0);
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate
231*319Sgbrunett static int
tio(char * a,int f)232216Sakaplan tio(char *a, int f)
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate if (access(a, f) == 0)
235*319Sgbrunett return (1);
2360Sstevel@tonic-gate else
237*319Sgbrunett return (0);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate
240*319Sgbrunett static int
ftype(char * f,int field)241216Sakaplan ftype(char *f, int field)
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate struct stat statb;
2440Sstevel@tonic-gate
245*319Sgbrunett if (stat(f, &statb) < 0)
246*319Sgbrunett return (0);
247*319Sgbrunett if ((statb.st_mode & field) == field)
248*319Sgbrunett return (1);
249*319Sgbrunett return (0);
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate
252*319Sgbrunett static int
filtyp(char * f,int field)253216Sakaplan filtyp(char *f, int field)
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate struct stat statb;
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate if (field == S_IFLNK) {
258*319Sgbrunett if (lstat(f, &statb) < 0)
259*319Sgbrunett return (0);
2600Sstevel@tonic-gate } else {
261*319Sgbrunett if (stat(f, &statb) < 0)
262*319Sgbrunett return (0);
2630Sstevel@tonic-gate }
264*319Sgbrunett if ((statb.st_mode & S_IFMT) == field)
265*319Sgbrunett return (1);
2660Sstevel@tonic-gate else
267*319Sgbrunett return (0);
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate
270*319Sgbrunett static int
fsizep(char * f)271216Sakaplan fsizep(char *f)
2720Sstevel@tonic-gate {
2730Sstevel@tonic-gate struct stat statb;
2740Sstevel@tonic-gate
275*319Sgbrunett if (stat(f, &statb) < 0)
276*319Sgbrunett return (0);
277*319Sgbrunett return (statb.st_size > 0);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate
280*319Sgbrunett static void
synbad(char * s1,char * s2)281216Sakaplan synbad(char *s1, char *s2)
2820Sstevel@tonic-gate {
2830Sstevel@tonic-gate (void) write(2, "test: ", 6);
2840Sstevel@tonic-gate (void) write(2, s1, strlen(s1));
2850Sstevel@tonic-gate (void) write(2, s2, strlen(s2));
2860Sstevel@tonic-gate (void) write(2, "\n", 1);
2870Sstevel@tonic-gate exit(255);
2880Sstevel@tonic-gate }
289