13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier * POSIX standard
33e12c5d1SDavid du Colombier * test expression
43e12c5d1SDavid du Colombier * [ expression ]
59a747e4fSDavid du Colombier *
69a747e4fSDavid du Colombier * Plan 9 additions:
79a747e4fSDavid du Colombier * -A file exists and is append-only
89a747e4fSDavid du Colombier * -L file exists and is exclusive-use
9b7327ca2SDavid du Colombier * -T file exists and is temporary
103e12c5d1SDavid du Colombier */
113e12c5d1SDavid du Colombier
123e12c5d1SDavid du Colombier #include <u.h>
133e12c5d1SDavid du Colombier #include <libc.h>
144cffb70cSDavid du Colombier
153e12c5d1SDavid du Colombier #define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0))
163e12c5d1SDavid du Colombier
173e12c5d1SDavid du Colombier int ap;
183e12c5d1SDavid du Colombier int ac;
193e12c5d1SDavid du Colombier char **av;
203e12c5d1SDavid du Colombier char *tmp;
213e12c5d1SDavid du Colombier
223e12c5d1SDavid du Colombier void synbad(char *, char *);
233e12c5d1SDavid du Colombier int fsizep(char *);
243e12c5d1SDavid du Colombier int isdir(char *);
253e12c5d1SDavid du Colombier int isreg(char *);
263e12c5d1SDavid du Colombier int isatty(int);
273e12c5d1SDavid du Colombier int isint(char *, int *);
28cd1a0026SDavid du Colombier int isolder(char *, char *);
2980b7488dSDavid du Colombier int isolderthan(char *, char *);
3080b7488dSDavid du Colombier int isnewerthan(char *, char *);
319a747e4fSDavid du Colombier int hasmode(char *, ulong);
323e12c5d1SDavid du Colombier int tio(char *, int);
333e12c5d1SDavid du Colombier int e(void), e1(void), e2(void), e3(void);
341066d6deSDavid du Colombier char *nxtarg(int);
353e12c5d1SDavid du Colombier
363e12c5d1SDavid du Colombier void
main(int argc,char * argv[])373e12c5d1SDavid du Colombier main(int argc, char *argv[])
383e12c5d1SDavid du Colombier {
391066d6deSDavid du Colombier int r;
401066d6deSDavid du Colombier char *c;
413e12c5d1SDavid du Colombier
423e12c5d1SDavid du Colombier ac = argc; av = argv; ap = 1;
433e12c5d1SDavid du Colombier if(EQ(argv[0],"[")) {
443e12c5d1SDavid du Colombier if(!EQ(argv[--ac],"]"))
453e12c5d1SDavid du Colombier synbad("] missing","");
463e12c5d1SDavid du Colombier }
473e12c5d1SDavid du Colombier argv[ac] = 0;
484cffb70cSDavid du Colombier if (ac<=1)
494cffb70cSDavid du Colombier exits("usage");
501066d6deSDavid du Colombier r = e();
514cffb70cSDavid du Colombier /*
524cffb70cSDavid du Colombier * nice idea but short-circuit -o and -a operators may have
534cffb70cSDavid du Colombier * not consumed their right-hand sides.
544cffb70cSDavid du Colombier */
554cffb70cSDavid du Colombier if(0 && (c = nxtarg(1)) != nil)
561066d6deSDavid du Colombier synbad("unexpected operator/operand: ", c);
571066d6deSDavid du Colombier exits(r?0:"false");
583e12c5d1SDavid du Colombier }
593e12c5d1SDavid du Colombier
603e12c5d1SDavid du Colombier char *
nxtarg(int mt)613e12c5d1SDavid du Colombier nxtarg(int mt)
623e12c5d1SDavid du Colombier {
633e12c5d1SDavid du Colombier if(ap>=ac){
643e12c5d1SDavid du Colombier if(mt){
653e12c5d1SDavid du Colombier ap++;
663e12c5d1SDavid du Colombier return(0);
673e12c5d1SDavid du Colombier }
683e12c5d1SDavid du Colombier synbad("argument expected","");
693e12c5d1SDavid du Colombier }
703e12c5d1SDavid du Colombier return(av[ap++]);
713e12c5d1SDavid du Colombier }
723e12c5d1SDavid du Colombier
733e12c5d1SDavid du Colombier int
nxtintarg(int * pans)743e12c5d1SDavid du Colombier nxtintarg(int *pans)
753e12c5d1SDavid du Colombier {
763e12c5d1SDavid du Colombier if(ap<ac && isint(av[ap], pans)){
773e12c5d1SDavid du Colombier ap++;
783e12c5d1SDavid du Colombier return 1;
793e12c5d1SDavid du Colombier }
803e12c5d1SDavid du Colombier return 0;
813e12c5d1SDavid du Colombier }
823e12c5d1SDavid du Colombier
833e12c5d1SDavid du Colombier int
e(void)844cffb70cSDavid du Colombier e(void)
854cffb70cSDavid du Colombier {
863e12c5d1SDavid du Colombier int p1;
873e12c5d1SDavid du Colombier
883e12c5d1SDavid du Colombier p1 = e1();
894cffb70cSDavid du Colombier if (EQ(nxtarg(1), "-o"))
904cffb70cSDavid du Colombier return(p1 || e());
913e12c5d1SDavid du Colombier ap--;
923e12c5d1SDavid du Colombier return(p1);
933e12c5d1SDavid du Colombier }
943e12c5d1SDavid du Colombier
953e12c5d1SDavid du Colombier int
e1(void)964cffb70cSDavid du Colombier e1(void)
974cffb70cSDavid du Colombier {
983e12c5d1SDavid du Colombier int p1;
993e12c5d1SDavid du Colombier
1003e12c5d1SDavid du Colombier p1 = e2();
1014cffb70cSDavid du Colombier if (EQ(nxtarg(1), "-a"))
1024cffb70cSDavid du Colombier return (p1 && e1());
1033e12c5d1SDavid du Colombier ap--;
1043e12c5d1SDavid du Colombier return(p1);
1053e12c5d1SDavid du Colombier }
1063e12c5d1SDavid du Colombier
1073e12c5d1SDavid du Colombier int
e2(void)1084cffb70cSDavid du Colombier e2(void)
1094cffb70cSDavid du Colombier {
1103e12c5d1SDavid du Colombier if (EQ(nxtarg(0), "!"))
1117dd7cddfSDavid du Colombier return(!e2());
1123e12c5d1SDavid du Colombier ap--;
1133e12c5d1SDavid du Colombier return(e3());
1143e12c5d1SDavid du Colombier }
1153e12c5d1SDavid du Colombier
1163e12c5d1SDavid du Colombier int
e3(void)1174cffb70cSDavid du Colombier e3(void)
1184cffb70cSDavid du Colombier {
1194cffb70cSDavid du Colombier int p1, int1, int2;
1204cffb70cSDavid du Colombier char *a, *p2;
1213e12c5d1SDavid du Colombier
1223e12c5d1SDavid du Colombier a = nxtarg(0);
1233e12c5d1SDavid du Colombier if(EQ(a, "(")) {
1243e12c5d1SDavid du Colombier p1 = e();
1254cffb70cSDavid du Colombier if(!EQ(nxtarg(0), ")"))
1264cffb70cSDavid du Colombier synbad(") expected","");
1273e12c5d1SDavid du Colombier return(p1);
1283e12c5d1SDavid du Colombier }
1293e12c5d1SDavid du Colombier
1309a747e4fSDavid du Colombier if(EQ(a, "-A"))
1319a747e4fSDavid du Colombier return(hasmode(nxtarg(0), DMAPPEND));
1329a747e4fSDavid du Colombier
1339a747e4fSDavid du Colombier if(EQ(a, "-L"))
1349a747e4fSDavid du Colombier return(hasmode(nxtarg(0), DMEXCL));
1359a747e4fSDavid du Colombier
136b7327ca2SDavid du Colombier if(EQ(a, "-T"))
137b7327ca2SDavid du Colombier return(hasmode(nxtarg(0), DMTMP));
138b7327ca2SDavid du Colombier
1393e12c5d1SDavid du Colombier if(EQ(a, "-f"))
1403e12c5d1SDavid du Colombier return(isreg(nxtarg(0)));
1413e12c5d1SDavid du Colombier
1423e12c5d1SDavid du Colombier if(EQ(a, "-d"))
1433e12c5d1SDavid du Colombier return(isdir(nxtarg(0)));
1443e12c5d1SDavid du Colombier
1453e12c5d1SDavid du Colombier if(EQ(a, "-r"))
1463e12c5d1SDavid du Colombier return(tio(nxtarg(0), 4));
1473e12c5d1SDavid du Colombier
1483e12c5d1SDavid du Colombier if(EQ(a, "-w"))
1493e12c5d1SDavid du Colombier return(tio(nxtarg(0), 2));
1503e12c5d1SDavid du Colombier
1513e12c5d1SDavid du Colombier if(EQ(a, "-x"))
1523e12c5d1SDavid du Colombier return(tio(nxtarg(0), 1));
1533e12c5d1SDavid du Colombier
1543e12c5d1SDavid du Colombier if(EQ(a, "-e"))
1553e12c5d1SDavid du Colombier return(tio(nxtarg(0), 0));
1563e12c5d1SDavid du Colombier
1573e12c5d1SDavid du Colombier if(EQ(a, "-c"))
1583e12c5d1SDavid du Colombier return(0);
1593e12c5d1SDavid du Colombier
1603e12c5d1SDavid du Colombier if(EQ(a, "-b"))
1613e12c5d1SDavid du Colombier return(0);
1623e12c5d1SDavid du Colombier
1633e12c5d1SDavid du Colombier if(EQ(a, "-u"))
1643e12c5d1SDavid du Colombier return(0);
1653e12c5d1SDavid du Colombier
1663e12c5d1SDavid du Colombier if(EQ(a, "-g"))
1673e12c5d1SDavid du Colombier return(0);
1683e12c5d1SDavid du Colombier
1693e12c5d1SDavid du Colombier if(EQ(a, "-s"))
1703e12c5d1SDavid du Colombier return(fsizep(nxtarg(0)));
1713e12c5d1SDavid du Colombier
1723e12c5d1SDavid du Colombier if(EQ(a, "-t"))
1731066d6deSDavid du Colombier if(ap>=ac)
1743e12c5d1SDavid du Colombier return(isatty(1));
1751066d6deSDavid du Colombier else if(nxtintarg(&int1))
1763e12c5d1SDavid du Colombier return(isatty(int1));
1771066d6deSDavid du Colombier else
1781066d6deSDavid du Colombier synbad("not a valid file descriptor number ", "");
1793e12c5d1SDavid du Colombier
1803e12c5d1SDavid du Colombier if(EQ(a, "-n"))
1813e12c5d1SDavid du Colombier return(!EQ(nxtarg(0), ""));
1823e12c5d1SDavid du Colombier if(EQ(a, "-z"))
1833e12c5d1SDavid du Colombier return(EQ(nxtarg(0), ""));
1843e12c5d1SDavid du Colombier
1853e12c5d1SDavid du Colombier p2 = nxtarg(1);
1863e12c5d1SDavid du Colombier if (p2==0)
1873e12c5d1SDavid du Colombier return(!EQ(a,""));
1883e12c5d1SDavid du Colombier if(EQ(p2, "="))
1893e12c5d1SDavid du Colombier return(EQ(nxtarg(0), a));
1903e12c5d1SDavid du Colombier
1913e12c5d1SDavid du Colombier if(EQ(p2, "!="))
1923e12c5d1SDavid du Colombier return(!EQ(nxtarg(0), a));
1933e12c5d1SDavid du Colombier
194cd1a0026SDavid du Colombier if(EQ(p2, "-older"))
195cd1a0026SDavid du Colombier return(isolder(nxtarg(0), a));
196cd1a0026SDavid du Colombier
19780b7488dSDavid du Colombier if(EQ(p2, "-ot"))
19880b7488dSDavid du Colombier return(isolderthan(nxtarg(0), a));
19980b7488dSDavid du Colombier
20080b7488dSDavid du Colombier if(EQ(p2, "-nt"))
20180b7488dSDavid du Colombier return(isnewerthan(nxtarg(0), a));
20280b7488dSDavid du Colombier
2033e12c5d1SDavid du Colombier if(!isint(a, &int1))
2041066d6deSDavid du Colombier synbad("unexpected operator/operand: ", p2);
2053e12c5d1SDavid du Colombier
2063e12c5d1SDavid du Colombier if(nxtintarg(&int2)){
2073e12c5d1SDavid du Colombier if(EQ(p2, "-eq"))
2083e12c5d1SDavid du Colombier return(int1==int2);
2093e12c5d1SDavid du Colombier if(EQ(p2, "-ne"))
2103e12c5d1SDavid du Colombier return(int1!=int2);
2113e12c5d1SDavid du Colombier if(EQ(p2, "-gt"))
2123e12c5d1SDavid du Colombier return(int1>int2);
2133e12c5d1SDavid du Colombier if(EQ(p2, "-lt"))
2143e12c5d1SDavid du Colombier return(int1<int2);
2153e12c5d1SDavid du Colombier if(EQ(p2, "-ge"))
2163e12c5d1SDavid du Colombier return(int1>=int2);
2173e12c5d1SDavid du Colombier if(EQ(p2, "-le"))
2183e12c5d1SDavid du Colombier return(int1<=int2);
2193e12c5d1SDavid du Colombier }
2203e12c5d1SDavid du Colombier
2213e12c5d1SDavid du Colombier synbad("unknown operator ",p2);
2223e12c5d1SDavid du Colombier return 0; /* to shut ken up */
2233e12c5d1SDavid du Colombier }
2243e12c5d1SDavid du Colombier
2253e12c5d1SDavid du Colombier int
tio(char * a,int f)2263e12c5d1SDavid du Colombier tio(char *a, int f)
2273e12c5d1SDavid du Colombier {
2283e12c5d1SDavid du Colombier return access (a, f) >= 0;
2293e12c5d1SDavid du Colombier }
2303e12c5d1SDavid du Colombier
231055c7668SDavid du Colombier /*
232055c7668SDavid du Colombier * note that the name strings pointed to by Dir members are
233055c7668SDavid du Colombier * allocated with the Dir itself (by the same call to malloc),
234055c7668SDavid du Colombier * but are not included in sizeof(Dir), so copying a Dir won't
235055c7668SDavid du Colombier * copy the strings it points to.
236055c7668SDavid du Colombier */
2379a747e4fSDavid du Colombier
2389a747e4fSDavid du Colombier int
hasmode(char * f,ulong m)2399a747e4fSDavid du Colombier hasmode(char *f, ulong m)
2409a747e4fSDavid du Colombier {
241055c7668SDavid du Colombier int r;
242055c7668SDavid du Colombier Dir *dir;
2439a747e4fSDavid du Colombier
244055c7668SDavid du Colombier dir = dirstat(f);
245055c7668SDavid du Colombier if (dir == nil)
246055c7668SDavid du Colombier return 0;
247055c7668SDavid du Colombier r = (dir->mode & m) != 0;
248055c7668SDavid du Colombier free(dir);
249055c7668SDavid du Colombier return r;
2509a747e4fSDavid du Colombier }
2519a747e4fSDavid du Colombier
2523e12c5d1SDavid du Colombier int
isdir(char * f)2533e12c5d1SDavid du Colombier isdir(char *f)
2543e12c5d1SDavid du Colombier {
255055c7668SDavid du Colombier return hasmode(f, DMDIR);
2563e12c5d1SDavid du Colombier }
2573e12c5d1SDavid du Colombier
2583e12c5d1SDavid du Colombier int
isreg(char * f)2593e12c5d1SDavid du Colombier isreg(char *f)
2603e12c5d1SDavid du Colombier {
261014ad43fSDavid du Colombier int r;
262014ad43fSDavid du Colombier Dir *dir;
263014ad43fSDavid du Colombier
264014ad43fSDavid du Colombier dir = dirstat(f);
265014ad43fSDavid du Colombier if (dir == nil)
266014ad43fSDavid du Colombier return 0;
267014ad43fSDavid du Colombier r = (dir->mode & DMDIR) == 0;
268014ad43fSDavid du Colombier free(dir);
269014ad43fSDavid du Colombier return r;
2703e12c5d1SDavid du Colombier }
2713e12c5d1SDavid du Colombier
2723e12c5d1SDavid du Colombier int
isatty(int fd)2733e12c5d1SDavid du Colombier isatty(int fd)
2743e12c5d1SDavid du Colombier {
275055c7668SDavid du Colombier int r;
276055c7668SDavid du Colombier Dir *d1, *d2;
2773e12c5d1SDavid du Colombier
278055c7668SDavid du Colombier d1 = dirfstat(fd);
279055c7668SDavid du Colombier d2 = dirstat("/dev/cons");
280055c7668SDavid du Colombier if (d1 == nil || d2 == nil)
281055c7668SDavid du Colombier r = 0;
282055c7668SDavid du Colombier else
283055c7668SDavid du Colombier r = d1->type == d2->type && d1->dev == d2->dev &&
284055c7668SDavid du Colombier d1->qid.path == d2->qid.path;
285055c7668SDavid du Colombier free(d1);
286055c7668SDavid du Colombier free(d2);
287055c7668SDavid du Colombier return r;
2883e12c5d1SDavid du Colombier }
2893e12c5d1SDavid du Colombier
2903e12c5d1SDavid du Colombier int
fsizep(char * f)2913e12c5d1SDavid du Colombier fsizep(char *f)
2923e12c5d1SDavid du Colombier {
293055c7668SDavid du Colombier int r;
294055c7668SDavid du Colombier Dir *dir;
2959a747e4fSDavid du Colombier
296055c7668SDavid du Colombier dir = dirstat(f);
297055c7668SDavid du Colombier if (dir == nil)
298055c7668SDavid du Colombier return 0;
299055c7668SDavid du Colombier r = dir->length > 0;
300055c7668SDavid du Colombier free(dir);
301055c7668SDavid du Colombier return r;
3023e12c5d1SDavid du Colombier }
3033e12c5d1SDavid du Colombier
3043e12c5d1SDavid du Colombier void
synbad(char * s1,char * s2)3053e12c5d1SDavid du Colombier synbad(char *s1, char *s2)
3063e12c5d1SDavid du Colombier {
3073e12c5d1SDavid du Colombier int len;
3083e12c5d1SDavid du Colombier
3093e12c5d1SDavid du Colombier write(2, "test: ", 6);
3103e12c5d1SDavid du Colombier if ((len = strlen(s1)) != 0)
3113e12c5d1SDavid du Colombier write(2, s1, len);
3123e12c5d1SDavid du Colombier if ((len = strlen(s2)) != 0)
3133e12c5d1SDavid du Colombier write(2, s2, len);
3143e12c5d1SDavid du Colombier write(2, "\n", 1);
3153e12c5d1SDavid du Colombier exits("bad syntax");
3163e12c5d1SDavid du Colombier }
3173e12c5d1SDavid du Colombier
3183e12c5d1SDavid du Colombier int
isint(char * s,int * pans)3193e12c5d1SDavid du Colombier isint(char *s, int *pans)
3203e12c5d1SDavid du Colombier {
3213e12c5d1SDavid du Colombier char *ep;
3223e12c5d1SDavid du Colombier
3233e12c5d1SDavid du Colombier *pans = strtol(s, &ep, 0);
3243e12c5d1SDavid du Colombier return (*ep == 0);
3253e12c5d1SDavid du Colombier }
326cd1a0026SDavid du Colombier
327cd1a0026SDavid du Colombier int
isolder(char * pin,char * f)328cd1a0026SDavid du Colombier isolder(char *pin, char *f)
329cd1a0026SDavid du Colombier {
330*728c92e5SDavid du Colombier int r, rel;
331cd1a0026SDavid du Colombier ulong n, m;
332055c7668SDavid du Colombier char *p = pin;
333055c7668SDavid du Colombier Dir *dir;
334cd1a0026SDavid du Colombier
335055c7668SDavid du Colombier dir = dirstat(f);
336055c7668SDavid du Colombier if (dir == nil)
337055c7668SDavid du Colombier return 0;
338cd1a0026SDavid du Colombier
339cd1a0026SDavid du Colombier /* parse time */
340cd1a0026SDavid du Colombier n = 0;
341*728c92e5SDavid du Colombier rel = 0;
342cd1a0026SDavid du Colombier while(*p){
343cd1a0026SDavid du Colombier m = strtoul(p, &p, 0);
344cd1a0026SDavid du Colombier switch(*p){
345cd1a0026SDavid du Colombier case 0:
346cd1a0026SDavid du Colombier n = m;
347cd1a0026SDavid du Colombier break;
348cd1a0026SDavid du Colombier case 'y':
349cd1a0026SDavid du Colombier m *= 12;
350cd1a0026SDavid du Colombier /* fall through */
351cd1a0026SDavid du Colombier case 'M':
352cd1a0026SDavid du Colombier m *= 30;
353cd1a0026SDavid du Colombier /* fall through */
354cd1a0026SDavid du Colombier case 'd':
355cd1a0026SDavid du Colombier m *= 24;
356cd1a0026SDavid du Colombier /* fall through */
357cd1a0026SDavid du Colombier case 'h':
358cd1a0026SDavid du Colombier m *= 60;
359cd1a0026SDavid du Colombier /* fall through */
360cd1a0026SDavid du Colombier case 'm':
361cd1a0026SDavid du Colombier m *= 60;
362cd1a0026SDavid du Colombier /* fall through */
363cd1a0026SDavid du Colombier case 's':
364cd1a0026SDavid du Colombier n += m;
365cd1a0026SDavid du Colombier p++;
366*728c92e5SDavid du Colombier rel = 1;
367cd1a0026SDavid du Colombier break;
368cd1a0026SDavid du Colombier default:
369cd1a0026SDavid du Colombier synbad("bad time syntax, ", pin);
370cd1a0026SDavid du Colombier }
371cd1a0026SDavid du Colombier }
372*728c92e5SDavid du Colombier if (!rel)
373*728c92e5SDavid du Colombier m = n;
374*728c92e5SDavid du Colombier else{
375*728c92e5SDavid du Colombier m = time(0);
376*728c92e5SDavid du Colombier if (n > m) /* before epoch? */
377*728c92e5SDavid du Colombier m = 0;
378*728c92e5SDavid du Colombier else
379*728c92e5SDavid du Colombier m -= n;
380*728c92e5SDavid du Colombier }
381*728c92e5SDavid du Colombier r = dir->mtime < m;
382055c7668SDavid du Colombier free(dir);
383055c7668SDavid du Colombier return r;
384cd1a0026SDavid du Colombier }
38580b7488dSDavid du Colombier
38680b7488dSDavid du Colombier int
isolderthan(char * a,char * b)38780b7488dSDavid du Colombier isolderthan(char *a, char *b)
38880b7488dSDavid du Colombier {
389055c7668SDavid du Colombier int r;
390055c7668SDavid du Colombier Dir *ad, *bd;
39180b7488dSDavid du Colombier
392055c7668SDavid du Colombier ad = dirstat(a);
393055c7668SDavid du Colombier bd = dirstat(b);
394055c7668SDavid du Colombier if (ad == nil || bd == nil)
395055c7668SDavid du Colombier r = 0;
396055c7668SDavid du Colombier else
397055c7668SDavid du Colombier r = ad->mtime > bd->mtime;
398055c7668SDavid du Colombier free(ad);
399055c7668SDavid du Colombier free(bd);
400055c7668SDavid du Colombier return r;
40180b7488dSDavid du Colombier }
40280b7488dSDavid du Colombier
40380b7488dSDavid du Colombier int
isnewerthan(char * a,char * b)40480b7488dSDavid du Colombier isnewerthan(char *a, char *b)
40580b7488dSDavid du Colombier {
406055c7668SDavid du Colombier int r;
407055c7668SDavid du Colombier Dir *ad, *bd;
40880b7488dSDavid du Colombier
409055c7668SDavid du Colombier ad = dirstat(a);
410055c7668SDavid du Colombier bd = dirstat(b);
411055c7668SDavid du Colombier if (ad == nil || bd == nil)
412055c7668SDavid du Colombier r = 0;
413055c7668SDavid du Colombier else
414055c7668SDavid du Colombier r = ad->mtime < bd->mtime;
415055c7668SDavid du Colombier free(ad);
416055c7668SDavid du Colombier free(bd);
417055c7668SDavid du Colombier return r;
41880b7488dSDavid du Colombier }
419