aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/lib.h2
-rw-r--r--lib/llist.c8
-rw-r--r--toys/patch.c78
3 files changed, 59 insertions, 29 deletions
diff --git a/lib/lib.h b/lib/lib.h
index cfbeeb3a..70c0c48d 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -27,7 +27,7 @@ struct double_list {
void llist_free(void *list, void (*freeit)(void *data));
void *llist_pop(void *list); // actually void **list, but the compiler's dumb
-void dlist_add(struct double_list **list, char *data);
+struct double_list *dlist_add(struct double_list **list, char *data);
// args.c
void get_optflags(void);
diff --git a/lib/llist.c b/lib/llist.c
index 4f9bc220..9adb64e0 100644
--- a/lib/llist.c
+++ b/lib/llist.c
@@ -14,6 +14,10 @@ void llist_free(void *list, void (*freeit)(void *data))
while (list) {
void *pop = llist_pop(&list);
if (freeit) freeit(pop);
+ else free(pop);
+
+ // End doubly linked list too.
+ if (list==pop) break;
}
}
@@ -32,7 +36,7 @@ void *llist_pop(void *list)
}
// Add an entry to the end off a doubly linked list
-void dlist_add(struct double_list **list, char *data)
+struct double_list *dlist_add(struct double_list **list, char *data)
{
struct double_list *line = xmalloc(sizeof(struct double_list));
@@ -43,4 +47,6 @@ void dlist_add(struct double_list **list, char *data)
(*list)->prev->next = line;
(*list)->prev = line;
} else *list = line->next = line->prev = line;
+
+ return line;
}
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;
}