Use strtonum and libutf in test(1), refactor code and manpage
and mark it as finished in README.
This commit is contained in:
parent
856c79e242
commit
360a63769c
2
README
2
README
@ -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
|
||||
|
@ -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
131
test.1
@ -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
|
||||
|
57
test.c
57
test.c
@ -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,11 +146,10 @@ 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)
|
||||
enprintf(2, "no matching ]\n");
|
||||
if (len && argv[0][len - 1] == '[' && strcmp(argv[--argc], "]") != 0)
|
||||
enprintf(2, "no matching ]\n");
|
||||
|
||||
--argc; ++argv;
|
||||
|
||||
|
1
util.h
1
util.h
@ -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 *);
|
||||
|
Loading…
Reference in New Issue
Block a user