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++;