xref: /plan9-contrib/sys/src/cmd/test.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
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  *	-T file exists and is temporary
10  */
11 
12 #include <u.h>
13 #include <libc.h>
14 #define EQ(a,b)	((tmp=a)==0?0:(strcmp(tmp,b)==0))
15 
16 int	ap;
17 int	ac;
18 char	**av;
19 char	*tmp;
20 
21 void	synbad(char *, char *);
22 int	fsizep(char *);
23 int	isdir(char *);
24 int	isreg(char *);
25 int	isatty(int);
26 int	isint(char *, int *);
27 int	isolder(char *, char *);
28 int	isolderthan(char *, char *);
29 int	isnewerthan(char *, char *);
30 int	hasmode(char *, ulong);
31 int	tio(char *, int);
32 int	e(void), e1(void), e2(void), e3(void);
33 
34 void
35 main(int argc, char *argv[])
36 {
37 
38 	ac = argc; av = argv; ap = 1;
39 	if(EQ(argv[0],"[")) {
40 		if(!EQ(argv[--ac],"]"))
41 			synbad("] missing","");
42 	}
43 	argv[ac] = 0;
44 	if (ac<=1) exits("usage");
45 	exits(e()?0:"false");
46 }
47 
48 char *
49 nxtarg(int mt)
50 {
51 	if(ap>=ac){
52 		if(mt){
53 			ap++;
54 			return(0);
55 		}
56 		synbad("argument expected","");
57 	}
58 	return(av[ap++]);
59 }
60 
61 int
62 nxtintarg(int *pans)
63 {
64 	if(ap<ac && isint(av[ap], pans)){
65 		ap++;
66 		return 1;
67 	}
68 	return 0;
69 }
70 
71 int
72 e(void) {
73 	int p1;
74 
75 	p1 = e1();
76 	if (EQ(nxtarg(1), "-o")) return(p1 || e());
77 	ap--;
78 	return(p1);
79 }
80 
81 int
82 e1(void) {
83 	int p1;
84 
85 	p1 = e2();
86 	if (EQ(nxtarg(1), "-a")) return (p1 && e1());
87 	ap--;
88 	return(p1);
89 }
90 
91 int
92 e2(void) {
93 	if (EQ(nxtarg(0), "!"))
94 		return(!e2());
95 	ap--;
96 	return(e3());
97 }
98 
99 int
100 e3(void) {
101 	int p1;
102 	char *a;
103 	char *p2;
104 	int int1, int2;
105 
106 	a = nxtarg(0);
107 	if(EQ(a, "(")) {
108 		p1 = e();
109 		if(!EQ(nxtarg(0), ")")) synbad(") expected","");
110 		return(p1);
111 	}
112 
113 	if(EQ(a, "-A"))
114 		return(hasmode(nxtarg(0), DMAPPEND));
115 
116 	if(EQ(a, "-L"))
117 		return(hasmode(nxtarg(0), DMEXCL));
118 
119 	if(EQ(a, "-T"))
120 		return(hasmode(nxtarg(0), DMTMP));
121 
122 	if(EQ(a, "-f"))
123 		return(isreg(nxtarg(0)));
124 
125 	if(EQ(a, "-d"))
126 		return(isdir(nxtarg(0)));
127 
128 	if(EQ(a, "-r"))
129 		return(tio(nxtarg(0), 4));
130 
131 	if(EQ(a, "-w"))
132 		return(tio(nxtarg(0), 2));
133 
134 	if(EQ(a, "-x"))
135 		return(tio(nxtarg(0), 1));
136 
137 	if(EQ(a, "-e"))
138 		return(tio(nxtarg(0), 0));
139 
140 	if(EQ(a, "-c"))
141 		return(0);
142 
143 	if(EQ(a, "-b"))
144 		return(0);
145 
146 	if(EQ(a, "-u"))
147 		return(0);
148 
149 	if(EQ(a, "-g"))
150 		return(0);
151 
152 	if(EQ(a, "-s"))
153 		return(fsizep(nxtarg(0)));
154 
155 	if(EQ(a, "-t"))
156 		if(ap>=ac || !nxtintarg(&int1))
157 			return(isatty(1));
158 		else
159 			return(isatty(int1));
160 
161 	if(EQ(a, "-n"))
162 		return(!EQ(nxtarg(0), ""));
163 	if(EQ(a, "-z"))
164 		return(EQ(nxtarg(0), ""));
165 
166 	p2 = nxtarg(1);
167 	if (p2==0)
168 		return(!EQ(a,""));
169 	if(EQ(p2, "="))
170 		return(EQ(nxtarg(0), a));
171 
172 	if(EQ(p2, "!="))
173 		return(!EQ(nxtarg(0), a));
174 
175 	if(EQ(p2, "-older"))
176 		return(isolder(nxtarg(0), a));
177 
178 	if(EQ(p2, "-ot"))
179 		return(isolderthan(nxtarg(0), a));
180 
181 	if(EQ(p2, "-nt"))
182 		return(isnewerthan(nxtarg(0), a));
183 
184 	if(!isint(a, &int1))
185 		return(!EQ(a,""));
186 
187 	if(nxtintarg(&int2)){
188 		if(EQ(p2, "-eq"))
189 			return(int1==int2);
190 		if(EQ(p2, "-ne"))
191 			return(int1!=int2);
192 		if(EQ(p2, "-gt"))
193 			return(int1>int2);
194 		if(EQ(p2, "-lt"))
195 			return(int1<int2);
196 		if(EQ(p2, "-ge"))
197 			return(int1>=int2);
198 		if(EQ(p2, "-le"))
199 			return(int1<=int2);
200 	}
201 
202 	synbad("unknown operator ",p2);
203 	return 0;		/* to shut ken up */
204 }
205 
206 int
207 tio(char *a, int f)
208 {
209 	return access (a, f) >= 0;
210 }
211 
212 /* copy to local memory; clear names for safety */
213 int
214 localstat(char *f, Dir *dir)
215 {
216 	Dir *d;
217 
218 	d = dirstat(f);
219 	if(d == 0)
220 		return(-1);
221 	*dir = *d;
222 	dir->name = 0;
223 	dir->uid = 0;
224 	dir->gid = 0;
225 	dir->muid = 0;
226 	return 0;
227 }
228 
229 /* copy to local memory; clear names for safety */
230 int
231 localfstat(int f, Dir *dir)
232 {
233 	Dir *d;
234 
235 	d = dirfstat(f);
236 	if(d == 0)
237 		return(-1);
238 	*dir = *d;
239 	dir->name = 0;
240 	dir->uid = 0;
241 	dir->gid = 0;
242 	dir->muid = 0;
243 	return 0;
244 }
245 
246 int
247 hasmode(char *f, ulong m)
248 {
249 	Dir dir;
250 
251 	if(localstat(f,&dir)<0)
252 		return(0);
253 	return(dir.mode&m);
254 }
255 
256 int
257 isdir(char *f)
258 {
259 	Dir dir;
260 
261 	if(localstat(f,&dir)<0)
262 		return(0);
263 	return(dir.mode&DMDIR);
264 }
265 
266 int
267 isreg(char *f)
268 {
269 	Dir dir;
270 
271 	if(localstat(f,&dir)<0)
272 		return(0);
273 	return(!(dir.mode&DMDIR));
274 }
275 
276 int
277 isatty(int fd)
278 {
279 	Dir d1, d2;
280 
281 	if(localfstat(fd, &d1) < 0)
282 		return 0;
283 	if(localstat("/dev/cons", &d2) < 0)
284 		return 0;
285 	return d1.type==d2.type && d1.dev==d2.dev && d1.qid.path==d2.qid.path;
286 }
287 
288 int
289 fsizep(char *f)
290 {
291 	Dir dir;
292 
293 	if(localstat(f,&dir)<0)
294 		return(0);
295 	return(dir.length>0);
296 }
297 
298 void
299 synbad(char *s1, char *s2)
300 {
301 	int len;
302 
303 	write(2, "test: ", 6);
304 	if ((len = strlen(s1)) != 0)
305 		write(2, s1, len);
306 	if ((len = strlen(s2)) != 0)
307 		write(2, s2, len);
308 	write(2, "\n", 1);
309 	exits("bad syntax");
310 }
311 
312 int
313 isint(char *s, int *pans)
314 {
315 	char *ep;
316 
317 	*pans = strtol(s, &ep, 0);
318 	return (*ep == 0);
319 }
320 
321 int
322 isolder(char *pin, char *f)
323 {
324 	char *p = pin;
325 	ulong n, m;
326 	Dir dir;
327 
328 	if(localstat(f,&dir)<0)
329 		return(0);
330 
331 	/* parse time */
332 	n = 0;
333 	while(*p){
334 		m = strtoul(p, &p, 0);
335 		switch(*p){
336 		case 0:
337 			n = m;
338 			break;
339 		case 'y':
340 			m *= 12;
341 			/* fall through */
342 		case 'M':
343 			m *= 30;
344 			/* fall through */
345 		case 'd':
346 			m *= 24;
347 			/* fall through */
348 		case 'h':
349 			m *= 60;
350 			/* fall through */
351 		case 'm':
352 			m *= 60;
353 			/* fall through */
354 		case 's':
355 			n += m;
356 			p++;
357 			break;
358 		default:
359 			synbad("bad time syntax, ", pin);
360 		}
361 	}
362 
363 	return(dir.mtime+n < time(0));
364 }
365 
366 int
367 isolderthan(char *a, char *b)
368 {
369 	Dir ad, bd;
370 
371 	if(localstat(a, &ad)<0)
372 		return(0);
373 	if(localstat(b, &bd)<0)
374 		return(0);
375 	return ad.mtime > bd.mtime;
376 }
377 
378 int
379 isnewerthan(char *a, char *b)
380 {
381 	Dir ad, bd;
382 
383 	if(localstat(a, &ad)<0)
384 		return(0);
385 	if(localstat(b, &bd)<0)
386 		return(0);
387 	return ad.mtime < bd.mtime;
388 }
389