ref: 800170c6559b633c92d742d2950ecd1ce5ffb961
parent: 002384634cb0ca367eebda0b4f9dc9a11a29b3f5
author: Michael Forney <mforney@mforney.org>
date: Sun Oct 30 00:21:31 EDT 2022
patch: improve hunk search Keep track of last hunk offset so we are more likely to find future hunks. Start search within the range of lines where we could possibly find the hunk. This fixes a bug where if the file shrunk since the patch was generated, and we start the search past the end of the file and immediately abort the search. Add an extra offset for the end of the file to the lines array so that lines[nlines] is the length of the file. This way, when we start the search at line nlines-oldcnt, we don't access past the end of the array if oldcnt==0. When we find a hunk, set lastln to ln + h->oldcnt; we can't apply another hunk that starts before the previous hunk ends.
--- a/sys/src/cmd/patch.c
+++ b/sys/src/cmd/patch.c
@@ -36,6 +36,7 @@
int *lines;
int nlines;
int lastln;
+ int lastfuzz;
char *buf;
int len;
};
@@ -491,50 +492,59 @@
for(i = 0; i < len; i++){
if(buf[i] != '\n')
continue;
- if(nlines+1 == linesz){
+ if(nlines+2 == linesz){
linesz *= 2;
lines = erealloc(lines, linesz*sizeof(int));
}
lines[nlines++] = i+1;
}
+ lines[nlines] = len;
f->len = len;
f->buf = buf;
f->lines = lines;
f->nlines = nlines;
- f->lastln = -1;
+ f->lastln = 0;
+ f->lastfuzz = 0;
}
char*
+searchln(Fbuf *f, Hunk *h, int ln)
+{
+ int off;
+
+ off = f->lines[ln];
+ if(off + h->oldlen > f->len)
+ return nil;
+ if(memcmp(f->buf + off, h->old, h->oldlen) != 0)
+ return nil;
+ f->lastln = ln + h->oldcnt;
+ f->lastfuzz = ln - h->oldln;
+ return f->buf + off;
+}
+
+char*
search(Fbuf *f, Hunk *h, char *fname)
{
- int ln, len, off, fuzz, nfuzz, scanning;
+ int ln, oldln, fuzz, scanning;
+ char *p;
- scanning = 1;
- len = h->oldlen;
- nfuzz = (f->nlines < 250) ? f->nlines : 250;
- for(fuzz = 0; scanning && fuzz <= nfuzz; fuzz++){
+ oldln = h->oldln + f->lastfuzz;
+ if(oldln + h->oldcnt > f->nlines)
+ oldln = f->nlines - h->oldcnt;
+ scanning = oldln >= f->lastln;
+ for(fuzz = 0; scanning && fuzz < 250; fuzz++){
scanning = 0;
- ln = h->oldln - fuzz;
- if(ln > f->lastln && ln < f->nlines){
- off = f->lines[ln];
- if(off + len > f->len)
- continue;
+ ln = oldln - fuzz;
+ if(ln >= f->lastln){
scanning = 1;
- if(memcmp(f->buf + off, h->old, h->oldlen) == 0){
- f->lastln = ln;
- return f->buf + off;
- }
+ if((p = searchln(f, h, ln)) != nil)
+ return p;
}
- ln = h->oldln + fuzz + 1;
- if(ln > f->lastln && ln < f->nlines){
- off = f->lines[ln];
- if(off + len > f->len)
- continue;
+ ln = oldln + fuzz + 1;
+ if(ln + h->oldcnt <= f->nlines){
scanning = 1;
- if(memcmp(f->buf + off, h->old, h->oldlen) == 0){
- f->lastln = ln;
- return f->buf + off;
- }
+ if((p = searchln(f, h, ln)) != nil)
+ return p;
}
}
sysfatal("%s:%d: unable to find hunk offset in %s", fname, h->lnum, h->oldpath);