xref: /plan9/sys/src/cmd/test.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
1 /*
2  * POSIX standard
3  *	test expression
4  *	[ expression ]
5  *
6  * Plan 9 additions:
7  *	-A file exists and is append-only
8  *	-L file exists and is exclusive-use
9  */
10 
11 #include <u.h>
12 #include <libc.h>
13 #define EQ(a,b)	((tmp=a)==0?0:(strcmp(tmp,b)==0))
14 
15 int	ap;
16 int	ac;
17 char	**av;
18 char	*tmp;
19 
20 void	synbad(char *, char *);
21 int	fsizep(char *);
22 int	isdir(char *);
23 int	isreg(char *);
24 int	isatty(int);
25 int	isint(char *, int *);
26 int	hasmode(char *, ulong);
27 int	tio(char *, int);
28 int	e(void), e1(void), e2(void), e3(void);
29 
30 void
31 main(int argc, char *argv[])
32 {
33 
34 	ac = argc; av = argv; ap = 1;
35 	if(EQ(argv[0],"[")) {
36 		if(!EQ(argv[--ac],"]"))
37 			synbad("] missing","");
38 	}
39 	argv[ac] = 0;
40 	if (ac<=1) exits("usage");
41 	exits(e()?0:"false");
42 }
43 
44 char *
45 nxtarg(int mt)
46 {
47 	if(ap>=ac){
48 		if(mt){
49 			ap++;
50 			return(0);
51 		}
52 		synbad("argument expected","");
53 	}
54 	return(av[ap++]);
55 }
56 
57 int
58 nxtintarg(int *pans)
59 {
60 	if(ap<ac && isint(av[ap], pans)){
61 		ap++;
62 		return 1;
63 	}
64 	return 0;
65 }
66 
67 int
68 e(void) {
69 	int p1;
70 
71 	p1 = e1();
72 	if (EQ(nxtarg(1), "-o")) return(p1 || e());
73 	ap--;
74 	return(p1);
75 }
76 
77 int
78 e1(void) {
79 	int p1;
80 
81 	p1 = e2();
82 	if (EQ(nxtarg(1), "-a")) return (p1 && e1());
83 	ap--;
84 	return(p1);
85 }
86 
87 int
88 e2(void) {
89 	if (EQ(nxtarg(0), "!"))
90 		return(!e2());
91 	ap--;
92 	return(e3());
93 }
94 
95 int
96 e3(void) {
97 	int p1;
98 	char *a;
99 	char *p2;
100 	int int1, int2;
101 
102 	a = nxtarg(0);
103 	if(EQ(a, "(")) {
104 		p1 = e();
105 		if(!EQ(nxtarg(0), ")")) synbad(") expected","");
106 		return(p1);
107 	}
108 
109 	if(EQ(a, "-A"))
110 		return(hasmode(nxtarg(0), DMAPPEND));
111 
112 	if(EQ(a, "-L"))
113 		return(hasmode(nxtarg(0), DMEXCL));
114 
115 	if(EQ(a, "-f"))
116 		return(isreg(nxtarg(0)));
117 
118 	if(EQ(a, "-d"))
119 		return(isdir(nxtarg(0)));
120 
121 	if(EQ(a, "-r"))
122 		return(tio(nxtarg(0), 4));
123 
124 	if(EQ(a, "-w"))
125 		return(tio(nxtarg(0), 2));
126 
127 	if(EQ(a, "-x"))
128 		return(tio(nxtarg(0), 1));
129 
130 	if(EQ(a, "-e"))
131 		return(tio(nxtarg(0), 0));
132 
133 	if(EQ(a, "-c"))
134 		return(0);
135 
136 	if(EQ(a, "-b"))
137 		return(0);
138 
139 	if(EQ(a, "-u"))
140 		return(0);
141 
142 	if(EQ(a, "-g"))
143 		return(0);
144 
145 	if(EQ(a, "-s"))
146 		return(fsizep(nxtarg(0)));
147 
148 	if(EQ(a, "-t"))
149 		if(ap>=ac || !nxtintarg(&int1))
150 			return(isatty(1));
151 		else
152 			return(isatty(int1));
153 
154 	if(EQ(a, "-n"))
155 		return(!EQ(nxtarg(0), ""));
156 	if(EQ(a, "-z"))
157 		return(EQ(nxtarg(0), ""));
158 
159 	p2 = nxtarg(1);
160 	if (p2==0)
161 		return(!EQ(a,""));
162 	if(EQ(p2, "="))
163 		return(EQ(nxtarg(0), a));
164 
165 	if(EQ(p2, "!="))
166 		return(!EQ(nxtarg(0), a));
167 
168 	if(!isint(a, &int1))
169 		return(!EQ(a,""));
170 
171 	if(nxtintarg(&int2)){
172 		if(EQ(p2, "-eq"))
173 			return(int1==int2);
174 		if(EQ(p2, "-ne"))
175 			return(int1!=int2);
176 		if(EQ(p2, "-gt"))
177 			return(int1>int2);
178 		if(EQ(p2, "-lt"))
179 			return(int1<int2);
180 		if(EQ(p2, "-ge"))
181 			return(int1>=int2);
182 		if(EQ(p2, "-le"))
183 			return(int1<=int2);
184 	}
185 
186 	synbad("unknown operator ",p2);
187 	return 0;		/* to shut ken up */
188 }
189 
190 int
191 tio(char *a, int f)
192 {
193 	return access (a, f) >= 0;
194 }
195 
196 /* copy to local memory; clear names for safety */
197 int
198 localstat(char *f, Dir *dir)
199 {
200 	Dir *d;
201 
202 	d = dirstat(f);
203 	if(d == 0)
204 		return(-1);
205 	*dir = *d;
206 	dir->name = 0;
207 	dir->uid = 0;
208 	dir->gid = 0;
209 	dir->muid = 0;
210 	return 0;
211 }
212 
213 /* copy to local memory; clear names for safety */
214 int
215 localfstat(int f, Dir *dir)
216 {
217 	Dir *d;
218 
219 	d = dirfstat(f);
220 	if(d == 0)
221 		return(-1);
222 	*dir = *d;
223 	dir->name = 0;
224 	dir->uid = 0;
225 	dir->gid = 0;
226 	dir->muid = 0;
227 	return 0;
228 }
229 
230 int
231 hasmode(char *f, ulong m)
232 {
233 	Dir dir;
234 
235 	if(localstat(f,&dir)<0)
236 		return(0);
237 	return(dir.mode&m);
238 }
239 
240 int
241 isdir(char *f)
242 {
243 	Dir dir;
244 
245 	if(localstat(f,&dir)<0)
246 		return(0);
247 	return(dir.mode&DMDIR);
248 }
249 
250 int
251 isreg(char *f)
252 {
253 	Dir dir;
254 
255 	if(localstat(f,&dir)<0)
256 		return(0);
257 	return(!(dir.mode&DMDIR));
258 }
259 
260 int
261 isatty(int fd)
262 {
263 	Dir d1, d2;
264 
265 	if(localfstat(fd, &d1) < 0)
266 		return 0;
267 	if(localstat("/dev/cons", &d2) < 0)
268 		return 0;
269 	return d1.type==d2.type && d1.dev==d2.dev && d1.qid.path==d2.qid.path;
270 }
271 
272 int
273 fsizep(char *f)
274 {
275 	Dir dir;
276 
277 	if(localstat(f,&dir)<0)
278 		return(0);
279 	return(dir.length>0);
280 }
281 
282 void
283 synbad(char *s1, char *s2)
284 {
285 	int len;
286 
287 	write(2, "test: ", 6);
288 	if ((len = strlen(s1)) != 0)
289 		write(2, s1, len);
290 	if ((len = strlen(s2)) != 0)
291 		write(2, s2, len);
292 	write(2, "\n", 1);
293 	exits("bad syntax");
294 }
295 
296 int
297 isint(char *s, int *pans)
298 {
299 	char *ep;
300 
301 	*pans = strtol(s, &ep, 0);
302 	return (*ep == 0);
303 }
304