aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2023-02-21 10:51:15 +0000
committerRon Yorston <rmy@pobox.com>2023-02-21 10:51:15 +0000
commit665f3ac4ad7e5f32b88860f413fdb9fafd0eb3e5 (patch)
treecd57156c0337e23a523308282fcba525e5953e94
parent98e16f25885fa49e30003d39e9b7316163c14e83 (diff)
downloadbusybox-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.c65
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
806static struct parsefile basepf; /* top level input file */ 811static 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 */
11738static inline ssize_t
11739nonblock_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
11728static int 11781static int
11729preadfd(void) 11782preadfd(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++;