[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

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