| /* 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; |
| } |