[net.sources.bugs] patch bug #2

lwall@sdcrdcf.UUCP (Larry Wall) (12/05/84)

System: patch version 1.2
Bug #: 2
Priority: MEDIUM
Subject: patch won't work on files with munged whitespace

Description:
	Patch uses a strncmp to match context lines with the input file.
	This works as long as the input file hasn't been munged by an
	editor or some other program that translates spaces to tabs or tabs
	to spaces.

Repeat-By:
	Run a source file through expand(1), and then try to do a patch on it.

Fix:	Add a -l switch to do "loose" string comparison.

	From rn, say "| patch -d DIR", where DIR is your patch source
	directory.  Outside of rn, say "cd DIR; patch <thisarticle".

	After applying the patches, you will need to recompile patch, and
	reinstall the manual page.

Index: patch.c
Prereq: 1.2.1.2
***************
*** 1,6
  /* patch - a program to apply diffs to original files
   *
!  * $Header: patch.c,v 1.2.1.2 84/12/04 09:47:13 lwall Exp $
   *
   * Copyright 1984, Larry Wall
   *

--- 1,6 -----
  /* patch - a program to apply diffs to original files
   *
!  * $Header: patch.c,v 1.2.1.3 84/12/05 11:18:43 lwall Exp $
   *
   * Copyright 1984, Larry Wall
   *
***************
*** 8,13
   * money off of it, or pretend that you wrote it.
   *
   * $Log:	patch.c,v $
   * Revision 1.2.1.2  84/12/04  09:47:13  lwall
   * Failed hunk count not reset on multiple patch file.
   * 

--- 8,16 -----
   * money off of it, or pretend that you wrote it.
   *
   * $Log:	patch.c,v $
+  * Revision 1.2.1.3  84/12/05  11:18:43  lwall
+  * Added -l switch to do loose string comparison.
+  * 
   * Revision 1.2.1.2  84/12/04  09:47:13  lwall
   * Failed hunk count not reset on multiple patch file.
   * 
***************
*** 119,124
  #endif
  bool verbose = TRUE;
  bool reverse = FALSE;
  
  #define CONTEXT_DIFF 1
  #define NORMAL_DIFF 2

--- 122,128 -----
  #endif
  bool verbose = TRUE;
  bool reverse = FALSE;
+ bool canonicalize = FALSE;
  
  #define CONTEXT_DIFF 1
  #define NORMAL_DIFF 2
***************
*** 131,136
  
  LINENUM locate_hunk();
  bool patch_match();
  char *malloc();
  char *savestr();
  char *strcpy();

--- 135,141 -----
  
  LINENUM locate_hunk();
  bool patch_match();
+ bool similar();
  char *malloc();
  char *savestr();
  char *strcpy();
***************
*** 348,353
  	    case 'e':
  		diff_type = ED_DIFF;
  		break;
  	    case 'n':
  		diff_type = NORMAL_DIFF;
  		break;

--- 353,361 -----
  	    case 'e':
  		diff_type = ED_DIFF;
  		break;
+ 	    case 'l':
+ 		canonicalize = TRUE;
+ 		break;
  	    case 'n':
  		diff_type = NORMAL_DIFF;
  		break;
***************
*** 701,707
      register LINENUM pat_lines = pch_ptrn_lines();
  
      for (pline = 1, iline=base+offset; pline <= pat_lines; pline++,iline++) {
! 	if (strnNE(ifetch(iline,(offset >= 0)),
  		   pfetch(pline),
  		   pch_line_len(pline) ))
  	    return FALSE;

--- 709,721 -----
      register LINENUM pat_lines = pch_ptrn_lines();
  
      for (pline = 1, iline=base+offset; pline <= pat_lines; pline++,iline++) {
! 	if (canonicalize) {
! 	    if (!similar(ifetch(iline,(offset >= 0)),
! 			 pfetch(pline),
! 			 pch_line_len(pline) ))
! 		return FALSE;
! 	}
! 	else if (strnNE(ifetch(iline,(offset >= 0)),
  		   pfetch(pline),
  		   pch_line_len(pline) ))
  	    return FALSE;
***************
*** 707,712
  	    return FALSE;
      }
      return TRUE;
  }
  
  /* input file with indexable lines abstract type */

--- 721,753 -----
  	    return FALSE;
      }
      return TRUE;
+ }
+ 
+ /* match two lines with canonicalized white space */
+ 
+ bool
+ similar(a,b,len)
+ register char *a, *b;
+ register int len;
+ {
+     while (len) {
+ 	if (isspace(*b)) {		/* whitespace (or \n) to match? */
+ 	    if (!isspace(*a))		/* no corresponding whitespace? */
+ 		return FALSE;
+ 	    while (len && isspace(*b) && *b != '\n')
+ 		b++,len--;		/* skip pattern whitespace */
+ 	    while (isspace(*a) && *a != '\n')
+ 		a++;			/* skip target whitespace */
+ 	    if (*a == '\n' || *b == '\n')
+ 		return (*a == *b);	/* should end in sync */
+ 	}
+ 	else if (*a++ != *b++)		/* match non-whitespace chars */
+ 	    return FALSE;
+ 	else
+ 	    len--;			/* probably not necessary */
+     }
+     return TRUE;			/* actually, this is not reached */
+ 					/* since there is always a \n */
  }
  
  /* input file with indexable lines abstract type */

Index: patch.nr
***************
*** 1,4
! ''' $Header:$
  ''' 
  ''' $Log:$
  .de Sh

--- 1,4 -----
! ''' $Header: patch.nr,v 1.2.1.2 84/12/05 11:06:55 lwall Exp $
  ''' 
  ''' $Log:	patch.nr,v $
  ''' Revision 1.2.1.2  84/12/05  11:06:55  lwall
***************
*** 1,6
  ''' $Header:$
  ''' 
! ''' $Log:$
  .de Sh
  .br
  .ne 5

--- 1,15 -----
  ''' $Header: patch.nr,v 1.2.1.2 84/12/05 11:06:55 lwall Exp $
  ''' 
! ''' $Log:	patch.nr,v $
! ''' Revision 1.2.1.2  84/12/05  11:06:55  lwall
! ''' Added -l switch, and noted bistability bug.
! ''' 
! ''' Revision 1.2.1.1  84/12/04  17:23:39  lwall
! ''' Branch for sdcrdcf changes.
! ''' 
! ''' Revision 1.2  84/12/04  17:22:02  lwall
! ''' Baseline version.
! ''' 
  .de Sh
  .br
  .ne 5
***************
*** 175,180
  .I patch
  to interpret the patch file as an ed script.
  .TP 5
  .B \-n
  forces
  .I patch

--- 184,197 -----
  .I patch
  to interpret the patch file as an ed script.
  .TP 5
+ .B \-l
+ causes the pattern matching to be done loosely, in case the tabs and
+ spaces have been munged in you input file.
+ Any sequence of whitespace in the pattern line will match any sequence
+ in the input file.
+ Normal characters must still match exactly.
+ Each line of the context must still match a line in the input file.
+ .TP 5
  .B \-n
  forces
  .I patch
***************
*** 251,253
  .SH BUGS
  Could be smarter about partial matches, excessively \&deviant offsets and
  swapped code, but that would take an extra pass.

--- 268,275 -----
  .SH BUGS
  Could be smarter about partial matches, excessively \&deviant offsets and
  swapped code, but that would take an extra pass.
+ .PP
+ If you apply a patch you've already applied,
+ .I patch
+ will think it is a reversed patch, and un-apply the patch.
+ This could be construed as a feature.