aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2020-11-16 13:00:44 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2020-11-16 13:00:44 +0100
commitdc9c10a7b29c93a36ff17c562cb14e11eb169f19 (patch)
treee3ec11dd1d0d0bf0fa37df32d26a7c583052b59d /shell
parentefe99b59c6cd3d9de91ebfc39f9870b8708e5b92 (diff)
downloadbusybox-w32-dc9c10a7b29c93a36ff17c562cb14e11eb169f19.tar.gz
busybox-w32-dc9c10a7b29c93a36ff17c562cb14e11eb169f19.tar.bz2
busybox-w32-dc9c10a7b29c93a36ff17c562cb14e11eb169f19.zip
hush: make interactive ^C break out of PS2 mode
function old new delta syntax_error_unterm_str - 26 +26 parse_stream 2238 2251 +13 fgetc_interactive 243 249 +6 parse_dollar 824 817 -7 syntax_error_unterm_ch 29 21 -8 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/2 up/down: 45/-15) Total: 30 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c86
1 files changed, 51 insertions, 35 deletions
diff --git a/shell/hush.c b/shell/hush.c
index ab7263381..f1a7e07ee 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -916,6 +916,9 @@ struct globals {
916 char opt_c; 916 char opt_c;
917#if ENABLE_HUSH_INTERACTIVE 917#if ENABLE_HUSH_INTERACTIVE
918 smallint promptmode; /* 0: PS1, 1: PS2 */ 918 smallint promptmode; /* 0: PS1, 1: PS2 */
919# if ENABLE_FEATURE_EDITING
920 smallint flag_ctrlC; /* when set, suppresses syntax error messages */
921# endif
919#endif 922#endif
920 smallint flag_SIGINT; 923 smallint flag_SIGINT;
921#if ENABLE_HUSH_LOOPS 924#if ENABLE_HUSH_LOOPS
@@ -1425,7 +1428,10 @@ static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg)
1425 1428
1426static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) 1429static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s)
1427{ 1430{
1428 bb_error_msg("syntax error: unterminated %s", s); 1431#if ENABLE_FEATURE_EDITING
1432 if (!G.flag_ctrlC)
1433#endif
1434 bb_error_msg("syntax error: unterminated %s", s);
1429//? source4.tests fails: in bash, echo ${^} in script does not terminate the script 1435//? source4.tests fails: in bash, echo ${^} in script does not terminate the script
1430// die_if_script(); 1436// die_if_script();
1431} 1437}
@@ -2629,26 +2635,27 @@ static int get_user_input(struct in_str *i)
2629# if ENABLE_FEATURE_EDITING 2635# if ENABLE_FEATURE_EDITING
2630 for (;;) { 2636 for (;;) {
2631 reinit_unicode_for_hush(); 2637 reinit_unicode_for_hush();
2632 if (G.flag_SIGINT) { 2638 G.flag_SIGINT = 0;
2633 /* There was ^C'ed, make it look prettier: */
2634 bb_putchar('\n');
2635 G.flag_SIGINT = 0;
2636 }
2637 /* buglet: SIGINT will not make new prompt to appear _at once_, 2639 /* buglet: SIGINT will not make new prompt to appear _at once_,
2638 * only after <Enter>. (^C works immediately) */ 2640 * only after <Enter>. (^C works immediately) */
2639 r = read_line_input(G.line_input_state, prompt_str, 2641 r = read_line_input(G.line_input_state, prompt_str,
2640 G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1 2642 G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1
2641 ); 2643 );
2642 /* read_line_input intercepts ^C, "convert" it to SIGINT */ 2644 /* read_line_input intercepts ^C, "convert" it to SIGINT */
2643 if (r == 0) 2645 if (r == 0) {
2646 G.flag_ctrlC = 1;
2644 raise(SIGINT); 2647 raise(SIGINT);
2648 }
2645 check_and_run_traps(); 2649 check_and_run_traps();
2646 if (r != 0 && !G.flag_SIGINT) 2650 if (r != 0 && !G.flag_SIGINT)
2647 break; 2651 break;
2648 /* ^C or SIGINT: repeat */ 2652 /* ^C or SIGINT: return EOF */
2649 /* bash prints ^C even on real SIGINT (non-kbd generated) */ 2653 /* bash prints ^C even on real SIGINT (non-kbd generated) */
2650 write(STDOUT_FILENO, "^C", 2); 2654 write(STDOUT_FILENO, "^C\n", 3);
2651 G.last_exitcode = 128 + SIGINT; 2655 G.last_exitcode = 128 + SIGINT;
2656 i->p = NULL;
2657 i->peek_buf[0] = r = EOF;
2658 return r;
2652 } 2659 }
2653 if (r < 0) { 2660 if (r < 0) {
2654 /* EOF/error detected */ 2661 /* EOF/error detected */
@@ -5260,22 +5267,31 @@ static struct pipe *parse_stream(char **pstring,
5260 ch, ch, !!(ctx.word.o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); 5267 ch, ch, !!(ctx.word.o_expflags & EXP_FLAG_ESC_GLOB_CHARS));
5261 if (ch == EOF) { 5268 if (ch == EOF) {
5262 struct pipe *pi; 5269 struct pipe *pi;
5263 5270#if ENABLE_FEATURE_EDITING
5271 if (G.flag_ctrlC) {
5272 /* testcase: interactively entering
5273 * 'qwe <cr> ^C
5274 * should not leave input in PS2 mode, waiting to close single quote.
5275 */
5276 G.flag_ctrlC = 0;
5277 goto parse_error;
5278 }
5279#endif
5264 if (heredoc_cnt) { 5280 if (heredoc_cnt) {
5265 syntax_error_unterm_str("here document"); 5281 syntax_error_unterm_str("here document");
5266 goto parse_error; 5282 goto parse_error_exitcode1;
5267 } 5283 }
5268 if (end_trigger == ')') { 5284 if (end_trigger == ')') {
5269 syntax_error_unterm_ch('('); 5285 syntax_error_unterm_ch('(');
5270 goto parse_error; 5286 goto parse_error_exitcode1;
5271 } 5287 }
5272 if (end_trigger == '}') { 5288 if (end_trigger == '}') {
5273 syntax_error_unterm_ch('{'); 5289 syntax_error_unterm_ch('{');
5274 goto parse_error; 5290 goto parse_error_exitcode1;
5275 } 5291 }
5276 5292
5277 if (done_word(&ctx)) { 5293 if (done_word(&ctx)) {
5278 goto parse_error; 5294 goto parse_error_exitcode1;
5279 } 5295 }
5280 o_free_and_set_NULL(&ctx.word); 5296 o_free_and_set_NULL(&ctx.word);
5281 done_pipe(&ctx, PIPE_SEQ); 5297 done_pipe(&ctx, PIPE_SEQ);
@@ -5345,7 +5361,7 @@ static struct pipe *parse_stream(char **pstring,
5345 while (1) { 5361 while (1) {
5346 if (ch == EOF) { 5362 if (ch == EOF) {
5347 syntax_error_unterm_ch('\''); 5363 syntax_error_unterm_ch('\'');
5348 goto parse_error; 5364 goto parse_error_exitcode1;
5349 } 5365 }
5350 nommu_addchr(&ctx.as_string, ch); 5366 nommu_addchr(&ctx.as_string, ch);
5351 if (ch == '\'') 5367 if (ch == '\'')
@@ -5424,7 +5440,7 @@ static struct pipe *parse_stream(char **pstring,
5424 /* ch == last eaten whitespace char */ 5440 /* ch == last eaten whitespace char */
5425#endif 5441#endif
5426 if (done_word(&ctx)) { 5442 if (done_word(&ctx)) {
5427 goto parse_error; 5443 goto parse_error_exitcode1;
5428 } 5444 }
5429 if (ch == '\n') { 5445 if (ch == '\n') {
5430 /* Is this a case when newline is simply ignored? 5446 /* Is this a case when newline is simply ignored?
@@ -5467,7 +5483,7 @@ static struct pipe *parse_stream(char **pstring,
5467 if (heredoc_cnt) { 5483 if (heredoc_cnt) {
5468 heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input); 5484 heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input);
5469 if (heredoc_cnt != 0) 5485 if (heredoc_cnt != 0)
5470 goto parse_error; 5486 goto parse_error_exitcode1;
5471 } 5487 }
5472 ctx.is_assignment = MAYBE_ASSIGNMENT; 5488 ctx.is_assignment = MAYBE_ASSIGNMENT;
5473 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); 5489 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
@@ -5517,7 +5533,7 @@ static struct pipe *parse_stream(char **pstring,
5517#endif 5533#endif
5518 ) { 5534 ) {
5519 if (done_word(&ctx)) { 5535 if (done_word(&ctx)) {
5520 goto parse_error; 5536 goto parse_error_exitcode1;
5521 } 5537 }
5522 done_pipe(&ctx, PIPE_SEQ); 5538 done_pipe(&ctx, PIPE_SEQ);
5523 ctx.is_assignment = MAYBE_ASSIGNMENT; 5539 ctx.is_assignment = MAYBE_ASSIGNMENT;
@@ -5538,7 +5554,7 @@ static struct pipe *parse_stream(char **pstring,
5538 /* Example: bare "{ }", "()" */ 5554 /* Example: bare "{ }", "()" */
5539 G.last_exitcode = 2; /* bash compat */ 5555 G.last_exitcode = 2; /* bash compat */
5540 syntax_error_unexpected_ch(ch); 5556 syntax_error_unexpected_ch(ch);
5541 goto parse_error2; 5557 goto parse_error;
5542 } 5558 }
5543 if (heredoc_cnt_ptr) 5559 if (heredoc_cnt_ptr)
5544 *heredoc_cnt_ptr = heredoc_cnt; 5560 *heredoc_cnt_ptr = heredoc_cnt;
@@ -5560,7 +5576,7 @@ static struct pipe *parse_stream(char **pstring,
5560 case '>': 5576 case '>':
5561 redir_fd = redirect_opt_num(&ctx.word); 5577 redir_fd = redirect_opt_num(&ctx.word);
5562 if (done_word(&ctx)) { 5578 if (done_word(&ctx)) {
5563 goto parse_error; 5579 goto parse_error_exitcode1;
5564 } 5580 }
5565 redir_style = REDIRECT_OVERWRITE; 5581 redir_style = REDIRECT_OVERWRITE;
5566 if (next == '>') { 5582 if (next == '>') {
@@ -5571,16 +5587,16 @@ static struct pipe *parse_stream(char **pstring,
5571#if 0 5587#if 0
5572 else if (next == '(') { 5588 else if (next == '(') {
5573 syntax_error(">(process) not supported"); 5589 syntax_error(">(process) not supported");
5574 goto parse_error; 5590 goto parse_error_exitcode1;
5575 } 5591 }
5576#endif 5592#endif
5577 if (parse_redirect(&ctx, redir_fd, redir_style, input)) 5593 if (parse_redirect(&ctx, redir_fd, redir_style, input))
5578 goto parse_error; 5594 goto parse_error_exitcode1;
5579 continue; /* get next char */ 5595 continue; /* get next char */
5580 case '<': 5596 case '<':
5581 redir_fd = redirect_opt_num(&ctx.word); 5597 redir_fd = redirect_opt_num(&ctx.word);
5582 if (done_word(&ctx)) { 5598 if (done_word(&ctx)) {
5583 goto parse_error; 5599 goto parse_error_exitcode1;
5584 } 5600 }
5585 redir_style = REDIRECT_INPUT; 5601 redir_style = REDIRECT_INPUT;
5586 if (next == '<') { 5602 if (next == '<') {
@@ -5597,11 +5613,11 @@ static struct pipe *parse_stream(char **pstring,
5597#if 0 5613#if 0
5598 else if (next == '(') { 5614 else if (next == '(') {
5599 syntax_error("<(process) not supported"); 5615 syntax_error("<(process) not supported");
5600 goto parse_error; 5616 goto parse_error_exitcode1;
5601 } 5617 }
5602#endif 5618#endif
5603 if (parse_redirect(&ctx, redir_fd, redir_style, input)) 5619 if (parse_redirect(&ctx, redir_fd, redir_style, input))
5604 goto parse_error; 5620 goto parse_error_exitcode1;
5605 continue; /* get next char */ 5621 continue; /* get next char */
5606 case '#': 5622 case '#':
5607 if (ctx.word.length == 0 && !ctx.word.has_quoted_part) { 5623 if (ctx.word.length == 0 && !ctx.word.has_quoted_part) {
@@ -5655,7 +5671,7 @@ static struct pipe *parse_stream(char **pstring,
5655 if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) { 5671 if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) {
5656 debug_printf_parse("parse_stream parse error: " 5672 debug_printf_parse("parse_stream parse error: "
5657 "parse_dollar returned 0 (error)\n"); 5673 "parse_dollar returned 0 (error)\n");
5658 goto parse_error; 5674 goto parse_error_exitcode1;
5659 } 5675 }
5660 continue; /* get next char */ 5676 continue; /* get next char */
5661 case '"': 5677 case '"':
@@ -5671,7 +5687,7 @@ static struct pipe *parse_stream(char **pstring,
5671 if (ctx.is_assignment == NOT_ASSIGNMENT) 5687 if (ctx.is_assignment == NOT_ASSIGNMENT)
5672 ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; 5688 ctx.word.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS;
5673 if (!encode_string(&ctx.as_string, &ctx.word, input, '"')) 5689 if (!encode_string(&ctx.as_string, &ctx.word, input, '"'))
5674 goto parse_error; 5690 goto parse_error_exitcode1;
5675 ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; 5691 ctx.word.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS;
5676 continue; /* get next char */ 5692 continue; /* get next char */
5677#if ENABLE_HUSH_TICK 5693#if ENABLE_HUSH_TICK
@@ -5682,7 +5698,7 @@ static struct pipe *parse_stream(char **pstring,
5682 o_addchr(&ctx.word, '`'); 5698 o_addchr(&ctx.word, '`');
5683 USE_FOR_NOMMU(pos = ctx.word.length;) 5699 USE_FOR_NOMMU(pos = ctx.word.length;)
5684 if (!add_till_backquote(&ctx.word, input, /*in_dquote:*/ 0)) 5700 if (!add_till_backquote(&ctx.word, input, /*in_dquote:*/ 0))
5685 goto parse_error; 5701 goto parse_error_exitcode1;
5686# if !BB_MMU 5702# if !BB_MMU
5687 o_addstr(&ctx.as_string, ctx.word.data + pos); 5703 o_addstr(&ctx.as_string, ctx.word.data + pos);
5688 o_addchr(&ctx.as_string, '`'); 5704 o_addchr(&ctx.as_string, '`');
@@ -5697,7 +5713,7 @@ static struct pipe *parse_stream(char **pstring,
5697 case_semi: 5713 case_semi:
5698#endif 5714#endif
5699 if (done_word(&ctx)) { 5715 if (done_word(&ctx)) {
5700 goto parse_error; 5716 goto parse_error_exitcode1;
5701 } 5717 }
5702 done_pipe(&ctx, PIPE_SEQ); 5718 done_pipe(&ctx, PIPE_SEQ);
5703#if ENABLE_HUSH_CASE 5719#if ENABLE_HUSH_CASE
@@ -5724,7 +5740,7 @@ static struct pipe *parse_stream(char **pstring,
5724 continue; /* get next char */ 5740 continue; /* get next char */
5725 case '&': 5741 case '&':
5726 if (done_word(&ctx)) { 5742 if (done_word(&ctx)) {
5727 goto parse_error; 5743 goto parse_error_exitcode1;
5728 } 5744 }
5729 if (next == '&') { 5745 if (next == '&') {
5730 ch = i_getch(input); 5746 ch = i_getch(input);
@@ -5736,7 +5752,7 @@ static struct pipe *parse_stream(char **pstring,
5736 goto new_cmd; 5752 goto new_cmd;
5737 case '|': 5753 case '|':
5738 if (done_word(&ctx)) { 5754 if (done_word(&ctx)) {
5739 goto parse_error; 5755 goto parse_error_exitcode1;
5740 } 5756 }
5741#if ENABLE_HUSH_CASE 5757#if ENABLE_HUSH_CASE
5742 if (ctx.ctx_res_w == RES_MATCH) 5758 if (ctx.ctx_res_w == RES_MATCH)
@@ -5768,7 +5784,7 @@ static struct pipe *parse_stream(char **pstring,
5768 case '{': { 5784 case '{': {
5769 int n = parse_group(&ctx, input, ch); 5785 int n = parse_group(&ctx, input, ch);
5770 if (n < 0) { 5786 if (n < 0) {
5771 goto parse_error; 5787 goto parse_error_exitcode1;
5772 } 5788 }
5773 debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n); 5789 debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n);
5774 heredoc_cnt += n; 5790 heredoc_cnt += n;
@@ -5786,16 +5802,16 @@ static struct pipe *parse_stream(char **pstring,
5786 * and it will match } earlier (not here). */ 5802 * and it will match } earlier (not here). */
5787 G.last_exitcode = 2; 5803 G.last_exitcode = 2;
5788 syntax_error_unexpected_ch(ch); 5804 syntax_error_unexpected_ch(ch);
5789 goto parse_error2; 5805 goto parse_error;
5790 default: 5806 default:
5791 if (HUSH_DEBUG) 5807 if (HUSH_DEBUG)
5792 bb_error_msg_and_die("BUG: unexpected %c", ch); 5808 bb_error_msg_and_die("BUG: unexpected %c", ch);
5793 } 5809 }
5794 } /* while (1) */ 5810 } /* while (1) */
5795 5811
5796 parse_error: 5812 parse_error_exitcode1:
5797 G.last_exitcode = 1; 5813 G.last_exitcode = 1;
5798 parse_error2: 5814 parse_error:
5799 { 5815 {
5800 struct parse_context *pctx; 5816 struct parse_context *pctx;
5801 IF_HAS_KEYWORDS(struct parse_context *p2;) 5817 IF_HAS_KEYWORDS(struct parse_context *p2;)