diff options
author | Ron Yorston <rmy@pobox.com> | 2023-02-21 10:51:15 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2023-02-21 10:51:15 +0000 |
commit | 665f3ac4ad7e5f32b88860f413fdb9fafd0eb3e5 (patch) | |
tree | cd57156c0337e23a523308282fcba525e5953e94 | |
parent | 98e16f25885fa49e30003d39e9b7316163c14e83 (diff) | |
download | busybox-w32-665f3ac4ad7e5f32b88860f413fdb9fafd0eb3e5.tar.gz busybox-w32-665f3ac4ad7e5f32b88860f413fdb9fafd0eb3e5.tar.bz2 busybox-w32-665f3ac4ad7e5f32b88860f413fdb9fafd0eb3e5.zip |
ash: revised CRLF handling for scripts
As noted in commit 2d848eba5 (ash: fix CRLF handling), removing
CRs from CRLF pairs in preadbuffer() is complicated by the
possibility that a CRLF pair might be split across the boundary
between buffers.
Add a wrapper around calls to nonblock_immune_read() to allow for
this.
Adds 104-128 bytes.
(GitHub issue #280)
-rw-r--r-- | shell/ash.c | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/shell/ash.c b/shell/ash.c index 152ca198d..742067216 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -801,6 +801,11 @@ struct parsefile { | |||
801 | 801 | ||
802 | /* Number of outstanding calls to pungetc. */ | 802 | /* Number of outstanding calls to pungetc. */ |
803 | int unget; | 803 | int unget; |
804 | |||
805 | #if ENABLE_PLATFORM_MINGW32 | ||
806 | /* True if a trailing CR from a previous read was left unprocessed. */ | ||
807 | int cr; | ||
808 | #endif | ||
804 | }; | 809 | }; |
805 | 810 | ||
806 | static struct parsefile basepf; /* top level input file */ | 811 | static struct parsefile basepf; /* top level input file */ |
@@ -11725,6 +11730,54 @@ static void popstring(void) | |||
11725 | INT_ON; | 11730 | INT_ON; |
11726 | } | 11731 | } |
11727 | 11732 | ||
11733 | #if ENABLE_ASH_IGNORE_CR | ||
11734 | /* | ||
11735 | * Wrapper around nonblock_immune_read() to remove CRs, but only from | ||
11736 | * CRLF pairs. The tricky part is handling a CR at the end of the buffer. | ||
11737 | */ | ||
11738 | static inline ssize_t | ||
11739 | nonblock_immune_wrapper(struct parsefile *pf, char *buffer, size_t count) | ||
11740 | { | ||
11741 | int nr, injected_cr; | ||
11742 | |||
11743 | // Inject unprocessed CR from previous read into the buffer. | ||
11744 | if (pf->cr) | ||
11745 | *buffer = '\r'; | ||
11746 | retry: | ||
11747 | nr = nonblock_immune_read(pf->pf_fd, buffer + pf->cr, count - pf->cr); | ||
11748 | if (nr < 0) | ||
11749 | return nr; | ||
11750 | |||
11751 | injected_cr = pf->cr; | ||
11752 | nr += pf->cr; | ||
11753 | pf->cr = 0; | ||
11754 | |||
11755 | if (nr > 0) { | ||
11756 | nr = remove_cr(buffer, nr); | ||
11757 | // remove_cr() won't reduce size to zero, so [nr - 1] is OK. | ||
11758 | if (buffer[nr - 1] == '\r') { | ||
11759 | if (nr > 1) { | ||
11760 | // Ignore trailing CR for now: we'll deal with it later. | ||
11761 | pf->cr = 1; | ||
11762 | --nr; | ||
11763 | } else if (injected_cr) { // nr == 1 | ||
11764 | // Buffer only contains an injected CR. This means the | ||
11765 | // read returned EOF. Return the buffer as-is. The | ||
11766 | // next call will detect EOF. | ||
11767 | } else { | ||
11768 | // Buffer only contains a CR from the most recent read. | ||
11769 | // Try another read, treating the CR as injected. We'll | ||
11770 | // either get more characters or EOF. Either way we | ||
11771 | // won't end up here again. | ||
11772 | pf->cr = 1; | ||
11773 | goto retry; | ||
11774 | } | ||
11775 | } | ||
11776 | } | ||
11777 | return nr; | ||
11778 | } | ||
11779 | #endif | ||
11780 | |||
11728 | static int | 11781 | static int |
11729 | preadfd(void) | 11782 | preadfd(void) |
11730 | { | 11783 | { |
@@ -11735,7 +11788,11 @@ preadfd(void) | |||
11735 | #if ENABLE_FEATURE_EDITING | 11788 | #if ENABLE_FEATURE_EDITING |
11736 | /* retry: */ | 11789 | /* retry: */ |
11737 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) | 11790 | if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) |
11791 | #if ENABLE_ASH_IGNORE_CR | ||
11792 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
11793 | #else | ||
11738 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 11794 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
11795 | #endif | ||
11739 | else { | 11796 | else { |
11740 | # if ENABLE_ASH_IDLE_TIMEOUT | 11797 | # if ENABLE_ASH_IDLE_TIMEOUT |
11741 | int timeout = -1; | 11798 | int timeout = -1; |
@@ -11812,7 +11869,11 @@ preadfd(void) | |||
11812 | } | 11869 | } |
11813 | } | 11870 | } |
11814 | #else | 11871 | #else |
11872 | # if ENABLE_ASH_IGNORE_CR | ||
11873 | nr = nonblock_immune_wrapper(g_parsefile, buf, IBUFSIZ - 1); | ||
11874 | # else | ||
11815 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); | 11875 | nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); |
11876 | # endif | ||
11816 | #endif | 11877 | #endif |
11817 | 11878 | ||
11818 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ | 11879 | #if 0 /* disabled: nonblock_immune_read() handles this problem */ |
@@ -11883,7 +11944,9 @@ preadbuffer(void) | |||
11883 | more--; | 11944 | more--; |
11884 | 11945 | ||
11885 | c = *q; | 11946 | c = *q; |
11886 | if (c == '\0' || (ENABLE_PLATFORM_MINGW32 && c == '\r')) { | 11947 | /* Remove CR from input buffer as an alternative to ASH_IGNORE_CR. */ |
11948 | if (c == '\0' || (c == '\r' && | ||
11949 | ENABLE_PLATFORM_MINGW32 && !ENABLE_ASH_IGNORE_CR)) { | ||
11887 | memmove(q, q + 1, more); | 11950 | memmove(q, q + 1, more); |
11888 | } else { | 11951 | } else { |
11889 | q++; | 11952 | q++; |