[BACK]Return to test.c CVS log [TXT][DIR] Up to [local] / prex-old / usr / bin / test

Annotation of prex-old/usr/bin/test/test.c, Revision 1.1

1.1     ! nbrk        1: /* $NetBSD: test.c,v 1.26 2005/02/10 06:56:55 simonb Exp $ */
        !             2:
        !             3: /*
        !             4:  * test(1); version 7-like  --  author Erik Baalbergen
        !             5:  * modified by Eric Gisin to be used as built-in.
        !             6:  * modified by Arnold Robbins to add SVR3 compatibility
        !             7:  * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
        !             8:  * modified by J.T. Conklin for NetBSD.
        !             9:  *
        !            10:  * This program is in the Public Domain.
        !            11:  */
        !            12:
        !            13: #include <sys/cdefs.h>
        !            14: #include <sys/stat.h>
        !            15: #include <sys/types.h>
        !            16:
        !            17: #include <ctype.h>
        !            18: #include <err.h>
        !            19: #include <errno.h>
        !            20: #include <stdio.h>
        !            21: #include <stdlib.h>
        !            22: #include <string.h>
        !            23: #include <unistd.h>
        !            24: #include <stdarg.h>
        !            25:
        !            26: #ifdef CMDBOX
        !            27: #define main(argc, argv)       test_main(argc, argv)
        !            28: #endif
        !            29:
        !            30: /* test(1) accepts the following grammar:
        !            31:        oexpr   ::= aexpr | aexpr "-o" oexpr ;
        !            32:        aexpr   ::= nexpr | nexpr "-a" aexpr ;
        !            33:        nexpr   ::= primary | "!" primary
        !            34:        primary ::= unary-operator operand
        !            35:                | operand binary-operator operand
        !            36:                | operand
        !            37:                | "(" oexpr ")"
        !            38:                ;
        !            39:        unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
        !            40:                "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
        !            41:
        !            42:        binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
        !            43:                        "-nt"|"-ot"|"-ef";
        !            44:        operand ::= <any legal UNIX file name>
        !            45: */
        !            46:
        !            47: enum token {
        !            48:        EOI,
        !            49:        FILRD,
        !            50:        FILWR,
        !            51:        FILEX,
        !            52:        FILEXIST,
        !            53:        FILREG,
        !            54:        FILDIR,
        !            55:        FILCDEV,
        !            56:        FILBDEV,
        !            57:        FILFIFO,
        !            58:        FILSOCK,
        !            59:        FILSYM,
        !            60:        FILGZ,
        !            61:        FILTT,
        !            62:        FILSUID,
        !            63:        FILSGID,
        !            64:        FILSTCK,
        !            65:        FILNT,
        !            66:        FILOT,
        !            67:        FILEQ,
        !            68:        FILUID,
        !            69:        FILGID,
        !            70:        STREZ,
        !            71:        STRNZ,
        !            72:        STREQ,
        !            73:        STRNE,
        !            74:        STRLT,
        !            75:        STRGT,
        !            76:        INTEQ,
        !            77:        INTNE,
        !            78:        INTGE,
        !            79:        INTGT,
        !            80:        INTLE,
        !            81:        INTLT,
        !            82:        UNOT,
        !            83:        BAND,
        !            84:        BOR,
        !            85:        LPAREN,
        !            86:        RPAREN,
        !            87:        OPERAND
        !            88: };
        !            89:
        !            90: enum token_types {
        !            91:        UNOP,
        !            92:        BINOP,
        !            93:        BUNOP,
        !            94:        BBINOP,
        !            95:        PAREN
        !            96: };
        !            97:
        !            98: static struct t_op {
        !            99:        const char *op_text;
        !           100:        short op_num, op_type;
        !           101: } const ops [] = {
        !           102:        {"-r",  FILRD,  UNOP},
        !           103:        {"-w",  FILWR,  UNOP},
        !           104:        {"-x",  FILEX,  UNOP},
        !           105:        {"-e",  FILEXIST,UNOP},
        !           106:        {"-f",  FILREG, UNOP},
        !           107:        {"-d",  FILDIR, UNOP},
        !           108:        {"-c",  FILCDEV,UNOP},
        !           109:        {"-b",  FILBDEV,UNOP},
        !           110:        {"-p",  FILFIFO,UNOP},
        !           111:        {"-u",  FILSUID,UNOP},
        !           112:        {"-g",  FILSGID,UNOP},
        !           113:        {"-k",  FILSTCK,UNOP},
        !           114:        {"-s",  FILGZ,  UNOP},
        !           115:        {"-t",  FILTT,  UNOP},
        !           116:        {"-z",  STREZ,  UNOP},
        !           117:        {"-n",  STRNZ,  UNOP},
        !           118:        {"-h",  FILSYM, UNOP},          /* for backwards compat */
        !           119:        {"-O",  FILUID, UNOP},
        !           120:        {"-G",  FILGID, UNOP},
        !           121:        {"-L",  FILSYM, UNOP},
        !           122:        {"-S",  FILSOCK,UNOP},
        !           123:        {"=",   STREQ,  BINOP},
        !           124:        {"!=",  STRNE,  BINOP},
        !           125:        {"<",   STRLT,  BINOP},
        !           126:        {">",   STRGT,  BINOP},
        !           127:        {"-eq", INTEQ,  BINOP},
        !           128:        {"-ne", INTNE,  BINOP},
        !           129:        {"-ge", INTGE,  BINOP},
        !           130:        {"-gt", INTGT,  BINOP},
        !           131:        {"-le", INTLE,  BINOP},
        !           132:        {"-lt", INTLT,  BINOP},
        !           133:        {"-nt", FILNT,  BINOP},
        !           134:        {"-ot", FILOT,  BINOP},
        !           135:        {"-ef", FILEQ,  BINOP},
        !           136:        {"!",   UNOT,   BUNOP},
        !           137:        {"-a",  BAND,   BBINOP},
        !           138:        {"-o",  BOR,    BBINOP},
        !           139:        {"(",   LPAREN, PAREN},
        !           140:        {")",   RPAREN, PAREN},
        !           141:        {0,     0,      0}
        !           142: };
        !           143:
        !           144: static char **t_wp;
        !           145: static struct t_op const *t_wp_op;
        !           146:
        !           147: static void syntax(const char *, const char *);
        !           148: static int oexpr(enum token);
        !           149: static int aexpr(enum token);
        !           150: static int nexpr(enum token);
        !           151: static int primary(enum token);
        !           152: static int binop(void);
        !           153: static int filstat(char *, enum token);
        !           154: static enum token t_lex(char *);
        !           155: static int isoperand(void);
        !           156: static int getn(const char *);
        !           157: static int newerf(const char *, const char *);
        !           158: static int olderf(const char *, const char *);
        !           159: static int equalf(const char *, const char *);
        !           160:
        !           161: static void error(const char *, ...);
        !           162:
        !           163: static void
        !           164: error(const char *msg, ...)
        !           165: {
        !           166:        va_list ap;
        !           167:
        !           168:        va_start(ap, msg);
        !           169:        verrx(2, msg, ap);
        !           170:        va_end(ap);
        !           171:        /*NOTREACHED*/
        !           172: }
        !           173:
        !           174: int
        !           175: main(int argc, char *argv[])
        !           176: {
        !           177:        int res;
        !           178:
        !           179:        if (strcmp(argv[0], "[") == 0) {
        !           180:                if (strcmp(argv[--argc], "]"))
        !           181:                        error("missing ]");
        !           182:                argv[argc] = NULL;
        !           183:        }
        !           184:
        !           185:        if (argc < 2)
        !           186:                return 1;
        !           187:
        !           188:        t_wp = &argv[1];
        !           189:        res = !oexpr(t_lex(*t_wp));
        !           190:
        !           191:        if (*t_wp != NULL && *++t_wp != NULL)
        !           192:                syntax(*t_wp, "unexpected operator");
        !           193:
        !           194:        return res;
        !           195: }
        !           196:
        !           197: static void
        !           198: syntax(const char *op, const char *msg)
        !           199: {
        !           200:
        !           201:        if (op && *op)
        !           202:                error("%s: %s", op, msg);
        !           203:        else
        !           204:                error("%s", msg);
        !           205: }
        !           206:
        !           207: static int
        !           208: oexpr(enum token n)
        !           209: {
        !           210:        int res;
        !           211:
        !           212:        res = aexpr(n);
        !           213:        if (t_lex(*++t_wp) == BOR)
        !           214:                return oexpr(t_lex(*++t_wp)) || res;
        !           215:        t_wp--;
        !           216:        return res;
        !           217: }
        !           218:
        !           219: static int
        !           220: aexpr(enum token n)
        !           221: {
        !           222:        int res;
        !           223:
        !           224:        res = nexpr(n);
        !           225:        if (t_lex(*++t_wp) == BAND)
        !           226:                return aexpr(t_lex(*++t_wp)) && res;
        !           227:        t_wp--;
        !           228:        return res;
        !           229: }
        !           230:
        !           231: static int
        !           232: nexpr(enum token n)
        !           233: {
        !           234:
        !           235:        if (n == UNOT)
        !           236:                return !nexpr(t_lex(*++t_wp));
        !           237:        return primary(n);
        !           238: }
        !           239:
        !           240: static int
        !           241: primary(enum token n)
        !           242: {
        !           243:        enum token nn;
        !           244:        int res;
        !           245:
        !           246:        if (n == EOI)
        !           247:                return 0;               /* missing expression */
        !           248:        if (n == LPAREN) {
        !           249:                if ((nn = t_lex(*++t_wp)) == RPAREN)
        !           250:                        return 0;       /* missing expression */
        !           251:                res = oexpr(nn);
        !           252:                if (t_lex(*++t_wp) != RPAREN)
        !           253:                        syntax(NULL, "closing paren expected");
        !           254:                return res;
        !           255:        }
        !           256:        if (t_wp_op && t_wp_op->op_type == UNOP) {
        !           257:                /* unary expression */
        !           258:                if (*++t_wp == NULL)
        !           259:                        syntax(t_wp_op->op_text, "argument expected");
        !           260:                switch (n) {
        !           261:                case STREZ:
        !           262:                        return strlen(*t_wp) == 0;
        !           263:                case STRNZ:
        !           264:                        return strlen(*t_wp) != 0;
        !           265:                case FILTT:
        !           266:                        return isatty(getn(*t_wp));
        !           267:                default:
        !           268:                        return filstat(*t_wp, n);
        !           269:                }
        !           270:        }
        !           271:
        !           272:        if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
        !           273:                return binop();
        !           274:        }
        !           275:
        !           276:        return strlen(*t_wp) > 0;
        !           277: }
        !           278:
        !           279: static int
        !           280: binop(void)
        !           281: {
        !           282:        const char *opnd1, *opnd2;
        !           283:        struct t_op const *op;
        !           284:
        !           285:        opnd1 = *t_wp;
        !           286:        (void) t_lex(*++t_wp);
        !           287:        op = t_wp_op;
        !           288:
        !           289:        if ((opnd2 = *++t_wp) == NULL)
        !           290:                syntax(op->op_text, "argument expected");
        !           291:
        !           292:        switch (op->op_num) {
        !           293:        case STREQ:
        !           294:                return strcmp(opnd1, opnd2) == 0;
        !           295:        case STRNE:
        !           296:                return strcmp(opnd1, opnd2) != 0;
        !           297:        case STRLT:
        !           298:                return strcmp(opnd1, opnd2) < 0;
        !           299:        case STRGT:
        !           300:                return strcmp(opnd1, opnd2) > 0;
        !           301:        case INTEQ:
        !           302:                return getn(opnd1) == getn(opnd2);
        !           303:        case INTNE:
        !           304:                return getn(opnd1) != getn(opnd2);
        !           305:        case INTGE:
        !           306:                return getn(opnd1) >= getn(opnd2);
        !           307:        case INTGT:
        !           308:                return getn(opnd1) > getn(opnd2);
        !           309:        case INTLE:
        !           310:                return getn(opnd1) <= getn(opnd2);
        !           311:        case INTLT:
        !           312:                return getn(opnd1) < getn(opnd2);
        !           313:        case FILNT:
        !           314:                return newerf(opnd1, opnd2);
        !           315:        case FILOT:
        !           316:                return olderf(opnd1, opnd2);
        !           317:        case FILEQ:
        !           318:                return equalf(opnd1, opnd2);
        !           319:        default:
        !           320:                abort();
        !           321:                /* NOTREACHED */
        !           322:        }
        !           323: }
        !           324:
        !           325: static int
        !           326: filstat(char *nm, enum token mode)
        !           327: {
        !           328:        struct stat s;
        !           329:
        !           330:        if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
        !           331:                return 0;
        !           332:
        !           333:        switch (mode) {
        !           334:        case FILRD:
        !           335:                return access(nm, R_OK) == 0;
        !           336:        case FILWR:
        !           337:                return access(nm, W_OK) == 0;
        !           338:        case FILEX:
        !           339:                return access(nm, X_OK) == 0;
        !           340:        case FILEXIST:
        !           341:                return access(nm, F_OK) == 0;
        !           342:        case FILREG:
        !           343:                return S_ISREG(s.st_mode);
        !           344:        case FILDIR:
        !           345:                return S_ISDIR(s.st_mode);
        !           346:        case FILCDEV:
        !           347:                return S_ISCHR(s.st_mode);
        !           348:        case FILBDEV:
        !           349:                return S_ISBLK(s.st_mode);
        !           350:        case FILFIFO:
        !           351:                return S_ISFIFO(s.st_mode);
        !           352:        case FILSOCK:
        !           353:                return S_ISSOCK(s.st_mode);
        !           354:        case FILSYM:
        !           355:                return S_ISLNK(s.st_mode);
        !           356:        case FILSUID:
        !           357:                return (s.st_mode & S_ISUID) != 0;
        !           358:        case FILSGID:
        !           359:                return (s.st_mode & S_ISGID) != 0;
        !           360:        case FILSTCK:
        !           361:                return (s.st_mode & S_ISVTX) != 0;
        !           362:        case FILGZ:
        !           363:                return s.st_size > (off_t)0;
        !           364:        case FILUID:
        !           365:                return s.st_uid == geteuid();
        !           366:        case FILGID:
        !           367:                return s.st_gid == getegid();
        !           368:        default:
        !           369:                return 1;
        !           370:        }
        !           371: }
        !           372:
        !           373: static enum token
        !           374: t_lex(char *s)
        !           375: {
        !           376:        struct t_op const *op;
        !           377:
        !           378:        op = ops;
        !           379:
        !           380:        if (s == 0) {
        !           381:                t_wp_op = NULL;
        !           382:                return EOI;
        !           383:        }
        !           384:        while (op->op_text) {
        !           385:                if (strcmp(s, op->op_text) == 0) {
        !           386:                        if ((op->op_type == UNOP && isoperand()) ||
        !           387:                            (op->op_num == LPAREN && *(t_wp+1) == 0))
        !           388:                                break;
        !           389:                        t_wp_op = op;
        !           390:                        return op->op_num;
        !           391:                }
        !           392:                op++;
        !           393:        }
        !           394:        t_wp_op = NULL;
        !           395:        return OPERAND;
        !           396: }
        !           397:
        !           398: static int
        !           399: isoperand(void)
        !           400: {
        !           401:        struct t_op const *op;
        !           402:        char *s, *t;
        !           403:
        !           404:        op = ops;
        !           405:        if ((s  = *(t_wp+1)) == 0)
        !           406:                return 1;
        !           407:        if ((t = *(t_wp+2)) == 0)
        !           408:                return 0;
        !           409:        while (op->op_text) {
        !           410:                if (strcmp(s, op->op_text) == 0)
        !           411:                        return op->op_type == BINOP &&
        !           412:                            (t[0] != ')' || t[1] != '\0');
        !           413:                op++;
        !           414:        }
        !           415:        return 0;
        !           416: }
        !           417:
        !           418: /* atoi with error detection */
        !           419: static int
        !           420: getn(const char *s)
        !           421: {
        !           422:        char *p;
        !           423:        long r;
        !           424:
        !           425:        errno = 0;
        !           426:        r = strtol(s, &p, 10);
        !           427:
        !           428:        if (errno != 0)
        !           429:              error("%s: out of range", s);
        !           430:
        !           431:        while (isspace((unsigned char)*p))
        !           432:              p++;
        !           433:
        !           434:        if (*p)
        !           435:              error("%s: bad number", s);
        !           436:
        !           437:        return (int) r;
        !           438: }
        !           439:
        !           440: static int
        !           441: newerf(const char *f1, const char *f2)
        !           442: {
        !           443:        struct stat b1, b2;
        !           444:
        !           445:        return (stat(f1, &b1) == 0 &&
        !           446:                stat(f2, &b2) == 0 &&
        !           447:                b1.st_mtime > b2.st_mtime);
        !           448: }
        !           449:
        !           450: static int
        !           451: olderf(const char *f1, const char *f2)
        !           452: {
        !           453:        struct stat b1, b2;
        !           454:
        !           455:        return (stat(f1, &b1) == 0 &&
        !           456:                stat(f2, &b2) == 0 &&
        !           457:                b1.st_mtime < b2.st_mtime);
        !           458: }
        !           459:
        !           460: static int
        !           461: equalf(const char *f1, const char *f2)
        !           462: {
        !           463:        struct stat b1, b2;
        !           464:
        !           465:        return (stat(f1, &b1) == 0 &&
        !           466:                stat(f2, &b2) == 0 &&
        !           467:                b1.st_dev == b2.st_dev &&
        !           468:                b1.st_ino == b2.st_ino);
        !           469: }

CVSweb