Re: [PATCH] patch: handle files with no final newline
Denys Vlasenko via busybox <[email protected]>
| Newsgroups | gmane.linux.busybox |
|---|---|
| Message-ID | <CAK1hOcP_47i7pmE9z=eLRw=dQx=ntD_RS1vmfGocXQT0R9qPiA@mail.gmail.com> |
Applied, thank you. On Sun, Apr 19, 2026 at 11:03 AM Ron Yorston via busybox <[email protected]> wrote: > > GNU and BSD patch both handle patches which include the annotation > '\ No newline at end of file'. BusyBox patch doesn't, even though > its diff emits it. > > Implement this feature and add some tests. > > function old new delta > patch_main 1912 2002 +90 > do_line 88 116 +28 > ------------------------------------------------------------------------------ > (add/remove: 0/0 grow/shrink: 2/0 up/down: 118/0) Total: 118 bytes > > Signed-off-by: Ron Yorston <[email protected]> > --- > editors/patch.c | 33 ++++++++++++++++++++--- > testsuite/patch.tests | 63 +++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 92 insertions(+), 4 deletions(-) > > diff --git a/editors/patch.c b/editors/patch.c > index 5a768b23f..ee0ccd384 100644 > --- a/editors/patch.c > +++ b/editors/patch.c > @@ -57,6 +57,7 @@ struct double_list { > struct double_list *next; > struct double_list *prev; > char *data; > + int no_newline; > }; > > // Free all the elements of a linked list > @@ -76,7 +77,7 @@ static void dlist_free(struct double_list *list, void (*freeit)(void *data)) > static struct double_list *dlist_add(struct double_list **list, char *data) > { > struct double_list *llist; > - struct double_list *line = xmalloc(sizeof(*line)); > + struct double_list *line = xzalloc(sizeof(*line)); > > line->data = data; > llist = *list; > @@ -140,7 +141,8 @@ static void do_line(void *data) > > if (TT.state > 1 && *dlist->data != TT.state) > fdprintf(TT.state == 2 ? 2 : TT.fileout, > - "%s\n", dlist->data + (TT.state > 3 ? 1 : 0)); > + dlist->no_newline && TT.state != 2 ? "%s" : "%s\n", > + dlist->data + (TT.state > 3 ? 1 : 0)); > > if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data); > > @@ -433,7 +435,17 @@ int patch_main(int argc UNUSED_PARAM, char **argv) > > // Are we assembling a hunk? > if (state >= 2) { > - if (*patchline == ' ' || *patchline == '+' || *patchline == '-') { > + switch (*patchline) { > + case '\\': > + // '\ No newline at end of file' detected, mark > + // previous line, if it exists. > + if (TT.current_hunk->prev) > + TT.current_hunk->prev->no_newline = TRUE; > + free(patchline); > + continue; > + case ' ': > + case '+': > + case '-': > dlist_add(&TT.current_hunk, patchline); > > if (*patchline != '+') oldlen--; > @@ -445,7 +457,20 @@ int patch_main(int argc UNUSED_PARAM, char **argv) > > // If we've consumed all expected hunk lines, apply the hunk. > > - if (!oldlen && !newlen) state = apply_one_hunk(); > + if (!oldlen && !newlen) { > + // Peek ahead for '\ No newline at end of file', mark > + // previous line, if it exists. > + int c = getchar(); > + ungetc(c, stdin); > + if (c == '\\') { > + if (TT.current_hunk->prev) > + TT.current_hunk->prev->no_newline = TRUE; > + do { > + c = getchar(); > + } while (c != EOF && c != '\n'); > + } > + state = apply_one_hunk(); > + } > continue; > } > fail_hunk(); > diff --git a/testsuite/patch.tests b/testsuite/patch.tests > index 1d48e90be..1a786aa71 100755 > --- a/testsuite/patch.tests > +++ b/testsuite/patch.tests > @@ -287,6 +287,69 @@ bar > 2.9.2 > " \ > > +# testing "test name" "command(s)" "expected result" "file input" "stdin" > +testing "patch file with no last newline" \ > + 'patch 2>&1; cat input' \ > +"\ > +patching file input > +first line > +last line with newline > +" \ > +"\ > +first line > +last line with no newline" \ > +"\ > +--- input > ++++ input > +@@ -1,2 +1,2 @@ > + first line > +-last line with no newline > +\ No newline at end of file > ++last line with newline > +" \ > + > +# testing "test name" "command(s)" "expected result" "file input" "stdin" > +testing "patch -R to revert previous test" \ > + 'patch -R 2>&1; cat input' \ > +"\ > +patching file input > +first line > +last line with no newline" \ > +"\ > +first line > +last line with newline > +" \ > +"\ > +--- input > ++++ input > +@@ -1,2 +1,2 @@ > + first line > +-last line with no newline > +\ No newline at end of file > ++last line with newline > +" \ > + > +# testing "test name" "command(s)" "expected result" "file input" "stdin" > +testing "patch file so it has no last newline" \ > + 'patch 2>&1; cat input' \ > +"\ > +patching file input > +first line > +last line with no newline" \ > +"\ > +first line > +last line with newline > +" \ > +"\ > +--- input > ++++ input > +@@ -1,2 +1,2 @@ > + first line > +-last line with newline > ++last line with no newline > +\ No newline at end of file > +" \ > + > rm input.orig 2>/dev/null > > exit $FAILCOUNT > -- > 2.53.0 > > _______________________________________________ > busybox mailing list > [email protected] > https://lists.busybox.net/mailman/listinfo/busybox _______________________________________________ busybox mailing list [email protected] https://lists.busybox.net/mailman/listinfo/busybox