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>
diff --git a/shell/ash.c b/shell/ash.c
index 4641dfd..f74bef6 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -13762,38 +13762,35 @@
static int FAST_FUNC
readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{
- char *opt_n = NULL;
- char *opt_p = NULL;
- char *opt_t = NULL;
- char *opt_u = NULL;
- char *opt_d = NULL; /* optimized out if !BASH */
- int read_flags = 0;
+ struct builtin_read_params params;
const char *r;
int i;
+ memset(¶ms, 0, sizeof(params));
+
while ((i = nextopt("p:u:rt:n:sd:")) != '\0') {
switch (i) {
case 'p':
- opt_p = optionarg;
+ params.opt_p = optionarg;
break;
case 'n':
- opt_n = optionarg;
+ params.opt_n = optionarg;
break;
case 's':
- read_flags |= BUILTIN_READ_SILENT;
+ params.read_flags |= BUILTIN_READ_SILENT;
break;
case 't':
- opt_t = optionarg;
+ params.opt_t = optionarg;
break;
case 'r':
- read_flags |= BUILTIN_READ_RAW;
+ params.read_flags |= BUILTIN_READ_RAW;
break;
case 'u':
- opt_u = optionarg;
+ params.opt_u = optionarg;
break;
#if BASH_READ_D
case 'd':
- opt_d = optionarg;
+ params.opt_d = optionarg;
break;
#endif
default:
@@ -13801,21 +13798,16 @@
}
}
+ params.argv = argptr;
+ params.setvar = setvar0;
+ params.ifs = bltinlookup("IFS"); /* can be NULL */
+
/* "read -s" needs to save/restore termios, can't allow ^C
* to jump out of it.
*/
again:
INT_OFF;
- r = shell_builtin_read(setvar0,
- argptr,
- bltinlookup("IFS"), /* can be NULL */
- read_flags,
- opt_n,
- opt_p,
- opt_t,
- opt_u,
- opt_d
- );
+ r = shell_builtin_read(¶ms);
INT_ON;
if ((uintptr_t)r == 1 && errno == EINTR) {
diff --git a/shell/hush.c b/shell/hush.c
index 4c8814a..3c19bce 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -10500,40 +10500,29 @@
static int FAST_FUNC builtin_read(char **argv)
{
const char *r;
- char *opt_n = NULL;
- char *opt_p = NULL;
- char *opt_t = NULL;
- char *opt_u = NULL;
- char *opt_d = NULL; /* optimized out if !BASH */
- const char *ifs;
- int read_flags;
+ struct builtin_read_params params;
+
+ memset(¶ms, 0, sizeof(params));
/* "!": do not abort on errors.
* Option string must start with "sr" to match BUILTIN_READ_xxx
*/
- read_flags = getopt32(argv,
+ params.read_flags = getopt32(argv,
#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
- "!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
);
- if (read_flags == (uint32_t)-1)
+ if ((uint32_t)params.read_flags == (uint32_t)-1)
return EXIT_FAILURE;
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:
- r = shell_builtin_read(set_local_var_from_halves,
- argv,
- ifs,
- read_flags,
- opt_n,
- opt_p,
- opt_t,
- opt_u,
- opt_d
- );
+ r = shell_builtin_read(¶ms);
if ((uintptr_t)r == 1 && errno == EINTR) {
unsigned sig = check_and_run_traps();
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 0a07296..f2bf5ab 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -46,16 +46,7 @@
//Here we can simply store "VAR=" at buffer start and store read data directly
//after "=", then pass buffer to setvar() to consume.
const char* FAST_FUNC
-shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
- 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
-)
+shell_builtin_read(struct builtin_read_params *params)
{
struct pollfd pfd[1];
#define fd (pfd[0].fd) /* -u FD */
@@ -70,9 +61,13 @@
int bufpos; /* need to be able to hold -1 */
int startword;
smallint backslash;
+ char **argv;
+ const char *ifs;
+ int read_flags;
errno = err = 0;
+ argv = params->argv;
pp = argv;
while (*pp) {
if (!is_well_formed_var_name(*pp, '\0')) {
@@ -84,29 +79,29 @@
}
nchars = 0; /* if != 0, -n is in effect */
- if (opt_n) {
- nchars = bb_strtou(opt_n, NULL, 10);
+ if (params->opt_n) {
+ nchars = bb_strtou(params->opt_n, NULL, 10);
if (nchars < 0 || errno)
return "invalid count";
/* note: "-n 0": off (bash 3.2 does this too) */
}
end_ms = 0;
- if (opt_t && !ENABLE_FEATURE_SH_READ_FRAC) {
- end_ms = bb_strtou(opt_t, NULL, 10);
+ if (params->opt_t && !ENABLE_FEATURE_SH_READ_FRAC) {
+ end_ms = bb_strtou(params->opt_t, NULL, 10);
if (errno)
return "invalid timeout";
if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */
end_ms = UINT_MAX / 2048;
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 */
char *p;
/* Eat up to three fractional digits */
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 */
end_ms = UINT_MAX / 2048;
@@ -128,13 +123,13 @@
}
fd = STDIN_FILENO;
- if (opt_u) {
- fd = bb_strtou(opt_u, NULL, 10);
+ if (params->opt_u) {
+ fd = bb_strtou(params->opt_u, NULL, 10);
if (fd < 0 || errno)
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
* to read any data. The exit status is 0 if input is available
* on the specified file descriptor, non-zero otherwise."
@@ -147,14 +142,16 @@
return (const char *)(uintptr_t)(r <= 0);
}
- if (opt_p && isatty(fd)) {
- fputs(opt_p, stderr);
+ if (params->opt_p && isatty(fd)) {
+ fputs(params->opt_p, stderr);
fflush_all();
}
+ ifs = params->ifs;
if (ifs == NULL)
ifs = defifs;
+ read_flags = params->read_flags;
if (nchars || (read_flags & BUILTIN_READ_SILENT)) {
tcgetattr(fd, &tty);
old_tty = tty;
@@ -181,11 +178,11 @@
retval = (const char *)(uintptr_t)0;
startword = 1;
backslash = 0;
- if (opt_t)
+ if (params->opt_t)
end_ms += (unsigned)monotonic_ms();
buffer = NULL;
bufpos = 0;
- delim = opt_d ? *opt_d : '\n';
+ delim = params->opt_d ? params->opt_d[0] : '\n';
do {
char c;
int timeout;
@@ -194,7 +191,7 @@
buffer = xrealloc(buffer, bufpos + 0x101);
timeout = -1;
- if (opt_t) {
+ if (params->opt_t) {
timeout = end_ms - (unsigned)monotonic_ms();
/* ^^^^^^^^^^^^^ all values are unsigned,
* wrapping math is used here, good even if
@@ -246,7 +243,7 @@
* without variable names (bash compat).
* 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 */
const char *is_ifs = strchr(ifs, c);
if (startword && is_ifs) {
@@ -261,7 +258,7 @@
if (argv[1] != NULL && is_ifs) {
buffer[bufpos] = '\0';
bufpos = 0;
- setvar(*argv, buffer);
+ params->setvar(*argv, buffer);
argv++;
/* can we skip one non-space ifs char? (2: yes) */
startword = isspace(c) ? 2 : 1;
@@ -313,14 +310,14 @@
}
/* Use the remainder as a value for the next variable */
- setvar(*argv, buffer);
+ params->setvar(*argv, buffer);
/* Set the rest to "" */
while (*++argv)
- setvar(*argv, "");
+ params->setvar(*argv, "");
} else {
/* Note: no $IFS removal */
buffer[bufpos] = '\0';
- setvar("REPLY", buffer);
+ params->setvar("REPLY", buffer);
}
ret:
diff --git a/shell/shell_common.h b/shell/shell_common.h
index 875fd9e..a132302 100644
--- a/shell/shell_common.h
+++ b/shell/shell_common.h
@@ -30,6 +30,17 @@
/* 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 {
BUILTIN_READ_SILENT = 1 << 0,
BUILTIN_READ_RAW = 1 << 1,
@@ -40,16 +51,7 @@
// shell_builtin_read(setvar,argv,ifs,read_flags)
//#endif
const char* FAST_FUNC
-shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val),
- 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
-);
+shell_builtin_read(struct builtin_read_params *params);
int FAST_FUNC
shell_builtin_ulimit(char **argv);