From c3b18681264e9118fe5f2e97542ddce226bd06ea Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Wed, 24 Feb 2021 15:32:34 -0500 Subject: [PATCH] commit bash-20210217 snapshot --- CWRU/CWRU.chlog | 12 ++++++++++++ doc/bash.1 | 10 +++++----- doc/bashref.texi | 6 +++--- lib/readline/rlprivate.h | 12 ++++++------ parse.y | 12 +++++++++++- tests/case.right | 1 + tests/case.tests | 6 ++++++ tests/comsub-posix5.sub | 2 ++ tests/posix2.right | 6 ++---- tests/posix2.tests | 8 +++++--- variables.c | 6 ++++-- 11 files changed, 57 insertions(+), 24 deletions(-) diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 5398d7bc..42296d06 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -9634,3 +9634,15 @@ parse.y - parse_comsub: case_level: simple counter to count the number of esacs we need to see before we're no longer in a case statement; analog of esacs_needed_count from the lexer + + 2/19 + ---- +parse.y + - CHECK_FOR_RESERVED_WORD: don't return ESAC if we read `esac' after a + left paren in a case pattern list. From an austingroup-bugs discussion + about https://www.austingroupbugs.net/view.php?id=1454 + - parse_comsub: if we read a `(' while looking for a case pattern list + and LEX_CKESAC is set, we have a leading left paren in the pattern + list and should turn off LEX_CKESAC so (esac) doesn't prematurely + terminate the case command. From an austingroup-bugs discussion + about https://www.austingroupbugs.net/view.php?id=1454 diff --git a/doc/bash.1 b/doc/bash.1 index d3dd3084..8d2a83a4 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -529,24 +529,24 @@ or \fB|&\fP. The format for a pipeline is: .RS .PP -[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand\fP [ [\fB|\fP\(bv\fB|&\fP] \fIcommand2\fP ... ] +[\fBtime\fP [\fB\-p\fP]] [ ! ] \fIcommand1\fP [ [\fB|\fP\(bv\fB|&\fP] \fIcommand2\fP ... ] .RE .PP The standard output of -.I command +.I command1 is connected via a pipe to the standard input of .IR command2 . This connection is performed before any redirections specified by the -command (see +.IR command1 (see .SM .B REDIRECTION below). -If \fB|&\fP is used, \fIcommand\fP's standard error, in addition to its +If \fB|&\fP is used, \fIcommand1\fP's standard error, in addition to its standard output, is connected to \fIcommand2\fP's standard input through the pipe; it is shorthand for \fB2>&1 |\fP. This implicit redirection of the standard error to the standard output is -performed after any redirections specified by the command. +performed after any redirections specified by \fIcommand1\fP. .PP The return status of a pipeline is the exit status of the last command, unless the \fBpipefail\fP option is enabled. diff --git a/doc/bashref.texi b/doc/bashref.texi index cceef130..d10d3a86 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -656,15 +656,15 @@ The format for a pipeline is The output of each command in the pipeline is connected via a pipe to the input of the next command. That is, each command reads the previous command's output. This -connection is performed before any redirections specified by the -command. +connection is performed before any redirections specified by +@var{command1}. If @samp{|&} is used, @var{command1}'s standard error, in addition to its standard output, is connected to @var{command2}'s standard input through the pipe; it is shorthand for @code{2>&1 |}. This implicit redirection of the standard error to the standard output is -performed after any redirections specified by the command. +performed after any redirections specified by @var{command1}. The reserved word @code{time} causes timing statistics to be printed for the pipeline once it finishes. diff --git a/lib/readline/rlprivate.h b/lib/readline/rlprivate.h index 7d7c3819..d42b638c 100644 --- a/lib/readline/rlprivate.h +++ b/lib/readline/rlprivate.h @@ -4,7 +4,7 @@ /* Copyright (C) 1999-2021 Free Software Foundation, Inc. This file is part of the GNU Readline Library (Readline), a library - for reading lines of text with interactive input and history editing. + for reading lines of text with interactive input and history editing. Readline is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -78,7 +78,7 @@ typedef struct __rl_search_context int search_string_size; char **lines; - char *allocated_line; + char *allocated_line; int hlen; int hindex; @@ -169,7 +169,7 @@ typedef struct __rl_vimotion_context /* fill in more as needed */ /* `Generic' callback data and functions */ -typedef struct __rl_callback_generic_arg +typedef struct __rl_callback_generic_arg { int count; int i1, i2; @@ -259,7 +259,7 @@ extern void _rl_keyseq_cxt_dispose (_rl_keyseq_cxt *); extern void _rl_keyseq_chain_dispose (void); extern int _rl_dispatch_callback (_rl_keyseq_cxt *); - + /* callback.c */ extern _rl_callback_generic_arg *_rl_callback_data_alloc (int); extern void _rl_callback_data_dispose (_rl_callback_generic_arg *); @@ -371,7 +371,7 @@ extern void _rl_internal_char_cleanup (void); extern void _rl_init_executing_keyseq (void); extern void _rl_term_executing_keyseq (void); extern void _rl_end_executing_keyseq (void); -extern void _rl_add_executing_keyseq (int); +extern void _rl_add_executing_keyseq (int); /* rltty.c */ extern int _rl_disable_tty_signals (void); @@ -469,7 +469,7 @@ extern int _rl_vi_domove_motion_cleanup (int, _rl_vimotion_cxt *); /* Use HS_HISTORY_VERSION as the sentinel to see if we've included history.h and so can use HIST_ENTRY */ #if defined (HS_HISTORY_VERSION) -extern void _rl_free_history_entry (HIST_ENTRY *); +extern void _rl_free_history_entry (HIST_ENTRY *); #endif /************************************************************************* diff --git a/parse.y b/parse.y index f42c8adb..cc66f810 100644 --- a/parse.y +++ b/parse.y @@ -2893,6 +2893,8 @@ static int open_brace_count; break; \ if ((parser_state & PST_CASEPAT) && last_read_token == '|' && word_token_alist[i].token == ESAC) \ break; /* Posix grammar rule 4 */ \ + if ((parser_state & PST_CASEPAT) && last_read_token == '(' && word_token_alist[i].token == ESAC) /*)*/ \ + break; /* phantom Posix grammar rule 4 */ \ if (word_token_alist[i].token == ESAC) \ parser_state &= ~(PST_CASEPAT|PST_CASESTMT); \ else if (word_token_alist[i].token == CASE) \ @@ -4219,6 +4221,12 @@ eof_error: shell_ungetc (peekc); continue; } + else if ((tflags & (LEX_PATLIST|LEX_CKESAC)) && ch == '(') /*)*/ + { + shell_ungetc (peekc); + tflags &= ~LEX_CKESAC; + continue; + } else if (ch == '\n' || COMSUB_META(ch)) { shell_ungetc (peekc); @@ -4252,7 +4260,9 @@ eof_error: /* XXX - check LEX_PATLIST here? */ else if ((tflags & LEX_INCASE) && (tflags & LEX_CKESAC)) { - if MBTEST(ch == 'e' && (tflags & LEX_RESWDOK) == 0) + peekc = shell_getc (1); + shell_ungetc (peekc); + if MBTEST(ch == 'e' && peekc == 's' && (tflags & LEX_RESWDOK) == 0) { tflags |= LEX_RESWDOK; lex_rwlen = 0; diff --git a/tests/case.right b/tests/case.right index 557bcadf..d33c8c5a 100644 --- a/tests/case.right +++ b/tests/case.right @@ -14,6 +14,7 @@ no no no ok +esac ok 1 ok 2 ok 3 diff --git a/tests/case.tests b/tests/case.tests index 2ffcb906..1ffba97b 100644 --- a/tests/case.tests +++ b/tests/case.tests @@ -62,6 +62,12 @@ case abc in (["$empty"]|[!a-z]*) echo yes ;; (*) echo no ;; esac case " " in ( [" "] ) echo ok;; ( * ) echo no;; esac +# posix issue discovered after bash-5.1 was released +case esac in (esac) echo esac;; esac +case k in else|done|time|esac) for f in 1 2 3 ; do :; done esac + + + # tests of quote removal and pattern matching ${THIS_SH} ./case1.sub ${THIS_SH} ./case2.sub diff --git a/tests/comsub-posix5.sub b/tests/comsub-posix5.sub index 64aa9187..0c4c7f21 100644 --- a/tests/comsub-posix5.sub +++ b/tests/comsub-posix5.sub @@ -61,6 +61,8 @@ : $(case in in esac) : $(case x in in|esac) foo;; esac) +: $(case esac in (esac) echo esac;; esac) +: $(case k in else|done|time|esac) for f in 1 2 3 ; do :; done esac) # this is an error ${THIS_SH} -c ': $(case x in esac|in) foo;; esac)' bash diff --git a/tests/posix2.right b/tests/posix2.right index 40aea039..5d3f734a 100644 --- a/tests/posix2.right +++ b/tests/posix2.right @@ -1,6 +1,4 @@ Testing for POSIX.2 conformance -./posix2.tests: eval: line 195: syntax error near unexpected token `esac' -./posix2.tests: eval: line 195: `case esac in (esac) ;; *) echo "case esac test 3" ;; esac' -./posix2.tests: eval: line 197: syntax error near unexpected token `)' -./posix2.tests: eval: line 197: `case esac in esac) ;; *) echo "case esac test 4";; esac' +./posix2.tests: eval: line 199: syntax error near unexpected token `)' +./posix2.tests: eval: line 199: `case esac in esac) ;; *) echo "case esac test 4";; esac' All tests passed diff --git a/tests/posix2.tests b/tests/posix2.tests index 9b6c0932..0f5fce15 100644 --- a/tests/posix2.tests +++ b/tests/posix2.tests @@ -190,11 +190,13 @@ case esac in (foo|esac) ;; *) testfail "case esac test 1" ;; esac newtest case esac in foo|esac) ;; *) testfail "case esac test 2" ;; esac +# POSIX.2 grammar rule 4 problem through bash-5.1 +newtest +eval 'case esac in (esac) ;; *) testfail "case esac test 3" ;; esac' + # these are supposed to be syntax errors newtest -eval 'case esac in (esac) ;; *) echo "case esac test 3" ;; esac' -newtest -eval 'case esac in esac) ;; *) echo "case esac test 4";; esac' +eval 'case esac in esac) ;; *) echo "case esac test 4";; esac' && testfail 'case esac test 4' if [ $exitval = 0 ]; then echo "All tests passed" diff --git a/variables.c b/variables.c index ebff0138..431e69c6 100644 --- a/variables.c +++ b/variables.c @@ -3433,11 +3433,13 @@ bind_int_variable (lhs, rhs, flags) int flags; { register SHELL_VAR *v; - int isint, isarr, implicitarray; + int isint, isarr, implicitarray, vflags; isint = isarr = implicitarray = 0; #if defined (ARRAY_VARS) - if (valid_array_reference (lhs, (flags & ASS_NOEXPAND) != 0)) + /* Don't rely on VA_NOEXPAND being 1, set it explicitly */ + vflags = (flags & ASS_NOEXPAND) ? VA_NOEXPAND : 0; + if (valid_array_reference (lhs, vflags)) { isarr = 1; v = array_variable_part (lhs, (flags & ASS_NOEXPAND) != 0, (char **)0, (int *)0);