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
=* tar non-posix none
=* tee yes none
test yes none
#* test yes none
=* touch yes none
#* tr yes none
=* true yes none

View File

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

55
test.c
View File

@ -1,22 +1,14 @@
/* See LICENSE file for copyright and license details. */
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "utf.h"
#include "util.h"
static void
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);
}
#define STOI(s) enstrtonum(2, s, LLONG_MIN, LLONG_MAX)
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); }
@ -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_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_z(char *s) { return !strlen(s); }
static int unary_n(char *s) { return utflen(s); }
static int unary_z(char *s) { return !utflen(s); }
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_w(char *s) { return access(s, W_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_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_ne(char *s1, char *s2) { int a, b; stoi(s1, &a); stoi(s2, &b); 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_ge(char *s1, char *s2) { int a, b; stoi(s1, &a); stoi(s2, &b); 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_le(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) { long long a = STOI(s1), b = STOI(s2); 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) { long long a = STOI(s1), b = STOI(s2); 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) { long long a = STOI(s1), b = STOI(s2); return a <= b; }
typedef struct {
struct test {
char *name;
int (*func)();
} Test;
};
static Test unary[] = {
static struct test unary[] = {
{ "-b", unary_b },
{ "-c", unary_c },
{ "-d", unary_d },
@ -77,7 +69,7 @@ static Test unary[] = {
{ NULL, NULL },
};
static Test binary[] = {
static struct test binary[] = {
{ "=" , binary_se },
{ "!=" , binary_sn },
{ "-eq", binary_eq },
@ -90,10 +82,10 @@ static Test binary[] = {
{ NULL, NULL },
};
static Test *
find_test(Test *tests, char *name)
static struct test *
find_test(struct test *tests, char *name)
{
Test *t;
struct test *t;
for (t = tests; t->name; ++t)
if (strcmp(t->name, name) == 0)
@ -116,7 +108,7 @@ onearg(char **argv)
static int
twoarg(char **argv)
{
Test *t = find_test(unary, *argv);
struct test *t = find_test(unary, *argv);
if (strcmp(argv[0], "!") == 0)
return !onearg(argv + 1);
@ -130,7 +122,7 @@ twoarg(char **argv)
static int
threearg(char **argv)
{
Test *t = find_test(binary, argv[1]);
struct test *t = find_test(binary, argv[1]);
if (t)
return t->func(argv[0], argv[2]);
@ -154,10 +146,9 @@ int
main(int argc, char **argv)
{
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 (strcmp(argv[--argc], "]") != 0)
if (len && argv[0][len - 1] == '[' && strcmp(argv[--argc], "]") != 0)
enprintf(2, "no matching ]\n");
--argc; ++argv;

1
util.h
View File

@ -57,5 +57,6 @@ void putword(const char *);
void recurse(const char *, void (*)(const char *));
#undef strtonum
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);
size_t unescape(char *);