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

Reply via email to