aboutsummaryrefslogtreecommitdiff
path: root/toys/patch.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/patch.c')
-rw-r--r--toys/patch.c78
1 files changed, 51 insertions, 27 deletions
diff --git a/toys/patch.c b/toys/patch.c
index 10615e3e..41371a3e 100644
--- a/toys/patch.c
+++ b/toys/patch.c
@@ -52,7 +52,7 @@ DEFINE_GLOBALS(
struct double_list *plines, *flines;
long oldline, oldlen, newline, newlen, linenum;
- int context, state, filein, fileout, filepatch;
+ int context, state, filein, fileout, filepatch, hunknum;
char *tempname, *oldname;
)
@@ -66,9 +66,11 @@ static void do_line(void *data)
struct double_list *dlist = (struct double_list *)data;
if (TT.state && *dlist->data != TT.state)
- fdprintf(TT.state == 2 ? 2: TT.fileout,
+ fdprintf(TT.state == 2 ? 2 : TT.fileout,
"%s\n", dlist->data+(TT.state>2 ? 1 : 0));
+
free(dlist->data);
+ free(data);
}
static void finish_oldfile(void)
@@ -81,7 +83,7 @@ static void fail_hunk(void)
if (!TT.plines) return;
TT.plines->prev->next = 0;
- printf("Hunk FAILED.\n");
+ fdprintf(2, "Hunk %d FAILED.\n", TT.hunknum);
toys.exitval = 1;
// If we got to this point, we've seeked to the end. Discard changes to
@@ -96,7 +98,7 @@ static void fail_hunk(void)
static void apply_hunk(void)
{
- struct double_list *plist, *buf = NULL;
+ struct double_list *plist, *buf = NULL, *check;
int i = 0, backwards = 0, matcheof = 0,
reverse = toys.optflags & FLAG_REVERSE;
@@ -119,42 +121,62 @@ static void apply_hunk(void)
// Start of for loop
if (TT.context) for (;;) {
char *data = get_line(TT.filein);
+
TT.linenum++;
- // Skip lines we'd add.
+ // Skip lines of the hunk we'd be adding.
while (plist && *plist->data == "+-"[reverse]) {
- if (data && !backwards && !strcmp(data, plist->data+1)) {
- backwards = 1;
- fdprintf(2,"Possibly reversed hunk at %ld\n", TT.linenum);
- }
+ if (data && !strcmp(data, plist->data+1)) {
+ if (++backwards == TT.context)
+ fdprintf(2,"Possibly reversed hunk %d at %ld\n",
+ TT.hunknum, TT.linenum);
+ } else backwards=0;
plist = plist->next;
}
+ // Is this EOF?
if (!data) {
- // Matched EOF?
+ // Does this hunk need to match EOF?
if (!plist && matcheof) break;
- // File ended before we found a home for this hunk?
+
+ // File ended before we found a place for this hunk.
fail_hunk();
goto done;
}
- dlist_add(&buf, data);
-
- if (!plist || strcmp(data, plist->data+1)) { // Ignore whitespace?
- // Match failed, hunk doesn't go here. Flush accumulated buffer
- // so far.
-
- buf->prev->next = NULL;
- TT.state = 1;
- llist_free(buf, do_line);
- buf = NULL;
- plist = TT.plines;
- } else {
- // Match, advance plist.
- plist = plist->next;
- if (!plist && !matcheof) break;
+ check = dlist_add(&buf, data);
+
+ // todo: teach the strcmp() to ignore whitespace.
+
+ for (;;) {
+ // If we hit the end of a hunk that needed EOF and this isn't EOF,
+ // or next line doesn't match, flush first line of buffered data and
+ // recheck match until we find a new match or run out of buffer.
+
+ if (!plist || strcmp(check->data, plist->data+1)) {
+ // First line isn't a match, write it out.
+ TT.state = 1;
+ check = llist_pop(&buf);
+ check->prev->next = buf;
+ buf->prev = check->prev;
+ do_line(check);
+ plist = TT.plines;
+
+ // Out of buffered lines?
+ if (check==buf) {
+ buf = 0;
+ break;
+ }
+ check = buf;
+ } else {
+ // This line matches. Advance plist, detect successful match.
+ plist = plist->next;
+ if (!plist && !matcheof) goto out;
+ check = check->next;
+ if (check == buf) break;
+ }
}
}
-
+out:
// Got it. Emit changed data.
TT.state = "-+"[reverse];
llist_free(TT.plines, do_line);
@@ -266,6 +288,7 @@ void patch_main(void)
TT.state = 1;
TT.context = 0;
TT.linenum = 0;
+ TT.hunknum = 0;
}
// Start a new hunk?
@@ -275,6 +298,7 @@ void patch_main(void)
&TT.oldlen, &TT.newline, &TT.newlen))
{
TT.context = 0;
+ TT.hunknum++;
TT.state = 2;
continue;
}