aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2023-02-10 12:54:03 +0000
committerRon Yorston <rmy@pobox.com>2023-02-10 13:21:02 +0000
commitd9916c6344c806696554115baa764eea09ca5f08 (patch)
treea25f6f4aaf4e91915b615af7e4bbc09bd68f6ac9
parent4b894b60ae377ee2a04ae209c14bb1e714ecf6f4 (diff)
downloadbusybox-w32-d9916c6344c806696554115baa764eea09ca5f08.tar.gz
busybox-w32-d9916c6344c806696554115baa764eea09ca5f08.tar.bz2
busybox-w32-d9916c6344c806696554115baa764eea09ca5f08.zip
ash: remove CRs from CRLF during field splitting
Commit e371e46fa0 (shell: add \r to IFS) added '\r' to the IFS variable so field splitting would remove carriage returns. Rather than change IFS, remove CRs preceding LFs in regions being scanned for field splitting before IFS is applied. This prevents free-standing CRs from being removed. Costs 112-120 bytes. (GitHub issue #285)
-rw-r--r--shell/ash.c37
-rw-r--r--shell/shell_common.c2
-rwxr-xr-xtestsuite/sh.tests6
3 files changed, 40 insertions, 5 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 63eb4947c..87190c453 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -193,12 +193,14 @@
193//config: case-insensitive filename globbing. 193//config: case-insensitive filename globbing.
194//config: 194//config:
195//config:config ASH_IGNORE_CR 195//config:config ASH_IGNORE_CR
196//config: bool "Ignore CR in scripts" 196//config: bool "Ignore CR in CRLF line endings"
197//config: default y 197//config: default y
198//config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32 198//config: depends on (ASH || SH_IS_ASH || BASH_IS_ASH) && PLATFORM_MINGW32
199//config: help 199//config: help
200//config: Allow CRs to be ignored when shell scripts are parsed. This 200//config: Allow CRs to be ignored when they appear in CRLF line endings
201//config: makes it possible to run scripts with CRLF line endings. 201//config: but not in other circumstances. This isn't a general-purpose
202//config: option: it only covers certain new cases which are under test.
203//config: Enabled by default. May be removed in future.
202//config: 204//config:
203//config:endif # ash options 205//config:endif # ash options
204 206
@@ -6806,6 +6808,9 @@ ifsbreakup(char *string, struct arglist *arglist)
6806 const char *ifs, *realifs; 6808 const char *ifs, *realifs;
6807 int ifsspc; 6809 int ifsspc;
6808 int nulonly; 6810 int nulonly;
6811#if ENABLE_ASH_IGNORE_CR
6812 int lshift = 0;
6813#endif
6809 6814
6810 start = string; 6815 start = string;
6811 if (ifslastp != NULL) { 6816 if (ifslastp != NULL) {
@@ -6816,7 +6821,33 @@ ifsbreakup(char *string, struct arglist *arglist)
6816 do { 6821 do {
6817 int afternul; 6822 int afternul;
6818 6823
6824#if ENABLE_ASH_IGNORE_CR
6825 /* Adjust region offsets for left-shifted string. */
6826 ifsp->begoff -= lshift;
6827 ifsp->endoff -= lshift;
6828#endif
6819 p = string + ifsp->begoff; 6829 p = string + ifsp->begoff;
6830#if ENABLE_ASH_IGNORE_CR
6831 if (ifsp->endoff > ifsp->begoff + 1) {
6832 /* Transform CRLF to LF. Skip regions having zero or
6833 * one characters: they can't contain CRLF. If the
6834 * region shrinks shift the rest of the string left. */
6835 int oldlen = ifsp->endoff - ifsp->begoff;
6836 int newlen = remove_cr(p, oldlen);
6837 int delta = oldlen - newlen;
6838
6839 if (delta > 0) {
6840 char *t = string + ifsp->endoff;
6841 char *s = string + ifsp->endoff - delta;
6842
6843 while (*t)
6844 *s++ = *t++;
6845 *s = '\0';
6846 lshift += delta;
6847 ifsp->endoff -= delta;
6848 }
6849 }
6850#endif
6820 afternul = nulonly; 6851 afternul = nulonly;
6821 nulonly = ifsp->nulonly; 6852 nulonly = ifsp->nulonly;
6822 ifs = nulonly ? nullstr : realifs; 6853 ifs = nulonly ? nullstr : realifs;
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 399d5e684..c0dd32fb4 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -19,7 +19,7 @@
19#include "libbb.h" 19#include "libbb.h"
20#include "shell_common.h" 20#include "shell_common.h"
21 21
22#if !ENABLE_PLATFORM_MINGW32 22#if !ENABLE_PLATFORM_MINGW32 || ENABLE_ASH_IGNORE_CR
23const char defifsvar[] ALIGN1 = "IFS= \t\n"; 23const char defifsvar[] ALIGN1 = "IFS= \t\n";
24#else 24#else
25const char defifsvar[] ALIGN1 = "IFS= \t\n\r"; 25const char defifsvar[] ALIGN1 = "IFS= \t\n\r";
diff --git a/testsuite/sh.tests b/testsuite/sh.tests
index 872611a1b..6fc3ca104 100755
--- a/testsuite/sh.tests
+++ b/testsuite/sh.tests
@@ -89,8 +89,12 @@ IyEvYmluL3NoICAtIAplY2hvICJIZWxsbyB3b3JsZCIK
89" 89"
90rm -f shebang_leading_argument_trailing_space.sh 90rm -f shebang_leading_argument_trailing_space.sh
91 91
92testing "remove CRs from string being evaluated" \ 92testing "sh remove CRs from string being evaluated" \
93 "sh -c \"$(printf 'set -e\r\necho Hello world\r\n')\"" \ 93 "sh -c \"$(printf 'set -e\r\necho Hello world\r\n')\"" \
94 "Hello world\n" "" "" 94 "Hello world\n" "" ""
95 95
96testing "sh preserve lone CRs during field splitting" \
97 "sh input" \
98 "Hello\r world\n" "echo \$(printf \"Hello\\\\r\\\\r\\\\nworld\\\\r\\\\n\")" ""
99
96exit $FAILCOUNT 100exit $FAILCOUNT