[comp.sources.bugs] Patch breaks under -D cond

ksb@mentor.cc.purdue.edu (Kevin Braunsdorf) (09/05/90)

[  This is an unofficial patch to patch by Larry Wall.  I've contacted
   Larry and he said I could send this out because he was busy with
   other things.  I'm sure an official patch will be out later.  -- ksb ]

Priority:  high (if you use `patch -D foo ...')

Description:
	Patch will generate incorrect #if ... #else ... #endif
	constructs given some new-style context diff hunks.

Version:
	$Header: patch.c,v 2.0.1.6 88/06/22 20:46:39 lwall Locked $
	Patch level: 12

Repeat-By:
	Extract the shell archieve below then,
		make

	Note that unifdef exits with an error
		unifdef: Error in test line 4: Premature EOF in ifdef.
	(see broken.script for all the expected output).

Fix:
	Apply the patch file (patch.c.patch) to patch.c with:
		patch patch.c <patch.c.patch
	
	rebuild and install patch.  Then
		make clean
		make
	
	and note that patch now passes this test (see OK.script).

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	bug
# This archive created: Tue Sep  4 13:46:34 1990
# By:	Kevin Braunsdorf (Purdue UNIX Group)
mkdir bug
cd bug
sed 's/^K//' << \SHAR_EOF > patch.c.patch
K*** /usr/src/unsup/bin/patch/patch.c	Thu Jun 23 16:35:06 1988
K--- ./patch.c	Thu Aug 16 13:46:02 1990
K***************
K*** 402,422 ****
K  		}
K  		if (chdir(s) < 0)
K  		    fatal2("Can't cd to %s.\n", s);
K  		break;
K  	    case 'D':
K  	    	do_defines = TRUE;
K  		if (!*++s) {
K  		    Argc--,Argv++;
K  		    s = Argv[0];
K  		}
K! 		if (!isalpha(*s))
K  		    fatal1("Argument to -D not an identifier.\n");
K  		Sprintf(if_defined, "#ifdef %s\n", s);
K  		Sprintf(not_defined, "#ifndef %s\n", s);
K  		Sprintf(end_defined, "#endif /* %s */\n", s);
K  		break;
K  	    case 'e':
K  		diff_type = ED_DIFF;
K  		break;
K  	    case 'f':
K  		force = TRUE;
K--- 402,422 ----
K  		}
K  		if (chdir(s) < 0)
K  		    fatal2("Can't cd to %s.\n", s);
K  		break;
K  	    case 'D':
K  	    	do_defines = TRUE;
K  		if (!*++s) {
K  		    Argc--,Argv++;
K  		    s = Argv[0];
K  		}
K! 		if (!isalpha(*s) && '_' != *s)
K  		    fatal1("Argument to -D not an identifier.\n");
K  		Sprintf(if_defined, "#ifdef %s\n", s);
K  		Sprintf(not_defined, "#ifndef %s\n", s);
K  		Sprintf(end_defined, "#endif /* %s */\n", s);
K  		break;
K  	    case 'e':
K  		diff_type = ED_DIFF;
K  		break;
K  	    case 'f':
K  		force = TRUE;
K***************
K*** 595,672 ****
K  		}
K  		else if (def_state == IN_IFDEF) {
K  		    fputs(else_defined, ofp);
K  		    def_state = IN_ELSE;
K  		}
K  		fputs(pfetch(old), ofp);
K  	    }
K  	    last_frozen_line++;
K  	    old++;
K  	}
K! 	else if (new > pat_end)
K  	    break;
K  	else if (pch_char(new) == '+') {
K  	    copy_till(where + old - 1);
K  	    if (R_do_defines) {
K  		if (def_state == IN_IFNDEF) {
K  		    fputs(else_defined, ofp);
K  		    def_state = IN_ELSE;
K  		}
K  		else if (def_state == OUTSIDE) {
K  		    fputs(if_defined, ofp);
K  		    def_state = IN_IFDEF;
K  		}
K  	    }
K  	    fputs(pfetch(new), ofp);
K  	    new++;
K  	}
K! 	else {
K! 	    if (pch_char(new) != pch_char(old)) {
K! 		say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
K! 		    pch_hunk_beg() + old,
K! 		    pch_hunk_beg() + new);
K  #ifdef DEBUGGING
K! 		say3("oldchar = '%c', newchar = '%c'\n",
K! 		    pch_char(old), pch_char(new));
K  #endif
K! 		my_exit(1);
K  	    }
K! 	    if (pch_char(new) == '!') {
K! 		copy_till(where + old - 1);
K  		if (R_do_defines) {
K! 		   fputs(not_defined, ofp);
K! 		   def_state = IN_IFNDEF;
K  		}
K! 		while (pch_char(old) == '!') {
K! 		    if (R_do_defines) {
K! 			fputs(pfetch(old), ofp);
K! 		    }
K! 		    last_frozen_line++;
K! 		    old++;
K! 		}
K! 		if (R_do_defines) {
K! 		    fputs(else_defined, ofp);
K! 		    def_state = IN_ELSE;
K! 		}
K! 		while (pch_char(new) == '!') {
K! 		    fputs(pfetch(new), ofp);
K! 		    new++;
K! 		}
K! 		if (R_do_defines) {
K! 		    fputs(end_defined, ofp);
K! 		    def_state = OUTSIDE;
K! 		}
K! 	    }
K! 	    else {
K! 		assert(pch_char(new) == ' ');
K  		old++;
K  		new++;
K  	    }
K  	}
K      }
K      if (new <= pat_end && pch_char(new) == '+') {
K  	copy_till(where + old - 1);
K  	if (R_do_defines) {
K  	    if (def_state == OUTSIDE) {
K  	    	fputs(if_defined, ofp);
K  		def_state = IN_IFDEF;
K  	    }
K--- 595,671 ----
K  		}
K  		else if (def_state == IN_IFDEF) {
K  		    fputs(else_defined, ofp);
K  		    def_state = IN_ELSE;
K  		}
K  		fputs(pfetch(old), ofp);
K  	    }
K  	    last_frozen_line++;
K  	    old++;
K  	}
K! 	else if (new > pat_end) {
K  	    break;
K+ 	}
K  	else if (pch_char(new) == '+') {
K  	    copy_till(where + old - 1);
K  	    if (R_do_defines) {
K  		if (def_state == IN_IFNDEF) {
K  		    fputs(else_defined, ofp);
K  		    def_state = IN_ELSE;
K  		}
K  		else if (def_state == OUTSIDE) {
K  		    fputs(if_defined, ofp);
K  		    def_state = IN_IFDEF;
K  		}
K  	    }
K  	    fputs(pfetch(new), ofp);
K  	    new++;
K  	}
K! 	else if (pch_char(new) != pch_char(old)) {
K! 	    say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
K! 		pch_hunk_beg() + old,
K! 		pch_hunk_beg() + new);
K  #ifdef DEBUGGING
K! 	    say3("oldchar = '%c', newchar = '%c'\n",
K! 		pch_char(old), pch_char(new));
K  #endif
K! 	    my_exit(1);
K! 	}
K! 	else if (pch_char(new) == '!') {
K! 	    copy_till(where + old - 1);
K! 	    if (R_do_defines) {
K! 	       fputs(not_defined, ofp);
K! 	       def_state = IN_IFNDEF;
K  	    }
K! 	    while (pch_char(old) == '!') {
K  		if (R_do_defines) {
K! 		    fputs(pfetch(old), ofp);
K  		}
K! 		last_frozen_line++;
K  		old++;
K+ 	    }
K+ 	    if (R_do_defines) {
K+ 		fputs(else_defined, ofp);
K+ 		def_state = IN_ELSE;
K+ 	    }
K+ 	    while (pch_char(new) == '!') {
K+ 		fputs(pfetch(new), ofp);
K  		new++;
K+ 	    }
K+ 	}
K+ 	else {
K+ 	    assert(pch_char(new) == ' ');
K+ 	    old++;
K+ 	    new++;
K+ 	    if (R_do_defines && def_state != OUTSIDE) {
K+ 		fputs(end_defined, ofp);
K+ 		def_state = OUTSIDE;
K  	    }
K  	}
K      }
K      if (new <= pat_end && pch_char(new) == '+') {
K  	copy_till(where + old - 1);
K  	if (R_do_defines) {
K  	    if (def_state == OUTSIDE) {
K  	    	fputs(if_defined, ofp);
K  		def_state = IN_IFDEF;
K  	    }
SHAR_EOF
sed 's/^K//' << \SHAR_EOF > file1
Kline 1
Kline 2
Kline 3
Kline 4
Kline 5
Kline 6
Kline 7
Kline 8
Kline 9
Kline 10
SHAR_EOF
sed 's/^K//' << \SHAR_EOF > file2
Kline 1
Kline 2
Kline 3
Kline 3a
Kline 3b
Kline 4
Kline 5
Kline 6
Kline 7
Kline 7a
Kline 8
Kline 9a
Kline 10
SHAR_EOF
sed 's/^K//' << \SHAR_EOF > Makefile
K
K#
K# handy Makefile to test patch before and after the ksb fix
K#
K
Kall: file1 file2 shouldbe1 shouldbe2
K	cmp -s shouldbe1 file1 && echo defined side OK
K	cmp -s shouldbe2 file2 && echo undefined side OK
K
Kclean: FRC
K	rm -f shouldbe[12] file1.patch test test.orig test~
K
K
Kfile1.patch: file1 file2
K	-diff -c file1 file2 >file1.patch
K
Ktest: file1 file1.patch
K	cp file1 test
K	patch -DKSB test <file1.patch
K
Kshouldbe1: test
K	-unifdef -UKSB test >shouldbe1
K
Kshouldbe2: test
K	-unifdef -DKSB test >shouldbe2
K
K
KFRC:
SHAR_EOF
sed 's/^K//' << \SHAR_EOF > broken.script
KScript started on Tue Sep  4 13:38:28 1990
Kmentor /userb/ksb/uxg/bug 358   make
K        diff -c file1 file2 >file1.patch
K*** Error code 1 (ignored)
K        cp file1 test
K        patch -DKSB test <file1.patch
KHmm...  Looks like a new-style context diff to me...
KThe text leading up to this was:
K--------------------------
K|*** file1      Tue Sep  4 13:01:09 1990
K|--- file2      Tue Sep  4 13:01:36 1990
K--------------------------
KPatching file test using Plan A...
KHunk #1 succeeded at 1.
Kdone
K        unifdef -UKSB test >shouldbe1
Kunifdef: Error in test line 4: Premature EOF in ifdef.
K*** Error code 2
KMake: .  Stop.
Kmentor /userb/ksb/uxg/bug 359   exit
K
Kscript done on Tue Sep  4 13:38:36 1990
SHAR_EOF
sed 's/^K//' << \SHAR_EOF > OK.script
KScript started on Tue Sep  4 13:44:58 1990
Kmentor /userb/ksb/uxg/bug 387   make clean
K        rm -f shouldbe[12] file1.patch test test.orig test~
Kmentor /userb/ksb/uxg/bug 388   make
K        diff -c file1 file2 >file1.patch
K*** Error code 1 (ignored)
K        cp file1 test
K        patch -DKSB test <file1.patch
KHmm...  Looks like a new-style context diff to me...
KThe text leading up to this was:
K--------------------------
K|*** file1      Tue Sep  4 13:01:09 1990
K|--- file2      Tue Sep  4 13:01:36 1990
K--------------------------
KPatching file test using Plan A...
KHunk #1 succeeded at 1.
Kdone
K        unifdef -UKSB test >shouldbe1
K*** Error code 1 (ignored)
K        unifdef -DKSB test >shouldbe2
K*** Error code 1 (ignored)
K        cmp -s shouldbe1 file1 && echo defined side OK
Kdefined side OK
K        cmp -s shouldbe2 file2 && echo undefined side OK
Kundefined side OK
Kmentor /userb/ksb/uxg/bug 389   exit
K
Kscript done on Tue Sep  4 13:45:11 1990
SHAR_EOF
cd ..
#	End of shell archive
exit 0