The POSIX standard only requires the `read` builtin to handle `-r`:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html

However, Bash introduced the option `-d <DELIM>` to override IFS for
just one invocation, and it is quite useful.

It is also super easy to implement in BusyBox' ash, so let's do that.

The motivation: This option is used by Git's test suite.

function                                             old     new   delta
.rodata                                           163505  163587     +82
shell_builtin_read                                  1244    1289     +45
readcmd                                              233     259     +26
builtin_read                                         258     263      +5
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 4/0 up/down: 158/0)             Total: 158 bytes

Signed-off-by: Johannes Schindelin <johannes.schinde...@gmx.de>
---
 shell/ash.c          | 19 ++++++++++++++++---
 shell/hush.c         |  3 ++-
 shell/shell_common.c | 10 +++++++---
 shell/shell_common.h |  3 ++-
 4 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 6dc1cfef7..4b0896573 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -189,6 +189,8 @@
 #define    BASH_HOSTNAME_VAR    ENABLE_ASH_BASH_COMPAT
 #define    BASH_SHLVL_VAR       ENABLE_ASH_BASH_COMPAT
 #define    BASH_XTRACEFD        ENABLE_ASH_BASH_COMPAT
+#define    BASH_READ_D          ENABLE_ASH_BASH_COMPAT
+#define IF_BASH_READ_D              IF_ASH_BASH_COMPAT
 
 #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
 /* Bionic at least up to version 24 has no glob() */
@@ -13402,10 +13404,10 @@ letcmd(int argc UNUSED_PARAM, char **argv)
  *      -p PROMPT       Display PROMPT on stderr (if input is from tty)
  *      -t SECONDS      Timeout after SECONDS (tty or pipe only)
  *      -u FD           Read from given FD instead of fd 0
+ *      -d DELIM        End on DELIM char, not newline
  * This uses unbuffered input, which may be avoidable in some cases.
  * TODO: bash also has:
  *      -a ARRAY        Read into array[0],[1],etc
- *      -d DELIM        End on DELIM char, not newline
  *      -e              Use line editing (tty only)
  */
 static int FAST_FUNC
@@ -13415,11 +13417,12 @@ readcmd(int argc UNUSED_PARAM, char **argv 
UNUSED_PARAM)
        char *opt_p = NULL;
        char *opt_t = NULL;
        char *opt_u = NULL;
+       IF_BASH_READ_D(char *opt_d = NULL;)
        int read_flags = 0;
        const char *r;
        int i;
 
-       while ((i = nextopt("p:u:rt:n:s")) != '\0') {
+       while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
                switch (i) {
                case 'p':
                        opt_p = optionarg;
@@ -13439,6 +13442,11 @@ readcmd(int argc UNUSED_PARAM, char **argv 
UNUSED_PARAM)
                case 'u':
                        opt_u = optionarg;
                        break;
+#if BASH_READ_D
+               case 'd':
+                       opt_d = optionarg;
+                       break;
+#endif
                default:
                        break;
                }
@@ -13456,7 +13464,12 @@ readcmd(int argc UNUSED_PARAM, char **argv 
UNUSED_PARAM)
                opt_n,
                opt_p,
                opt_t,
-               opt_u
+               opt_u,
+#if BASH_READ_D
+               opt_d
+#else
+               NULL
+#endif
        );
        INT_ON;
 
diff --git a/shell/hush.c b/shell/hush.c
index 8dc531657..d4e647fc0 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -9454,7 +9454,8 @@ static int FAST_FUNC builtin_read(char **argv)
                opt_n,
                opt_p,
                opt_t,
-               opt_u
+               opt_u,
+        NULL
        );
 
        if ((uintptr_t)r == 1 && errno == EINTR) {
diff --git a/shell/shell_common.c b/shell/shell_common.c
index a9f8d8413..2db8ea3e2 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -54,7 +54,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, 
const char *val),
        const char *opt_n,
        const char *opt_p,
        const char *opt_t,
-       const char *opt_u
+       const char *opt_u,
+       const char *opt_d
 )
 {
        struct pollfd pfd[1];
@@ -237,14 +238,17 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char 
*name, const char *val),
                                continue;
                        }
                }
-               if (c == '\n')
+               if (opt_d) {
+                       if (c == *opt_d)
+                               break;
+               } else if (c == '\n')
                        break;
 
                /* $IFS splitting. NOT done if we run "read"
                 * without variable names (bash compat).
                 * Thus, "read" and "read REPLY" are not the same.
                 */
-               if (argv[0]) {
+               if (!opt_d && argv[0]) {
 /* 
http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
 */
                        const char *is_ifs = strchr(ifs, c);
                        if (startword && is_ifs) {
diff --git a/shell/shell_common.h b/shell/shell_common.h
index a82535c86..1b79bffca 100644
--- a/shell/shell_common.h
+++ b/shell/shell_common.h
@@ -42,7 +42,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, 
const char *val),
        const char *opt_n,
        const char *opt_p,
        const char *opt_t,
-       const char *opt_u
+       const char *opt_u,
+       const char *opt_d
 );
 
 int FAST_FUNC
-- 
2.14.0.windows.1.2.g0f3342804fc


_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to