| @@ -1272,7 +1272,7 @@ static void xxfree(void *ptr) |
| * HUSH_DEBUG >= 2 prints line number in this file where it was detected. |
| */ |
| #if HUSH_DEBUG < 2 |
| - | # define die_if_script(lineno, ...) die_if_script(__VA_ARGS__) |
| + | # define msg_and_die_if_script(lineno, ...) msg_and_die_if_script(__VA_ARGS__) |
| # define syntax_error(lineno, msg) syntax_error(msg) |
| # define syntax_error_at(lineno, msg) syntax_error_at(msg) |
| # define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) |
| @@ -1280,7 +1280,16 @@ static void xxfree(void *ptr) |
| # define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch) |
| #endif |
| |
| - | static void die_if_script(unsigned lineno, const char *fmt, ...) |
| + | static void die_if_script(void) |
| + | { |
| + | if (!G_interactive_fd) { |
| + | if (G.last_exitcode) /* sometines it's 2, not 1 (bash compat) */ |
| + | xfunc_error_retval = G.last_exitcode; |
| + | xfunc_die(); |
| + | } |
| + | } |
| + | |
| + | static void msg_and_die_if_script(unsigned lineno, const char *fmt, ...) |
| { |
| va_list p; |
| |
| @@ -1290,8 +1299,7 @@ static void die_if_script(unsigned lineno, const char *fmt, ...) |
| va_start(p, fmt); |
| bb_verror_msg(fmt, p, NULL); |
| va_end(p); |
| - | if (!G_interactive_fd) |
| - | xfunc_die(); |
| + | die_if_script(); |
| } |
| |
| static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) |
| @@ -1300,16 +1308,20 @@ static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) |
| bb_error_msg("syntax error: %s", msg); |
| else |
| bb_error_msg("syntax error"); |
| + | die_if_script(); |
| } |
| |
| static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) |
| { |
| bb_error_msg("syntax error at '%s'", msg); |
| + | die_if_script(); |
| } |
| |
| static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) |
| { |
| bb_error_msg("syntax error: unterminated %s", s); |
| + | //? source4.tests fails: in bash, echo ${^} in script does not terminate the script |
| + | // die_if_script(); |
| } |
| |
| static void syntax_error_unterm_ch(unsigned lineno, char ch) |
| @@ -1327,17 +1339,18 @@ static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch) |
| bb_error_msg("hush.c:%u", lineno); |
| #endif |
| bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); |
| + | die_if_script(); |
| } |
| |
| #if HUSH_DEBUG < 2 |
| - | # undef die_if_script |
| + | # undef msg_and_die_if_script |
| # undef syntax_error |
| # undef syntax_error_at |
| # undef syntax_error_unterm_ch |
| # undef syntax_error_unterm_str |
| # undef syntax_error_unexpected_ch |
| #else |
| - | # define die_if_script(...) die_if_script(__LINE__, __VA_ARGS__) |
| + | # define msg_and_die_if_script(...) msg_and_die_if_script(__LINE__, __VA_ARGS__) |
| # define syntax_error(msg) syntax_error(__LINE__, msg) |
| # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) |
| # define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) |
| @@ -1800,7 +1813,7 @@ static void restore_ttypgrp_and__exit(void) |
| * echo END_OF_SCRIPT |
| * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". |
| * This makes "echo END_OF_SCRIPT" executed twice. |
| - | * Similar problems can be seen with die_if_script() -> xfunc_die() |
| + | * Similar problems can be seen with msg_and_die_if_script() -> xfunc_die() |
| * and in `cmd` handling. |
| * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): |
| */ |
| @@ -3383,7 +3396,7 @@ static int done_command(struct parse_context *ctx) |
| #if 0 /* Instead we emit error message at run time */ |
| if (ctx->pending_redirect) { |
| /* For example, "cmd >" (no filename to redirect to) */ |
| - | die_if_script("syntax error: %s", "invalid redirect"); |
| + | syntax_error("invalid redirect"); |
| ctx->pending_redirect = NULL; |
| } |
| #endif |
| @@ -3949,7 +3962,7 @@ static int parse_redirect(struct parse_context *ctx, |
| #if 0 /* Instead we emit error message at run time */ |
| if (ctx->pending_redirect) { |
| /* For example, "cmd > <file" */ |
| - | die_if_script("syntax error: %s", "invalid redirect"); |
| + | syntax_error("invalid redirect"); |
| } |
| #endif |
| /* Set ctx->pending_redirect, so we know what to do at the |
| @@ -5021,10 +5034,16 @@ static struct pipe *parse_stream(char **pstring, |
| else |
| o_free_unsafe(&ctx.as_string); |
| #endif |
| - | debug_leave(); |
| + | if (ch != ';' && IS_NULL_PIPE(ctx.list_head)) { |
| + | /* Example: bare "{ }", "()" */ |
| + | G.last_exitcode = 2; /* bash compat */ |
| + | syntax_error_unexpected_ch(ch); |
| + | goto parse_error2; |
| + | } |
| debug_printf_parse("parse_stream return %p: " |
| "end_trigger char found\n", |
| ctx.list_head); |
| + | debug_leave(); |
| return ctx.list_head; |
| } |
| } |
| @@ -5282,8 +5301,8 @@ static struct pipe *parse_stream(char **pstring, |
| /* proper use of this character is caught by end_trigger: |
| * if we see {, we call parse_group(..., end_trigger='}') |
| * and it will match } earlier (not here). */ |
| - | syntax_error_unexpected_ch(ch); |
| G.last_exitcode = 2; |
| + | syntax_error_unexpected_ch(ch); |
| goto parse_error2; |
| default: |
| if (HUSH_DEBUG) |
| @@ -5513,7 +5532,7 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p) |
| if (errmsg_p) |
| *errmsg_p = math_state.errmsg; |
| if (math_state.errmsg) |
| - | die_if_script(math_state.errmsg); |
| + | msg_and_die_if_script(math_state.errmsg); |
| return res; |
| } |
| #endif |
| @@ -5780,7 +5799,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha |
| /* in bash, len=-n means strlen()-n */ |
| len = (arith_t)strlen(val) - beg + len; |
| if (len < 0) /* bash compat */ |
| - | die_if_script("%s: substring expression < 0", var); |
| + | msg_and_die_if_script("%s: substring expression < 0", var); |
| } |
| if (len <= 0 || !val || beg >= strlen(val)) { |
| arith_err: |
| @@ -5794,7 +5813,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha |
| } |
| debug_printf_varexp("val:'%s'\n", val); |
| #else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */ |
| - | die_if_script("malformed ${%s:...}", var); |
| + | msg_and_die_if_script("malformed ${%s:...}", var); |
| val = NULL; |
| #endif |
| } else { /* one of "-=+?" */ |
| @@ -5831,7 +5850,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha |
| exp_word = to_be_freed; |
| if (exp_op == '?') { |
| /* mimic bash message */ |
| - | die_if_script("%s: %s", |
| + | msg_and_die_if_script("%s: %s", |
| var, |
| exp_word[0] |
| ? exp_word |
| @@ -5848,7 +5867,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha |
| /* ${var=[word]} or ${var:=[word]} */ |
| if (isdigit(var[0]) || var[0] == '#') { |
| /* mimic bash message */ |
| - | die_if_script("$%s: cannot assign in this way", var); |
| + | msg_and_die_if_script("$%s: cannot assign in this way", var); |
| val = NULL; |
| } else { |
| char *new_var = xasprintf("%s=%s", var, val); |
| @@ -6862,7 +6881,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp) |
| * "cmd >" (no filename) |
| * "cmd > <file" (2nd redirect starts too early) |
| */ |
| - | die_if_script("syntax error: %s", "invalid redirect"); |
| + | syntax_error("invalid redirect"); |
| continue; |
| } |
| mode = redir_table[redir->rd_type].mode; |