On Fri, Aug 15, 2014 at 02:13:55PM -0700, Philip Guenther wrote:
> In case someone is bored (heh) and looking for a user land bug to fix...
> 
> Given this:
>    printf '1\n2' >a
>    printf '1\n2\n3' >b
> 
> Compare the output of
>    diff -u a b
> 
> with the output of
>    diff -uw a b
> 
> The former gives this:
> --- a   Fri Aug 15 14:08:26 2014
> +++ b   Fri Aug 15 14:08:25 2014
> @@ -1,2 +1,3 @@
>  1
> -2
> \ No newline at end of file
> +2
> +3
> \ No newline at end of file
> 
> Good enough.
> 
> The latter however gives a diff that cannot be applied:
> 
> --- a   Fri Aug 15 14:08:26 2014
> +++ b   Fri Aug 15 14:08:25 2014
> @@ -1,2 +1,3 @@
>  1
>  2+
> 3
> 
> ...with no newline on that last line of output.  That's wrong: the -w
> option shouldn't break the output format.

Here's what I came up with.  All regress tests pass and I added your
specific example as a new testcase.

Index: regress/usr.bin/diff/Makefile
===================================================================
RCS file: /work/cvsroot/src/regress/usr.bin/diff/Makefile,v
retrieving revision 1.6
diff -p -u -r1.6 Makefile
--- regress/usr.bin/diff/Makefile       16 Jul 2010 19:58:22 -0000      1.6
+++ regress/usr.bin/diff/Makefile       17 Aug 2014 03:58:16 -0000
@@ -1,13 +1,13 @@
 # $OpenBSD: Makefile,v 1.6 2010/07/16 19:58:22 ray Exp $
 
-REGRESS_TARGETS=t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13
+REGRESS_TARGETS=t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14
 
 DIFF=diff
 PATCH=patch
 PATCHOPTIONS=-sb
 
 # Skip the cmp(1) part for ed(1) style diffs for these tests
-EDSKIPCMP=t7 t10 t12
+EDSKIPCMP=t7 t10 t12 t14
 
 # .1 and .2:   input files
 
@@ -24,6 +24,8 @@ EDSKIPCMP=t7 t10 t12
 # t11: rev 1.3 and 1.36 of usr.bin/ed/ed.1.
 # t12: rev 1.1 and 1.2 of sbin/isakmpd/regress/hmac/Makefile.
 # t13: a case to check the single dot on a line handling for ed(1) patches.
+# t14: a case to ensure unified diffs ignoring whitespace produce valid output
+#      when no newline at end of file
 
 .SUFFIXES: .1 .2
 
@@ -51,7 +53,14 @@ all: clean ${REGRESS_TARGET}
        @( echo ${EDSKIPCMP} | grep -q '[[:<:]]${*}[[:>:]]' ) || \
                cmp -s ${.CURDIR}/${*}.2 ${*}.e.copy || \
                (echo "XXX ${*} ed diff failed" && false)
-       
+
+t14.1:
+       @cp ${.CURDIR}/${*}.1 ${*}.uw.copy
+       @${DIFF} -uw  ${.CURDIR}/${*}.1 ${.CURDIR}/${*}.2 > ${*}.uw.patch || 
true
+       @${PATCH} ${PATCHOPTIONS} ${*}.uw.copy ${*}.uw.patch || true
+       @cmp -s ${.CURDIR}/${*}.2 ${*}.uw.copy || \
+               (echo "XXX ${*} unified diff ignoring whitespace failed" && 
false)
+
 # Clean all files generated
 clean:
        rm -f *.copy *.patch *.orig
Index: regress/usr.bin/diff/t14.1
===================================================================
RCS file: regress/usr.bin/diff/t14.1
diff -N regress/usr.bin/diff/t14.1
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/usr.bin/diff/t14.1  17 Aug 2014 03:17:47 -0000
@@ -0,0 +1,2 @@
+1
+2
\ No newline at end of file
Index: regress/usr.bin/diff/t14.2
===================================================================
RCS file: regress/usr.bin/diff/t14.2
diff -N regress/usr.bin/diff/t14.2
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/usr.bin/diff/t14.2  17 Aug 2014 03:17:57 -0000
@@ -0,0 +1,3 @@
+1
+2
+3
\ No newline at end of file
Index: usr.bin/diff/diffreg.c
===================================================================
RCS file: /work/cvsroot/src/usr.bin/diff/diffreg.c,v
retrieving revision 1.82
diff -p -u -r1.82 diffreg.c
--- usr.bin/diff/diffreg.c      8 Jul 2012 15:48:56 -0000       1.82
+++ usr.bin/diff/diffreg.c      17 Aug 2014 03:54:51 -0000
@@ -778,10 +778,14 @@ check(FILE *f1, FILE *f2, int flags)
                                 * GNU diff ignores a missing newline
                                 * in one file for -b or -w.
                                 */
-                               if ((flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) &&
-                                   ((c == EOF && d == '\n') ||
-                                   (c == '\n' && d == EOF))) {
-                                       break;
+                               if (flags & (D_FOLDBLANKS|D_IGNOREBLANKS)) {
+                                       if (c == EOF && d == '\n') {
+                                               ctnew++;
+                                               break;
+                                       } else if (c == '\n' && d == EOF) {
+                                               ctold++;
+                                               break;
+                                       }
                                }
                                ctold++;
                                ctnew++;

Reply via email to