aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-09-30 01:49:53 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2016-09-30 01:49:53 +0200
commit4074d495577739d658ba04840b6a0876dfa236b0 (patch)
tree5d88d93040d4455cfed1cf468a85257ff3818628
parent0448c55cc84294d330305066d8f0a16b56e04b8b (diff)
downloadbusybox-w32-4074d495577739d658ba04840b6a0876dfa236b0.tar.gz
busybox-w32-4074d495577739d658ba04840b6a0876dfa236b0.tar.bz2
busybox-w32-4074d495577739d658ba04840b6a0876dfa236b0.zip
hush: fix interactive input handling of backslash+newline
function old new delta fgetc_interactive - 258 +258 i_peek_and_eat_bkslash_nl 43 93 +50 static_peek2 7 - -7 setup_string_in_str 46 39 -7 setup_file_in_str 47 40 -7 file_peek 72 52 -20 expand_vars_to_list 1167 1143 -24 file_peek2 74 - -74 file_get 326 65 -261 ------------------------------------------------------------------------------ (add/remove: 1/2 grow/shrink: 1/5 up/down: 308/-400) Total: -92 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/hush.c163
1 files changed, 89 insertions, 74 deletions
diff --git a/shell/hush.c b/shell/hush.c
index d0b53339d..1674598b6 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -470,11 +470,9 @@ typedef struct in_str {
470 FILE *file; 470 FILE *file;
471 int (*get) (struct in_str *) FAST_FUNC; 471 int (*get) (struct in_str *) FAST_FUNC;
472 int (*peek) (struct in_str *) FAST_FUNC; 472 int (*peek) (struct in_str *) FAST_FUNC;
473 int (*peek2) (struct in_str *) FAST_FUNC;
474} in_str; 473} in_str;
475#define i_getch(input) ((input)->get(input)) 474#define i_getch(input) ((input)->get(input))
476#define i_peek(input) ((input)->peek(input)) 475#define i_peek(input) ((input)->peek(input))
477#define i_peek2(input) ((input)->peek2(input))
478 476
479/* The descrip member of this structure is only used to make 477/* The descrip member of this structure is only used to make
480 * debugging output pretty */ 478 * debugging output pretty */
@@ -2129,6 +2127,14 @@ static void reinit_unicode_for_hush(void)
2129 */ 2127 */
2130 2128
2131#if ENABLE_HUSH_INTERACTIVE 2129#if ENABLE_HUSH_INTERACTIVE
2130/* To test correct lineedit/interactive behavior, type from command line:
2131 * echo $P\
2132 * \
2133 * AT\
2134 * H\
2135 * \
2136 * It excercises a lot of corner cases.
2137 */
2132static void cmdedit_update_prompt(void) 2138static void cmdedit_update_prompt(void)
2133{ 2139{
2134 if (ENABLE_FEATURE_EDITING_FANCY_PROMPT) { 2140 if (ENABLE_FEATURE_EDITING_FANCY_PROMPT) {
@@ -2159,7 +2165,7 @@ static const char *setup_prompt_string(int promptmode)
2159 prompt_str = G.PS2; 2165 prompt_str = G.PS2;
2160 } else 2166 } else
2161 prompt_str = (promptmode == 0) ? G.PS1 : G.PS2; 2167 prompt_str = (promptmode == 0) ? G.PS1 : G.PS2;
2162 debug_printf("result '%s'\n", prompt_str); 2168 debug_printf("prompt_str '%s'\n", prompt_str);
2163 return prompt_str; 2169 return prompt_str;
2164} 2170}
2165static int get_user_input(struct in_str *i) 2171static int get_user_input(struct in_str *i)
@@ -2169,8 +2175,6 @@ static int get_user_input(struct in_str *i)
2169 2175
2170 prompt_str = setup_prompt_string(i->promptmode); 2176 prompt_str = setup_prompt_string(i->promptmode);
2171# if ENABLE_FEATURE_EDITING 2177# if ENABLE_FEATURE_EDITING
2172 /* Enable command line editing only while a command line
2173 * is actually being read */
2174 do { 2178 do {
2175 reinit_unicode_for_hush(); 2179 reinit_unicode_for_hush();
2176 G.flag_SIGINT = 0; 2180 G.flag_SIGINT = 0;
@@ -2183,13 +2187,13 @@ static int get_user_input(struct in_str *i)
2183 /* catch *SIGINT* etc (^C is handled by read_line_input) */ 2187 /* catch *SIGINT* etc (^C is handled by read_line_input) */
2184 check_and_run_traps(); 2188 check_and_run_traps();
2185 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ 2189 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */
2186 i->p = G.user_input_buf;
2187 if (r < 0) { 2190 if (r < 0) {
2188 /* EOF/error detected */ 2191 /* EOF/error detected */
2189 G.user_input_buf[0] = '\0'; 2192 i->p = NULL;
2190 i->peek_buf[1] = i->peek_buf[0] = r = EOF; 2193 i->peek_buf[0] = r = EOF;
2191 return r; 2194 return r;
2192 } 2195 }
2196 i->p = G.user_input_buf;
2193 return (unsigned char)*i->p++; 2197 return (unsigned char)*i->p++;
2194# else 2198# else
2195 do { 2199 do {
@@ -2209,18 +2213,45 @@ static int get_user_input(struct in_str *i)
2209 return r; 2213 return r;
2210# endif 2214# endif
2211} 2215}
2212#endif /* INTERACTIVE */
2213
2214/* This is the magic location that prints prompts 2216/* This is the magic location that prints prompts
2215 * and gets data back from the user */ 2217 * and gets data back from the user */
2218static int fgetc_interactive(struct in_str *i)
2219{
2220 int ch;
2221 /* If it's interactive stdin, get new line. */
2222 if (G_interactive_fd && i->file == stdin) {
2223 /* Returns first char (or EOF), the rest is in i->p[] */
2224 ch = get_user_input(i);
2225 i->promptmode = 1; /* PS2 */
2226 } else {
2227 /* Not stdin: script file, sourced file, etc */
2228 do ch = fgetc(i->file); while (ch == '\0');
2229 }
2230 return ch;
2231}
2232#else
2233static inline int fgetc_interactive(struct in_str *i)
2234{
2235 int ch;
2236 do ch = fgetc(i->file); while (ch == '\0');
2237 return ch;
2238}
2239#endif /* INTERACTIVE */
2240
2216static int FAST_FUNC file_get(struct in_str *i) 2241static int FAST_FUNC file_get(struct in_str *i)
2217{ 2242{
2218 int ch; 2243 int ch;
2219 2244
2220 /* If there is data waiting, eat it up */ 2245#if ENABLE_FEATURE_EDITING
2246 /* This can be stdin, check line editing char[] buffer */
2247 if (i->p && *i->p != '\0') {
2248 ch = (unsigned char)*i->p++;
2249 goto out;
2250 }
2251#endif
2221 /* peek_buf[] is an int array, not char. Can contain EOF. */ 2252 /* peek_buf[] is an int array, not char. Can contain EOF. */
2222 ch = i->peek_buf[0]; 2253 ch = i->peek_buf[0];
2223 if (ch != '\0') { 2254 if (ch != 0) {
2224 int ch2 = i->peek_buf[1]; 2255 int ch2 = i->peek_buf[1];
2225 i->peek_buf[0] = ch2; 2256 i->peek_buf[0] = ch2;
2226 if (ch2 == 0) /* very likely, avoid redundant write */ 2257 if (ch2 == 0) /* very likely, avoid redundant write */
@@ -2229,86 +2260,46 @@ static int FAST_FUNC file_get(struct in_str *i)
2229 goto out; 2260 goto out;
2230 } 2261 }
2231 2262
2232#if ENABLE_HUSH_INTERACTIVE 2263 ch = fgetc_interactive(i);
2233 /* This can be stdin, check line editing char[] buffer */
2234 if (i->p && *i->p != '\0') {
2235 ch = (unsigned char)*i->p++;
2236 goto out;
2237 }
2238 /* It's empty.
2239 * If it's interactive stdin, get new line.
2240 */
2241 if (G_interactive_fd && i->file == stdin) {
2242 /* Returns first char (or EOF), the rest are in i->p[] */
2243 ch = get_user_input(i);
2244 i->promptmode = 1; /* PS2 */
2245 goto out;
2246 }
2247 /* Not stdin: script file */
2248#endif
2249 do ch = fgetc(i->file); while (ch == '\0');
2250 out: 2264 out:
2251 debug_printf("file_get: got '%c' %d\n", ch, ch); 2265 debug_printf("file_get: got '%c' %d\n", ch, ch);
2252 i->last_char = ch; 2266 i->last_char = ch;
2253 return ch; 2267 return ch;
2254} 2268}
2255 2269
2256/* All callers guarantee this routine will never
2257 * be used right after a newline, so prompting is not needed.
2258 */
2259static int FAST_FUNC file_peek(struct in_str *i) 2270static int FAST_FUNC file_peek(struct in_str *i)
2260{ 2271{
2261 int ch; 2272 int ch;
2262 2273
2263 /* peek_buf[] is an int array, not char. Can contain EOF. */ 2274#if ENABLE_FEATURE_EDITING && ENABLE_HUSH_INTERACTIVE
2264 ch = i->peek_buf[0];
2265 if (ch != '\0')
2266 return ch;
2267
2268#if ENABLE_HUSH_INTERACTIVE
2269 /* This can be stdin, check line editing char[] buffer */ 2275 /* This can be stdin, check line editing char[] buffer */
2270 if (i->p && *i->p != '\0') 2276 if (i->p && *i->p != '\0')
2271 return (unsigned char)*i->p; 2277 return (unsigned char)*i->p;
2272#endif 2278#endif
2279 /* peek_buf[] is an int array, not char. Can contain EOF. */
2280 ch = i->peek_buf[0];
2281 if (ch != 0)
2282 return ch;
2273 2283
2274 do ch = fgetc(i->file); while (ch == '\0'); 2284 /* Need to get a new char */
2275 i->peek_buf[0] = ch; 2285 ch = fgetc_interactive(i);
2276 i->peek_buf[1] = 0;
2277 debug_printf("file_peek: got '%c' %d\n", ch, ch); 2286 debug_printf("file_peek: got '%c' %d\n", ch, ch);
2278 return ch;
2279}
2280 2287
2281/* Only ever called if i_peek() was called, and did not return EOF */ 2288 /* Save it by either rolling back line editing buffer, or in i->peek_buf[0] */
2282static int FAST_FUNC file_peek2(struct in_str *i) 2289#if ENABLE_FEATURE_EDITING && ENABLE_HUSH_INTERACTIVE
2283{ 2290 if (i->p) {
2284 int ch; 2291 i->p -= 1;
2285 2292 return ch;
2286 /* peek_buf[] is an int array, not char. Can contain EOF. */
2287 ch = i->peek_buf[0];
2288 if (ch != 0) {
2289 /* peek_buf[] is not empty. Is there 2nd char? */
2290 ch = i->peek_buf[1];
2291 if (ch == 0) {
2292 /* We did not read it yet, get it now */
2293 do ch = fgetc(i->file); while (ch == '\0');
2294 i->peek_buf[1] = ch;
2295 }
2296 goto out;
2297 } 2293 }
2298
2299#if ENABLE_HUSH_INTERACTIVE
2300 /* This can be stdin, check line editing char[] buffer */
2301 if (i->p && i->p[0] != '\0')
2302 ch = i->p[1];
2303#endif 2294#endif
2304 out: 2295 i->peek_buf[0] = ch;
2305 debug_printf("file_peek2: got '%c' %d\n", ch, ch); 2296 /*i->peek_buf[1] = 0; - already is */
2306 return ch; 2297 return ch;
2307} 2298}
2308 2299
2309static int FAST_FUNC static_get(struct in_str *i) 2300static int FAST_FUNC static_get(struct in_str *i)
2310{ 2301{
2311 int ch = *i->p; 2302 int ch = (unsigned char)*i->p;
2312 if (ch != '\0') { 2303 if (ch != '\0') {
2313 i->p++; 2304 i->p++;
2314 i->last_char = ch; 2305 i->last_char = ch;
@@ -2320,13 +2311,39 @@ static int FAST_FUNC static_get(struct in_str *i)
2320static int FAST_FUNC static_peek(struct in_str *i) 2311static int FAST_FUNC static_peek(struct in_str *i)
2321{ 2312{
2322 /* Doesn't report EOF on NUL. None of the callers care. */ 2313 /* Doesn't report EOF on NUL. None of the callers care. */
2323 return *i->p; 2314 return (unsigned char)*i->p;
2324} 2315}
2325 2316
2326/* Only ever called if i_peek() was called, and did not return EOF */ 2317/* Only ever called if i_peek() was called, and did not return EOF.
2327static int FAST_FUNC static_peek2(struct in_str *i) 2318 * IOW: we know the previous peek saw an ordinary char, not EOF, not NUL,
2319 * not end-of-line. Therefore we never need to read a new editing line here.
2320 */
2321static int i_peek2(struct in_str *i)
2328{ 2322{
2329 return i->p[1]; 2323 int ch;
2324
2325 /* There are two cases when i->p[] buffer exists.
2326 * (1) it's a string in_str.
2327 * (2) It's a file, and we have s saved line editing buffer.
2328 * In both cases, we know that i->p[0] exists and not NUL, and
2329 * the peek2 result is in i->p[1].
2330 */
2331 if (i->p)
2332 return (unsigned char)i->p[1];
2333
2334 /* Now we know it is a file-based in_str. */
2335
2336 /* peek_buf[] is an int array, not char. Can contain EOF. */
2337 /* Is there 2nd char? */
2338 ch = i->peek_buf[1];
2339 if (ch == 0) {
2340 /* We did not read it yet, get it now */
2341 do ch = fgetc(i->file); while (ch == '\0');
2342 i->peek_buf[1] = ch;
2343 }
2344
2345 debug_printf("file_peek2: got '%c' %d\n", ch, ch);
2346 return ch;
2330} 2347}
2331 2348
2332static void setup_file_in_str(struct in_str *i, FILE *f) 2349static void setup_file_in_str(struct in_str *i, FILE *f)
@@ -2334,7 +2351,6 @@ static void setup_file_in_str(struct in_str *i, FILE *f)
2334 memset(i, 0, sizeof(*i)); 2351 memset(i, 0, sizeof(*i));
2335 i->get = file_get; 2352 i->get = file_get;
2336 i->peek = file_peek; 2353 i->peek = file_peek;
2337 i->peek2 = file_peek2;
2338 /* i->promptmode = 0; - PS1 (memset did it) */ 2354 /* i->promptmode = 0; - PS1 (memset did it) */
2339 i->file = f; 2355 i->file = f;
2340 /* i->p = NULL; */ 2356 /* i->p = NULL; */
@@ -2345,7 +2361,6 @@ static void setup_string_in_str(struct in_str *i, const char *s)
2345 memset(i, 0, sizeof(*i)); 2361 memset(i, 0, sizeof(*i));
2346 i->get = static_get; 2362 i->get = static_get;
2347 i->peek = static_peek; 2363 i->peek = static_peek;
2348 i->peek2 = static_peek2;
2349 /* i->promptmode = 0; - PS1 (memset did it) */ 2364 /* i->promptmode = 0; - PS1 (memset did it) */
2350 i->p = s; 2365 i->p = s;
2351} 2366}