diff options
-rw-r--r-- | lib/lib.h | 2 | ||||
-rw-r--r-- | lib/llist.c | 8 | ||||
-rw-r--r-- | toys/patch.c | 78 |
3 files changed, 59 insertions, 29 deletions
@@ -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; } |