aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-09-29 18:02:37 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2016-09-29 18:02:37 +0200
commitd17a91db6e0817644445f28515d68b3033388eb4 (patch)
tree427cb084faadaad8a3027564100b4f75e21bb5b8
parent459293b1c536515fbe7fafbae9932aefadb2fbaf (diff)
downloadbusybox-w32-d17a91db6e0817644445f28515d68b3033388eb4.tar.gz
busybox-w32-d17a91db6e0817644445f28515d68b3033388eb4.tar.bz2
busybox-w32-d17a91db6e0817644445f28515d68b3033388eb4.zip
hush: rework input char buffering to allow more than one-deep peek
...this time with actual hush.c changes too :) Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/hush.c193
1 files changed, 125 insertions, 68 deletions
diff --git a/shell/hush.c b/shell/hush.c
index d7d152c10..e3dcf2c38 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -462,19 +462,19 @@ static const char *const assignment_flag[] = {
462 462
463typedef struct in_str { 463typedef struct in_str {
464 const char *p; 464 const char *p;
465 /* eof_flag=1: last char in ->p is really an EOF */
466 char eof_flag; /* meaningless if ->p == NULL */
467 char peek_buf[2];
468#if ENABLE_HUSH_INTERACTIVE 465#if ENABLE_HUSH_INTERACTIVE
469 smallint promptmode; /* 0: PS1, 1: PS2 */ 466 smallint promptmode; /* 0: PS1, 1: PS2 */
470#endif 467#endif
468 int peek_buf[2];
471 int last_char; 469 int last_char;
472 FILE *file; 470 FILE *file;
473 int (*get) (struct in_str *) FAST_FUNC; 471 int (*get) (struct in_str *) FAST_FUNC;
474 int (*peek) (struct in_str *) FAST_FUNC; 472 int (*peek) (struct in_str *) FAST_FUNC;
473 int (*peek2) (struct in_str *) FAST_FUNC;
475} in_str; 474} in_str;
476#define i_getch(input) ((input)->get(input)) 475#define i_getch(input) ((input)->get(input))
477#define i_peek(input) ((input)->peek(input)) 476#define i_peek(input) ((input)->peek(input))
477#define i_peek2(input) ((input)->peek2(input))
478 478
479/* The descrip member of this structure is only used to make 479/* The descrip member of this structure is only used to make
480 * debugging output pretty */ 480 * debugging output pretty */
@@ -2122,28 +2122,11 @@ static void reinit_unicode_for_hush(void)
2122 } 2122 }
2123} 2123}
2124 2124
2125
2126/* 2125/*
2127 * in_str support 2126 * in_str support (strings, and "strings" read from files).
2128 */ 2127 */
2129static int FAST_FUNC static_get(struct in_str *i)
2130{
2131 int ch = *i->p;
2132 if (ch != '\0') {
2133 i->p++;
2134 i->last_char = ch;
2135 return ch;
2136 }
2137 return EOF;
2138}
2139
2140static int FAST_FUNC static_peek(struct in_str *i)
2141{
2142 return *i->p;
2143}
2144 2128
2145#if ENABLE_HUSH_INTERACTIVE 2129#if ENABLE_HUSH_INTERACTIVE
2146
2147static void cmdedit_update_prompt(void) 2130static void cmdedit_update_prompt(void)
2148{ 2131{
2149 if (ENABLE_FEATURE_EDITING_FANCY_PROMPT) { 2132 if (ENABLE_FEATURE_EDITING_FANCY_PROMPT) {
@@ -2157,7 +2140,6 @@ static void cmdedit_update_prompt(void)
2157 if (G.PS2 == NULL) 2140 if (G.PS2 == NULL)
2158 G.PS2 = "> "; 2141 G.PS2 = "> ";
2159} 2142}
2160
2161static const char *setup_prompt_string(int promptmode) 2143static const char *setup_prompt_string(int promptmode)
2162{ 2144{
2163 const char *prompt_str; 2145 const char *prompt_str;
@@ -2178,8 +2160,7 @@ static const char *setup_prompt_string(int promptmode)
2178 debug_printf("result '%s'\n", prompt_str); 2160 debug_printf("result '%s'\n", prompt_str);
2179 return prompt_str; 2161 return prompt_str;
2180} 2162}
2181 2163static int get_user_input(struct in_str *i)
2182static void get_user_input(struct in_str *i)
2183{ 2164{
2184 int r; 2165 int r;
2185 const char *prompt_str; 2166 const char *prompt_str;
@@ -2197,11 +2178,14 @@ static void get_user_input(struct in_str *i)
2197 /* catch *SIGINT* etc (^C is handled by read_line_input) */ 2178 /* catch *SIGINT* etc (^C is handled by read_line_input) */
2198 check_and_run_traps(); 2179 check_and_run_traps();
2199 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ 2180 } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */
2200 i->eof_flag = (r < 0); 2181 i->p = G.user_input_buf;
2201 if (i->eof_flag) { /* EOF/error detected */ 2182 if (r < 0) {
2202 G.user_input_buf[0] = EOF; /* yes, it will be truncated, it's ok */ 2183 /* EOF/error detected */
2203 G.user_input_buf[1] = '\0'; 2184 G.user_input_buf[0] = '\0';
2185 i->peek_buf[1] = i->peek_buf[0] = r = EOF;
2186 return r;
2204 } 2187 }
2188 return (unsigned char)*i->p++;
2205# else 2189# else
2206 do { 2190 do {
2207 G.flag_SIGINT = 0; 2191 G.flag_SIGINT = 0;
@@ -2215,14 +2199,11 @@ static void get_user_input(struct in_str *i)
2215 fputs(prompt_str, stdout); 2199 fputs(prompt_str, stdout);
2216 } 2200 }
2217 fflush_all(); 2201 fflush_all();
2218 G.user_input_buf[0] = r = fgetc(i->file); 2202 r = fgetc(i->file);
2219 /*G.user_input_buf[1] = '\0'; - already is and never changed */ 2203 } while (G.flag_SIGINT || r == '\0');
2220 } while (G.flag_SIGINT); 2204 return r;
2221 i->eof_flag = (r == EOF);
2222# endif 2205# endif
2223 i->p = G.user_input_buf;
2224} 2206}
2225
2226#endif /* INTERACTIVE */ 2207#endif /* INTERACTIVE */
2227 2208
2228/* This is the magic location that prints prompts 2209/* This is the magic location that prints prompts
@@ -2232,28 +2213,36 @@ static int FAST_FUNC file_get(struct in_str *i)
2232 int ch; 2213 int ch;
2233 2214
2234 /* If there is data waiting, eat it up */ 2215 /* If there is data waiting, eat it up */
2235 if (i->p && *i->p) { 2216 /* peek_buf[] is an int array, not char. Can contain EOF. */
2236#if ENABLE_HUSH_INTERACTIVE 2217 ch = i->peek_buf[0];
2237 take_cached: 2218 if (ch != '\0') {
2238#endif 2219 int ch2 = i->peek_buf[1];
2239 ch = *i->p++; 2220 i->peek_buf[0] = ch2;
2240 if (i->eof_flag && !*i->p) 2221 if (ch2 == 0) /* very likely, avoid redundant write */
2241 ch = EOF; 2222 goto out;
2242 /* note: ch is never NUL */ 2223 i->peek_buf[1] = 0;
2243 } else { 2224 goto out;
2244 /* need to double check i->file because we might be doing something 2225 }
2245 * more complicated by now, like sourcing or substituting. */ 2226
2246#if ENABLE_HUSH_INTERACTIVE 2227#if ENABLE_HUSH_INTERACTIVE
2247 if (G_interactive_fd && i->file == stdin) { 2228 /* This can be stdin, check line editing char[] buffer */
2248 do { 2229 if (i->p && *i->p != '\0') {
2249 get_user_input(i); 2230 ch = (unsigned char)*i->p++;
2250 } while (!*i->p); /* need non-empty line */ 2231 goto out;
2251 i->promptmode = 1; /* PS2 */ 2232 }
2252 goto take_cached; 2233 /* It's empty.
2253 } 2234 * If it's interactive stdin, get new line.
2254#endif 2235 */
2255 do ch = fgetc(i->file); while (ch == '\0'); 2236 if (G_interactive_fd && i->file == stdin) {
2237 /* Returns first char (or EOF), the rest are in i->p[] */
2238 ch = get_user_input(i);
2239 i->promptmode = 1; /* PS2 */
2240 goto out;
2256 } 2241 }
2242 /* Not stdin: script file */
2243#endif
2244 do ch = fgetc(i->file); while (ch == '\0');
2245 out:
2257 debug_printf("file_get: got '%c' %d\n", ch, ch); 2246 debug_printf("file_get: got '%c' %d\n", ch, ch);
2258 i->last_char = ch; 2247 i->last_char = ch;
2259 return ch; 2248 return ch;
@@ -2265,26 +2254,82 @@ static int FAST_FUNC file_get(struct in_str *i)
2265static int FAST_FUNC file_peek(struct in_str *i) 2254static int FAST_FUNC file_peek(struct in_str *i)
2266{ 2255{
2267 int ch; 2256 int ch;
2268 if (i->p && *i->p) { 2257
2269 if (i->eof_flag && !i->p[1]) 2258 /* peek_buf[] is an int array, not char. Can contain EOF. */
2270 return EOF; 2259 ch = i->peek_buf[0];
2271 return *i->p; 2260 if (ch != '\0')
2272 /* note: ch is never NUL */ 2261 return ch;
2273 } 2262
2263#if ENABLE_HUSH_INTERACTIVE
2264 /* This can be stdin, check line editing char[] buffer */
2265 if (i->p && *i->p != '\0')
2266 return (unsigned char)*i->p;
2267#endif
2268
2274 do ch = fgetc(i->file); while (ch == '\0'); 2269 do ch = fgetc(i->file); while (ch == '\0');
2275 i->eof_flag = (ch == EOF);
2276 i->peek_buf[0] = ch; 2270 i->peek_buf[0] = ch;
2277 i->peek_buf[1] = '\0'; 2271 i->peek_buf[1] = 0;
2278 i->p = i->peek_buf;
2279 debug_printf("file_peek: got '%c' %d\n", ch, ch); 2272 debug_printf("file_peek: got '%c' %d\n", ch, ch);
2280 return ch; 2273 return ch;
2281} 2274}
2282 2275
2276/* Only ever called if i_peek() was called, and did not return EOF */
2277static int FAST_FUNC file_peek2(struct in_str *i)
2278{
2279 int ch;
2280
2281 /* peek_buf[] is an int array, not char. Can contain EOF. */
2282 ch = i->peek_buf[0];
2283 if (ch != 0) {
2284 /* peek_buf[] is not empty. Is there 2nd char? */
2285 ch = i->peek_buf[1];
2286 if (ch == 0) {
2287 /* We did not read it yet, get it now */
2288 do ch = fgetc(i->file); while (ch == '\0');
2289 i->peek_buf[1] = ch;
2290 }
2291 goto out;
2292 }
2293
2294#if ENABLE_HUSH_INTERACTIVE
2295 /* This can be stdin, check line editing char[] buffer */
2296 if (i->p && i->p[0] != '\0')
2297 ch = i->p[1];
2298#endif
2299 out:
2300 debug_printf("file_peek2: got '%c' %d\n", ch, ch);
2301 return ch;
2302}
2303
2304static int FAST_FUNC static_get(struct in_str *i)
2305{
2306 int ch = *i->p;
2307 if (ch != '\0') {
2308 i->p++;
2309 i->last_char = ch;
2310 return ch;
2311 }
2312 return EOF;
2313}
2314
2315static int FAST_FUNC static_peek(struct in_str *i)
2316{
2317 /* Doesn't report EOF on NUL. None of the callers care. */
2318 return *i->p;
2319}
2320
2321/* Only ever called if i_peek() was called, and did not return EOF */
2322static int FAST_FUNC static_peek2(struct in_str *i)
2323{
2324 return i->p[1];
2325}
2326
2283static void setup_file_in_str(struct in_str *i, FILE *f) 2327static void setup_file_in_str(struct in_str *i, FILE *f)
2284{ 2328{
2285 memset(i, 0, sizeof(*i)); 2329 memset(i, 0, sizeof(*i));
2286 i->peek = file_peek;
2287 i->get = file_get; 2330 i->get = file_get;
2331 i->peek = file_peek;
2332 i->peek2 = file_peek2;
2288 /* i->promptmode = 0; - PS1 (memset did it) */ 2333 /* i->promptmode = 0; - PS1 (memset did it) */
2289 i->file = f; 2334 i->file = f;
2290 /* i->p = NULL; */ 2335 /* i->p = NULL; */
@@ -2293,11 +2338,11 @@ static void setup_file_in_str(struct in_str *i, FILE *f)
2293static void setup_string_in_str(struct in_str *i, const char *s) 2338static void setup_string_in_str(struct in_str *i, const char *s)
2294{ 2339{
2295 memset(i, 0, sizeof(*i)); 2340 memset(i, 0, sizeof(*i));
2296 i->peek = static_peek;
2297 i->get = static_get; 2341 i->get = static_get;
2342 i->peek = static_peek;
2343 i->peek2 = static_peek2;
2298 /* i->promptmode = 0; - PS1 (memset did it) */ 2344 /* i->promptmode = 0; - PS1 (memset did it) */
2299 i->p = s; 2345 i->p = s;
2300 /* i->eof_flag = 0; */
2301} 2346}
2302 2347
2303 2348
@@ -4040,9 +4085,21 @@ static int parse_dollar(o_string *as_string,
4040 debug_printf_parse(": '%c'\n", ch); 4085 debug_printf_parse(": '%c'\n", ch);
4041 o_addchr(dest, ch | quote_mask); 4086 o_addchr(dest, ch | quote_mask);
4042 quote_mask = 0; 4087 quote_mask = 0;
4088 next_ch:
4043 ch = i_peek(input); 4089 ch = i_peek(input);
4044 if (!isalnum(ch) && ch != '_') 4090 if (!isalnum(ch) && ch != '_') {
4091 if (ch == '\\') {
4092 /* If backslash+newline, skip it */
4093 int ch2 = i_peek2(input);
4094 if (ch2 == '\n') {
4095 i_getch(input);
4096 i_getch(input);
4097 goto next_ch;
4098 }
4099 }
4100 /* End of variable name reached */
4045 break; 4101 break;
4102 }
4046 ch = i_getch(input); 4103 ch = i_getch(input);
4047 nommu_addchr(as_string, ch); 4104 nommu_addchr(as_string, ch);
4048 } 4105 }