diff options
Diffstat (limited to 'shell/shell_common.c')
-rw-r--r-- | shell/shell_common.c | 57 |
1 files changed, 27 insertions, 30 deletions
diff --git a/shell/shell_common.c b/shell/shell_common.c index 82102778c..23e5f1c25 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -50,16 +50,7 @@ int FAST_FUNC is_well_formed_var_name(const char *s, char terminator) | |||
50 | //Here we can simply store "VAR=" at buffer start and store read data directly | 50 | //Here we can simply store "VAR=" at buffer start and store read data directly |
51 | //after "=", then pass buffer to setvar() to consume. | 51 | //after "=", then pass buffer to setvar() to consume. |
52 | const char* FAST_FUNC | 52 | const char* FAST_FUNC |
53 | shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | 53 | shell_builtin_read(struct builtin_read_params *params) |
54 | char **argv, | ||
55 | const char *ifs, | ||
56 | int read_flags, | ||
57 | const char *opt_n, | ||
58 | const char *opt_p, | ||
59 | const char *opt_t, | ||
60 | const char *opt_u, | ||
61 | const char *opt_d | ||
62 | ) | ||
63 | { | 54 | { |
64 | struct pollfd pfd[1]; | 55 | struct pollfd pfd[1]; |
65 | #define fd (pfd[0].fd) /* -u FD */ | 56 | #define fd (pfd[0].fd) /* -u FD */ |
@@ -76,9 +67,13 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
76 | int bufpos; /* need to be able to hold -1 */ | 67 | int bufpos; /* need to be able to hold -1 */ |
77 | int startword; | 68 | int startword; |
78 | smallint backslash; | 69 | smallint backslash; |
70 | char **argv; | ||
71 | const char *ifs; | ||
72 | int read_flags; | ||
79 | 73 | ||
80 | errno = err = 0; | 74 | errno = err = 0; |
81 | 75 | ||
76 | argv = params->argv; | ||
82 | pp = argv; | 77 | pp = argv; |
83 | while (*pp) { | 78 | while (*pp) { |
84 | if (!is_well_formed_var_name(*pp, '\0')) { | 79 | if (!is_well_formed_var_name(*pp, '\0')) { |
@@ -90,29 +85,29 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
90 | } | 85 | } |
91 | 86 | ||
92 | nchars = 0; /* if != 0, -n is in effect */ | 87 | nchars = 0; /* if != 0, -n is in effect */ |
93 | if (opt_n) { | 88 | if (params->opt_n) { |
94 | nchars = bb_strtou(opt_n, NULL, 10); | 89 | nchars = bb_strtou(params->opt_n, NULL, 10); |
95 | if (nchars < 0 || errno) | 90 | if (nchars < 0 || errno) |
96 | return "invalid count"; | 91 | return "invalid count"; |
97 | /* note: "-n 0": off (bash 3.2 does this too) */ | 92 | /* note: "-n 0": off (bash 3.2 does this too) */ |
98 | } | 93 | } |
99 | 94 | ||
100 | end_ms = 0; | 95 | end_ms = 0; |
101 | if (opt_t && !ENABLE_FEATURE_SH_READ_FRAC) { | 96 | if (params->opt_t && !ENABLE_FEATURE_SH_READ_FRAC) { |
102 | end_ms = bb_strtou(opt_t, NULL, 10); | 97 | end_ms = bb_strtou(params->opt_t, NULL, 10); |
103 | if (errno) | 98 | if (errno) |
104 | return "invalid timeout"; | 99 | return "invalid timeout"; |
105 | if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */ | 100 | if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */ |
106 | end_ms = UINT_MAX / 2048; | 101 | end_ms = UINT_MAX / 2048; |
107 | end_ms *= 1000; | 102 | end_ms *= 1000; |
108 | } | 103 | } |
109 | if (opt_t && ENABLE_FEATURE_SH_READ_FRAC) { | 104 | if (params->opt_t && ENABLE_FEATURE_SH_READ_FRAC) { |
110 | /* bash 4.3 (maybe earlier) supports -t N.NNNNNN */ | 105 | /* bash 4.3 (maybe earlier) supports -t N.NNNNNN */ |
111 | char *p; | 106 | char *p; |
112 | /* Eat up to three fractional digits */ | 107 | /* Eat up to three fractional digits */ |
113 | int frac_digits = 3 + 1; | 108 | int frac_digits = 3 + 1; |
114 | 109 | ||
115 | end_ms = bb_strtou(opt_t, &p, 10); | 110 | end_ms = bb_strtou(params->opt_t, &p, 10); |
116 | if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */ | 111 | if (end_ms > UINT_MAX / 2048) /* be safely away from overflow */ |
117 | end_ms = UINT_MAX / 2048; | 112 | end_ms = UINT_MAX / 2048; |
118 | 113 | ||
@@ -134,13 +129,13 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
134 | } | 129 | } |
135 | 130 | ||
136 | fd = STDIN_FILENO; | 131 | fd = STDIN_FILENO; |
137 | if (opt_u) { | 132 | if (params->opt_u) { |
138 | fd = bb_strtou(opt_u, NULL, 10); | 133 | fd = bb_strtou(params->opt_u, NULL, 10); |
139 | if (fd < 0 || errno) | 134 | if (fd < 0 || errno) |
140 | return "invalid file descriptor"; | 135 | return "invalid file descriptor"; |
141 | } | 136 | } |
142 | 137 | ||
143 | if (opt_t && end_ms == 0) { | 138 | if (params->opt_t && end_ms == 0) { |
144 | #if !ENABLE_PLATFORM_MINGW32 | 139 | #if !ENABLE_PLATFORM_MINGW32 |
145 | /* "If timeout is 0, read returns immediately, without trying | 140 | /* "If timeout is 0, read returns immediately, without trying |
146 | * to read any data. The exit status is 0 if input is available | 141 | * to read any data. The exit status is 0 if input is available |
@@ -157,14 +152,16 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
157 | #endif | 152 | #endif |
158 | } | 153 | } |
159 | 154 | ||
160 | if (opt_p && isatty(fd)) { | 155 | if (params->opt_p && isatty(fd)) { |
161 | fputs(opt_p, stderr); | 156 | fputs(params->opt_p, stderr); |
162 | fflush_all(); | 157 | fflush_all(); |
163 | } | 158 | } |
164 | 159 | ||
160 | ifs = params->ifs; | ||
165 | if (ifs == NULL) | 161 | if (ifs == NULL) |
166 | ifs = defifs; | 162 | ifs = defifs; |
167 | 163 | ||
164 | read_flags = params->read_flags; | ||
168 | #if !ENABLE_PLATFORM_MINGW32 | 165 | #if !ENABLE_PLATFORM_MINGW32 |
169 | if (nchars || (read_flags & BUILTIN_READ_SILENT)) { | 166 | if (nchars || (read_flags & BUILTIN_READ_SILENT)) { |
170 | tcgetattr(fd, &tty); | 167 | tcgetattr(fd, &tty); |
@@ -193,11 +190,11 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
193 | retval = (const char *)(uintptr_t)0; | 190 | retval = (const char *)(uintptr_t)0; |
194 | startword = 1; | 191 | startword = 1; |
195 | backslash = 0; | 192 | backslash = 0; |
196 | if (opt_t) | 193 | if (params->opt_t) |
197 | end_ms += (unsigned)monotonic_ms(); | 194 | end_ms += (unsigned)monotonic_ms(); |
198 | buffer = NULL; | 195 | buffer = NULL; |
199 | bufpos = 0; | 196 | bufpos = 0; |
200 | delim = opt_d ? *opt_d : '\n'; | 197 | delim = params->opt_d ? params->opt_d[0] : '\n'; |
201 | do { | 198 | do { |
202 | char c; | 199 | char c; |
203 | int timeout; | 200 | int timeout; |
@@ -206,7 +203,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
206 | buffer = xrealloc(buffer, bufpos + 0x101); | 203 | buffer = xrealloc(buffer, bufpos + 0x101); |
207 | 204 | ||
208 | timeout = -1; | 205 | timeout = -1; |
209 | if (opt_t) { | 206 | if (params->opt_t) { |
210 | timeout = end_ms - (unsigned)monotonic_ms(); | 207 | timeout = end_ms - (unsigned)monotonic_ms(); |
211 | /* ^^^^^^^^^^^^^ all values are unsigned, | 208 | /* ^^^^^^^^^^^^^ all values are unsigned, |
212 | * wrapping math is used here, good even if | 209 | * wrapping math is used here, good even if |
@@ -238,7 +235,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
238 | } | 235 | } |
239 | #else | 236 | #else |
240 | errno = 0; | 237 | errno = 0; |
241 | if (isatty(fd) && (opt_n || opt_d || opt_t || | 238 | if (isatty(fd) && (params->opt_n || params->opt_d || params->opt_t || |
242 | (read_flags & BUILTIN_READ_SILENT))) { | 239 | (read_flags & BUILTIN_READ_SILENT))) { |
243 | int64_t key; | 240 | int64_t key; |
244 | 241 | ||
@@ -285,7 +282,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
285 | * without variable names (bash compat). | 282 | * without variable names (bash compat). |
286 | * Thus, "read" and "read REPLY" are not the same. | 283 | * Thus, "read" and "read REPLY" are not the same. |
287 | */ | 284 | */ |
288 | if (!opt_d && argv[0]) { | 285 | if (!params->opt_d && argv[0]) { |
289 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ | 286 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ |
290 | const char *is_ifs = strchr(ifs, c); | 287 | const char *is_ifs = strchr(ifs, c); |
291 | if (startword && is_ifs) { | 288 | if (startword && is_ifs) { |
@@ -300,7 +297,7 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
300 | if (argv[1] != NULL && is_ifs) { | 297 | if (argv[1] != NULL && is_ifs) { |
301 | buffer[bufpos] = '\0'; | 298 | buffer[bufpos] = '\0'; |
302 | bufpos = 0; | 299 | bufpos = 0; |
303 | setvar(*argv, buffer); | 300 | params->setvar(*argv, buffer); |
304 | argv++; | 301 | argv++; |
305 | /* can we skip one non-space ifs char? (2: yes) */ | 302 | /* can we skip one non-space ifs char? (2: yes) */ |
306 | startword = isspace(c) ? 2 : 1; | 303 | startword = isspace(c) ? 2 : 1; |
@@ -352,14 +349,14 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |||
352 | } | 349 | } |
353 | 350 | ||
354 | /* Use the remainder as a value for the next variable */ | 351 | /* Use the remainder as a value for the next variable */ |
355 | setvar(*argv, buffer); | 352 | params->setvar(*argv, buffer); |
356 | /* Set the rest to "" */ | 353 | /* Set the rest to "" */ |
357 | while (*++argv) | 354 | while (*++argv) |
358 | setvar(*argv, ""); | 355 | params->setvar(*argv, ""); |
359 | } else { | 356 | } else { |
360 | /* Note: no $IFS removal */ | 357 | /* Note: no $IFS removal */ |
361 | buffer[bufpos] = '\0'; | 358 | buffer[bufpos] = '\0'; |
362 | setvar("REPLY", buffer); | 359 | params->setvar("REPLY", buffer); |
363 | } | 360 | } |
364 | 361 | ||
365 | ret: | 362 | ret: |