diff options
-rw-r--r-- | shell/hush.c | 64 |
1 files changed, 37 insertions, 27 deletions
diff --git a/shell/hush.c b/shell/hush.c index e4c3a7d77..a47652470 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -445,8 +445,6 @@ enum { /* Used for initialization: o_string foo = NULL_O_STRING; */ #define NULL_O_STRING { NULL } -/* I can almost use ordinary FILE*. Is open_memstream() universally - * available? Where is it documented? */ typedef struct in_str { const char *p; /* eof_flag=1: last char in ->p is really an EOF */ @@ -455,6 +453,7 @@ typedef struct in_str { #if ENABLE_HUSH_INTERACTIVE smallint promptmode; /* 0: PS1, 1: PS2 */ #endif + int last_char; FILE *file; int (*get) (struct in_str *) FAST_FUNC; int (*peek) (struct in_str *) FAST_FUNC; @@ -1077,22 +1076,22 @@ static void die_if_script(unsigned lineno, const char *fmt, ...) xfunc_die(); } -static void syntax_error(unsigned lineno, const char *msg) +static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) { if (msg) - die_if_script(lineno, "syntax error: %s", msg); + bb_error_msg("syntax error: %s", msg); else - die_if_script(lineno, "syntax error", NULL); + bb_error_msg("syntax error"); } -static void syntax_error_at(unsigned lineno, const char *msg) +static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) { - die_if_script(lineno, "syntax error at '%s'", msg); + bb_error_msg("syntax error at '%s'", msg); } -static void syntax_error_unterm_str(unsigned lineno, const char *s) +static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) { - die_if_script(lineno, "syntax error: unterminated %s", s); + bb_error_msg("syntax error: unterminated %s", s); } static void syntax_error_unterm_ch(unsigned lineno, char ch) @@ -1101,12 +1100,12 @@ static void syntax_error_unterm_ch(unsigned lineno, char ch) syntax_error_unterm_str(lineno, msg); } -static void syntax_error_unexpected_ch(unsigned lineno, int ch) +static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch) { char msg[2]; msg[0] = ch; msg[1] = '\0'; - die_if_script(lineno, "syntax error: unexpected %s", ch == EOF ? "EOF" : msg); + bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); } #if HUSH_DEBUG < 2 @@ -1843,6 +1842,7 @@ static int FAST_FUNC static_get(struct in_str *i) int ch = *i->p; if (ch != '\0') { i->p++; + i->last_char = ch; return ch; } return EOF; @@ -1964,6 +1964,7 @@ static int FAST_FUNC file_get(struct in_str *i) do ch = fgetc(i->file); while (ch == '\0'); } debug_printf("file_get: got '%c' %d\n", ch, ch); + i->last_char = ch; return ch; } @@ -4008,7 +4009,7 @@ static int encode_string(o_string *as_string, * Scan input until EOF or end_trigger char. * Return a list of pipes to execute, or NULL on EOF * or if end_trigger character is met. - * On syntax error, exit is shell is not interactive, + * On syntax error, exit if shell is not interactive, * reset parsing machinery and start parsing anew, * or return ERR_PTR. */ @@ -4037,8 +4038,6 @@ static struct pipe *parse_stream(char **pstring, * here we should use blank chars as separators, not $IFS */ - reset: /* we come back here only on syntax errors in interactive shell */ - if (MAYBE_ASSIGNMENT != 0) dest.o_assignment = MAYBE_ASSIGNMENT; initialize_context(&ctx); @@ -4532,20 +4531,17 @@ static struct pipe *parse_stream(char **pstring, } while (HAS_KEYWORDS && pctx); /* Free text, clear all dest fields */ o_free(&dest); + + G.last_exitcode = 1; /* If we are not in top-level parse, we return, * our caller will propagate error. */ - if (end_trigger != ';') { #if !BB_MMU - if (pstring) - *pstring = NULL; + if (pstring) + *pstring = NULL; #endif - debug_leave(); - return ERR_PTR; - } - /* Discard cached input, force prompt */ - input->p = NULL; - goto reset; + debug_leave(); + return ERR_PTR; } } @@ -5550,8 +5546,24 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger) inp->promptmode = 0; /* PS1 */ #endif pipe_list = parse_stream(NULL, inp, end_trigger); - if (!pipe_list) { /* EOF */ - if (empty) + if (!pipe_list || pipe_list == ERR_PTR) { /* EOF/error */ + /* If we are in "big" script + * (not in `cmd` or something similar)... + */ + if (pipe_list == ERR_PTR && end_trigger == ';') { + /* Discard cached input (rest of line) */ + int ch = inp->last_char; + while (ch != EOF && ch != '\n') { + //bb_error_msg("Discarded:'%c'", ch); + ch = i_getch(inp); + } + /* Force prompt */ + inp->p = NULL; + /* This stream isn't empty */ + empty = 0; + continue; + } + if (!pipe_list && empty) G.last_exitcode = 0; break; } @@ -8630,8 +8642,6 @@ static int FAST_FUNC builtin_source(char **argv) #endif save_and_replace_G_args(&sv, argv); -//TODO: syntax errors in sourced file should never abort the "calling" script. -//Try: bash -c '. ./bad_file; echo YES' parse_and_run_file(input); fclose(input); |