diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-08-05 15:42:29 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-08-05 18:11:15 +0200 |
| commit | 19358cc31317dca4642417066c1445ce00438e18 (patch) | |
| tree | 08b922ba5bbfe026432dc814341bc855892f90dd /shell | |
| parent | fd6f295a98956b7f495ba09a56528ef9e0d51398 (diff) | |
| download | busybox-w32-19358cc31317dca4642417066c1445ce00438e18.tar.gz busybox-w32-19358cc31317dca4642417066c1445ce00438e18.tar.bz2 busybox-w32-19358cc31317dca4642417066c1445ce00438e18.zip | |
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>
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/ash.c | 38 | ||||
| -rw-r--r-- | shell/hush.c | 33 | ||||
| -rw-r--r-- | shell/shell_common.c | 55 | ||||
| -rw-r--r-- | shell/shell_common.h | 22 |
4 files changed, 64 insertions, 84 deletions
diff --git a/shell/ash.c b/shell/ash.c index 4641dfd19..f74bef6b1 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -13762,38 +13762,35 @@ letcmd(int argc UNUSED_PARAM, char **argv) | |||
| 13762 | static int FAST_FUNC | 13762 | static int FAST_FUNC |
| 13763 | readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | 13763 | readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
| 13764 | { | 13764 | { |
| 13765 | char *opt_n = NULL; | 13765 | struct builtin_read_params params; |
| 13766 | char *opt_p = NULL; | ||
| 13767 | char *opt_t = NULL; | ||
| 13768 | char *opt_u = NULL; | ||
| 13769 | char *opt_d = NULL; /* optimized out if !BASH */ | ||
| 13770 | int read_flags = 0; | ||
| 13771 | const char *r; | 13766 | const char *r; |
| 13772 | int i; | 13767 | int i; |
| 13773 | 13768 | ||
| 13769 | memset(¶ms, 0, sizeof(params)); | ||
| 13770 | |||
| 13774 | while ((i = nextopt("p:u:rt:n:sd:")) != '\0') { | 13771 | while ((i = nextopt("p:u:rt:n:sd:")) != '\0') { |
| 13775 | switch (i) { | 13772 | switch (i) { |
| 13776 | case 'p': | 13773 | case 'p': |
| 13777 | opt_p = optionarg; | 13774 | params.opt_p = optionarg; |
| 13778 | break; | 13775 | break; |
| 13779 | case 'n': | 13776 | case 'n': |
| 13780 | opt_n = optionarg; | 13777 | params.opt_n = optionarg; |
| 13781 | break; | 13778 | break; |
| 13782 | case 's': | 13779 | case 's': |
| 13783 | read_flags |= BUILTIN_READ_SILENT; | 13780 | params.read_flags |= BUILTIN_READ_SILENT; |
| 13784 | break; | 13781 | break; |
| 13785 | case 't': | 13782 | case 't': |
| 13786 | opt_t = optionarg; | 13783 | params.opt_t = optionarg; |
| 13787 | break; | 13784 | break; |
| 13788 | case 'r': | 13785 | case 'r': |
| 13789 | read_flags |= BUILTIN_READ_RAW; | 13786 | params.read_flags |= BUILTIN_READ_RAW; |
| 13790 | break; | 13787 | break; |
| 13791 | case 'u': | 13788 | case 'u': |
| 13792 | opt_u = optionarg; | 13789 | params.opt_u = optionarg; |
| 13793 | break; | 13790 | break; |
| 13794 | #if BASH_READ_D | 13791 | #if BASH_READ_D |
| 13795 | case 'd': | 13792 | case 'd': |
| 13796 | opt_d = optionarg; | 13793 | params.opt_d = optionarg; |
| 13797 | break; | 13794 | break; |
| 13798 | #endif | 13795 | #endif |
| 13799 | default: | 13796 | default: |
| @@ -13801,21 +13798,16 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
| 13801 | } | 13798 | } |
| 13802 | } | 13799 | } |
| 13803 | 13800 | ||
| 13801 | params.argv = argptr; | ||
| 13802 | params.setvar = setvar0; | ||
| 13803 | params.ifs = bltinlookup("IFS"); /* can be NULL */ | ||
| 13804 | |||
| 13804 | /* "read -s" needs to save/restore termios, can't allow ^C | 13805 | /* "read -s" needs to save/restore termios, can't allow ^C |
| 13805 | * to jump out of it. | 13806 | * to jump out of it. |
| 13806 | */ | 13807 | */ |
| 13807 | again: | 13808 | again: |
| 13808 | INT_OFF; | 13809 | INT_OFF; |
| 13809 | r = shell_builtin_read(setvar0, | 13810 | r = shell_builtin_read(¶ms); |
| 13810 | argptr, | ||
| 13811 | bltinlookup("IFS"), /* can be NULL */ | ||
| 13812 | read_flags, | ||
| 13813 | opt_n, | ||
| 13814 | opt_p, | ||
| 13815 | opt_t, | ||
| 13816 | opt_u, | ||
| 13817 | opt_d | ||
| 13818 | ); | ||
| 13819 | INT_ON; | 13811 | INT_ON; |
| 13820 | 13812 | ||
| 13821 | if ((uintptr_t)r == 1 && errno == EINTR) { | 13813 | if ((uintptr_t)r == 1 && errno == EINTR) { |
diff --git a/shell/hush.c b/shell/hush.c index 4c8814a01..3c19bceaa 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -10500,40 +10500,29 @@ static int FAST_FUNC builtin_type(char **argv) | |||
| 10500 | static int FAST_FUNC builtin_read(char **argv) | 10500 | static int FAST_FUNC builtin_read(char **argv) |
| 10501 | { | 10501 | { |
| 10502 | const char *r; | 10502 | const char *r; |
| 10503 | char *opt_n = NULL; | 10503 | struct builtin_read_params params; |
| 10504 | char *opt_p = NULL; | 10504 | |
| 10505 | char *opt_t = NULL; | 10505 | memset(¶ms, 0, sizeof(params)); |
| 10506 | char *opt_u = NULL; | ||
| 10507 | char *opt_d = NULL; /* optimized out if !BASH */ | ||
| 10508 | const char *ifs; | ||
| 10509 | int read_flags; | ||
| 10510 | 10506 | ||
| 10511 | /* "!": do not abort on errors. | 10507 | /* "!": do not abort on errors. |
| 10512 | * Option string must start with "sr" to match BUILTIN_READ_xxx | 10508 | * Option string must start with "sr" to match BUILTIN_READ_xxx |
| 10513 | */ | 10509 | */ |
| 10514 | read_flags = getopt32(argv, | 10510 | params.read_flags = getopt32(argv, |
| 10515 | #if BASH_READ_D | 10511 | #if BASH_READ_D |
| 10516 | "!srn:p:t:u:d:", &opt_n, &opt_p, &opt_t, &opt_u, &opt_d | 10512 | "!srn:p:t:u:d:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u, ¶ms.opt_d |
| 10517 | #else | 10513 | #else |
| 10518 | "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u | 10514 | "!srn:p:t:u:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u |
| 10519 | #endif | 10515 | #endif |
| 10520 | ); | 10516 | ); |
| 10521 | if (read_flags == (uint32_t)-1) | 10517 | if ((uint32_t)params.read_flags == (uint32_t)-1) |
| 10522 | return EXIT_FAILURE; | 10518 | return EXIT_FAILURE; |
| 10523 | argv += optind; | 10519 | argv += optind; |
| 10524 | ifs = get_local_var_value("IFS"); /* can be NULL */ | 10520 | params.argv = argv; |
| 10521 | params.setvar = set_local_var_from_halves; | ||
| 10522 | params.ifs = get_local_var_value("IFS"); /* can be NULL */ | ||
| 10525 | 10523 | ||
| 10526 | again: | 10524 | again: |
| 10527 | r = shell_builtin_read(set_local_var_from_halves, | 10525 | r = shell_builtin_read(¶ms); |
| 10528 | argv, | ||
| 10529 | ifs, | ||
| 10530 | read_flags, | ||
| 10531 | opt_n, | ||
| 10532 | opt_p, | ||
| 10533 | opt_t, | ||
| 10534 | opt_u, | ||
| 10535 | opt_d | ||
| 10536 | ); | ||
| 10537 | 10526 | ||
| 10538 | if ((uintptr_t)r == 1 && errno == EINTR) { | 10527 | if ((uintptr_t)r == 1 && errno == EINTR) { |
| 10539 | unsigned sig = check_and_run_traps(); | 10528 | unsigned sig = check_and_run_traps(); |
diff --git a/shell/shell_common.c b/shell/shell_common.c index 0a07296f3..f2bf5ab65 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
| @@ -46,16 +46,7 @@ int FAST_FUNC is_well_formed_var_name(const char *s, char terminator) | |||
| 46 | //Here we can simply store "VAR=" at buffer start and store read data directly | 46 | //Here we can simply store "VAR=" at buffer start and store read data directly |
| 47 | //after "=", then pass buffer to setvar() to consume. | 47 | //after "=", then pass buffer to setvar() to consume. |
| 48 | const char* FAST_FUNC | 48 | const char* FAST_FUNC |
| 49 | shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | 49 | shell_builtin_read(struct builtin_read_params *params) |
| 50 | char **argv, | ||
| 51 | const char *ifs, | ||
| 52 | int read_flags, | ||
| 53 | const char *opt_n, | ||
| 54 | const char *opt_p, | ||
| 55 | const char *opt_t, | ||
| 56 | const char *opt_u, | ||
| 57 | const char *opt_d | ||
| 58 | ) | ||
| 59 | { | 50 | { |
| 60 | struct pollfd pfd[1]; | 51 | struct pollfd pfd[1]; |
| 61 | #define fd (pfd[0].fd) /* -u FD */ | 52 | #define fd (pfd[0].fd) /* -u FD */ |
| @@ -70,9 +61,13 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
| 70 | int bufpos; /* need to be able to hold -1 */ | 61 | int bufpos; /* need to be able to hold -1 */ |
| 71 | int startword; | 62 | int startword; |
| 72 | smallint backslash; | 63 | smallint backslash; |
| 64 | char **argv; | ||
| 65 | const char *ifs; | ||
| 66 | int read_flags; | ||
| 73 | 67 | ||
| 74 | errno = err = 0; | 68 | errno = err = 0; |
| 75 | 69 | ||
| 70 | argv = params->argv; | ||
| 76 | pp = argv; | 71 | pp = argv; |
| 77 | while (*pp) { | 72 | while (*pp) { |
| 78 | if (!is_well_formed_var_name(*pp, '\0')) { | 73 | 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), | |||
| 84 | } | 79 | } |
| 85 | 80 | ||
| 86 | nchars = 0; /* if != 0, -n is in effect */ | 81 | nchars = 0; /* if != 0, -n is in effect */ |
| 87 | if (opt_n) { | 82 | if (params->opt_n) { |
| 88 | nchars = bb_strtou(opt_n, NULL, 10); | 83 | nchars = bb_strtou(params->opt_n, NULL, 10); |
| 89 | if (nchars < 0 || errno) | 84 | if (nchars < 0 || errno) |
| 90 | return "invalid count"; | 85 | return "invalid count"; |
| 91 | /* note: "-n 0": off (bash 3.2 does this too) */ | 86 | /* note: "-n 0": off (bash 3.2 does this too) */ |
| 92 | } | 87 | } |
| 93 | 88 | ||
| 94 | end_ms = 0; | 89 | end_ms = 0; |
| 95 | if (opt_t && !ENABLE_FEATURE_SH_READ_FRAC) { | 90 | if (params->opt_t && !ENABLE_FEATURE_SH_READ_FRAC) { |
| 96 | end_ms = bb_strtou(opt_t, NULL, 10); | 91 | end_ms = bb_strtou(params->opt_t, NULL, 10); |
| 97 | if (errno) | 92 | if (errno) |
| 98 | return "invalid timeout"; | 93 | return "invalid timeout"; |
| 99 | if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */ | 94 | if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */ |
| 100 | end_ms = UINT_MAX / 2048; | 95 | end_ms = UINT_MAX / 2048; |
| 101 | end_ms *= 1000; | 96 | end_ms *= 1000; |
| 102 | } | 97 | } |
| 103 | if (opt_t && ENABLE_FEATURE_SH_READ_FRAC) { | 98 | if (params->opt_t && ENABLE_FEATURE_SH_READ_FRAC) { |
| 104 | /* bash 4.3 (maybe earlier) supports -t N.NNNNNN */ | 99 | /* bash 4.3 (maybe earlier) supports -t N.NNNNNN */ |
| 105 | char *p; | 100 | char *p; |
| 106 | /* Eat up to three fractional digits */ | 101 | /* Eat up to three fractional digits */ |
| 107 | int frac_digits = 3 + 1; | 102 | int frac_digits = 3 + 1; |
| 108 | 103 | ||
| 109 | end_ms = bb_strtou(opt_t, &p, 10); | 104 | end_ms = bb_strtou(params->opt_t, &p, 10); |
| 110 | if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */ | 105 | if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */ |
| 111 | end_ms = UINT_MAX / 2048; | 106 | end_ms = UINT_MAX / 2048; |
| 112 | 107 | ||
| @@ -128,13 +123,13 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
| 128 | } | 123 | } |
| 129 | 124 | ||
| 130 | fd = STDIN_FILENO; | 125 | fd = STDIN_FILENO; |
| 131 | if (opt_u) { | 126 | if (params->opt_u) { |
| 132 | fd = bb_strtou(opt_u, NULL, 10); | 127 | fd = bb_strtou(params->opt_u, NULL, 10); |
| 133 | if (fd < 0 || errno) | 128 | if (fd < 0 || errno) |
| 134 | return "invalid file descriptor"; | 129 | return "invalid file descriptor"; |
| 135 | } | 130 | } |
| 136 | 131 | ||
| 137 | if (opt_t && end_ms == 0) { | 132 | if (params->opt_t && end_ms == 0) { |
| 138 | /* "If timeout is 0, read returns immediately, without trying | 133 | /* "If timeout is 0, read returns immediately, without trying |
| 139 | * to read any data. The exit status is 0 if input is available | 134 | * to read any data. The exit status is 0 if input is available |
| 140 | * on the specified file descriptor, non-zero otherwise." | 135 | * 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), | |||
| 147 | return (const char *)(uintptr_t)(r <= 0); | 142 | return (const char *)(uintptr_t)(r <= 0); |
| 148 | } | 143 | } |
| 149 | 144 | ||
| 150 | if (opt_p && isatty(fd)) { | 145 | if (params->opt_p && isatty(fd)) { |
| 151 | fputs(opt_p, stderr); | 146 | fputs(params->opt_p, stderr); |
| 152 | fflush_all(); | 147 | fflush_all(); |
| 153 | } | 148 | } |
| 154 | 149 | ||
| 150 | ifs = params->ifs; | ||
| 155 | if (ifs == NULL) | 151 | if (ifs == NULL) |
| 156 | ifs = defifs; | 152 | ifs = defifs; |
| 157 | 153 | ||
| 154 | read_flags = params->read_flags; | ||
| 158 | if (nchars || (read_flags & BUILTIN_READ_SILENT)) { | 155 | if (nchars || (read_flags & BUILTIN_READ_SILENT)) { |
| 159 | tcgetattr(fd, &tty); | 156 | tcgetattr(fd, &tty); |
| 160 | old_tty = tty; | 157 | old_tty = tty; |
| @@ -181,11 +178,11 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
| 181 | retval = (const char *)(uintptr_t)0; | 178 | retval = (const char *)(uintptr_t)0; |
| 182 | startword = 1; | 179 | startword = 1; |
| 183 | backslash = 0; | 180 | backslash = 0; |
| 184 | if (opt_t) | 181 | if (params->opt_t) |
| 185 | end_ms += (unsigned)monotonic_ms(); | 182 | end_ms += (unsigned)monotonic_ms(); |
| 186 | buffer = NULL; | 183 | buffer = NULL; |
| 187 | bufpos = 0; | 184 | bufpos = 0; |
| 188 | delim = opt_d ? *opt_d : '\n'; | 185 | delim = params->opt_d ? params->opt_d[0] : '\n'; |
| 189 | do { | 186 | do { |
| 190 | char c; | 187 | char c; |
| 191 | int timeout; | 188 | int timeout; |
| @@ -194,7 +191,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
| 194 | buffer = xrealloc(buffer, bufpos + 0x101); | 191 | buffer = xrealloc(buffer, bufpos + 0x101); |
| 195 | 192 | ||
| 196 | timeout = -1; | 193 | timeout = -1; |
| 197 | if (opt_t) { | 194 | if (params->opt_t) { |
| 198 | timeout = end_ms - (unsigned)monotonic_ms(); | 195 | timeout = end_ms - (unsigned)monotonic_ms(); |
| 199 | /* ^^^^^^^^^^^^^ all values are unsigned, | 196 | /* ^^^^^^^^^^^^^ all values are unsigned, |
| 200 | * wrapping math is used here, good even if | 197 | * 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), | |||
| 246 | * without variable names (bash compat). | 243 | * without variable names (bash compat). |
| 247 | * Thus, "read" and "read REPLY" are not the same. | 244 | * Thus, "read" and "read REPLY" are not the same. |
| 248 | */ | 245 | */ |
| 249 | if (!opt_d && argv[0]) { | 246 | if (!params->opt_d && argv[0]) { |
| 250 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ | 247 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ |
| 251 | const char *is_ifs = strchr(ifs, c); | 248 | const char *is_ifs = strchr(ifs, c); |
| 252 | if (startword && is_ifs) { | 249 | if (startword && is_ifs) { |
| @@ -261,7 +258,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
| 261 | if (argv[1] != NULL && is_ifs) { | 258 | if (argv[1] != NULL && is_ifs) { |
| 262 | buffer[bufpos] = '\0'; | 259 | buffer[bufpos] = '\0'; |
| 263 | bufpos = 0; | 260 | bufpos = 0; |
| 264 | setvar(*argv, buffer); | 261 | params->setvar(*argv, buffer); |
| 265 | argv++; | 262 | argv++; |
| 266 | /* can we skip one non-space ifs char? (2: yes) */ | 263 | /* can we skip one non-space ifs char? (2: yes) */ |
| 267 | startword = isspace(c) ? 2 : 1; | 264 | startword = isspace(c) ? 2 : 1; |
| @@ -313,14 +310,14 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
| 313 | } | 310 | } |
| 314 | 311 | ||
| 315 | /* Use the remainder as a value for the next variable */ | 312 | /* Use the remainder as a value for the next variable */ |
| 316 | setvar(*argv, buffer); | 313 | params->setvar(*argv, buffer); |
| 317 | /* Set the rest to "" */ | 314 | /* Set the rest to "" */ |
| 318 | while (*++argv) | 315 | while (*++argv) |
| 319 | setvar(*argv, ""); | 316 | params->setvar(*argv, ""); |
| 320 | } else { | 317 | } else { |
| 321 | /* Note: no $IFS removal */ | 318 | /* Note: no $IFS removal */ |
| 322 | buffer[bufpos] = '\0'; | 319 | buffer[bufpos] = '\0'; |
| 323 | setvar("REPLY", buffer); | 320 | params->setvar("REPLY", buffer); |
| 324 | } | 321 | } |
| 325 | 322 | ||
| 326 | ret: | 323 | ret: |
diff --git a/shell/shell_common.h b/shell/shell_common.h index 875fd9ea7..a1323021d 100644 --- a/shell/shell_common.h +++ b/shell/shell_common.h | |||
| @@ -30,6 +30,17 @@ int FAST_FUNC is_well_formed_var_name(const char *s, char terminator); | |||
| 30 | 30 | ||
| 31 | /* Builtins */ | 31 | /* Builtins */ |
| 32 | 32 | ||
| 33 | struct builtin_read_params { | ||
| 34 | int read_flags; | ||
| 35 | void FAST_FUNC (*setvar)(const char *name, const char *val); | ||
| 36 | char **argv; | ||
| 37 | const char *ifs; | ||
| 38 | const char *opt_n; | ||
| 39 | const char *opt_p; | ||
| 40 | const char *opt_t; | ||
| 41 | const char *opt_u; | ||
| 42 | const char *opt_d; | ||
| 43 | }; | ||
| 33 | enum { | 44 | enum { |
| 34 | BUILTIN_READ_SILENT = 1 << 0, | 45 | BUILTIN_READ_SILENT = 1 << 0, |
| 35 | BUILTIN_READ_RAW = 1 << 1, | 46 | BUILTIN_READ_RAW = 1 << 1, |
| @@ -40,16 +51,7 @@ enum { | |||
| 40 | // shell_builtin_read(setvar,argv,ifs,read_flags) | 51 | // shell_builtin_read(setvar,argv,ifs,read_flags) |
| 41 | //#endif | 52 | //#endif |
| 42 | const char* FAST_FUNC | 53 | const char* FAST_FUNC |
| 43 | shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | 54 | shell_builtin_read(struct builtin_read_params *params); |
| 44 | char **argv, | ||
| 45 | const char *ifs, | ||
| 46 | int read_flags, | ||
| 47 | const char *opt_n, | ||
| 48 | const char *opt_p, | ||
| 49 | const char *opt_t, | ||
| 50 | const char *opt_u, | ||
| 51 | const char *opt_d | ||
| 52 | ); | ||
| 53 | 55 | ||
| 54 | int FAST_FUNC | 56 | int FAST_FUNC |
| 55 | shell_builtin_ulimit(char **argv); | 57 | shell_builtin_ulimit(char **argv); |
