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
|
=* 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
|
||||||
|
|
|
@ -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
131
test.1
|
@ -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
|
||||||
|
|
55
test.c
55
test.c
|
@ -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,10 +146,9 @@ 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
1
util.h
|
@ -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 *);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user