From ac05c6d549bb0731386ca2251c92b91be2e95228 Mon Sep 17 00:00:00 2001 From: Paul Eggert 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. address@hidden 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 address@hidden 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