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 | |
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>
-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); |