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