From 0f2feac4b7e518e838b80d7b8ceac8f9699ae997 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 12 Feb 2023 08:57:15 +0000 Subject: ash: improve CRLF handling in read Commit deae0c7bf3 (Skip carriage return in read builtin command) caused all CRs to be removed from input to the read builtin. Only remove CRs that are part of a CRLF pair. Adds 64-80 bytes. (GitHub issue #285) --- shell/shell_common.c | 24 ++++++++++++++++++++++++ testsuite/sh.tests | 16 ++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/shell/shell_common.c b/shell/shell_common.c index c0dd32fb4..eb2c4fbf5 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c @@ -273,11 +273,35 @@ shell_builtin_read(struct builtin_read_params *params) c = buffer[bufpos]; #if ENABLE_PLATFORM_MINGW32 +# if !ENABLE_ASH_IGNORE_CR if (c == '\r') continue; +# else + if (c == '\n') { + if (backslash == 2 || (bufpos > 0 && buffer[bufpos - 1] == '\r')) { + /* We saw either: + * - BS CR LF: remove CR, fall through to ignore escaped LF + * and exit BS context. + * - CR LF not in BS context: replace CR with LF */ + buffer[--bufpos] = c; + ++nchars; + } + } else if (backslash == 2) { + /* We saw BS CR ??, keep escaped CR, exit BS context, + * process ?? */ + backslash = 0; + } +# endif #endif if (!(read_flags & BUILTIN_READ_RAW)) { if (backslash) { +#if ENABLE_ASH_IGNORE_CR + if (c == '\r') { + /* We have BS CR, keep CR for now, might see LF next */ + backslash = 2; + goto put; + } +#endif backslash = 0; if (c != '\n') goto put; diff --git a/testsuite/sh.tests b/testsuite/sh.tests index 6fc3ca104..749d2dde2 100755 --- a/testsuite/sh.tests +++ b/testsuite/sh.tests @@ -97,4 +97,20 @@ testing "sh preserve lone CRs during field splitting" \ "sh input" \ "Hello\r world\n" "echo \$(printf \"Hello\\\\r\\\\r\\\\nworld\\\\r\\\\n\")" "" +testing "sh read with CRLF" \ + "printf '1 2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \ + "1 2\n" "" "" + +testing "sh read with CR" \ + "printf '1\\r2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \ + "1\r2\n" "" "" + +testing "sh read with \\CRLF" \ + "printf '1\\\\\r\\n2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \ + "12\n" "" "" + +testing "sh read with \\CR" \ + "printf '1\\\\\r2\\r\\n' | { read var; printf \"\${var}\\\\n\"; }" \ + "1\r2\n" "" "" + exit $FAILCOUNT -- cgit v1.2.3-55-g6feb