summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2025-08-12 18:30:51 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2025-08-12 20:29:26 +0200
commit2b0b74e8b468496e903f8ed62d2c37fcef165170 (patch)
treeb50a12da9b8bd2a13b6963caddf85447432109ef
parent5ecbed0e2660f74f3690de52387a7c2f3ea3f2d2 (diff)
hush: drop ctx_inverted, use pipe->pi_inverted
function old new delta done_word 776 799 +23 parse_stream 2456 2453 -3 done_pipe 252 242 -10 .rodata 105837 105825 -12 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/3 up/down: 23/-25) Total: -2 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/hush.c43
-rw-r--r--shell/hush_test/hush-misc/syntax_err_negate.right2
2 files changed, 25 insertions, 20 deletions
diff --git a/shell/hush.c b/shell/hush.c
index fe3d77c65..bca27e038 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -748,7 +748,6 @@ struct parse_context {
smallint is_assignment; /* 0:maybe, 1:yes, 2:no, 3:keyword */
#if HAS_KEYWORDS
smallint ctx_res_w;
- smallint ctx_inverted; /* "! cmd | cmd" */
#if ENABLE_HUSH_CASE
smallint ctx_dsemicolon; /* ";;" seen */
#endif
@@ -3960,9 +3959,10 @@ static int done_command(struct parse_context *ctx)
}
/* Parsing of a pipe is completed.
- * Finish prsing current command via done_command().
+ * Finish parsing current command via done_command().
* (If the pipe is not empty, but done_command() did not change the number
* of commands in pipe, return value is 1. Used for catching syntax errors)
+ * Then append a new pipe with one empty command.
*/
static int done_pipe(struct parse_context *ctx, pipe_style type)
{
@@ -3983,8 +3983,6 @@ static int done_pipe(struct parse_context *ctx, pipe_style type)
last_cmd_is_null = (oldnum != 0 && num_cmds == oldnum);
#if HAS_KEYWORDS
- ctx->pipe->pi_inverted = ctx->ctx_inverted;
- ctx->ctx_inverted = 0;
ctx->pipe->res_word = ctx->ctx_res_w;
#endif
if (type == PIPE_BG && ctx->list_head != ctx->pipe) {
@@ -4031,7 +4029,7 @@ static int done_pipe(struct parse_context *ctx, pipe_style type)
/* Without this check, even just <enter> on command line generates
* tree of three NOPs (!). Which is harmless but annoying.
- * IOW: it is safe to do it unconditionally. */
+ * IOW: it is safe to do the following unconditionally. */
if (num_cmds != 0
#if ENABLE_HUSH_IF
|| ctx->ctx_res_w == RES_FI
@@ -4055,10 +4053,11 @@ static int done_pipe(struct parse_context *ctx, pipe_style type)
/* RES_THEN, RES_DO etc are "sticky" -
* they remain set for pipes inside if/while.
* This is used to control execution.
- * RES_FOR and RES_IN are NOT sticky (needed to support
- * cases where variable or value happens to match a keyword):
*/
#if ENABLE_HUSH_LOOPS
+ /* RES_FOR and RES_IN are NOT sticky (needed to support
+ * cases where variable or value happens to match a keyword):
+ */
if (ctx->ctx_res_w == RES_FOR
|| ctx->ctx_res_w == RES_IN)
ctx->ctx_res_w = RES_NONE;
@@ -4069,11 +4068,11 @@ static int done_pipe(struct parse_context *ctx, pipe_style type)
if (ctx->ctx_res_w == RES_CASE)
ctx->ctx_res_w = RES_CASE_IN;
#endif
- ctx->command = NULL; /* trick done_command below */
/* Create the memory for command, roughly:
* ctx->pipe->cmds = new struct command;
* ctx->command = &ctx->pipe->cmds[0];
*/
+ ctx->command = NULL;
done_command(ctx);
//debug_print_tree(ctx->list_head, 10);
}
@@ -4171,7 +4170,7 @@ static const struct reserved_combo* reserved_word(struct parse_context *ctx)
{
# if ENABLE_HUSH_CASE
static const struct reserved_combo reserved_match = {
- "", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC
+ "", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC
};
# endif
const struct reserved_combo *r;
@@ -4190,11 +4189,13 @@ static const struct reserved_combo* reserved_word(struct parse_context *ctx)
} else
# endif
if (r->flag == 0) { /* '!' */
- if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
- syntax_error("! ! command");
+ if (ctx->pipe->cmds != ctx->command /* bash disallows: nice | ! cat */
+ || ctx->pipe->pi_inverted /* bash disallows: ! ! true */
+ ) {
+ syntax_error_unexpected_ch('!');
ctx->ctx_res_w = RES_SNTX;
}
- ctx->ctx_inverted = 1;
+ ctx->pipe->pi_inverted = 1;
return r;
}
if (r->flag & FLAG_START) {
@@ -4274,7 +4275,7 @@ static int done_word(struct parse_context *ctx)
debug_printf_parse("done_word entered: '%s' %p\n", ctx->word.data, command);
if (ctx->word.length == 0 && !ctx->word.has_quoted_part) {
- debug_printf_parse("done_word return 0: true null, ignored\n");
+ debug_printf_parse("done_word return 0: no word, ignored\n");
return 0;
}
@@ -4323,9 +4324,12 @@ static int done_word(struct parse_context *ctx)
#if HAS_KEYWORDS
# if ENABLE_HUSH_CASE
+
if (ctx->ctx_dsemicolon
- && strcmp(ctx->word.data, "esac") != 0 /* not "... pattern) cmd;; esac" */
- ) {
+ && (ctx->word.has_quoted_part
+ || strcmp(ctx->word.data, "esac") != 0
+ )
+ ) { /* ";; WORD" but not "... PATTERN) CMD;; esac" */
/* already done when ctx_dsemicolon was set to 1: */
/* ctx->ctx_res_w = RES_MATCH; */
ctx->ctx_dsemicolon = 0;
@@ -4333,20 +4337,21 @@ static int done_word(struct parse_context *ctx)
# endif
# if defined(CMD_TEST2_SINGLEWORD_NOGLOB)
if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB
+ && !ctx->word.has_quoted_part
&& strcmp(ctx->word.data, "]]") == 0
) {
/* allow "[[ ]] >file" etc */
command->cmd_type = CMD_SINGLEWORD_NOGLOB;
} else
# endif
- if (!command->argv /* if it's the first word... */
- && !command->redirects /* and no redirects yet... try: </dev/null ! true; echo $? */
+ if (!command->argv /* if it's the first word of command... */
+ && !command->redirects /* no redirects yet... disallows: </dev/null ! true; echo $? */
# if ENABLE_HUSH_LOOPS
- && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */
+ && ctx->ctx_res_w != RES_FOR /* not after FOR or IN */
&& ctx->ctx_res_w != RES_IN
# endif
# if ENABLE_HUSH_CASE
- && ctx->ctx_res_w != RES_CASE
+ && ctx->ctx_res_w != RES_CASE /* not after CASE */
# endif
) {
const struct reserved_combo *reserved;
diff --git a/shell/hush_test/hush-misc/syntax_err_negate.right b/shell/hush_test/hush-misc/syntax_err_negate.right
index 8c7010629..0b8d211c7 100644
--- a/shell/hush_test/hush-misc/syntax_err_negate.right
+++ b/shell/hush_test/hush-misc/syntax_err_negate.right
@@ -1,2 +1,2 @@
bash 3.2 fails this
-hush: syntax error: ! ! command
+hush: syntax error: unexpected !