114 lines
4 KiB
C
114 lines
4 KiB
C
/* test.c - evaluate expression
|
|
*
|
|
* Copyright 2013 Rob Landley <rob@landley.net>
|
|
*
|
|
* See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
|
|
|
|
USE_TEST(NEWTOY(test, NULL, TOYFLAG_USR|TOYFLAG_BIN))
|
|
|
|
config TEST
|
|
bool "test"
|
|
default n
|
|
help
|
|
usage: test [-bcdefghLPrSsuwx PATH] [-nz STRING] [-t FD] [X ?? Y]
|
|
|
|
Return true or false by performing tests. (With no arguments return false.)
|
|
|
|
--- Tests with a single argument (after the option):
|
|
PATH is/has:
|
|
-b block device -f regular file -p fifo -u setuid bit
|
|
-c char device -g setgid -r read bit -w write bit
|
|
-d directory -h symlink -S socket -x execute bit
|
|
-e exists -L symlink -s nonzero size
|
|
STRING is:
|
|
-n nonzero size -z zero size (STRING by itself implies -n)
|
|
FD (integer file descriptor) is:
|
|
-t a TTY
|
|
|
|
--- Tests with one argument on each side of an operator:
|
|
Two strings:
|
|
= are identical != differ
|
|
Two integers:
|
|
-eq equal -gt first > second -lt first < second
|
|
-ne not equal -ge first >= second -le first <= second
|
|
|
|
--- Modify or combine tests:
|
|
! EXPR not (swap true/false) EXPR -a EXPR and (are both true)
|
|
( EXPR ) evaluate this first EXPR -o EXPR or (is either true)
|
|
*/
|
|
|
|
#include "toys.h"
|
|
|
|
void test_main(void)
|
|
{
|
|
int id, not;
|
|
char *s, *err_fmt = "Bad flag '%s'";
|
|
|
|
toys.exitval = 2;
|
|
if (!strcmp("[", toys.which->name))
|
|
if (!strcmp("]", toys.optargs[--toys.optc])) error_exit("Missing ']'");
|
|
if (!strcmp("!", toys.optargs[0])) {
|
|
not = 1;
|
|
toys.optargs++;
|
|
toys.optc--;
|
|
}
|
|
if (!toys.optc) toys.exitval = 0;
|
|
else if (toys.optargs[0][0] == '-') {
|
|
id = stridx("bcdefghLpSsurwxznt", toys.optargs[0][1]);
|
|
if (id == -1 || toys.optargs[0][2]) error_exit(err_fmt, toys.optargs[0]);
|
|
if (id < 12) {
|
|
struct stat st;
|
|
int nolink;
|
|
|
|
toys.exitval = 1;
|
|
if (lstat(toys.optargs[1], &st) == -1) return;
|
|
nolink = !S_ISLNK(st.st_mode);
|
|
if (!nolink && (stat(toys.optargs[1], &st) == -1)) return;
|
|
|
|
if (id == 0) toys.exitval = !S_ISBLK(st.st_mode); // b
|
|
else if (id == 1) toys.exitval = !S_ISCHR(st.st_mode); // c
|
|
else if (id == 2) toys.exitval = !S_ISDIR(st.st_mode); // d
|
|
else if (id == 3) toys.exitval = 0; // e
|
|
else if (id == 4) toys.exitval = !S_ISREG(st.st_mode); // f
|
|
else if (id == 5) toys.exitval = !(st.st_mode & S_ISGID); // g
|
|
else if ((id == 6) || (id == 7)) toys.exitval = nolink; // hL
|
|
else if (id == 8) toys.exitval = !S_ISFIFO(st.st_mode); // p
|
|
else if (id == 9) toys.exitval = !S_ISSOCK(st.st_mode); // S
|
|
else if (id == 10) toys.exitval = st.st_size == 0; // s
|
|
else toys.exitval = !(st.st_mode & S_ISUID); // u
|
|
}
|
|
else if (id < 15) // rwx
|
|
toys.exitval = access(toys.optargs[1], 1 << (id - 12)) == -1;
|
|
else if (id < 17) // zn
|
|
toys.exitval = toys.optargs[1] && !*toys.optargs[1] ^ (id - 15);
|
|
else { // t
|
|
struct termios termios;
|
|
toys.exitval = tcgetattr(atoi(toys.optargs[1]), &termios) == -1;
|
|
}
|
|
}
|
|
else if (toys.optc == 1) toys.exitval = *toys.optargs[0] == 0;
|
|
else if (toys.optc == 3) {
|
|
if (*toys.optargs[1] == '-') {
|
|
long a = atol(toys.optargs[0]), b = atol(toys.optargs[2]);
|
|
|
|
s = toys.optargs[1] + 1;
|
|
if (!strcmp("eq", s)) toys.exitval = a != b;
|
|
else if (!strcmp("ne", s)) toys.exitval = a == b;
|
|
else if (!strcmp("gt", s)) toys.exitval = a < b;
|
|
else if (!strcmp("ge", s)) toys.exitval = a <= b;
|
|
else if (!strcmp("lt", s)) toys.exitval = a > b;
|
|
else if (!strcmp("le", s)) toys.exitval = a >= b;
|
|
else error_exit(err_fmt, toys.optargs[1]);
|
|
}
|
|
else {
|
|
int result = strcmp(toys.optargs[0], toys.optargs[2]);
|
|
|
|
s = toys.optargs[1];
|
|
if (!strcmp("=", s)) toys.exitval = !!result;
|
|
else if (!strcmp("!=", s)) toys.exitval = !result;
|
|
else error_exit(err_fmt, toys.optargs[1]);
|
|
}
|
|
}
|
|
toys.exitval ^= not;
|
|
return;
|
|
}
|