#define _POSIX_C_SOURCE 200809L #include #include #include #include #include int unary_b(char *s) { struct stat buf; if ( stat(s, &buf)) return 1; return !(S_ISBLK (buf.st_mode)); } int unary_c(char *s) { struct stat buf; if ( stat(s, &buf)) return 1; return !(S_ISCHR (buf.st_mode)); } int unary_d(char *s) { struct stat buf; if ( stat(s, &buf)) return 1; return !(S_ISDIR (buf.st_mode)); } int unary_e(char *s) { struct stat buf; if ( stat(s, &buf)) return 1; return !( 1); } int unary_f(char *s) { struct stat buf; if ( stat(s, &buf)) return 1; return !(S_ISREG (buf.st_mode)); } int unary_g(char *s) { struct stat buf; if ( stat(s, &buf)) return 1; return !(S_ISGID & buf.st_mode ); } int unary_h(char *s) { struct stat buf; if (lstat(s, &buf)) return 1; return !(S_ISLNK (buf.st_mode)); } int unary_p(char *s) { struct stat buf; if ( stat(s, &buf)) return 1; return !(S_ISFIFO (buf.st_mode)); } int unary_S(char *s) { struct stat buf; if ( stat(s, &buf)) return 1; return !(S_ISSOCK (buf.st_mode)); } int unary_s(char *s) { struct stat buf; if ( stat(s, &buf)) return 1; return !( buf.st_size ); } int unary_u(char *s) { struct stat buf; if ( stat(s, &buf)) return 1; return !(S_ISUID & buf.st_mode ); } int unary_n(char *s) { return ! strlen(s); } int unary_z(char *s) { return !!strlen(s); } int unary_r(char *s) { return !!access(s, R_OK); } int unary_w(char *s) { return !!access(s, W_OK); } int unary_x(char *s) { return !!access(s, X_OK); } int unary_t(char *s) { char *p; int fd = strtol(s, &p, 0); if (!*s || *p) return 0; return !isatty(fd); } int binary_se(char *s1, char *s2) { return !!strcmp(s1, s2); } int binary_sn(char *s1, char *s2) { return ! strcmp(s1, s2); } int two_nums(char *s1, char *s2, int *a, int *b) { char *p, *q; *a = strtol(s1, &p, 0); *b = strtol(s2, &q, 0); if (!*s1 || *p || !*s2 || *q) return -1; return 0; } int binary_eq(char *s1, char *s2) { int a, b; if (two_nums(s1, s2, &a, &b)) return 2; return !(a == b); } int binary_ne(char *s1, char *s2) { int a, b; if (two_nums(s1, s2, &a, &b)) return 2; return !(a != b); } int binary_gt(char *s1, char *s2) { int a, b; if (two_nums(s1, s2, &a, &b)) return 2; return !(a > b); } int binary_ge(char *s1, char *s2) { int a, b; if (two_nums(s1, s2, &a, &b)) return 2; return !(a >= b); } int binary_lt(char *s1, char *s2) { int a, b; if (two_nums(s1, s2, &a, &b)) return 2; return !(a < b); } int binary_le(char *s1, char *s2) { int a, b; if (two_nums(s1, s2, &a, &b)) return 2; return !(a <= b); } typedef struct { char *name; int (*func)(); } Test; Test unary[] = { { "-b" , unary_b}, { "-c" , unary_c}, { "-d" , unary_d}, { "-e" , unary_e}, { "-f" , unary_f}, { "-g" , unary_g}, { "-h" , unary_h}, { "-L" , unary_h}, { "-n" , unary_n}, { "-p" , unary_p}, { "-r" , unary_r}, { "-S" , unary_S}, { "-s" , unary_s}, { "-t" , unary_t}, { "-u" , unary_u}, { "-w" , unary_w}, { "-x" , unary_x}, { "-z" , unary_z}, { NULL, NULL }, }; Test binary[] = { { "=" , binary_se }, { "!=" , binary_sn }, { "-eq", binary_eq }, { "-ne", binary_ne }, { "-gt", binary_gt }, { "-ge", binary_ge }, { "-lt", binary_lt }, { "-le", binary_le }, { NULL, NULL }, }; Test *find_test(Test *tests, char *name) { for (Test *t = tests; t->name; ++t) if (!strcmp(t->name, name)) return t; return NULL; } int noarg(char **argv) { return 1; } int onearg(char **argv) { return !strlen(*argv); } int twoarg(char **argv) { if (!strcmp(*argv, "!")) return !onearg(argv + 1); Test *t = find_test(unary, *argv); if (t) return t->func(argv[1]); return 2; } int threearg(char **argv) { Test *t = find_test(binary, argv[1]); if (t) return t->func(argv[0], argv[2]); if (!strcmp(*argv, "!")) return !twoarg(argv + 1); return 2; } int fourarg(char **argv) { if (!strcmp(*argv, "!")) return !threearg(argv + 1); return 2; } int (*nargs[])(char**) = { [0] = noarg, [1] = onearg, [2] = twoarg, [3] = threearg, [4] = fourarg, }; int main(int argc, char **argv) { if (argv[0][strlen(argv[0]) - 1] == '[') { if (strcmp(argv[--argc], "]")) return 2; argv[argc] = NULL; } --argc; ++argv; if (argc > 4) return 2; return nargs[argc](argv); }