After looking at the sbase TODO I threw together test(1). As far as I
can tell it's POSIX compliant. I used the POSIX description[0] to
write it. It exits 0 for true, 1 for false, and 2 for bad input. Let
me know what's good and what's bad. I'll work on addresing those
concerns and getting it into sbase format so I can submit a patch.
It specifically doesn't support parentheses and the -o and -a flags as
1) they are obsolete xsi extensions[1]
2) boolean operators are and should be handled by the shell. e.g. [
foo = bar ] || [ 4 -lt 5 ]
-emg
[0] http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
[1] http://pubs.opengroup.org/onlinepubs/9699919799/help/codes.html#OB XSI
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
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);
}