- debloat test. untested.
text data bss dec hex filename 3154 0 172 3326 cfe test.o.oorig 2683 0 172 2855 b27 test.o This applet should be rewritten not to use such odd lexer semantics. It duplicates code from all over the place (see XXX). brrr
This commit is contained in:
parent
eceecea568
commit
cc890264d9
211
coreutils/test.c
211
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';
|
||||
}
|
||||
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];
|
||||
_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 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,17 +294,15 @@ 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) {
|
||||
return 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;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return 1;
|
||||
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;
|
||||
}
|
||||
/* 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:
|
||||
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;
|
||||
goto filetype;
|
||||
case FILDIR:
|
||||
if (mode == FILDIR)
|
||||
i = S_IFDIR;
|
||||
goto filetype;
|
||||
case FILCDEV:
|
||||
if (mode == FILCDEV)
|
||||
i = S_IFCHR;
|
||||
goto filetype;
|
||||
case FILBDEV:
|
||||
if (mode == FILBDEV)
|
||||
i = S_IFBLK;
|
||||
goto filetype;
|
||||
case FILFIFO:
|
||||
if (mode == FILFIFO) {
|
||||
#ifdef S_IFIFO
|
||||
i = S_IFIFO;
|
||||
goto filetype;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
case FILSOCK:
|
||||
}
|
||||
if (mode == FILSOCK) {
|
||||
#ifdef S_IFSOCK
|
||||
i = S_IFSOCK;
|
||||
goto filetype;
|
||||
#else
|
||||
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:
|
||||
return s.st_size > 0L;
|
||||
case FILUID:
|
||||
return s.st_uid == geteuid();
|
||||
case FILGID:
|
||||
return s.st_gid == getegid();
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
filetype:
|
||||
filetype:
|
||||
return ((s.st_mode & S_IFMT) == i);
|
||||
|
||||
filebit:
|
||||
}
|
||||
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;
|
||||
else if (mode == FILUID)
|
||||
return s.st_uid == geteuid();
|
||||
else if (mode == FILGID)
|
||||
return s.st_gid == getegid();
|
||||
else
|
||||
return 1; /* NOTREACHED */
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user