diff options
| author | Johannes Schindelin <johannes.schindelin@gmx.de> | 2017-08-08 16:46:39 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-08-09 13:52:17 +0200 |
| commit | 3bef5d89b0c667e9fb7d1d9b44ba9b30d4d084e4 (patch) | |
| tree | 5f31bceb5e2b239d88f6465cc76f313a4d5ddc98 | |
| parent | 5856dc74be79fa288f481e1f19077518ae6d8303 (diff) | |
| download | busybox-w32-3bef5d89b0c667e9fb7d1d9b44ba9b30d4d084e4.tar.gz busybox-w32-3bef5d89b0c667e9fb7d1d9b44ba9b30d4d084e4.tar.bz2 busybox-w32-3bef5d89b0c667e9fb7d1d9b44ba9b30d4d084e4.zip | |
ash: implement -d DELIM option for read
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.schindelin@gmx.de>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | shell/ash.c | 15 | ||||
| -rw-r--r-- | shell/shell_common.c | 10 | ||||
| -rw-r--r-- | shell/shell_common.h | 3 |
3 files changed, 21 insertions, 7 deletions
diff --git a/shell/ash.c b/shell/ash.c index 6dc1cfef7..fd1772351 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -189,6 +189,8 @@ | |||
| 189 | #define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT | 189 | #define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT |
| 190 | #define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT | 190 | #define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT |
| 191 | #define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT | 191 | #define BASH_XTRACEFD ENABLE_ASH_BASH_COMPAT |
| 192 | #define BASH_READ_D ENABLE_ASH_BASH_COMPAT | ||
| 193 | #define IF_BASH_READ_D IF_ASH_BASH_COMPAT | ||
| 192 | 194 | ||
| 193 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 | 195 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 |
| 194 | /* Bionic at least up to version 24 has no glob() */ | 196 | /* Bionic at least up to version 24 has no glob() */ |
| @@ -13402,10 +13404,10 @@ letcmd(int argc UNUSED_PARAM, char **argv) | |||
| 13402 | * -p PROMPT Display PROMPT on stderr (if input is from tty) | 13404 | * -p PROMPT Display PROMPT on stderr (if input is from tty) |
| 13403 | * -t SECONDS Timeout after SECONDS (tty or pipe only) | 13405 | * -t SECONDS Timeout after SECONDS (tty or pipe only) |
| 13404 | * -u FD Read from given FD instead of fd 0 | 13406 | * -u FD Read from given FD instead of fd 0 |
| 13407 | * -d DELIM End on DELIM char, not newline | ||
| 13405 | * This uses unbuffered input, which may be avoidable in some cases. | 13408 | * This uses unbuffered input, which may be avoidable in some cases. |
| 13406 | * TODO: bash also has: | 13409 | * TODO: bash also has: |
| 13407 | * -a ARRAY Read into array[0],[1],etc | 13410 | * -a ARRAY Read into array[0],[1],etc |
| 13408 | * -d DELIM End on DELIM char, not newline | ||
| 13409 | * -e Use line editing (tty only) | 13411 | * -e Use line editing (tty only) |
| 13410 | */ | 13412 | */ |
| 13411 | static int FAST_FUNC | 13413 | static int FAST_FUNC |
| @@ -13415,11 +13417,12 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 13415 | char *opt_p = NULL; | 13417 | char *opt_p = NULL; |
| 13416 | char *opt_t = NULL; | 13418 | char *opt_t = NULL; |
| 13417 | char *opt_u = NULL; | 13419 | char *opt_u = NULL; |
| 13420 | char *opt_d = NULL; /* optimized out if !BASH */ | ||
| 13418 | int read_flags = 0; | 13421 | int read_flags = 0; |
| 13419 | const char *r; | 13422 | const char *r; |
| 13420 | int i; | 13423 | int i; |
| 13421 | 13424 | ||
| 13422 | while ((i = nextopt("p:u:rt:n:s")) != '\0') { | 13425 | while ((i = nextopt("p:u:rt:n:sd:")) != '\0') { |
| 13423 | switch (i) { | 13426 | switch (i) { |
| 13424 | case 'p': | 13427 | case 'p': |
| 13425 | opt_p = optionarg; | 13428 | opt_p = optionarg; |
| @@ -13439,6 +13442,11 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 13439 | case 'u': | 13442 | case 'u': |
| 13440 | opt_u = optionarg; | 13443 | opt_u = optionarg; |
| 13441 | break; | 13444 | break; |
| 13445 | #if BASH_READ_D | ||
| 13446 | case 'd': | ||
| 13447 | opt_d = optionarg; | ||
| 13448 | break; | ||
| 13449 | #endif | ||
| 13442 | default: | 13450 | default: |
| 13443 | break; | 13451 | break; |
| 13444 | } | 13452 | } |
| @@ -13456,7 +13464,8 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 13456 | opt_n, | 13464 | opt_n, |
| 13457 | opt_p, | 13465 | opt_p, |
| 13458 | opt_t, | 13466 | opt_t, |
| 13459 | opt_u | 13467 | opt_u, |
| 13468 | opt_d | ||
| 13460 | ); | 13469 | ); |
| 13461 | INT_ON; | 13470 | INT_ON; |
| 13462 | 13471 | ||
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), | |||
| 54 | const char *opt_n, | 54 | const char *opt_n, |
| 55 | const char *opt_p, | 55 | const char *opt_p, |
| 56 | const char *opt_t, | 56 | const char *opt_t, |
| 57 | const char *opt_u | 57 | const char *opt_u, |
| 58 | const char *opt_d | ||
| 58 | ) | 59 | ) |
| 59 | { | 60 | { |
| 60 | struct pollfd pfd[1]; | 61 | struct pollfd pfd[1]; |
| @@ -237,14 +238,17 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
| 237 | continue; | 238 | continue; |
| 238 | } | 239 | } |
| 239 | } | 240 | } |
| 240 | if (c == '\n') | 241 | if (opt_d) { |
| 242 | if (c == *opt_d) | ||
| 243 | break; | ||
| 244 | } else if (c == '\n') | ||
| 241 | break; | 245 | break; |
| 242 | 246 | ||
| 243 | /* $IFS splitting. NOT done if we run "read" | 247 | /* $IFS splitting. NOT done if we run "read" |
| 244 | * without variable names (bash compat). | 248 | * without variable names (bash compat). |
| 245 | * Thus, "read" and "read REPLY" are not the same. | 249 | * Thus, "read" and "read REPLY" are not the same. |
| 246 | */ | 250 | */ |
| 247 | if (argv[0]) { | 251 | if (!opt_d && argv[0]) { |
| 248 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ | 252 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ |
| 249 | const char *is_ifs = strchr(ifs, c); | 253 | const char *is_ifs = strchr(ifs, c); |
| 250 | if (startword && is_ifs) { | 254 | 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), | |||
| 42 | const char *opt_n, | 42 | const char *opt_n, |
| 43 | const char *opt_p, | 43 | const char *opt_p, |
| 44 | const char *opt_t, | 44 | const char *opt_t, |
| 45 | const char *opt_u | 45 | const char *opt_u, |
| 46 | const char *opt_d | ||
| 46 | ); | 47 | ); |
| 47 | 48 | ||
| 48 | int FAST_FUNC | 49 | int FAST_FUNC |
