1717a08b6SSheldon Hearn /* $NetBSD: test.c,v 1.21 1999/04/05 09:48:38 kleink Exp $ */ 2717a08b6SSheldon Hearn 39ddb49cbSWarner Losh /*- 4717a08b6SSheldon Hearn * test(1); version 7-like -- author Erik Baalbergen 5717a08b6SSheldon Hearn * modified by Eric Gisin to be used as built-in. 6717a08b6SSheldon Hearn * modified by Arnold Robbins to add SVR3 compatibility 7717a08b6SSheldon Hearn * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). 8717a08b6SSheldon Hearn * modified by J.T. Conklin for NetBSD. 94b88c807SRodney W. Grimes * 10717a08b6SSheldon Hearn * This program is in the Public Domain. 114b88c807SRodney W. Grimes */ 122fd7d6aaSJilles Tjoelker /* 132fd7d6aaSJilles Tjoelker * Important: This file is used both as a standalone program /bin/test and 142fd7d6aaSJilles Tjoelker * as a builtin for /bin/sh (#define SHELL). 152fd7d6aaSJilles Tjoelker */ 164b88c807SRodney W. Grimes 17717a08b6SSheldon Hearn #include <sys/types.h> 18007d3350SEivind Eklund #include <sys/stat.h> 194b88c807SRodney W. Grimes 204b88c807SRodney W. Grimes #include <ctype.h> 214b88c807SRodney W. Grimes #include <err.h> 224b88c807SRodney W. Grimes #include <errno.h> 2382ea3997SAndrey A. Chernov #include <inttypes.h> 2425e04004SAkinori MUSHA #include <stdarg.h> 254b88c807SRodney W. Grimes #include <stdlib.h> 264b88c807SRodney W. Grimes #include <string.h> 274b88c807SRodney W. Grimes #include <unistd.h> 284b88c807SRodney W. Grimes 29d90c5c4aSAkinori MUSHA #ifdef SHELL 30d90c5c4aSAkinori MUSHA #define main testcmd 31d90c5c4aSAkinori MUSHA #include "bltin/bltin.h" 32d919a882SAkinori MUSHA #else 333d09cebfSAndrey A. Chernov #include <locale.h> 343d09cebfSAndrey A. Chernov 35033be9aeSAlfred Perlstein static void error(const char *, ...) __dead2 __printf0like(1, 2); 36d919a882SAkinori MUSHA 37d919a882SAkinori MUSHA static void 38d919a882SAkinori MUSHA error(const char *msg, ...) 39d919a882SAkinori MUSHA { 40d919a882SAkinori MUSHA va_list ap; 41d919a882SAkinori MUSHA va_start(ap, msg); 42d919a882SAkinori MUSHA verrx(2, msg, ap); 43d919a882SAkinori MUSHA /*NOTREACHED*/ 44d919a882SAkinori MUSHA va_end(ap); 45d919a882SAkinori MUSHA } 46d90c5c4aSAkinori MUSHA #endif 47d90c5c4aSAkinori MUSHA 48717a08b6SSheldon Hearn /* test(1) accepts the following grammar: 49717a08b6SSheldon Hearn oexpr ::= aexpr | aexpr "-o" oexpr ; 50717a08b6SSheldon Hearn aexpr ::= nexpr | nexpr "-a" aexpr ; 51717a08b6SSheldon Hearn nexpr ::= primary | "!" primary 52717a08b6SSheldon Hearn primary ::= unary-operator operand 53717a08b6SSheldon Hearn | operand binary-operator operand 54717a08b6SSheldon Hearn | operand 55717a08b6SSheldon Hearn | "(" oexpr ")" 56717a08b6SSheldon Hearn ; 57717a08b6SSheldon Hearn unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"| 58717a08b6SSheldon Hearn "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; 594b88c807SRodney W. Grimes 60717a08b6SSheldon Hearn binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| 61f19825afSJilles Tjoelker "-nt"|"-ot"|"-ef"; 62717a08b6SSheldon Hearn operand ::= <any legal UNIX file name> 634b88c807SRodney W. Grimes */ 64717a08b6SSheldon Hearn 65577ad9b2SJilles Tjoelker enum token_types { 66577ad9b2SJilles Tjoelker UNOP = 0x100, 67577ad9b2SJilles Tjoelker BINOP = 0x200, 68577ad9b2SJilles Tjoelker BUNOP = 0x300, 69577ad9b2SJilles Tjoelker BBINOP = 0x400, 70577ad9b2SJilles Tjoelker PAREN = 0x500 71577ad9b2SJilles Tjoelker }; 72577ad9b2SJilles Tjoelker 73717a08b6SSheldon Hearn enum token { 74717a08b6SSheldon Hearn EOI, 75577ad9b2SJilles Tjoelker OPERAND, 76577ad9b2SJilles Tjoelker FILRD = UNOP + 1, 77717a08b6SSheldon Hearn FILWR, 78717a08b6SSheldon Hearn FILEX, 79717a08b6SSheldon Hearn FILEXIST, 80717a08b6SSheldon Hearn FILREG, 81717a08b6SSheldon Hearn FILDIR, 82717a08b6SSheldon Hearn FILCDEV, 83717a08b6SSheldon Hearn FILBDEV, 84717a08b6SSheldon Hearn FILFIFO, 85717a08b6SSheldon Hearn FILSOCK, 86717a08b6SSheldon Hearn FILSYM, 87717a08b6SSheldon Hearn FILGZ, 88717a08b6SSheldon Hearn FILTT, 89717a08b6SSheldon Hearn FILSUID, 90717a08b6SSheldon Hearn FILSGID, 91717a08b6SSheldon Hearn FILSTCK, 92717a08b6SSheldon Hearn STREZ, 93717a08b6SSheldon Hearn STRNZ, 94577ad9b2SJilles Tjoelker FILUID, 95577ad9b2SJilles Tjoelker FILGID, 96577ad9b2SJilles Tjoelker FILNT = BINOP + 1, 97577ad9b2SJilles Tjoelker FILOT, 98577ad9b2SJilles Tjoelker FILEQ, 99717a08b6SSheldon Hearn STREQ, 100717a08b6SSheldon Hearn STRNE, 101717a08b6SSheldon Hearn STRLT, 102717a08b6SSheldon Hearn STRGT, 103717a08b6SSheldon Hearn INTEQ, 104717a08b6SSheldon Hearn INTNE, 105717a08b6SSheldon Hearn INTGE, 106717a08b6SSheldon Hearn INTGT, 107717a08b6SSheldon Hearn INTLE, 108717a08b6SSheldon Hearn INTLT, 109577ad9b2SJilles Tjoelker UNOT = BUNOP + 1, 110577ad9b2SJilles Tjoelker BAND = BBINOP + 1, 111717a08b6SSheldon Hearn BOR, 112577ad9b2SJilles Tjoelker LPAREN = PAREN + 1, 113577ad9b2SJilles Tjoelker RPAREN 1144b88c807SRodney W. Grimes }; 1154b88c807SRodney W. Grimes 116577ad9b2SJilles Tjoelker #define TOKEN_TYPE(token) ((token) & 0xff00) 1174b88c807SRodney W. Grimes 118f1602fa5SJilles Tjoelker static const struct t_op { 119f1602fa5SJilles Tjoelker char op_text[2]; 120577ad9b2SJilles Tjoelker short op_num; 121f1602fa5SJilles Tjoelker } ops1[] = { 122577ad9b2SJilles Tjoelker {"=", STREQ}, 123577ad9b2SJilles Tjoelker {"<", STRLT}, 124577ad9b2SJilles Tjoelker {">", STRGT}, 125577ad9b2SJilles Tjoelker {"!", UNOT}, 126577ad9b2SJilles Tjoelker {"(", LPAREN}, 127577ad9b2SJilles Tjoelker {")", RPAREN}, 128f1602fa5SJilles Tjoelker }, opsm1[] = { 129f1602fa5SJilles Tjoelker {"r", FILRD}, 130f1602fa5SJilles Tjoelker {"w", FILWR}, 131f1602fa5SJilles Tjoelker {"x", FILEX}, 132f1602fa5SJilles Tjoelker {"e", FILEXIST}, 133f1602fa5SJilles Tjoelker {"f", FILREG}, 134f1602fa5SJilles Tjoelker {"d", FILDIR}, 135f1602fa5SJilles Tjoelker {"c", FILCDEV}, 136f1602fa5SJilles Tjoelker {"b", FILBDEV}, 137f1602fa5SJilles Tjoelker {"p", FILFIFO}, 138f1602fa5SJilles Tjoelker {"u", FILSUID}, 139f1602fa5SJilles Tjoelker {"g", FILSGID}, 140f1602fa5SJilles Tjoelker {"k", FILSTCK}, 141f1602fa5SJilles Tjoelker {"s", FILGZ}, 142f1602fa5SJilles Tjoelker {"t", FILTT}, 143f1602fa5SJilles Tjoelker {"z", STREZ}, 144f1602fa5SJilles Tjoelker {"n", STRNZ}, 145f1602fa5SJilles Tjoelker {"h", FILSYM}, /* for backwards compat */ 146f1602fa5SJilles Tjoelker {"O", FILUID}, 147f1602fa5SJilles Tjoelker {"G", FILGID}, 148f1602fa5SJilles Tjoelker {"L", FILSYM}, 149f1602fa5SJilles Tjoelker {"S", FILSOCK}, 150f1602fa5SJilles Tjoelker {"a", BAND}, 151f1602fa5SJilles Tjoelker {"o", BOR}, 152f1602fa5SJilles Tjoelker }, ops2[] = { 153f1602fa5SJilles Tjoelker {"==", STREQ}, 154f1602fa5SJilles Tjoelker {"!=", STRNE}, 155f1602fa5SJilles Tjoelker }, opsm2[] = { 156f1602fa5SJilles Tjoelker {"eq", INTEQ}, 157f1602fa5SJilles Tjoelker {"ne", INTNE}, 158f1602fa5SJilles Tjoelker {"ge", INTGE}, 159f1602fa5SJilles Tjoelker {"gt", INTGT}, 160f1602fa5SJilles Tjoelker {"le", INTLE}, 161f1602fa5SJilles Tjoelker {"lt", INTLT}, 162f1602fa5SJilles Tjoelker {"nt", FILNT}, 163f1602fa5SJilles Tjoelker {"ot", FILOT}, 164f1602fa5SJilles Tjoelker {"ef", FILEQ}, 1654b88c807SRodney W. Grimes }; 1664b88c807SRodney W. Grimes 167f9d4afb4SEd Schouten static int nargc; 168f9d4afb4SEd Schouten static char **t_wp; 169f9d4afb4SEd Schouten static int parenlevel; 170717a08b6SSheldon Hearn 1715134c3f7SWarner Losh static int aexpr(enum token); 172c80ad859SJilles Tjoelker static int binop(enum token); 1735134c3f7SWarner Losh static int equalf(const char *, const char *); 1745134c3f7SWarner Losh static int filstat(char *, enum token); 1755134c3f7SWarner Losh static int getn(const char *); 17682ea3997SAndrey A. Chernov static intmax_t getq(const char *); 1775134c3f7SWarner Losh static int intcmp(const char *, const char *); 17800e8c94fSJilles Tjoelker static int isunopoperand(void); 17900e8c94fSJilles Tjoelker static int islparenoperand(void); 18000e8c94fSJilles Tjoelker static int isrparenoperand(void); 181f19825afSJilles Tjoelker static int newerf(const char *, const char *); 1825134c3f7SWarner Losh static int nexpr(enum token); 1835134c3f7SWarner Losh static int oexpr(enum token); 184f19825afSJilles Tjoelker static int olderf(const char *, const char *); 1855134c3f7SWarner Losh static int primary(enum token); 1865134c3f7SWarner Losh static void syntax(const char *, const char *); 1875134c3f7SWarner Losh static enum token t_lex(char *); 1884b88c807SRodney W. Grimes 1894b88c807SRodney W. Grimes int 1905134c3f7SWarner Losh main(int argc, char **argv) 1914b88c807SRodney W. Grimes { 1926c62b047SMaxim Konovalov int res; 1939abf3043SSheldon Hearn char *p; 1944b88c807SRodney W. Grimes 1950cf90cd1SJilles Tjoelker if ((p = strrchr(argv[0], '/')) == NULL) 1969abf3043SSheldon Hearn p = argv[0]; 1979abf3043SSheldon Hearn else 1989abf3043SSheldon Hearn p++; 1999abf3043SSheldon Hearn if (strcmp(p, "[") == 0) { 200bd90b9c7SAkinori MUSHA if (strcmp(argv[--argc], "]") != 0) 201*5f659bb0SDaniel Tameling error("missing ']'"); 2024b88c807SRodney W. Grimes argv[argc] = NULL; 2034b88c807SRodney W. Grimes } 2044b88c807SRodney W. Grimes 2056c62b047SMaxim Konovalov /* no expression => false */ 2066c62b047SMaxim Konovalov if (--argc <= 0) 2076c62b047SMaxim Konovalov return 1; 2086c62b047SMaxim Konovalov 2093d09cebfSAndrey A. Chernov #ifndef SHELL 2103d09cebfSAndrey A. Chernov (void)setlocale(LC_CTYPE, ""); 2113d09cebfSAndrey A. Chernov #endif 2126c62b047SMaxim Konovalov nargc = argc; 213717a08b6SSheldon Hearn t_wp = &argv[1]; 21400e8c94fSJilles Tjoelker parenlevel = 0; 21500e8c94fSJilles Tjoelker if (nargc == 4 && strcmp(*t_wp, "!") == 0) { 21600e8c94fSJilles Tjoelker /* Things like ! "" -o x do not fit in the normal grammar. */ 21700e8c94fSJilles Tjoelker --nargc; 21800e8c94fSJilles Tjoelker ++t_wp; 21900e8c94fSJilles Tjoelker res = oexpr(t_lex(*t_wp)); 22000e8c94fSJilles Tjoelker } else 221717a08b6SSheldon Hearn res = !oexpr(t_lex(*t_wp)); 222717a08b6SSheldon Hearn 2236c62b047SMaxim Konovalov if (--nargc > 0) 224717a08b6SSheldon Hearn syntax(*t_wp, "unexpected operator"); 225717a08b6SSheldon Hearn 226717a08b6SSheldon Hearn return res; 2274b88c807SRodney W. Grimes } 228717a08b6SSheldon Hearn 229717a08b6SSheldon Hearn static void 2305134c3f7SWarner Losh syntax(const char *op, const char *msg) 231717a08b6SSheldon Hearn { 232717a08b6SSheldon Hearn 233717a08b6SSheldon Hearn if (op && *op) 234d919a882SAkinori MUSHA error("%s: %s", op, msg); 235717a08b6SSheldon Hearn else 236d919a882SAkinori MUSHA error("%s", msg); 2374b88c807SRodney W. Grimes } 238717a08b6SSheldon Hearn 239717a08b6SSheldon Hearn static int 2405134c3f7SWarner Losh oexpr(enum token n) 241717a08b6SSheldon Hearn { 242717a08b6SSheldon Hearn int res; 243717a08b6SSheldon Hearn 244717a08b6SSheldon Hearn res = aexpr(n); 2456c62b047SMaxim Konovalov if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) == BOR) 2466c62b047SMaxim Konovalov return oexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) || 2476c62b047SMaxim Konovalov res; 248717a08b6SSheldon Hearn t_wp--; 2496c62b047SMaxim Konovalov nargc++; 250717a08b6SSheldon Hearn return res; 2514b88c807SRodney W. Grimes } 252717a08b6SSheldon Hearn 253717a08b6SSheldon Hearn static int 2545134c3f7SWarner Losh aexpr(enum token n) 255717a08b6SSheldon Hearn { 256717a08b6SSheldon Hearn int res; 257717a08b6SSheldon Hearn 258717a08b6SSheldon Hearn res = nexpr(n); 2596c62b047SMaxim Konovalov if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) == BAND) 2606c62b047SMaxim Konovalov return aexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) && 2616c62b047SMaxim Konovalov res; 262717a08b6SSheldon Hearn t_wp--; 2636c62b047SMaxim Konovalov nargc++; 264717a08b6SSheldon Hearn return res; 265717a08b6SSheldon Hearn } 266717a08b6SSheldon Hearn 267717a08b6SSheldon Hearn static int 2685134c3f7SWarner Losh nexpr(enum token n) 269717a08b6SSheldon Hearn { 270717a08b6SSheldon Hearn if (n == UNOT) 2716c62b047SMaxim Konovalov return !nexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)); 272717a08b6SSheldon Hearn return primary(n); 273717a08b6SSheldon Hearn } 274717a08b6SSheldon Hearn 275717a08b6SSheldon Hearn static int 2765134c3f7SWarner Losh primary(enum token n) 277717a08b6SSheldon Hearn { 278717a08b6SSheldon Hearn enum token nn; 279717a08b6SSheldon Hearn int res; 280717a08b6SSheldon Hearn 281717a08b6SSheldon Hearn if (n == EOI) 282717a08b6SSheldon Hearn return 0; /* missing expression */ 283717a08b6SSheldon Hearn if (n == LPAREN) { 28400e8c94fSJilles Tjoelker parenlevel++; 2856c62b047SMaxim Konovalov if ((nn = t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) == 28600e8c94fSJilles Tjoelker RPAREN) { 28700e8c94fSJilles Tjoelker parenlevel--; 288717a08b6SSheldon Hearn return 0; /* missing expression */ 28900e8c94fSJilles Tjoelker } 290717a08b6SSheldon Hearn res = oexpr(nn); 2916c62b047SMaxim Konovalov if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) != RPAREN) 292717a08b6SSheldon Hearn syntax(NULL, "closing paren expected"); 29300e8c94fSJilles Tjoelker parenlevel--; 294717a08b6SSheldon Hearn return res; 295717a08b6SSheldon Hearn } 296577ad9b2SJilles Tjoelker if (TOKEN_TYPE(n) == UNOP) { 297717a08b6SSheldon Hearn /* unary expression */ 2986c62b047SMaxim Konovalov if (--nargc == 0) 299577ad9b2SJilles Tjoelker syntax(NULL, "argument expected"); /* impossible */ 300717a08b6SSheldon Hearn switch (n) { 301717a08b6SSheldon Hearn case STREZ: 3026c62b047SMaxim Konovalov return strlen(*++t_wp) == 0; 303717a08b6SSheldon Hearn case STRNZ: 3046c62b047SMaxim Konovalov return strlen(*++t_wp) != 0; 305717a08b6SSheldon Hearn case FILTT: 3066c62b047SMaxim Konovalov return isatty(getn(*++t_wp)); 3074b88c807SRodney W. Grimes default: 3086c62b047SMaxim Konovalov return filstat(*++t_wp, n); 309717a08b6SSheldon Hearn } 3104b88c807SRodney W. Grimes } 3114b88c807SRodney W. Grimes 312c80ad859SJilles Tjoelker nn = t_lex(nargc > 0 ? t_wp[1] : NULL); 313c80ad859SJilles Tjoelker if (TOKEN_TYPE(nn) == BINOP) 314c80ad859SJilles Tjoelker return binop(nn); 315717a08b6SSheldon Hearn 316717a08b6SSheldon Hearn return strlen(*t_wp) > 0; 3174b88c807SRodney W. Grimes } 3184b88c807SRodney W. Grimes 3194b88c807SRodney W. Grimes static int 320c80ad859SJilles Tjoelker binop(enum token n) 3214b88c807SRodney W. Grimes { 322577ad9b2SJilles Tjoelker const char *opnd1, *op, *opnd2; 3234b88c807SRodney W. Grimes 324717a08b6SSheldon Hearn opnd1 = *t_wp; 325c80ad859SJilles Tjoelker op = nargc > 0 ? (--nargc, *++t_wp) : NULL; 3264b88c807SRodney W. Grimes 3276c62b047SMaxim Konovalov if ((opnd2 = nargc > 0 ? (--nargc, *++t_wp) : NULL) == NULL) 328577ad9b2SJilles Tjoelker syntax(op, "argument expected"); 3294b88c807SRodney W. Grimes 330577ad9b2SJilles Tjoelker switch (n) { 3314b88c807SRodney W. Grimes case STREQ: 332717a08b6SSheldon Hearn return strcmp(opnd1, opnd2) == 0; 3334b88c807SRodney W. Grimes case STRNE: 334717a08b6SSheldon Hearn return strcmp(opnd1, opnd2) != 0; 335717a08b6SSheldon Hearn case STRLT: 336717a08b6SSheldon Hearn return strcmp(opnd1, opnd2) < 0; 337717a08b6SSheldon Hearn case STRGT: 338717a08b6SSheldon Hearn return strcmp(opnd1, opnd2) > 0; 339717a08b6SSheldon Hearn case INTEQ: 340de96f240SStefan Eßer return intcmp(opnd1, opnd2) == 0; 341717a08b6SSheldon Hearn case INTNE: 342de96f240SStefan Eßer return intcmp(opnd1, opnd2) != 0; 343717a08b6SSheldon Hearn case INTGE: 344de96f240SStefan Eßer return intcmp(opnd1, opnd2) >= 0; 345717a08b6SSheldon Hearn case INTGT: 346de96f240SStefan Eßer return intcmp(opnd1, opnd2) > 0; 347717a08b6SSheldon Hearn case INTLE: 348de96f240SStefan Eßer return intcmp(opnd1, opnd2) <= 0; 349717a08b6SSheldon Hearn case INTLT: 350de96f240SStefan Eßer return intcmp(opnd1, opnd2) < 0; 351f19825afSJilles Tjoelker case FILNT: 352f19825afSJilles Tjoelker return newerf (opnd1, opnd2); 353f19825afSJilles Tjoelker case FILOT: 354f19825afSJilles Tjoelker return olderf (opnd1, opnd2); 355717a08b6SSheldon Hearn case FILEQ: 356717a08b6SSheldon Hearn return equalf (opnd1, opnd2); 357717a08b6SSheldon Hearn default: 358717a08b6SSheldon Hearn abort(); 359717a08b6SSheldon Hearn /* NOTREACHED */ 360717a08b6SSheldon Hearn } 361717a08b6SSheldon Hearn } 362717a08b6SSheldon Hearn 363717a08b6SSheldon Hearn static int 3645134c3f7SWarner Losh filstat(char *nm, enum token mode) 365717a08b6SSheldon Hearn { 366717a08b6SSheldon Hearn struct stat s; 367717a08b6SSheldon Hearn 368717a08b6SSheldon Hearn if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s)) 369717a08b6SSheldon Hearn return 0; 370717a08b6SSheldon Hearn 371717a08b6SSheldon Hearn switch (mode) { 372717a08b6SSheldon Hearn case FILRD: 37389a3a364SMaxim Konovalov return (eaccess(nm, R_OK) == 0); 374717a08b6SSheldon Hearn case FILWR: 37589a3a364SMaxim Konovalov return (eaccess(nm, W_OK) == 0); 376717a08b6SSheldon Hearn case FILEX: 37789a3a364SMaxim Konovalov /* XXX work around eaccess(2) false positives for superuser */ 37889a3a364SMaxim Konovalov if (eaccess(nm, X_OK) != 0) 379eb5e5558SBrian Feldman return 0; 38089a3a364SMaxim Konovalov if (S_ISDIR(s.st_mode) || geteuid() != 0) 381eb5e5558SBrian Feldman return 1; 382d2fed466SBrian Feldman return (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0; 383717a08b6SSheldon Hearn case FILEXIST: 38489a3a364SMaxim Konovalov return (eaccess(nm, F_OK) == 0); 385717a08b6SSheldon Hearn case FILREG: 386717a08b6SSheldon Hearn return S_ISREG(s.st_mode); 387717a08b6SSheldon Hearn case FILDIR: 388717a08b6SSheldon Hearn return S_ISDIR(s.st_mode); 389717a08b6SSheldon Hearn case FILCDEV: 390717a08b6SSheldon Hearn return S_ISCHR(s.st_mode); 391717a08b6SSheldon Hearn case FILBDEV: 392717a08b6SSheldon Hearn return S_ISBLK(s.st_mode); 393717a08b6SSheldon Hearn case FILFIFO: 394717a08b6SSheldon Hearn return S_ISFIFO(s.st_mode); 395717a08b6SSheldon Hearn case FILSOCK: 396717a08b6SSheldon Hearn return S_ISSOCK(s.st_mode); 397717a08b6SSheldon Hearn case FILSYM: 398717a08b6SSheldon Hearn return S_ISLNK(s.st_mode); 399717a08b6SSheldon Hearn case FILSUID: 400717a08b6SSheldon Hearn return (s.st_mode & S_ISUID) != 0; 401717a08b6SSheldon Hearn case FILSGID: 402717a08b6SSheldon Hearn return (s.st_mode & S_ISGID) != 0; 403717a08b6SSheldon Hearn case FILSTCK: 404717a08b6SSheldon Hearn return (s.st_mode & S_ISVTX) != 0; 405717a08b6SSheldon Hearn case FILGZ: 406717a08b6SSheldon Hearn return s.st_size > (off_t)0; 407717a08b6SSheldon Hearn case FILUID: 408717a08b6SSheldon Hearn return s.st_uid == geteuid(); 409717a08b6SSheldon Hearn case FILGID: 410717a08b6SSheldon Hearn return s.st_gid == getegid(); 411717a08b6SSheldon Hearn default: 412717a08b6SSheldon Hearn return 1; 413717a08b6SSheldon Hearn } 414717a08b6SSheldon Hearn } 415717a08b6SSheldon Hearn 416f1602fa5SJilles Tjoelker static int 417f1602fa5SJilles Tjoelker find_op_1char(const struct t_op *op, const struct t_op *end, const char *s) 418717a08b6SSheldon Hearn { 419f1602fa5SJilles Tjoelker char c; 420717a08b6SSheldon Hearn 421f1602fa5SJilles Tjoelker c = s[0]; 422f1602fa5SJilles Tjoelker while (op != end) { 423f1602fa5SJilles Tjoelker if (c == *op->op_text) 424717a08b6SSheldon Hearn return op->op_num; 425717a08b6SSheldon Hearn op++; 426717a08b6SSheldon Hearn } 427717a08b6SSheldon Hearn return OPERAND; 4284b88c807SRodney W. Grimes } 4294b88c807SRodney W. Grimes 4304b88c807SRodney W. Grimes static int 431f1602fa5SJilles Tjoelker find_op_2char(const struct t_op *op, const struct t_op *end, const char *s) 432f1602fa5SJilles Tjoelker { 433f1602fa5SJilles Tjoelker while (op != end) { 434f1602fa5SJilles Tjoelker if (s[0] == op->op_text[0] && s[1] == op->op_text[1]) 435f1602fa5SJilles Tjoelker return op->op_num; 436f1602fa5SJilles Tjoelker op++; 437f1602fa5SJilles Tjoelker } 438f1602fa5SJilles Tjoelker return OPERAND; 439f1602fa5SJilles Tjoelker } 440f1602fa5SJilles Tjoelker 441f1602fa5SJilles Tjoelker static int 442f1602fa5SJilles Tjoelker find_op(const char *s) 443f1602fa5SJilles Tjoelker { 444f1602fa5SJilles Tjoelker if (s[0] == '\0') 445f1602fa5SJilles Tjoelker return OPERAND; 446f1602fa5SJilles Tjoelker else if (s[1] == '\0') 447f1602fa5SJilles Tjoelker return find_op_1char(ops1, (&ops1)[1], s); 448f1602fa5SJilles Tjoelker else if (s[2] == '\0') 449f1602fa5SJilles Tjoelker return s[0] == '-' ? find_op_1char(opsm1, (&opsm1)[1], s + 1) : 450f1602fa5SJilles Tjoelker find_op_2char(ops2, (&ops2)[1], s); 451f1602fa5SJilles Tjoelker else if (s[3] == '\0') 452f1602fa5SJilles Tjoelker return s[0] == '-' ? find_op_2char(opsm2, (&opsm2)[1], s + 1) : 453f1602fa5SJilles Tjoelker OPERAND; 454f1602fa5SJilles Tjoelker else 455f1602fa5SJilles Tjoelker return OPERAND; 456f1602fa5SJilles Tjoelker } 457f1602fa5SJilles Tjoelker 458f1602fa5SJilles Tjoelker static enum token 459f1602fa5SJilles Tjoelker t_lex(char *s) 460f1602fa5SJilles Tjoelker { 461f1602fa5SJilles Tjoelker int num; 462f1602fa5SJilles Tjoelker 463172c3b0bSMarcelo Araujo if (s == NULL) { 464f1602fa5SJilles Tjoelker return EOI; 465f1602fa5SJilles Tjoelker } 466f1602fa5SJilles Tjoelker num = find_op(s); 467f1602fa5SJilles Tjoelker if (((TOKEN_TYPE(num) == UNOP || TOKEN_TYPE(num) == BUNOP) 468f1602fa5SJilles Tjoelker && isunopoperand()) || 469f1602fa5SJilles Tjoelker (num == LPAREN && islparenoperand()) || 470f1602fa5SJilles Tjoelker (num == RPAREN && isrparenoperand())) 471f1602fa5SJilles Tjoelker return OPERAND; 472f1602fa5SJilles Tjoelker return num; 473f1602fa5SJilles Tjoelker } 474f1602fa5SJilles Tjoelker 475f1602fa5SJilles Tjoelker static int 47600e8c94fSJilles Tjoelker isunopoperand(void) 4774b88c807SRodney W. Grimes { 478717a08b6SSheldon Hearn char *s; 479717a08b6SSheldon Hearn char *t; 480f1602fa5SJilles Tjoelker int num; 4814b88c807SRodney W. Grimes 4826c62b047SMaxim Konovalov if (nargc == 1) 483717a08b6SSheldon Hearn return 1; 4846c62b047SMaxim Konovalov s = *(t_wp + 1); 48500e8c94fSJilles Tjoelker if (nargc == 2) 48600e8c94fSJilles Tjoelker return parenlevel == 1 && strcmp(s, ")") == 0; 4876c62b047SMaxim Konovalov t = *(t_wp + 2); 488f1602fa5SJilles Tjoelker num = find_op(s); 489f1602fa5SJilles Tjoelker return TOKEN_TYPE(num) == BINOP && 49000e8c94fSJilles Tjoelker (parenlevel == 0 || t[0] != ')' || t[1] != '\0'); 4914b88c807SRodney W. Grimes } 4924b88c807SRodney W. Grimes 49300e8c94fSJilles Tjoelker static int 49400e8c94fSJilles Tjoelker islparenoperand(void) 49500e8c94fSJilles Tjoelker { 49600e8c94fSJilles Tjoelker char *s; 497f1602fa5SJilles Tjoelker int num; 49800e8c94fSJilles Tjoelker 49900e8c94fSJilles Tjoelker if (nargc == 1) 50000e8c94fSJilles Tjoelker return 1; 50100e8c94fSJilles Tjoelker s = *(t_wp + 1); 50200e8c94fSJilles Tjoelker if (nargc == 2) 50300e8c94fSJilles Tjoelker return parenlevel == 1 && strcmp(s, ")") == 0; 50400e8c94fSJilles Tjoelker if (nargc != 3) 50500e8c94fSJilles Tjoelker return 0; 506f1602fa5SJilles Tjoelker num = find_op(s); 507f1602fa5SJilles Tjoelker return TOKEN_TYPE(num) == BINOP; 50800e8c94fSJilles Tjoelker } 50900e8c94fSJilles Tjoelker 51000e8c94fSJilles Tjoelker static int 51100e8c94fSJilles Tjoelker isrparenoperand(void) 51200e8c94fSJilles Tjoelker { 51300e8c94fSJilles Tjoelker char *s; 51400e8c94fSJilles Tjoelker 51500e8c94fSJilles Tjoelker if (nargc == 1) 51600e8c94fSJilles Tjoelker return 0; 51700e8c94fSJilles Tjoelker s = *(t_wp + 1); 51800e8c94fSJilles Tjoelker if (nargc == 2) 51900e8c94fSJilles Tjoelker return parenlevel == 1 && strcmp(s, ")") == 0; 52000e8c94fSJilles Tjoelker return 0; 52100e8c94fSJilles Tjoelker } 52200e8c94fSJilles Tjoelker 523717a08b6SSheldon Hearn /* atoi with error detection */ 5244b88c807SRodney W. Grimes static int 5255134c3f7SWarner Losh getn(const char *s) 5264b88c807SRodney W. Grimes { 527717a08b6SSheldon Hearn char *p; 528717a08b6SSheldon Hearn long r; 5294b88c807SRodney W. Grimes 5304b88c807SRodney W. Grimes errno = 0; 531717a08b6SSheldon Hearn r = strtol(s, &p, 10); 532717a08b6SSheldon Hearn 5333d09cebfSAndrey A. Chernov if (s == p) 5343d09cebfSAndrey A. Chernov error("%s: bad number", s); 5353d09cebfSAndrey A. Chernov 536717a08b6SSheldon Hearn if (errno != 0) 5379ea42c8eSAndrey A. Chernov error((errno == EINVAL) ? "%s: bad number" : 5389ea42c8eSAndrey A. Chernov "%s: out of range", s); 539717a08b6SSheldon Hearn 540717a08b6SSheldon Hearn while (isspace((unsigned char)*p)) 541717a08b6SSheldon Hearn p++; 542717a08b6SSheldon Hearn 543717a08b6SSheldon Hearn if (*p) 544d919a882SAkinori MUSHA error("%s: bad number", s); 545717a08b6SSheldon Hearn 546717a08b6SSheldon Hearn return (int) r; 5474b88c807SRodney W. Grimes } 5484b88c807SRodney W. Grimes 549de96f240SStefan Eßer /* atoi with error detection and 64 bit range */ 55082ea3997SAndrey A. Chernov static intmax_t 5515134c3f7SWarner Losh getq(const char *s) 552de96f240SStefan Eßer { 553de96f240SStefan Eßer char *p; 55482ea3997SAndrey A. Chernov intmax_t r; 555de96f240SStefan Eßer 556de96f240SStefan Eßer errno = 0; 55782ea3997SAndrey A. Chernov r = strtoimax(s, &p, 10); 558de96f240SStefan Eßer 5593d09cebfSAndrey A. Chernov if (s == p) 5603d09cebfSAndrey A. Chernov error("%s: bad number", s); 5613d09cebfSAndrey A. Chernov 562de96f240SStefan Eßer if (errno != 0) 5639ea42c8eSAndrey A. Chernov error((errno == EINVAL) ? "%s: bad number" : 5649ea42c8eSAndrey A. Chernov "%s: out of range", s); 565de96f240SStefan Eßer 566de96f240SStefan Eßer while (isspace((unsigned char)*p)) 567de96f240SStefan Eßer p++; 568de96f240SStefan Eßer 569de96f240SStefan Eßer if (*p) 570d919a882SAkinori MUSHA error("%s: bad number", s); 571de96f240SStefan Eßer 572de96f240SStefan Eßer return r; 573de96f240SStefan Eßer } 574de96f240SStefan Eßer 575de96f240SStefan Eßer static int 5765134c3f7SWarner Losh intcmp (const char *s1, const char *s2) 577de96f240SStefan Eßer { 57882ea3997SAndrey A. Chernov intmax_t q1, q2; 579de96f240SStefan Eßer 580de96f240SStefan Eßer 581de96f240SStefan Eßer q1 = getq(s1); 582de96f240SStefan Eßer q2 = getq(s2); 583de96f240SStefan Eßer 584de96f240SStefan Eßer if (q1 > q2) 585de96f240SStefan Eßer return 1; 586de96f240SStefan Eßer 587de96f240SStefan Eßer if (q1 < q2) 588de96f240SStefan Eßer return -1; 589de96f240SStefan Eßer 590de96f240SStefan Eßer return 0; 591de96f240SStefan Eßer } 592de96f240SStefan Eßer 593717a08b6SSheldon Hearn static int 594f19825afSJilles Tjoelker newerf (const char *f1, const char *f2) 5954b88c807SRodney W. Grimes { 596717a08b6SSheldon Hearn struct stat b1, b2; 5974b88c807SRodney W. Grimes 5986576952cSDavid Malone if (stat(f1, &b1) != 0 || stat(f2, &b2) != 0) 5996576952cSDavid Malone return 0; 6006576952cSDavid Malone 601f19825afSJilles Tjoelker if (b1.st_mtim.tv_sec > b2.st_mtim.tv_sec) 602293beebcSPeter Jeremy return 1; 603f19825afSJilles Tjoelker if (b1.st_mtim.tv_sec < b2.st_mtim.tv_sec) 604293beebcSPeter Jeremy return 0; 605293beebcSPeter Jeremy 606f19825afSJilles Tjoelker return (b1.st_mtim.tv_nsec > b2.st_mtim.tv_nsec); 607f19825afSJilles Tjoelker } 608f19825afSJilles Tjoelker 609f19825afSJilles Tjoelker static int 610f19825afSJilles Tjoelker olderf (const char *f1, const char *f2) 611f19825afSJilles Tjoelker { 612f19825afSJilles Tjoelker return (newerf(f2, f1)); 613717a08b6SSheldon Hearn } 614717a08b6SSheldon Hearn 615717a08b6SSheldon Hearn static int 6165134c3f7SWarner Losh equalf (const char *f1, const char *f2) 617717a08b6SSheldon Hearn { 618717a08b6SSheldon Hearn struct stat b1, b2; 619717a08b6SSheldon Hearn 620717a08b6SSheldon Hearn return (stat (f1, &b1) == 0 && 621717a08b6SSheldon Hearn stat (f2, &b2) == 0 && 622717a08b6SSheldon Hearn b1.st_dev == b2.st_dev && 623717a08b6SSheldon Hearn b1.st_ino == b2.st_ino); 6244b88c807SRodney W. Grimes } 625