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