diff options
-rw-r--r-- | coreutils/test.c | 227 |
1 files changed, 116 insertions, 111 deletions
diff --git a/coreutils/test.c b/coreutils/test.c index 6e0d5d38e..813cde47c 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -12,6 +12,7 @@ * modified by Herbert Xu to be used as built-in in ash. * modified by Erik Andersen <andersen@codepoet.org> to be used * in busybox. + * modified by Bernhard Fischer to be useable (i.e. a bit less bloaty). * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * @@ -85,7 +86,12 @@ enum token { RPAREN, OPERAND }; - +#define __is_int_op(a) (((unsigned char)((a) - INTEQ)) <= 5) +#define __is_str_op(a) (((unsigned char)((a) - STREZ)) <= 5) +#define __is_file_op(a) (((unsigned char)((a) - FILNT)) <= 2) +#define __is_file_access(a) (((unsigned char)((a) - FILRD)) <= 2) +#define __is_file_type(a) (((unsigned char)((a) - FILREG)) <= 5) +#define __is_file_bit(a) (((unsigned char)((a) - FILSUID)) <= 2) enum token_types { UNOP, BINOP, @@ -95,8 +101,8 @@ enum token_types { }; static const struct t_op { - const char *op_text; - short op_num, op_type; + const char * const op_text; + unsigned char op_num, op_type; } ops[] = { { "-r", FILRD, UNOP}, { @@ -206,34 +212,21 @@ int bb_test(int argc, char **argv) ngroups = 0; /* Implement special cases from POSIX.2, section 4.62.4 */ - switch (argc) { - case 1: + if (argc == 1) return 1; - case 2: + if (argc == 2) return *argv[1] == '\0'; - case 3: - if (argv[1][0] == '!' && argv[1][1] == '\0') { +//assert(argc); + if (LONE_CHAR(argv[1], '!')) { + bool _off; + if (argc == 3) return *argv[2] != '\0'; + _off = argc - 4; + if (t_lex(argv[2+_off]), t_wp_op && t_wp_op->op_type == BINOP) { + t_wp = &argv[1+_off]; + return binop() == 0; } - break; - case 4: - if (argv[1][0] != '!' || argv[1][1] != '\0') { - if (t_lex(argv[2]), t_wp_op && t_wp_op->op_type == BINOP) { - t_wp = &argv[1]; - return binop() == 0; - } - } - break; - case 5: - if (argv[1][0] == '!' && argv[1][1] == '\0') { - if (t_lex(argv[3]), t_wp_op && t_wp_op->op_type == BINOP) { - t_wp = &argv[2]; - return binop() != 0; - } - } - break; } - t_wp = &argv[1]; res = !oexpr(t_lex(*t_wp)); @@ -301,16 +294,14 @@ static arith_t primary(enum token n) /* unary expression */ if (*++t_wp == NULL) syntax(t_wp_op->op_text, "argument expected"); - switch (n) { - case STREZ: + if (n == STREZ) return strlen(*t_wp) == 0; - case STRNZ: + else if (n == STRNZ) return strlen(*t_wp) != 0; - case FILTT: + else if (n == FILTT) return isatty(getn(*t_wp)); - default: + else return filstat(*t_wp, n); - } } if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { @@ -324,6 +315,7 @@ static int binop(void) { const char *opnd1, *opnd2; struct t_op const *op; + smallint val1, val2; opnd1 = *t_wp; (void) t_lex(*++t_wp); @@ -332,42 +324,56 @@ static int binop(void) if ((opnd2 = *++t_wp) == (char *) 0) syntax(op->op_text, "argument expected"); - switch (op->op_num) { - case STREQ: - return strcmp(opnd1, opnd2) == 0; - case STRNE: - return strcmp(opnd1, opnd2) != 0; - case STRLT: - return strcmp(opnd1, opnd2) < 0; - case STRGT: - return strcmp(opnd1, opnd2) > 0; - case INTEQ: - return getn(opnd1) == getn(opnd2); - case INTNE: - return getn(opnd1) != getn(opnd2); - case INTGE: - return getn(opnd1) >= getn(opnd2); - case INTGT: - return getn(opnd1) > getn(opnd2); - case INTLE: - return getn(opnd1) <= getn(opnd2); - case INTLT: - return getn(opnd1) < getn(opnd2); - case FILNT: - return newerf(opnd1, opnd2); - case FILOT: - return olderf(opnd1, opnd2); - case FILEQ: - return equalf(opnd1, opnd2); + if (__is_int_op(op->op_num)) { + val1 = getn(opnd1); + val2 = getn(opnd2); + if (op->op_num == INTEQ) + return val1 == val2; + if (op->op_num == INTNE) + return val1 != val2; + if (op->op_num == INTGE) + return val1 >= val2; + if (op->op_num == INTGT) + return val1 > val2; + if (op->op_num == INTLE) + return val1 <= val2; + if (op->op_num == INTLT) + return val1 < val2; + } + if (__is_str_op(op->op_num)) { + val1 = strcmp(opnd1, opnd2); + if (op->op_num == STREQ) + return val1 == 0; + if (op->op_num == STRNE) + return val1 != 0; + if (op->op_num == STRLT) + return val1 < 0; + if (op->op_num == STRGT) + return val1 > 0; } - /* NOTREACHED */ - return 1; + /* We are sure that these three are by now the only binops we didn't check + * yet, so we do not check if the class is correct: + */ +/* if (__is_file_op(op->op_num)) */ + { + struct stat b1, b2; + + if (!(!stat(opnd1, &b1) && !stat(opnd2, &b2))) + return 0; /* false, since stat failed */ + if (op->op_num == FILNT) + return b1.st_mtime > b2.st_mtime; + if (op->op_num == FILOT) + return b1.st_mtime < b2.st_mtime; + if (op->op_num == FILEQ) + return b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino; + } + return 1; /* NOTREACHED */ } static int filstat(char *nm, enum token mode) { struct stat s; - unsigned int i; + int i; if (mode == FILSYM) { #ifdef S_IFLNK @@ -381,66 +387,61 @@ static int filstat(char *nm, enum token mode) if (stat(nm, &s) != 0) return 0; - - switch (mode) { - case FILRD: - return test_eaccess(nm, R_OK) == 0; - case FILWR: - return test_eaccess(nm, W_OK) == 0; - case FILEX: - return test_eaccess(nm, X_OK) == 0; - case FILEXIST: + if (mode == FILEXIST) return 1; - case FILREG: - i = S_IFREG; - goto filetype; - case FILDIR: - i = S_IFDIR; - goto filetype; - case FILCDEV: - i = S_IFCHR; - goto filetype; - case FILBDEV: - i = S_IFBLK; - goto filetype; - case FILFIFO: + else if (__is_file_access(mode)) { + if (mode == FILRD) + i = R_OK; + if (mode == FILWR) + i = W_OK; + if (mode == FILEX) + i = X_OK; + return test_eaccess(nm, i) == 0; + } + else if (__is_file_type(mode)) { + if (mode == FILREG) + i = S_IFREG; + if (mode == FILDIR) + i = S_IFDIR; + if (mode == FILCDEV) + i = S_IFCHR; + if (mode == FILBDEV) + i = S_IFBLK; + if (mode == FILFIFO) { #ifdef S_IFIFO - i = S_IFIFO; - goto filetype; + i = S_IFIFO; #else - return 0; + return 0; #endif - case FILSOCK: + } + if (mode == FILSOCK) { #ifdef S_IFSOCK - i = S_IFSOCK; - goto filetype; + i = S_IFSOCK; #else - return 0; + return 0; #endif - case FILSUID: - i = S_ISUID; - goto filebit; - case FILSGID: - i = S_ISGID; - goto filebit; - case FILSTCK: - i = S_ISVTX; - goto filebit; - case FILGZ: + } +filetype: + return ((s.st_mode & S_IFMT) == i); + } + else if (__is_file_bit(mode)) { + if (mode == FILSUID) + i = S_ISUID; + if (mode == FILSGID) + i = S_ISGID; + if (mode == FILSTCK) + i = S_ISVTX; + return ((s.st_mode & i) != 0); + } + else if (mode == FILGZ) return s.st_size > 0L; - case FILUID: + else if (mode == FILUID) return s.st_uid == geteuid(); - case FILGID: + else if (mode == FILGID) return s.st_gid == getegid(); - default: - return 1; - } - - filetype: - return ((s.st_mode & S_IFMT) == i); + else + return 1; /* NOTREACHED */ - filebit: - return ((s.st_mode & i) != 0); } static enum token t_lex(char *s) @@ -463,6 +464,7 @@ static enum token t_lex(char *s) } /* atoi with error detection */ +//XXX: FIXME: duplicate of existing libbb function? static arith_t getn(const char *s) { char *p; @@ -556,6 +558,9 @@ static void initialize_group_array(void) } /* Return non-zero if GID is one that we have in our groups list. */ +//XXX: FIXME: duplicate of existing libbb function? +// see toplevel TODO file: +// possible code duplication ingroup() and is_a_group_member() static int is_a_group_member(gid_t gid) { int i; |