Use strtonum and libutf in test(1), refactor code and manpage

and mark it as finished in README.
This commit is contained in:
FRIGN 2015-02-09 22:21:23 +01:00
parent 856c79e242
commit 360a63769c
5 changed files with 100 additions and 101 deletions

2
README
View File

@ -67,7 +67,7 @@ The following tools are implemented ('*' == finished, '#' == UTF-8 support,
=* tail yes none =* tail yes none
=* tar non-posix none =* tar non-posix none
=* tee yes none =* tee yes none
test yes none #* test yes none
=* touch yes none =* touch yes none
#* tr yes none #* tr yes none
=* true yes none =* true yes none

View File

@ -67,13 +67,19 @@ strtonum(const char *numstr, long long minval, long long maxval,
} }
long long long long
estrtonum(const char *numstr, long long minval, long long maxval) enstrtonum(int status, const char *numstr, long long minval, long long maxval)
{ {
const char *errstr; const char *errstr;
long long ll; long long ll;
ll = strtonum(numstr, minval, maxval, &errstr); ll = strtonum(numstr, minval, maxval, &errstr);
if (errstr) if (errstr)
eprintf("strtonum %s: %s\n", numstr, errstr); enprintf(status, "strtonum %s: %s\n", numstr, errstr);
return ll; return ll;
} }
long long
estrtonum(const char *numstr, long long minval, long long maxval)
{
return enstrtonum(1, numstr, minval, maxval);
}

131
test.1
View File

@ -1,75 +1,76 @@
.Dd January 30, 2015 .Dd February 9, 2015
.Dt TEST 1 .Dt TEST 1
.Os sbase .Os sbase
.Sh NAME .Sh NAME
.Nm test .Nm test
.Nd check file types and compare values .Nd evaluate expression
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Ar EXPRESSION .Ar expression
.Sh DESCRIPTION .Sh DESCRIPTION
Exit with the status determined by .Nm
.Ar EXPRESSION . returns the status of the
.Ar expression .
.Sh OPTIONS .Sh OPTIONS
.Bl -tag -width Ds .Bl -tag -width Ds
.It ! Ar EXPRESSION .It Sy ! Ar expression
invert EXPRESSION .Sy invert
.It Fl b Ar FILE .Ar expression .
FILE exists and is block special .It Sy -(e | s) Ar file
.It Fl c Ar FILE .Ar file
FILE exists and is character special .Sy exists
.It Fl d Ar FILE and has
FILE exists and is a directory .Sy arbitrary size | size greater than zero .
.It Fl e Ar FILE .It Sy -(f | d | p | hL | S | b | c) Ar file
FILE exists .Ar file
.It Fl f Ar FILE .Sy exists
FILE exists and is a regular file and is
.It Fl g Ar FILE .Sy regular file | directory | named pipe | symbolic link | socket | block special | character special .
FILE exists and is set-group-ID .It Sy -(k | g | u | r | w | x) Ar file
.It Fl h Ar FILE .Ar file
FILE exists and is a symbolic link (same as .Sy exists
.Fl L ) and is
.It Fl k Ar FILE .Sy sticky(1) | setgid(2) | setuid(4) | readable | writable | executable (or searchable) .
FILE exists and its sticky bit is set .It Fl t Ar fd
.It Fl L Ar FILE .Ar fd
FILE exists and is a symbolic link (same as as a file descriptor is
.Fl h ) .Sy associated with a terminal .
.It Fl n Ar STRING .It Ar string
the length of STRING is nonzero True if
.It Fl p Ar FILE .Ar string
FILE exists and is a named pipe is
.It Fl r Ar FILE .Sy not the null string .
FILE exists and read permission is granted .It Sy -(z | n) Ar string
.It Fl S Ar FILE True if
FILE exists and is a socket .Ar string
.It Fl s Ar FILE has
FILE exists and has a size greater than zero .Sy zero | non-zero
.It Fl t Ar FD length.
file descriptor FD is opened on a terminal .It Ar s1 Sy (= | !=) Ar s2
.It Fl u Ar FILE True if strings
exists and its set-user-ID bit is set .Ar s1
.It Fl w Ar FILE and
FILE exists and write permission is granted .Ar s2
.It Fl x Ar FILE are
FILE exists and execute (or search) permission is granted .Sy identical | different .
.It Fl z Ar STRING .It Ar n1 Sy -(eq | ne | gt | ge | le | lt) Ar n2
the length of STRING is zero True if integers
.It s1 = s2 .Ar n1
True if the strings s1 and s2 are identical and
.It s1 != s2 .Ar n2
True if the strings s1 and s2 are not identical are
.It s1 .Sy = | != | > | >= | <= | < .
True if s1 is not the null string .Sh EXIT STATUS
.It n1 -eq n2 .Bl -tag -width Ds
True if the integers n1 and n2 are equal .It 0
.It n1 -ne n2 .Ar expression
True if the integers n1 and n2 are not equal is true.
.It n1 -gt n2 .It 1
True if the integer n1 is greater than the integer n2 .Ar expression
.It n1 -ge n2 is false.
True if the integer n1 is great than or equal to the integer n2 .It > 1
.It n1 -lt n2 An error occurred.
True if the integer n1 is less than the integer n2
.It n1 -le n2
True if the integer n1 is less than or equal to the integer n2
.El .El
.Sh SEE ALSO
.Xr expr 1
.Sh STANDARDS

57
test.c
View File

@ -1,22 +1,14 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
#include <errno.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include "utf.h"
#include "util.h" #include "util.h"
static void #define STOI(s) enstrtonum(2, s, LLONG_MIN, LLONG_MAX)
stoi(char *s, int *a)
{
char *p;
errno = 0;
*a = strtol(s, &p, 0);
if (errno || !*s || *p)
enprintf(2, "bad integer %s\n", s);
}
static int unary_b(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISBLK (buf.st_mode); } static int unary_b(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISBLK (buf.st_mode); }
static int unary_c(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISCHR (buf.st_mode); } static int unary_c(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISCHR (buf.st_mode); }
@ -29,32 +21,32 @@ static int unary_S(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; ret
static int unary_s(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return buf.st_size ; } static int unary_s(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return buf.st_size ; }
static int unary_u(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISUID & buf.st_mode ; } static int unary_u(char *s) { struct stat buf; if ( stat(s, &buf)) return 0; return S_ISUID & buf.st_mode ; }
static int unary_n(char *s) { return strlen(s); } static int unary_n(char *s) { return utflen(s); }
static int unary_z(char *s) { return !strlen(s); } static int unary_z(char *s) { return !utflen(s); }
static int unary_e(char *s) { return access(s, F_OK); } static int unary_e(char *s) { return access(s, F_OK); }
static int unary_r(char *s) { return access(s, R_OK); } static int unary_r(char *s) { return access(s, R_OK); }
static int unary_w(char *s) { return access(s, W_OK); } static int unary_w(char *s) { return access(s, W_OK); }
static int unary_x(char *s) { return access(s, X_OK); } static int unary_x(char *s) { return access(s, X_OK); }
static int unary_t(char *s) { int fd; stoi(s, &fd); return isatty(fd); } static int unary_t(char *s) { int fd = enstrtonum(2, s, 0, INT_MAX); return isatty(fd); }
static int binary_se(char *s1, char *s2) { return strcmp(s1, s2) == 0; } static int binary_se(char *s1, char *s2) { return strcmp(s1, s2) == 0; }
static int binary_sn(char *s1, char *s2) { return strcmp(s1, s2) != 0; } static int binary_sn(char *s1, char *s2) { return strcmp(s1, s2) != 0; }
static int binary_eq(char *s1, char *s2) { int a, b; stoi(s1, &a); stoi(s2, &b); return a == b; } static int binary_eq(char *s1, char *s2) { long long a = STOI(s1), b = STOI(s2); return a == b; }
static int binary_ne(char *s1, char *s2) { int a, b; stoi(s1, &a); stoi(s2, &b); return a != b; } static int binary_ne(char *s1, char *s2) { long long a = STOI(s1), b = STOI(s2); return a != b; }
static int binary_gt(char *s1, char *s2) { int a, b; stoi(s1, &a); stoi(s2, &b); return a > b; } static int binary_gt(char *s1, char *s2) { long long a = STOI(s1), b = STOI(s2); return a > b; }
static int binary_ge(char *s1, char *s2) { int a, b; stoi(s1, &a); stoi(s2, &b); return a >= b; } static int binary_ge(char *s1, char *s2) { long long a = STOI(s1), b = STOI(s2); return a >= b; }
static int binary_lt(char *s1, char *s2) { int a, b; stoi(s1, &a); stoi(s2, &b); return a < b; } static int binary_lt(char *s1, char *s2) { long long a = STOI(s1), b = STOI(s2); return a < b; }
static int binary_le(char *s1, char *s2) { int a, b; stoi(s1, &a); stoi(s2, &b); return a <= b; } static int binary_le(char *s1, char *s2) { long long a = STOI(s1), b = STOI(s2); return a <= b; }
typedef struct { struct test {
char *name; char *name;
int (*func)(); int (*func)();
} Test; };
static Test unary[] = { static struct test unary[] = {
{ "-b", unary_b }, { "-b", unary_b },
{ "-c", unary_c }, { "-c", unary_c },
{ "-d", unary_d }, { "-d", unary_d },
@ -77,7 +69,7 @@ static Test unary[] = {
{ NULL, NULL }, { NULL, NULL },
}; };
static Test binary[] = { static struct test binary[] = {
{ "=" , binary_se }, { "=" , binary_se },
{ "!=" , binary_sn }, { "!=" , binary_sn },
{ "-eq", binary_eq }, { "-eq", binary_eq },
@ -90,10 +82,10 @@ static Test binary[] = {
{ NULL, NULL }, { NULL, NULL },
}; };
static Test * static struct test *
find_test(Test *tests, char *name) find_test(struct test *tests, char *name)
{ {
Test *t; struct test *t;
for (t = tests; t->name; ++t) for (t = tests; t->name; ++t)
if (strcmp(t->name, name) == 0) if (strcmp(t->name, name) == 0)
@ -116,7 +108,7 @@ onearg(char **argv)
static int static int
twoarg(char **argv) twoarg(char **argv)
{ {
Test *t = find_test(unary, *argv); struct test *t = find_test(unary, *argv);
if (strcmp(argv[0], "!") == 0) if (strcmp(argv[0], "!") == 0)
return !onearg(argv + 1); return !onearg(argv + 1);
@ -130,7 +122,7 @@ twoarg(char **argv)
static int static int
threearg(char **argv) threearg(char **argv)
{ {
Test *t = find_test(binary, argv[1]); struct test *t = find_test(binary, argv[1]);
if (t) if (t)
return t->func(argv[0], argv[2]); return t->func(argv[0], argv[2]);
@ -154,11 +146,10 @@ int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int (*narg[])(char**) = { noarg, onearg, twoarg, threearg, fourarg }; int (*narg[])(char**) = { noarg, onearg, twoarg, threearg, fourarg };
int len = strlen(argv[0]); size_t len = strlen(argv[0]);
if (len && argv[0][len - 1] == '[') if (len && argv[0][len - 1] == '[' && strcmp(argv[--argc], "]") != 0)
if (strcmp(argv[--argc], "]") != 0) enprintf(2, "no matching ]\n");
enprintf(2, "no matching ]\n");
--argc; ++argv; --argc; ++argv;

1
util.h
View File

@ -57,5 +57,6 @@ void putword(const char *);
void recurse(const char *, void (*)(const char *)); void recurse(const char *, void (*)(const char *));
#undef strtonum #undef strtonum
long long strtonum(const char *, long long, long long, const char **); long long strtonum(const char *, long long, long long, const char **);
long long enstrtonum(int, const char *, long long, long long);
long long estrtonum(const char *, long long, long long); long long estrtonum(const char *, long long, long long);
size_t unescape(char *); size_t unescape(char *);