diff options
author | Ron Yorston <rmy@pobox.com> | 2023-02-10 12:54:03 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2023-02-10 13:21:02 +0000 |
commit | d9916c6344c806696554115baa764eea09ca5f08 (patch) | |
tree | a25f6f4aaf4e91915b615af7e4bbc09bd68f6ac9 | |
parent | 4b894b60ae377ee2a04ae209c14bb1e714ecf6f4 (diff) | |
download | busybox-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.c | 37 | ||||
-rw-r--r-- | shell/shell_common.c | 2 | ||||
-rwxr-xr-x | testsuite/sh.tests | 6 |
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 |
23 | const char defifsvar[] ALIGN1 = "IFS= \t\n"; | 23 | const char defifsvar[] ALIGN1 = "IFS= \t\n"; |
24 | #else | 24 | #else |
25 | const char defifsvar[] ALIGN1 = "IFS= \t\n\r"; | 25 | const 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 | " |
90 | rm -f shebang_leading_argument_trailing_space.sh | 90 | rm -f shebang_leading_argument_trailing_space.sh |
91 | 91 | ||
92 | testing "remove CRs from string being evaluated" \ | 92 | testing "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 | ||
96 | testing "sh preserve lone CRs during field splitting" \ | ||
97 | "sh input" \ | ||
98 | "Hello\r world\n" "echo \$(printf \"Hello\\\\r\\\\r\\\\nworld\\\\r\\\\n\")" "" | ||
99 | |||
96 | exit $FAILCOUNT | 100 | exit $FAILCOUNT |