aboutsummaryrefslogtreecommitdiff
path: root/shell/shell_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/shell_common.c')
-rw-r--r--shell/shell_common.c57
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.
52const char* FAST_FUNC 52const char* FAST_FUNC
53shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), 53shell_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: