cmp: add -n, --bytes to limit number of bytes to compare
This is compatible with GNU cmp. Reviewed by: markj Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D32072
This commit is contained in:
parent
f6787614fd
commit
4e380e8474
@ -41,6 +41,7 @@
|
||||
.Nm
|
||||
.Op Fl l | s | x
|
||||
.Op Fl hz
|
||||
.Op Fl -bytes Ns Cm = Ns Ar num
|
||||
.Ar file1 file2
|
||||
.Op Ar skip1 Op Ar skip2
|
||||
.Sh DESCRIPTION
|
||||
@ -62,6 +63,10 @@ Do not follow symbolic links.
|
||||
.It Fl l , Fl -verbose
|
||||
Print the byte number (decimal) and the differing
|
||||
byte values (octal) for each difference.
|
||||
.It Fl n Ar num , Fl -bytes= Ns num
|
||||
Only compare up to
|
||||
.Ar num
|
||||
bytes.
|
||||
.It Fl s , Fl -silent , Fl -quiet
|
||||
Print nothing for differing files; return exit
|
||||
status only.
|
||||
@ -165,6 +170,7 @@ utility is expected to be
|
||||
compatible.
|
||||
The
|
||||
.Fl h ,
|
||||
.Fl n ,
|
||||
.Fl x ,
|
||||
and
|
||||
.Fl z
|
||||
|
@ -67,6 +67,7 @@ bool lflag, sflag, xflag, zflag;
|
||||
static const struct option long_opts[] =
|
||||
{
|
||||
{"verbose", no_argument, NULL, 'l'},
|
||||
{"bytes", required_argument, NULL, 'n'},
|
||||
{"silent", no_argument, NULL, 's'},
|
||||
{"quiet", no_argument, NULL, 's'},
|
||||
{NULL, no_argument, NULL, 0}
|
||||
@ -78,14 +79,14 @@ int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct stat sb1, sb2;
|
||||
off_t skip1, skip2;
|
||||
off_t skip1, skip2, limit;
|
||||
int ch, fd1, fd2, oflag;
|
||||
bool special;
|
||||
const char *file1, *file2;
|
||||
|
||||
skip1 = skip2 = 0;
|
||||
oflag = O_RDONLY;
|
||||
while ((ch = getopt_long(argc, argv, "+hlsxz", long_opts, NULL)) != -1)
|
||||
while ((ch = getopt_long(argc, argv, "+hln:sxz", long_opts, NULL)) != -1)
|
||||
switch (ch) {
|
||||
case 'h': /* Don't follow symlinks */
|
||||
oflag |= O_NOFOLLOW;
|
||||
@ -93,6 +94,13 @@ main(int argc, char *argv[])
|
||||
case 'l': /* print all differences */
|
||||
lflag = true;
|
||||
break;
|
||||
case 'n': /* Limit */
|
||||
if (expand_number(optarg, &limit) < 0 || limit < 0) {
|
||||
fprintf(stderr, "Invalid --bytes: %s\n",
|
||||
optarg);
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
case 's': /* silent run */
|
||||
sflag = true;
|
||||
break;
|
||||
@ -163,7 +171,7 @@ main(int argc, char *argv[])
|
||||
|
||||
if (fd1 == -1) {
|
||||
if (fd2 == -1) {
|
||||
c_link(file1, skip1, file2, skip2);
|
||||
c_link(file1, skip1, file2, skip2, limit);
|
||||
exit(0);
|
||||
} else if (!sflag)
|
||||
errx(ERR_EXIT, "%s: Not a symbolic link", file2);
|
||||
@ -201,7 +209,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (special)
|
||||
c_special(fd1, file1, skip1, fd2, file2, skip2);
|
||||
c_special(fd1, file1, skip1, fd2, file2, skip2, limit);
|
||||
else {
|
||||
if (zflag && sb1.st_size != sb2.st_size) {
|
||||
if (!sflag)
|
||||
@ -210,7 +218,7 @@ main(int argc, char *argv[])
|
||||
exit(DIFF_EXIT);
|
||||
}
|
||||
c_regular(fd1, file1, skip1, sb1.st_size,
|
||||
fd2, file2, skip2, sb2.st_size);
|
||||
fd2, file2, skip2, sb2.st_size, limit);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
@ -38,9 +38,10 @@
|
||||
#define DIFF_EXIT 1
|
||||
#define ERR_EXIT 2 /* error exit code */
|
||||
|
||||
void c_link(const char *, off_t, const char *, off_t);
|
||||
void c_regular(int, const char *, off_t, off_t, int, const char *, off_t, off_t);
|
||||
void c_special(int, const char *, off_t, int, const char *, off_t);
|
||||
void c_link(const char *, off_t, const char *, off_t, off_t);
|
||||
void c_regular(int, const char *, off_t, off_t, int, const char *, off_t,
|
||||
off_t, off_t);
|
||||
void c_special(int, const char *, off_t, int, const char *, off_t, off_t);
|
||||
void diffmsg(const char *, const char *, off_t, off_t);
|
||||
void eofmsg(const char *);
|
||||
|
||||
|
@ -40,7 +40,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include "extern.h"
|
||||
|
||||
void
|
||||
c_link(const char *file1, off_t skip1, const char *file2, off_t skip2)
|
||||
c_link(const char *file1, off_t skip1, const char *file2, off_t skip2,
|
||||
off_t limit)
|
||||
{
|
||||
char buf1[PATH_MAX], *p1;
|
||||
char buf2[PATH_MAX], *p2;
|
||||
@ -72,7 +73,8 @@ c_link(const char *file1, off_t skip1, const char *file2, off_t skip2)
|
||||
|
||||
dfound = 0;
|
||||
byte = 1;
|
||||
for (p1 = buf1 + skip1, p2 = buf2 + skip2; *p1 && *p2; p1++, p2++) {
|
||||
for (p1 = buf1 + skip1, p2 = buf2 + skip2;
|
||||
*p1 && *p2 && (limit == 0 || byte <= limit); p1++, p2++) {
|
||||
if ((ch = *p1) != *p2) {
|
||||
if (xflag) {
|
||||
dfound = 1;
|
||||
|
@ -60,7 +60,7 @@ static void segv_handler(int);
|
||||
|
||||
void
|
||||
c_regular(int fd1, const char *file1, off_t skip1, off_t len1,
|
||||
int fd2, const char *file2, off_t skip2, off_t len2)
|
||||
int fd2, const char *file2, off_t skip2, off_t len2, off_t limit)
|
||||
{
|
||||
struct sigaction act, oact;
|
||||
cap_rights_t rights;
|
||||
@ -86,15 +86,17 @@ c_regular(int fd1, const char *file1, off_t skip1, off_t len1,
|
||||
off2 = ROUNDPAGE(skip2);
|
||||
|
||||
length = MIN(len1, len2);
|
||||
if (limit > 0)
|
||||
length = MIN(length, limit);
|
||||
|
||||
if ((m1 = remmap(NULL, fd1, off1)) == NULL) {
|
||||
c_special(fd1, file1, skip1, fd2, file2, skip2);
|
||||
c_special(fd1, file1, skip1, fd2, file2, skip2, limit);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m2 = remmap(NULL, fd2, off2)) == NULL) {
|
||||
munmap(m1, MMAP_CHUNK);
|
||||
c_special(fd1, file1, skip1, fd2, file2, skip2);
|
||||
c_special(fd1, file1, skip1, fd2, file2, skip2, limit);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
void
|
||||
c_special(int fd1, const char *file1, off_t skip1,
|
||||
int fd2, const char *file2, off_t skip2)
|
||||
int fd2, const char *file2, off_t skip2, off_t limit)
|
||||
{
|
||||
int ch1, ch2;
|
||||
off_t byte, line;
|
||||
@ -76,7 +76,7 @@ c_special(int fd1, const char *file1, off_t skip1,
|
||||
if (getc(fp2) == EOF)
|
||||
goto eof;
|
||||
|
||||
for (byte = line = 1;; ++byte) {
|
||||
for (byte = line = 1; limit == 0 || byte <= limit; ++byte) {
|
||||
ch1 = getc(fp1);
|
||||
ch2 = getc(fp2);
|
||||
if (ch1 == EOF || ch2 == EOF)
|
||||
|
@ -91,10 +91,33 @@ skipsuff_body()
|
||||
atf_check -s exit:0 cmp -s a b 1k 1k
|
||||
}
|
||||
|
||||
atf_test_case limit
|
||||
limit_head()
|
||||
{
|
||||
atf_set "descr" "Test cmp(1) -n (limit)"
|
||||
}
|
||||
limit_body()
|
||||
{
|
||||
echo -n "aaaabbbb" > a
|
||||
echo -n "aaaaxxxx" > b
|
||||
|
||||
atf_check -s exit:1 -o ignore cmp -s a b
|
||||
atf_check -s exit:0 cmp -sn 4 a b
|
||||
atf_check -s exit:0 cmp -sn 3 a b
|
||||
atf_check -s exit:1 -o ignore cmp -sn 5 a b
|
||||
|
||||
# Test special, too. The implementation for link is effectively
|
||||
# identical.
|
||||
atf_check -s exit:0 -e empty -x "cat a | cmp -sn 4 b -"
|
||||
atf_check -s exit:0 -e empty -x "cat a | cmp -sn 3 b -"
|
||||
atf_check -s exit:1 -o ignore -x "cat a | cmp -sn 5 b -"
|
||||
}
|
||||
|
||||
atf_init_test_cases()
|
||||
{
|
||||
atf_add_test_case special
|
||||
atf_add_test_case symlink
|
||||
atf_add_test_case pr252542
|
||||
atf_add_test_case skipsuff
|
||||
atf_add_test_case limit
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user