- debloat test. untested. text data bss dec hex filename 3154 0 172 3326 cfe test.o.oorig 2683 0 172 2855 b27 test.o
No binary (build failed)
—
(log yok)
| @@ -12,6 +12,7 @@ | |
| * modified by Herbert Xu to be used as built-in in ash. | |
| * modified by Erik Andersen <[email protected]> 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; | |