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.