diff options
-rw-r--r-- | toys/pending/test.c | 225 |
1 files changed, 164 insertions, 61 deletions
diff --git a/toys/pending/test.c b/toys/pending/test.c index c03e4502..e64ebf14 100644 --- a/toys/pending/test.c +++ b/toys/pending/test.c @@ -27,7 +27,7 @@ config TEST --- Tests with one argument on each side of an operator: Two strings: - = are identical != differ + = are identical != differ Two integers: -eq equal -gt first > second -lt first < second -ne not equal -ge first >= second -le first <= second @@ -39,76 +39,179 @@ config TEST #include "toys.h" -void test_main(void) +int get_stat(struct stat *st, int *link, char* s) { - int id, not; - char *s, *err_fmt = "Bad flag '%s'"; + if (lstat(s, st) == -1) return 0; + *link = S_ISLNK(st->st_mode); + if (*link && (stat(s, st) == -1)) return 0; + return 1; +} - 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--; +// basic expression without !, -o, -a, ( +int test_basic(int optb, int opte) +{ + int id, val; + char *s, *err_fmt = "Bad flag '%s'", *err_int = "Bad integer '%s'"; + + if (optb == opte) val = 0; + else if (optb + 1 == opte) val = !!*toys.optargs[optb]; + else if (optb + 2 == opte && toys.optargs[optb][0] == '-') { + char c = toys.optargs[optb][1]; + struct stat st; + int link; + + if (!c || toys.optargs[optb][2]) error_exit(err_fmt, toys.optargs[optb]); + s = toys.optargs[optb + 1]; + if (c == 'b') val = get_stat(&st, &link, s) && S_ISBLK(st.st_mode); + else if (c == 'c') val = get_stat(&st, &link, s) && S_ISCHR(st.st_mode); + else if (c == 'd') val = get_stat(&st, &link, s) && S_ISDIR(st.st_mode); + else if (c == 'e') val = get_stat(&st, &link, s); + else if (c == 'f') val = get_stat(&st, &link, s) && S_ISREG(st.st_mode); + else if (c == 'g') val = get_stat(&st, &link, s) && (st.st_mode & S_ISGID); + else if (c == 'h' || c == 'L') val = get_stat(&st, &link, s) && link; + else if (c == 'p') val = get_stat(&st, &link, s) && S_ISFIFO(st.st_mode); + else if (c == 'S') val = get_stat(&st, &link, s) && S_ISSOCK(st.st_mode); + else if (c == 's') val = get_stat(&st, &link, s) && st.st_size != 0; + else if (c == 'u') val = get_stat(&st, &link, s) && (st.st_mode & S_ISUID); + else if (c == 'r') val = access(s, R_OK) != -1; + else if (c == 'w') val = access(s, W_OK) != -1; + else if (c == 'x') val = access(s, X_OK) != -1; + else if (c == 'z') val = !*s; + else if (c == 'n') val = !!*s; + else if (c == 't') { + struct termios termios; + val = tcgetattr(atoi(s), &termios) != -1; + } + else error_exit(err_fmt, toys.optargs[optb]); } - 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 (optb + 3 == opte) { + if (*toys.optargs[optb + 1] == '-') { + char *end_a, *end_b; + long a, b; + int errno_a, errno_b; + + errno = 0; + a = strtol(toys.optargs[optb], &end_a, 10); + errno_a = errno; + b = strtol(toys.optargs[optb + 2], &end_b, 10); + errno_b = errno; + s = toys.optargs[optb + 1] + 1; + if (!strcmp("eq", s)) val = a == b; + else if (!strcmp("ne", s)) val = a != b; + else if (!strcmp("gt", s)) val = a > b; + else if (!strcmp("ge", s)) val = a >= b; + else if (!strcmp("lt", s)) val = a < b; + else if (!strcmp("le", s)) val = a <= b; + else error_exit(err_fmt, toys.optargs[optb + 1]); + if (!*toys.optargs[optb] || *end_a || errno_a) + error_exit(err_int, toys.optargs[optb]); + if (!*toys.optargs[optb + 2] || *end_b || errno_b) + error_exit(err_int, toys.optargs[optb + 2]); } - 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 { + int result = strcmp(toys.optargs[optb], toys.optargs[optb + 2]); + + s = toys.optargs[optb + 1]; + if (!strcmp("=", s)) val = !result; + else if (!strcmp("!=", s)) val = !!result; + else error_exit(err_fmt, toys.optargs[optb + 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 error_exit("Syntax error"); + + return val; +} + +int test_sub(int optb, int opte) +{ + int not, and = 1, or = 0, i, expr; + char *err_syntax = "Syntax error"; + + for (;;) { + not = 0; + while (optb < opte && !strcmp("!", toys.optargs[optb])) { + not = !not; + optb++; + } + if (optb < opte && !strcmp("(", toys.optargs[optb])) { + int par = 1; + + for (i = optb + 1; par && i < opte; i++) { + if (!strcmp(")", toys.optargs[i])) par--; + else if (!strcmp("(", toys.optargs[i])) par++; + } + if (par) error_exit("Missing ')'"); + expr = not ^ test_sub(optb + 1, i - 1); + optb = i; } else { - int result = strcmp(toys.optargs[0], toys.optargs[2]); + for (i = 0; i < 4; ++i) { + if (optb + i == opte || !strcmp("-a", toys.optargs[optb + i]) + || !strcmp("-o", toys.optargs[optb + i])) break; + } + if (i == 4) error_exit(err_syntax); + expr = not ^ test_basic(optb, optb + i); + optb += i; + } - 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]); + if (optb == opte) { + return or || (and && expr); + } + else if (!strcmp("-o", toys.optargs[optb])) { + or = or || (and && expr); + and = 1; + optb++; + } + else if (!strcmp("-a", toys.optargs[optb])) { + and = and && expr; + optb++; } + else error_exit(err_syntax); + } +} + +int test_few_args(int optb, int opte) +{ + if (optb == opte) return 0; + else if (optb + 1 == opte) return !!*toys.optargs[optb]; + else if (optb + 2 == opte) { + if (!strcmp("!", toys.optargs[optb])) return !*toys.optargs[optb + 1]; + else if (toys.optargs[optb][0] == '-' && + stridx("bcdefghLpSsurwxznt", toys.optargs[optb][1]) != -1 && + !toys.optargs[optb][2]) return test_basic(optb, opte); } - toys.exitval ^= not; + else if (optb + 3 == opte) { + if (!strcmp("-eq", toys.optargs[optb + 1]) || + !strcmp("-ne", toys.optargs[optb + 1]) || + !strcmp("-gt", toys.optargs[optb + 1]) || + !strcmp("-ge", toys.optargs[optb + 1]) || + !strcmp("-lt", toys.optargs[optb + 1]) || + !strcmp("-le", toys.optargs[optb + 1]) || + !strcmp("=", toys.optargs[optb + 1]) || + !strcmp("!=", toys.optargs[optb + 1])) return test_basic(optb, opte); + else if (!strcmp("!", toys.optargs[optb])) + return !test_few_args(optb + 1, opte); + else if (!strcmp("(", toys.optargs[optb]) && + !strcmp(")", toys.optargs[optb + 2])) + return !!*toys.optargs[optb + 1]; + } + else { + if (!strcmp("!", toys.optargs[optb])) return !test_few_args(optb + 1, opte); + else if (!strcmp("(", toys.optargs[optb]) && + !strcmp(")", toys.optargs[optb + 3])) + return test_few_args(optb + 1, opte - 1); + } + return test_sub(optb, opte); +} + +void test_main(void) +{ + int optc = toys.optc; + + toys.exitval = 2; + if (!strcmp("[", toys.which->name)) + if (!optc || strcmp("]", toys.optargs[--optc])) error_exit("Missing ']'"); + if (optc <= 4) toys.exitval = !test_few_args(0, optc); + else toys.exitval = !test_sub(0, optc); return; } |