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>
This commit is contained in:
parent
5856dc74be
commit
3bef5d89b0
15
shell/ash.c
15
shell/ash.c
@ -189,6 +189,8 @@
|
|||||||
#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
|
#define BASH_HOSTNAME_VAR ENABLE_ASH_BASH_COMPAT
|
||||||
#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
|
#define BASH_SHLVL_VAR ENABLE_ASH_BASH_COMPAT
|
||||||
#define BASH_XTRACEFD 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
|
#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
|
||||||
/* Bionic at least up to version 24 has no glob() */
|
/* 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)
|
* -p PROMPT Display PROMPT on stderr (if input is from tty)
|
||||||
* -t SECONDS Timeout after SECONDS (tty or pipe only)
|
* -t SECONDS Timeout after SECONDS (tty or pipe only)
|
||||||
* -u FD Read from given FD instead of fd 0
|
* -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.
|
* This uses unbuffered input, which may be avoidable in some cases.
|
||||||
* TODO: bash also has:
|
* TODO: bash also has:
|
||||||
* -a ARRAY Read into array[0],[1],etc
|
* -a ARRAY Read into array[0],[1],etc
|
||||||
* -d DELIM End on DELIM char, not newline
|
|
||||||
* -e Use line editing (tty only)
|
* -e Use line editing (tty only)
|
||||||
*/
|
*/
|
||||||
static int FAST_FUNC
|
static int FAST_FUNC
|
||||||
@ -13415,11 +13417,12 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
|||||||
char *opt_p = NULL;
|
char *opt_p = NULL;
|
||||||
char *opt_t = NULL;
|
char *opt_t = NULL;
|
||||||
char *opt_u = NULL;
|
char *opt_u = NULL;
|
||||||
|
char *opt_d = NULL; /* optimized out if !BASH */
|
||||||
int read_flags = 0;
|
int read_flags = 0;
|
||||||
const char *r;
|
const char *r;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
while ((i = nextopt("p:u:rt:n:s")) != '\0') {
|
while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 'p':
|
case 'p':
|
||||||
opt_p = optionarg;
|
opt_p = optionarg;
|
||||||
@ -13439,6 +13442,11 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
|||||||
case 'u':
|
case 'u':
|
||||||
opt_u = optionarg;
|
opt_u = optionarg;
|
||||||
break;
|
break;
|
||||||
|
#if BASH_READ_D
|
||||||
|
case 'd':
|
||||||
|
opt_d = optionarg;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -13456,7 +13464,8 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
|||||||
opt_n,
|
opt_n,
|
||||||
opt_p,
|
opt_p,
|
||||||
opt_t,
|
opt_t,
|
||||||
opt_u
|
opt_u,
|
||||||
|
opt_d
|
||||||
);
|
);
|
||||||
INT_ON;
|
INT_ON;
|
||||||
|
|
||||||
|
@ -54,7 +54,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
const char *opt_n,
|
const char *opt_n,
|
||||||
const char *opt_p,
|
const char *opt_p,
|
||||||
const char *opt_t,
|
const char *opt_t,
|
||||||
const char *opt_u
|
const char *opt_u,
|
||||||
|
const char *opt_d
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
struct pollfd pfd[1];
|
struct pollfd pfd[1];
|
||||||
@ -237,14 +238,17 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (c == '\n')
|
if (opt_d) {
|
||||||
|
if (c == *opt_d)
|
||||||
|
break;
|
||||||
|
} else if (c == '\n')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* $IFS splitting. NOT done if we run "read"
|
/* $IFS splitting. NOT done if we run "read"
|
||||||
* without variable names (bash compat).
|
* without variable names (bash compat).
|
||||||
* Thus, "read" and "read REPLY" are not the same.
|
* 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 */
|
/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */
|
||||||
const char *is_ifs = strchr(ifs, c);
|
const char *is_ifs = strchr(ifs, c);
|
||||||
if (startword && is_ifs) {
|
if (startword && is_ifs) {
|
||||||
|
@ -42,7 +42,8 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
const char *opt_n,
|
const char *opt_n,
|
||||||
const char *opt_p,
|
const char *opt_p,
|
||||||
const char *opt_t,
|
const char *opt_t,
|
||||||
const char *opt_u
|
const char *opt_u,
|
||||||
|
const char *opt_d
|
||||||
);
|
);
|
||||||
|
|
||||||
int FAST_FUNC
|
int FAST_FUNC
|
||||||
|
Loading…
x
Reference in New Issue
Block a user