Jim Meyering wrote:
what should this print?
cmp <(printf '1\nfoo') <(printf '1\nfoolery\n')
Good point, I didn't think of that. Also, now that I think about it more, a
diagnostic ending in "after byte 0, line 0" is confusing in a command that
ordinarily uses origin-1 offsets.
I installed the attached further patch. With it, your example now outputs:
cmp: EOF on /dev/fd/63 after byte 5, line 2
This is more consistent with longstanding behavior:
$ cmp <(printf '1\nfoot') <(printf '1\nfoolery\n')
/dev/fd/63 /dev/fd/62 differ: byte 6, line 2
From ac05c6d549bb0731386ca2251c92b91be2e95228 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Thu, 4 May 2017 17:17:23 -0700
Subject: [PATCH] cmp: improve EOF diagnostic
This improves on yesterday's change, following up on a
remark by Jim Meyering (Bug#22816#21).
* doc/diffutils.texi (Invoking cmp, cmp Options): Follow POSIX more
closely in the documentation of the information appended to the EOF
diagnostic.
* src/cmp.c (cmp): Be more specific about the shorter file's length
and fix some off-by-1 issues in reporting line counts.
* tests/cmp: Adjust to match new behavior.
Don't assume internal details about stdio buffering.
---
doc/diffutils.texi | 12 +++++-----
src/cmp.c | 58 ++++++++++++++++++++++++++++++-----------------
tests/cmp | 66 +++++++++++++++++++++++++++++++++++++++++++++---------
3 files changed, 99 insertions(+), 37 deletions(-)
diff --git a/doc/diffutils.texi b/doc/diffutils.texi
index ccc034a..7139d3b 100644
--- a/doc/diffutils.texi
+++ b/doc/diffutils.texi
@@ -3511,15 +3511,16 @@ reports the location of the first difference to standard output:
@noindent
If one file is a prefix of the other, @command{cmp} reports the
-shorter file's length to standard error (@acronym{POSIX} allows but
-does not require the shorter file's name to be followed by a blank and
-additional information):
+shorter file's name to standard error, followed by a blank and extra
+information about the shorter file:
@example
-cmp: EOF on @var{shorter-file} after byte @var{byte-number}, line @var{line-number}
+cmp: EOF on @var{shorter-file} @var{extra-info}
@end example
The message formats can differ outside the @acronym{POSIX} locale.
+@acronym{POSIX} allows but does not require the EOF diagnostic's file
+name to be followed by a blank and additional information.
An exit status of 0 means no differences were found, 1 means some
differences were found, and 2 means trouble.
@@ -3566,8 +3567,7 @@ instead of the default standard output.
Each output line contains a differing byte's number relative to the
start of the input, followed by the differing byte values.
Byte numbers start at 1.
-Also, if one file is shorter than the other, output the @acronym{EOF}
-message with just a byte number.
+Also, output the @acronym{EOF} message if one file is shorter than the other.
@item -n @var{count}
@itemx --bytes=@var{count}
diff --git a/src/cmp.c b/src/cmp.c
index 9cf0517..2e6f793 100644
--- a/src/cmp.c
+++ b/src/cmp.c
@@ -378,6 +378,7 @@ main (int argc, char **argv)
static int
cmp (void)
{
+ bool at_line_start = true;
off_t line_number = 1; /* Line number (1...) of difference. */
off_t byte_number = 1; /* Byte number (1...) of difference. */
uintmax_t remaining = bytes; /* Remaining number of bytes to compare. */
@@ -463,8 +464,11 @@ cmp (void)
}
byte_number += first_diff;
- if (comparison_type == type_first_diff)
- line_number += count_newlines (buf0, first_diff);
+ if (comparison_type == type_first_diff && first_diff != 0)
+ {
+ line_number += count_newlines (buf0, first_diff);
+ at_line_start = buf0[first_diff - 1] == '\n';
+ }
if (first_diff < smaller)
{
@@ -478,9 +482,9 @@ cmp (void)
char const *line_num = offtostr (line_number, line_buf);
if (!opt_print_bytes)
{
- /* See POSIX 1003.1-2001 for this format. This
- message is used only in the POSIX locale, so it
- need not be translated. */
+ /* See POSIX for this format. This message is
+ used only in the POSIX locale, so it need not
+ be translated. */
static char const char_message[] =
"%s %s differ: char %s, line %s\n";
@@ -510,7 +514,7 @@ cmp (void)
printf (_("%s %s differ: byte %s, line %s is %3o %s %3o %s\n"),
file[0], file[1], byte_num, line_num,
c0, s0, c1, s1);
- }
+ }
}
/* Fall through. */
case type_status:
@@ -527,7 +531,7 @@ cmp (void)
char const *byte_num = offtostr (byte_number, byte_buf);
if (!opt_print_bytes)
{
- /* See POSIX 1003.1-2001 for this format. */
+ /* See POSIX for this format. */
printf ("%*s %3o %3o\n",
offset_width, byte_num, c0, c1);
}
@@ -559,23 +563,35 @@ cmp (void)
if (differing <= 0 && comparison_type != type_status)
{
char const *shorter_file = file[read1 < read0];
- char byte_buf[INT_BUFSIZE_BOUND (off_t)];
- char const *byte_num = offtostr (byte_number - 1, byte_buf);
- /* See POSIX 1003.1-2001 for the constraints on these
- format strings. */
- if (comparison_type == type_first_diff)
+ /* POSIX says that each of these format strings must be
+ "cmp: EOF on %s", optionally followed by a blank and
+ extra text sans newline, then terminated by "\n". */
+ if (byte_number == 1)
+ fprintf (stderr, _("cmp: EOF on %s which is empty\n"),
+ shorter_file);
+ else
{
- char line_buf[INT_BUFSIZE_BOUND (off_t)];
- char const *line_num = offtostr (line_number - 1, line_buf);
- fprintf (stderr,
- _("cmp: EOF on %s after byte %s, line %s\n"),
- shorter_file, byte_num, line_num);
+ char byte_buf[INT_BUFSIZE_BOUND (off_t)];
+ char const *byte_num = offtostr (byte_number - 1, byte_buf);
+
+ if (comparison_type == type_first_diff)
+ {
+ char line_buf[INT_BUFSIZE_BOUND (off_t)];
+ char const *line_num
+ = offtostr (line_number - at_line_start, line_buf);
+ fprintf (stderr,
+ (at_line_start
+ ? _("cmp: EOF on %s after byte %s, line %s\n")
+ : _("cmp: EOF on %s after byte %s,"
+ " in line %s\n")),
+ shorter_file, byte_num, line_num);
+ }
+ else
+ fprintf (stderr,
+ _("cmp: EOF on %s after byte %s\n"),
+ shorter_file, byte_num);
}
- else
- fprintf (stderr,
- _("cmp: EOF on %s after byte %s\n"),
- shorter_file, byte_num);
}
return EXIT_FAILURE;
diff --git a/tests/cmp b/tests/cmp
index 58061f2..082a931 100755
--- a/tests/cmp
+++ b/tests/cmp
@@ -27,7 +27,7 @@ cmp a b
a b differ: char 1, line 1
1
cmp a c
-cmp: EOF on c after byte 0, line 0
+cmp: EOF on c which is empty
1
cmp a d
cmp: d: No such file or directory
@@ -38,16 +38,16 @@ b a differ: char 1, line 1
cmp b b
0
cmp b c
-cmp: EOF on c after byte 0, line 0
+cmp: EOF on c which is empty
1
cmp b d
cmp: d: No such file or directory
2
cmp c a
-cmp: EOF on c after byte 0, line 0
+cmp: EOF on c which is empty
1
cmp c b
-cmp: EOF on c after byte 0, line 0
+cmp: EOF on c which is empty
1
cmp c c
0
@@ -72,7 +72,7 @@ cmp -l a b
1 141 142
1
cmp -l a c
-cmp: EOF on c after byte 0
+cmp: EOF on c which is empty
1
cmp -l a d
cmp: d: No such file or directory
@@ -83,16 +83,16 @@ cmp -l b a
cmp -l b b
0
cmp -l b c
-cmp: EOF on c after byte 0
+cmp: EOF on c which is empty
1
cmp -l b d
cmp: d: No such file or directory
2
cmp -l c a
-cmp: EOF on c after byte 0
+cmp: EOF on c which is empty
1
cmp -l c b
-cmp: EOF on c after byte 0
+cmp: EOF on c which is empty
1
cmp -l c c
0
@@ -154,12 +154,58 @@ for option in '' -l -s; do
for i in a b c d; do
for j in a b c d; do
echo cmp $option $i $j
- cmp $option $i $j 2>&1
- echo $?
+ cmp $option $i $j >stdout 2>stderr
+ status=$?
+ cat stderr stdout
+ echo $status
done
done
done >out
compare exp out || fail=1
+cat <<'EOF' > exp1 || fail=1
+cmp a0 a1
+cmp: EOF on a0 which is empty
+1
+cmp a1 a2
+cmp: EOF on a1 after byte 2, line 1
+1
+cmp a2 a3
+cmp: EOF on a2 after byte 5, in line 2
+1
+cmp -l a0 a1
+cmp: EOF on a0 which is empty
+1
+cmp -l a1 a2
+cmp: EOF on a1 after byte 2
+1
+cmp -l a2 a3
+cmp: EOF on a2 after byte 5
+1
+cmp -s a0 a1
+1
+cmp -s a1 a2
+1
+cmp -s a2 a3
+1
+EOF
+
+printf '' >a0
+printf '1\n' >a1
+printf '1\nfoo' >a2
+printf '1\nfoolery\n' >a3
+
+for option in '' -l -s; do
+ for files in 'a0 a1' 'a1 a2' 'a2 a3'; do
+ echo cmp $option $files
+ cmp $option $files >stdout 2>stderr
+ status=$?
+ cat stderr stdout
+ echo $status
+ done
+done >out1
+
+compare exp1 out1 || fail=1
+
Exit $fail
--
2.7.4