ash,hush: fold shell_builtin_read() way-too-many params into a struct param
function old new delta getoptscmd 587 584 -3 readcmd 240 224 -16 shell_builtin_read 1426 1399 -27 builtin_read 210 182 -28 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/4 up/down: 0/-74) Total: -74 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
fd6f295a98
commit
19358cc313
38
shell/ash.c
38
shell/ash.c
@ -13762,38 +13762,35 @@ letcmd(int argc UNUSED_PARAM, char **argv)
|
|||||||
static int FAST_FUNC
|
static int FAST_FUNC
|
||||||
readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
||||||
{
|
{
|
||||||
char *opt_n = NULL;
|
struct builtin_read_params params;
|
||||||
char *opt_p = NULL;
|
|
||||||
char *opt_t = NULL;
|
|
||||||
char *opt_u = NULL;
|
|
||||||
char *opt_d = NULL; /* optimized out if !BASH */
|
|
||||||
int read_flags = 0;
|
|
||||||
const char *r;
|
const char *r;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
memset(¶ms, 0, sizeof(params));
|
||||||
|
|
||||||
while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
|
while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 'p':
|
case 'p':
|
||||||
opt_p = optionarg;
|
params.opt_p = optionarg;
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
opt_n = optionarg;
|
params.opt_n = optionarg;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
read_flags |= BUILTIN_READ_SILENT;
|
params.read_flags |= BUILTIN_READ_SILENT;
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
opt_t = optionarg;
|
params.opt_t = optionarg;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
read_flags |= BUILTIN_READ_RAW;
|
params.read_flags |= BUILTIN_READ_RAW;
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
opt_u = optionarg;
|
params.opt_u = optionarg;
|
||||||
break;
|
break;
|
||||||
#if BASH_READ_D
|
#if BASH_READ_D
|
||||||
case 'd':
|
case 'd':
|
||||||
opt_d = optionarg;
|
params.opt_d = optionarg;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
@ -13801,21 +13798,16 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
params.argv = argptr;
|
||||||
|
params.setvar = setvar0;
|
||||||
|
params.ifs = bltinlookup("IFS"); /* can be NULL */
|
||||||
|
|
||||||
/* "read -s" needs to save/restore termios, can't allow ^C
|
/* "read -s" needs to save/restore termios, can't allow ^C
|
||||||
* to jump out of it.
|
* to jump out of it.
|
||||||
*/
|
*/
|
||||||
again:
|
again:
|
||||||
INT_OFF;
|
INT_OFF;
|
||||||
r = shell_builtin_read(setvar0,
|
r = shell_builtin_read(¶ms);
|
||||||
argptr,
|
|
||||||
bltinlookup("IFS"), /* can be NULL */
|
|
||||||
read_flags,
|
|
||||||
opt_n,
|
|
||||||
opt_p,
|
|
||||||
opt_t,
|
|
||||||
opt_u,
|
|
||||||
opt_d
|
|
||||||
);
|
|
||||||
INT_ON;
|
INT_ON;
|
||||||
|
|
||||||
if ((uintptr_t)r == 1 && errno == EINTR) {
|
if ((uintptr_t)r == 1 && errno == EINTR) {
|
||||||
|
33
shell/hush.c
33
shell/hush.c
@ -10500,40 +10500,29 @@ static int FAST_FUNC builtin_type(char **argv)
|
|||||||
static int FAST_FUNC builtin_read(char **argv)
|
static int FAST_FUNC builtin_read(char **argv)
|
||||||
{
|
{
|
||||||
const char *r;
|
const char *r;
|
||||||
char *opt_n = NULL;
|
struct builtin_read_params params;
|
||||||
char *opt_p = NULL;
|
|
||||||
char *opt_t = NULL;
|
memset(¶ms, 0, sizeof(params));
|
||||||
char *opt_u = NULL;
|
|
||||||
char *opt_d = NULL; /* optimized out if !BASH */
|
|
||||||
const char *ifs;
|
|
||||||
int read_flags;
|
|
||||||
|
|
||||||
/* "!": do not abort on errors.
|
/* "!": do not abort on errors.
|
||||||
* Option string must start with "sr" to match BUILTIN_READ_xxx
|
* Option string must start with "sr" to match BUILTIN_READ_xxx
|
||||||
*/
|
*/
|
||||||
read_flags = getopt32(argv,
|
params.read_flags = getopt32(argv,
|
||||||
#if BASH_READ_D
|
#if BASH_READ_D
|
||||||
"!srn:p:t:u:d:", &opt_n, &opt_p, &opt_t, &opt_u, &opt_d
|
"!srn:p:t:u:d:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u, ¶ms.opt_d
|
||||||
#else
|
#else
|
||||||
"!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u
|
"!srn:p:t:u:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
if (read_flags == (uint32_t)-1)
|
if ((uint32_t)params.read_flags == (uint32_t)-1)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
ifs = get_local_var_value("IFS"); /* can be NULL */
|
params.argv = argv;
|
||||||
|
params.setvar = set_local_var_from_halves;
|
||||||
|
params.ifs = get_local_var_value("IFS"); /* can be NULL */
|
||||||
|
|
||||||
again:
|
again:
|
||||||
r = shell_builtin_read(set_local_var_from_halves,
|
r = shell_builtin_read(¶ms);
|
||||||
argv,
|
|
||||||
ifs,
|
|
||||||
read_flags,
|
|
||||||
opt_n,
|
|
||||||
opt_p,
|
|
||||||
opt_t,
|
|
||||||
opt_u,
|
|
||||||
opt_d
|
|
||||||
);
|
|
||||||
|
|
||||||
if ((uintptr_t)r == 1 && errno == EINTR) {
|
if ((uintptr_t)r == 1 && errno == EINTR) {
|
||||||
unsigned sig = check_and_run_traps();
|
unsigned sig = check_and_run_traps();
|
||||||
|
@ -46,16 +46,7 @@ int FAST_FUNC is_well_formed_var_name(const char *s, char terminator)
|
|||||||
//Here we can simply store "VAR=" at buffer start and store read data directly
|
//Here we can simply store "VAR=" at buffer start and store read data directly
|
||||||
//after "=", then pass buffer to setvar() to consume.
|
//after "=", then pass buffer to setvar() to consume.
|
||||||
const char* FAST_FUNC
|
const char* FAST_FUNC
|
||||||
shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
shell_builtin_read(struct builtin_read_params *params)
|
||||||
char **argv,
|
|
||||||
const char *ifs,
|
|
||||||
int read_flags,
|
|
||||||
const char *opt_n,
|
|
||||||
const char *opt_p,
|
|
||||||
const char *opt_t,
|
|
||||||
const char *opt_u,
|
|
||||||
const char *opt_d
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
struct pollfd pfd[1];
|
struct pollfd pfd[1];
|
||||||
#define fd (pfd[0].fd) /* -u FD */
|
#define fd (pfd[0].fd) /* -u FD */
|
||||||
@ -70,9 +61,13 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
int bufpos; /* need to be able to hold -1 */
|
int bufpos; /* need to be able to hold -1 */
|
||||||
int startword;
|
int startword;
|
||||||
smallint backslash;
|
smallint backslash;
|
||||||
|
char **argv;
|
||||||
|
const char *ifs;
|
||||||
|
int read_flags;
|
||||||
|
|
||||||
errno = err = 0;
|
errno = err = 0;
|
||||||
|
|
||||||
|
argv = params->argv;
|
||||||
pp = argv;
|
pp = argv;
|
||||||
while (*pp) {
|
while (*pp) {
|
||||||
if (!is_well_formed_var_name(*pp, '\0')) {
|
if (!is_well_formed_var_name(*pp, '\0')) {
|
||||||
@ -84,29 +79,29 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
}
|
}
|
||||||
|
|
||||||
nchars = 0; /* if != 0, -n is in effect */
|
nchars = 0; /* if != 0, -n is in effect */
|
||||||
if (opt_n) {
|
if (params->opt_n) {
|
||||||
nchars = bb_strtou(opt_n, NULL, 10);
|
nchars = bb_strtou(params->opt_n, NULL, 10);
|
||||||
if (nchars < 0 || errno)
|
if (nchars < 0 || errno)
|
||||||
return "invalid count";
|
return "invalid count";
|
||||||
/* note: "-n 0": off (bash 3.2 does this too) */
|
/* note: "-n 0": off (bash 3.2 does this too) */
|
||||||
}
|
}
|
||||||
|
|
||||||
end_ms = 0;
|
end_ms = 0;
|
||||||
if (opt_t && !ENABLE_FEATURE_SH_READ_FRAC) {
|
if (params->opt_t && !ENABLE_FEATURE_SH_READ_FRAC) {
|
||||||
end_ms = bb_strtou(opt_t, NULL, 10);
|
end_ms = bb_strtou(params->opt_t, NULL, 10);
|
||||||
if (errno)
|
if (errno)
|
||||||
return "invalid timeout";
|
return "invalid timeout";
|
||||||
if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */
|
if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */
|
||||||
end_ms = UINT_MAX / 2048;
|
end_ms = UINT_MAX / 2048;
|
||||||
end_ms *= 1000;
|
end_ms *= 1000;
|
||||||
}
|
}
|
||||||
if (opt_t && ENABLE_FEATURE_SH_READ_FRAC) {
|
if (params->opt_t && ENABLE_FEATURE_SH_READ_FRAC) {
|
||||||
/* bash 4.3 (maybe earlier) supports -t N.NNNNNN */
|
/* bash 4.3 (maybe earlier) supports -t N.NNNNNN */
|
||||||
char *p;
|
char *p;
|
||||||
/* Eat up to three fractional digits */
|
/* Eat up to three fractional digits */
|
||||||
int frac_digits = 3 + 1;
|
int frac_digits = 3 + 1;
|
||||||
|
|
||||||
end_ms = bb_strtou(opt_t, &p, 10);
|
end_ms = bb_strtou(params->opt_t, &p, 10);
|
||||||
if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */
|
if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */
|
||||||
end_ms = UINT_MAX / 2048;
|
end_ms = UINT_MAX / 2048;
|
||||||
|
|
||||||
@ -128,13 +123,13 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
}
|
}
|
||||||
|
|
||||||
fd = STDIN_FILENO;
|
fd = STDIN_FILENO;
|
||||||
if (opt_u) {
|
if (params->opt_u) {
|
||||||
fd = bb_strtou(opt_u, NULL, 10);
|
fd = bb_strtou(params->opt_u, NULL, 10);
|
||||||
if (fd < 0 || errno)
|
if (fd < 0 || errno)
|
||||||
return "invalid file descriptor";
|
return "invalid file descriptor";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_t && end_ms == 0) {
|
if (params->opt_t && end_ms == 0) {
|
||||||
/* "If timeout is 0, read returns immediately, without trying
|
/* "If timeout is 0, read returns immediately, without trying
|
||||||
* to read any data. The exit status is 0 if input is available
|
* to read any data. The exit status is 0 if input is available
|
||||||
* on the specified file descriptor, non-zero otherwise."
|
* on the specified file descriptor, non-zero otherwise."
|
||||||
@ -147,14 +142,16 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
return (const char *)(uintptr_t)(r <= 0);
|
return (const char *)(uintptr_t)(r <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_p && isatty(fd)) {
|
if (params->opt_p && isatty(fd)) {
|
||||||
fputs(opt_p, stderr);
|
fputs(params->opt_p, stderr);
|
||||||
fflush_all();
|
fflush_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ifs = params->ifs;
|
||||||
if (ifs == NULL)
|
if (ifs == NULL)
|
||||||
ifs = defifs;
|
ifs = defifs;
|
||||||
|
|
||||||
|
read_flags = params->read_flags;
|
||||||
if (nchars || (read_flags & BUILTIN_READ_SILENT)) {
|
if (nchars || (read_flags & BUILTIN_READ_SILENT)) {
|
||||||
tcgetattr(fd, &tty);
|
tcgetattr(fd, &tty);
|
||||||
old_tty = tty;
|
old_tty = tty;
|
||||||
@ -181,11 +178,11 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
retval = (const char *)(uintptr_t)0;
|
retval = (const char *)(uintptr_t)0;
|
||||||
startword = 1;
|
startword = 1;
|
||||||
backslash = 0;
|
backslash = 0;
|
||||||
if (opt_t)
|
if (params->opt_t)
|
||||||
end_ms += (unsigned)monotonic_ms();
|
end_ms += (unsigned)monotonic_ms();
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
bufpos = 0;
|
bufpos = 0;
|
||||||
delim = opt_d ? *opt_d : '\n';
|
delim = params->opt_d ? params->opt_d[0] : '\n';
|
||||||
do {
|
do {
|
||||||
char c;
|
char c;
|
||||||
int timeout;
|
int timeout;
|
||||||
@ -194,7 +191,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
buffer = xrealloc(buffer, bufpos + 0x101);
|
buffer = xrealloc(buffer, bufpos + 0x101);
|
||||||
|
|
||||||
timeout = -1;
|
timeout = -1;
|
||||||
if (opt_t) {
|
if (params->opt_t) {
|
||||||
timeout = end_ms - (unsigned)monotonic_ms();
|
timeout = end_ms - (unsigned)monotonic_ms();
|
||||||
/* ^^^^^^^^^^^^^ all values are unsigned,
|
/* ^^^^^^^^^^^^^ all values are unsigned,
|
||||||
* wrapping math is used here, good even if
|
* wrapping math is used here, good even if
|
||||||
@ -246,7 +243,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
* 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 (!opt_d && argv[0]) {
|
if (!params->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) {
|
||||||
@ -261,7 +258,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
if (argv[1] != NULL && is_ifs) {
|
if (argv[1] != NULL && is_ifs) {
|
||||||
buffer[bufpos] = '\0';
|
buffer[bufpos] = '\0';
|
||||||
bufpos = 0;
|
bufpos = 0;
|
||||||
setvar(*argv, buffer);
|
params->setvar(*argv, buffer);
|
||||||
argv++;
|
argv++;
|
||||||
/* can we skip one non-space ifs char? (2: yes) */
|
/* can we skip one non-space ifs char? (2: yes) */
|
||||||
startword = isspace(c) ? 2 : 1;
|
startword = isspace(c) ? 2 : 1;
|
||||||
@ -313,14 +310,14 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Use the remainder as a value for the next variable */
|
/* Use the remainder as a value for the next variable */
|
||||||
setvar(*argv, buffer);
|
params->setvar(*argv, buffer);
|
||||||
/* Set the rest to "" */
|
/* Set the rest to "" */
|
||||||
while (*++argv)
|
while (*++argv)
|
||||||
setvar(*argv, "");
|
params->setvar(*argv, "");
|
||||||
} else {
|
} else {
|
||||||
/* Note: no $IFS removal */
|
/* Note: no $IFS removal */
|
||||||
buffer[bufpos] = '\0';
|
buffer[bufpos] = '\0';
|
||||||
setvar("REPLY", buffer);
|
params->setvar("REPLY", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret:
|
ret:
|
||||||
|
@ -30,6 +30,17 @@ int FAST_FUNC is_well_formed_var_name(const char *s, char terminator);
|
|||||||
|
|
||||||
/* Builtins */
|
/* Builtins */
|
||||||
|
|
||||||
|
struct builtin_read_params {
|
||||||
|
int read_flags;
|
||||||
|
void FAST_FUNC (*setvar)(const char *name, const char *val);
|
||||||
|
char **argv;
|
||||||
|
const char *ifs;
|
||||||
|
const char *opt_n;
|
||||||
|
const char *opt_p;
|
||||||
|
const char *opt_t;
|
||||||
|
const char *opt_u;
|
||||||
|
const char *opt_d;
|
||||||
|
};
|
||||||
enum {
|
enum {
|
||||||
BUILTIN_READ_SILENT = 1 << 0,
|
BUILTIN_READ_SILENT = 1 << 0,
|
||||||
BUILTIN_READ_RAW = 1 << 1,
|
BUILTIN_READ_RAW = 1 << 1,
|
||||||
@ -40,16 +51,7 @@ enum {
|
|||||||
// shell_builtin_read(setvar,argv,ifs,read_flags)
|
// shell_builtin_read(setvar,argv,ifs,read_flags)
|
||||||
//#endif
|
//#endif
|
||||||
const char* FAST_FUNC
|
const char* FAST_FUNC
|
||||||
shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
|
shell_builtin_read(struct builtin_read_params *params);
|
||||||
char **argv,
|
|
||||||
const char *ifs,
|
|
||||||
int read_flags,
|
|
||||||
const char *opt_n,
|
|
||||||
const char *opt_p,
|
|
||||||
const char *opt_t,
|
|
||||||
const char *opt_u,
|
|
||||||
const char *opt_d
|
|
||||||
);
|
|
||||||
|
|
||||||
int FAST_FUNC
|
int FAST_FUNC
|
||||||
shell_builtin_ulimit(char **argv);
|
shell_builtin_ulimit(char **argv);
|
||||||
|
Loading…
Reference in New Issue
Block a user