and though bugs are the bane of my existence, rest assured the wretched thing will get the best of care here

...
 
Commits (2)
...@@ -9462,3 +9462,77 @@ execute_cmd.c ...@@ -9462,3 +9462,77 @@ execute_cmd.c
exits unconditionally. exits unconditionally.
- execute_simple_command: make sure posix mode sets $? to non-zero - execute_simple_command: make sure posix mode sets $? to non-zero
if a variable assignment error occurs preceding a non-special builtin if a variable assignment error occurs preceding a non-special builtin
subst.c
- do_assignment_statements: take the code from expand_word_list_internal
that performs assignment statements, either standalone or preceding
simple command names, and factor it out into this function
- expand_word_list_internal: call do_assignment_statements where
appropriate
2/2
---
lib/glob/glob.c
- dequote_pathname: fix function definition for non-multibyte systems.
Report and fix from Marc Aur猫le La France <tsi@tuyoix.net>
Makefile.in,doc/Makefile.in
- for certain targets, remove files before creating them to deal with
symlinked build trees.
Report and fix from Marc Aur猫le La France <tsi@tuyoix.net>
examples/loadables/accept.c
- include limits.h before typemax.h
Report and fix from Marc Aur猫le La France <tsi@tuyoix.net>
builtins/gen-helpfiles.c
- if USING_BASH_MALLOC is defined, make sure to undefine malloc as well
as free. Fixes bug reported by George R Goffe <grgoffe@yahoo.com>
builtins/Makefile.in
- install-help: now depends on $(HELPFILES_TARGET) so we make sure the
separate helpfiles are created before we try to install them if we
don't go through the `all' makefile target
configure.ac
- HELPDIR: now ${datadir}/bash/helpfiles
2/3
---
parse.y
- parse_string_to_word_list: before expanding a compound assignment
statement body, make sure to save any alias that's currently being
expanded. Restore the alias after the compound assignment is parsed.
Reported back in 11/2020 by Alex fxmbsw7 Ratchev <fxmbsw7@gmail.com>
2/4
---
lib/readline/histexpand.c
- history_expand_internal: when calling the history_inhibit_expansion
function, make sure to call it using the string as we've expanded it
to that point (RESULT), adding the expansion and next characters
temporarily, since we make expansion decisions based on what we've
accumulated, not what we started with. This makes things like
echo abc!$!$ work, where before the second `!' inhibited expansion
because bash_history_inhibit_expansion mistakenly took it as the
second character in a `$!' word expansion. Fixes bug reported back
in 10/2020 by Paul Fox <paul.d.fox@gmail.com>
array.h
- array_pop: instead of calling array_dispose_element from this macro,
just call array_shift with the AS_DISPOSE flag
2/5
---
bashhist.c
- shell_comment: move condition to return 0 if the delimiter stack is
not empty or the shell is parsing a here document into the function
itself, don't have the callers check so the check is in one place.
Fixes bug reported by Oguz <oguzismailuysal@gmail.com>
array.h,variables.c
- ARRAY_ELEMENT_REPLACE: convenience define for modifying an array
element's value
variables.c
- pop_args: a couple of code simplifications
...@@ -649,6 +649,7 @@ ${GRAM_H}: y.tab.h ...@@ -649,6 +649,7 @@ ${GRAM_H}: y.tab.h
y.tab.c: parse.y y.tab.c: parse.y
# -if test -f y.tab.h; then mv -f y.tab.h old-y.tab.h; fi # -if test -f y.tab.h; then mv -f y.tab.h old-y.tab.h; fi
$(YACC) -d $(srcdir)/parse.y $(YACC) -d $(srcdir)/parse.y
$(RM) parser-built
touch parser-built touch parser-built
# -if cmp -s old-y.tab.h y.tab.h; then mv old-y.tab.h y.tab.h; else cp -p y.tab.h ${GRAM_H}; fi # -if cmp -s old-y.tab.h y.tab.h; then mv old-y.tab.h y.tab.h; else cp -p y.tab.h ${GRAM_H}; fi
......
...@@ -106,11 +106,14 @@ extern ARRAY *array_from_string PARAMS((char *, char *)); ...@@ -106,11 +106,14 @@ extern ARRAY *array_from_string PARAMS((char *, char *));
#define set_element_value(ae, val) ((ae)->value = (val)) #define set_element_value(ae, val) ((ae)->value = (val))
#define set_max_index(a, i) ((a)->max_index = (i))
#define set_num_elements(a, n) ((a)->num_elements = (n))
/* Convenience */ /* Convenience */
#define array_push(a,v) \ #define array_push(a,v) \
do { array_rshift ((a), 1, (v)); } while (0) do { array_rshift ((a), 1, (v)); } while (0)
#define array_pop(a) \ #define array_pop(a) \
do { array_dispose_element (array_shift ((a), 1, 0)); } while (0) do { array_shift ((a), 1, AS_DISPOSE); } while (0)
#define GET_ARRAY_FROM_VAR(n, v, a) \ #define GET_ARRAY_FROM_VAR(n, v, a) \
do { \ do { \
...@@ -118,6 +121,12 @@ extern ARRAY *array_from_string PARAMS((char *, char *)); ...@@ -118,6 +121,12 @@ extern ARRAY *array_from_string PARAMS((char *, char *));
(a) = ((v) && array_p ((v))) ? array_cell (v) : (ARRAY *)0; \ (a) = ((v) && array_p ((v))) ? array_cell (v) : (ARRAY *)0; \
} while (0) } while (0)
#define ARRAY_ELEMENT_REPLACE(ae, v) \
do { \
free ((ae)->value); \
(ae)->value = (v); \
} while (0)
#define ALL_ELEMENT_SUB(c) ((c) == '@' || (c) == '*') #define ALL_ELEMENT_SUB(c) ((c) == '@' || (c) == '*')
/* In eval.c, but uses ARRAY * */ /* In eval.c, but uses ARRAY * */
......
...@@ -653,6 +653,8 @@ shell_comment (line) ...@@ -653,6 +653,8 @@ shell_comment (line)
char *p; char *p;
int n; int n;
if (dstack.delimiter_depth != 0 || (parser_state & PST_HEREDOC))
return 0;
if (line == 0) if (line == 0)
return 0; return 0;
for (p = line; p && *p && whitespace (*p); p++) for (p = line; p && *p && whitespace (*p); p++)
...@@ -757,7 +759,7 @@ maybe_add_history (line) ...@@ -757,7 +759,7 @@ maybe_add_history (line)
int is_comment; int is_comment;
hist_last_line_added = 0; hist_last_line_added = 0;
is_comment = (parser_state & PST_HEREDOC) ? 0 : shell_comment (line); is_comment = shell_comment (line);
/* Don't use the value of history_control to affect the second /* Don't use the value of history_control to affect the second
and subsequent lines of a multi-line command (old code did and subsequent lines of a multi-line command (old code did
...@@ -874,7 +876,7 @@ bash_add_history (line) ...@@ -874,7 +876,7 @@ bash_add_history (line)
add_it = 1; add_it = 1;
if (command_oriented_history && current_command_line_count > 1) if (command_oriented_history && current_command_line_count > 1)
{ {
is_comment = (parser_state & PST_HEREDOC) ? 0 : shell_comment (line); is_comment = shell_comment (line);
/* The second and subsequent lines of a here document have the trailing /* The second and subsequent lines of a here document have the trailing
newline preserved. We don't want to add extra newlines here, but we newline preserved. We don't want to add extra newlines here, but we
......
...@@ -203,7 +203,7 @@ builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC) ...@@ -203,7 +203,7 @@ builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC)
helpdoc: gen-helpfiles helpdoc: gen-helpfiles
./gen-helpfiles ${HELPDIRDEFINE} ./gen-helpfiles ${HELPDIRDEFINE}
install-help: install-help: $(HELPFILES_TARGET)
@-if test -n "${HELPDIR}" && test -d helpfiles ; then \ @-if test -n "${HELPDIR}" && test -d helpfiles ; then \
test -d $(DESTDIR)${HELPDIR} || ${SHELL} ${MKDIRS} $(DESTDIR)$(HELPDIR) ;\ test -d $(DESTDIR)${HELPDIR} || ${SHELL} ${MKDIRS} $(DESTDIR)$(HELPDIR) ;\
( for f in helpfiles/*; do \ ( for f in helpfiles/*; do \
......
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
#undef xrealloc #undef xrealloc
#undef xfree #undef xfree
#undef malloc
#undef free /* defined in xmalloc.h */ #undef free /* defined in xmalloc.h */
#endif #endif
......
#! /bin/sh #! /bin/sh
# From configure.ac for Bash 5.1, version 5.022. # From configure.ac for Bash 5.1, version 5.023.
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for bash 5.1-maint. # Generated by GNU Autoconf 2.69 for bash 5.1-maint.
# #
...@@ -3400,7 +3400,7 @@ fi ...@@ -3400,7 +3400,7 @@ fi
HELPDIR= HELPDIRDEFINE= HELPINSTALL= HELPFILES_TARGET= HELPDIR= HELPDIRDEFINE= HELPINSTALL= HELPFILES_TARGET=
if test "$opt_separate_help" != no; then if test "$opt_separate_help" != no; then
if test "$opt_separate_help" = "yes" ; then if test "$opt_separate_help" = "yes" ; then
HELPDIR='${datadir}/bash' HELPDIR='${datadir}/bash/helpfiles'
else else
HELPDIR=$opt_separate_help HELPDIR=$opt_separate_help
fi fi
......
...@@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script. ...@@ -21,7 +21,7 @@ dnl Process this file with autoconf to produce a configure script.
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
AC_REVISION([for Bash 5.1, version 5.022])dnl AC_REVISION([for Bash 5.1, version 5.023])dnl
define(bashvers, 5.1) define(bashvers, 5.1)
define(relstatus, maint) define(relstatus, maint)
...@@ -368,7 +368,7 @@ fi ...@@ -368,7 +368,7 @@ fi
HELPDIR= HELPDIRDEFINE= HELPINSTALL= HELPFILES_TARGET= HELPDIR= HELPDIRDEFINE= HELPINSTALL= HELPFILES_TARGET=
if test "$opt_separate_help" != no; then if test "$opt_separate_help" != no; then
if test "$opt_separate_help" = "yes" ; then if test "$opt_separate_help" = "yes" ; then
HELPDIR='${datadir}/bash' HELPDIR='${datadir}/bash/helpfiles'
else else
HELPDIR=$opt_separate_help HELPDIR=$opt_separate_help
fi fi
......
...@@ -173,23 +173,26 @@ html: ${HTMLFILES} ...@@ -173,23 +173,26 @@ html: ${HTMLFILES}
pdf: ${PDFFILES} pdf: ${PDFFILES}
bashref.dvi: $(BASHREF_FILES) $(HSUSER) $(RLUSER) bashref.dvi: $(BASHREF_FILES) $(HSUSER) $(RLUSER)
$(RM) $@
${SET_TEXINPUTS} $(TEXI2DVI) $(srcdir)/bashref.texi || { ${RM} $@ ; exit 1; } ${SET_TEXINPUTS} $(TEXI2DVI) $(srcdir)/bashref.texi || { ${RM} $@ ; exit 1; }
bashref.info: $(BASHREF_FILES) $(HSUSER) $(RLUSER) bashref.info: $(BASHREF_FILES) $(HSUSER) $(RLUSER)
$(RM) $@
$(MAKEINFO) --no-split -I$(TEXINPUTDIR) $(srcdir)/bashref.texi $(MAKEINFO) --no-split -I$(TEXINPUTDIR) $(srcdir)/bashref.texi
# experimental # experimental
bashref.pdf: $(BASHREF_FILES) $(HSUSER) $(RLUSER) bashref.pdf: $(BASHREF_FILES) $(HSUSER) $(RLUSER)
$(RM) $@
${SET_TEXINPUTS} $(TEXI2PDF) $(srcdir)/bashref.texi || { ${RM} $@ ; exit 1; } ${SET_TEXINPUTS} $(TEXI2PDF) $(srcdir)/bashref.texi || { ${RM} $@ ; exit 1; }
# can also use: # can also use:
# $(TEXI2HTML) -menu -monolithic -I $(TEXINPUTDIR) $(srcdir)/bashref.texi # $(TEXI2HTML) -menu -monolithic -I $(TEXINPUTDIR) $(srcdir)/bashref.texi
bashref.html: $(BASHREF_FILES) $(HSUSER) $(RLUSER) bashref.html: $(BASHREF_FILES) $(HSUSER) $(RLUSER)
$(MAKEINFO) --html --no-split -I$(TEXINPUTDIR) $(srcdir)/bashref.texi $(MAKEINFO) --html --no-split -I$(TEXINPUTDIR) $(srcdir)/bashref.texi
bash.info: bashref.info bash.info: bashref.info
${SHELL} ${INFOPOST} < $(srcdir)/bashref.info > $@ ; \ $(RM) $@
${SHELL} ${INFOPOST} < $(srcdir)/bashref.info > $@
bash.txt: bash.1 bash.txt: bash.1
bash.ps: bash.1 bash.ps: bash.1
......
...@@ -596,7 +596,8 @@ See ...@@ -596,7 +596,8 @@ See
for a description of a subshell environment. for a description of a subshell environment.
If the \fBlastpipe\fP option is enabled using the \fBshopt\fP builtin If the \fBlastpipe\fP option is enabled using the \fBshopt\fP builtin
(see the description of \fBshopt\fP below), (see the description of \fBshopt\fP below),
the last element of a pipeline may be run by the shell process. the last element of a pipeline may be run by the shell process
when job control is not active.
.SS Lists .SS Lists
A \fIlist\fP is a sequence of one or more pipelines separated by one A \fIlist\fP is a sequence of one or more pipelines separated by one
of the operators of the operators
......
...@@ -695,7 +695,8 @@ Each command in a pipeline is executed in its own subshell, which is a ...@@ -695,7 +695,8 @@ Each command in a pipeline is executed in its own subshell, which is a
separate process (@pxref{Command Execution Environment}). separate process (@pxref{Command Execution Environment}).
If the @code{lastpipe} option is enabled using the @code{shopt} builtin If the @code{lastpipe} option is enabled using the @code{shopt} builtin
(@pxref{The Shopt Builtin}), (@pxref{The Shopt Builtin}),
the last element of a pipeline may be run by the shell process. the last element of a pipeline may be run by the shell process
when job control is not active.
The exit The exit
status of a pipeline is the exit status of the last command in the status of a pipeline is the exit status of the last command in the
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "bashtypes.h" #include "bashtypes.h"
#include <errno.h> #include <errno.h>
#include <time.h> #include <time.h>
#include <limits.h>
#include "typemax.h" #include "typemax.h"
#include <sys/socket.h> #include <sys/socket.h>
...@@ -44,7 +45,6 @@ int ...@@ -44,7 +45,6 @@ int
accept_builtin (list) accept_builtin (list)
WORD_LIST *list; WORD_LIST *list;
{ {
WORD_LIST *l;
SHELL_VAR *v; SHELL_VAR *v;
intmax_t iport; intmax_t iport;
int opt; int opt;
......
...@@ -4452,21 +4452,24 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) ...@@ -4452,21 +4452,24 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
func = find_function (words->word->word); func = find_function (words->word->word);
} }
/* In POSIX mode, assignment errors in the temporary environment cause a /* What happens in posix mode when an assignment preceding a command name
non-interactive shell executing a special builtin to exit and a non- fails. This should agree with the code in execute_cmd.c:
interactive shell to otherwise jump back to the top level. This is what do_assignment_statements(), even though I don't think it's executed any
POSIX says to do for variable assignment errors, and errors in assigning more. */
to the temporary environment are treated as variable assignment errors. */
if (posixly_correct && tempenv_assign_error) if (posixly_correct && tempenv_assign_error)
{ {
#if defined (DEBUG)
/* I don't know if this clause is ever executed, so let's check */
itrace("execute_simple_command: posix mode tempenv assignment error");
#endif
last_command_exit_value = EXECUTION_FAILURE; last_command_exit_value = EXECUTION_FAILURE;
#if defined (STRICT_POSIX) #if defined (STRICT_POSIX)
jump_to_top_level ((interactive_shell == 0) ? ERREXIT : DISCARD); jump_to_top_level ((interactive_shell == 0) ? FORCE_EOF : DISCARD);
#else #else
if (interactive_shell == 0 && builtin_is_special) if (interactive_shell == 0 && builtin_is_special)
jump_to_top_level (ERREXIT); jump_to_top_level (FORCE_EOF);
else if (interactive_shell == 0) else if (interactive_shell == 0)
jump_to_top_level (DISCARD); jump_to_top_level (DISCARD); /* XXX - maybe change later */
else else
jump_to_top_level (DISCARD); jump_to_top_level (DISCARD);
#endif #endif
......
...@@ -119,10 +119,10 @@ void udequote_pathname PARAMS((char *)); ...@@ -119,10 +119,10 @@ void udequote_pathname PARAMS((char *));
#if HANDLE_MULTIBYTE #if HANDLE_MULTIBYTE
void wcdequote_pathname PARAMS((wchar_t *)); void wcdequote_pathname PARAMS((wchar_t *));
static void wdequote_pathname PARAMS((char *)); static void wdequote_pathname PARAMS((char *));
static void dequote_pathname PARAMS((char *));
#else #else
# define dequote_pathname udequote_pathname # define dequote_pathname udequote_pathname
#endif #endif
static void dequote_pathname PARAMS((char *));
static int glob_testdir PARAMS((char *, int)); static int glob_testdir PARAMS((char *, int));
static char **glob_dir_to_array PARAMS((char *, char **, int)); static char **glob_dir_to_array PARAMS((char *, char **, int));
......
...@@ -1207,13 +1207,36 @@ history_expand (char *hstring, char **output) ...@@ -1207,13 +1207,36 @@ history_expand (char *hstring, char **output)
characters in history_no_expand_chars, then it is not a characters in history_no_expand_chars, then it is not a
candidate for expansion of any kind. */ candidate for expansion of any kind. */
if (cc == 0 || member (cc, history_no_expand_chars) || if (cc == 0 || member (cc, history_no_expand_chars) ||
(dquote && cc == '"') || (dquote && cc == '"'))
(history_inhibit_expansion_function && (*history_inhibit_expansion_function) (string, i)))
{ {
ADD_CHAR (string[i]); ADD_CHAR (string[i]);
break; break;
} }
/* If the application has defined a function to determine whether
or not a history expansion should be performed, call it here. */
/* We check against what we've expanded so far, with the current
expansion appended, because that seems to be what csh does. We
decide to expand based on what we have to this point, not what
we started with. */
if (history_inhibit_expansion_function)
{
int save_j, temp;
save_j = j;
ADD_CHAR (string[i]);
ADD_CHAR (cc);
temp = (*history_inhibit_expansion_function) (result, save_j);
if (temp)
{
result[--j] = '\0'; /* `unadd' cc, leaving ADD_CHAR(string[i]) */
break;
}
else
result[j = save_j] = '\0';
}
#if defined (NO_BANG_HASH_MODIFIERS) #if defined (NO_BANG_HASH_MODIFIERS)
/* There is something that is listed as a `word specifier' in csh /* There is something that is listed as a `word specifier' in csh
documentation which means `the expanded text to this point'. documentation which means `the expanded text to this point'.
......
...@@ -6493,10 +6493,8 @@ parse_string_to_word_list (s, flags, whom) ...@@ -6493,10 +6493,8 @@ parse_string_to_word_list (s, flags, whom)
old_expand_aliases = expand_aliases; old_expand_aliases = expand_aliases;
push_stream (1); push_stream (1);
#if 0 /* TAG: bash-5.2 Alex fxmbsw7 Ratchev <fxmbsw7@gmail.com> 11/17/2020 */
if (ea = expanding_alias ()) if (ea = expanding_alias ())
parser_save_alias (); parser_save_alias ();
#endif
last_read_token = WORD; /* WORD to allow reserved words here */ last_read_token = WORD; /* WORD to allow reserved words here */
current_command_line_count = 0; current_command_line_count = 0;
echo_input_at_read = expand_aliases = 0; echo_input_at_read = expand_aliases = 0;
...@@ -6531,10 +6529,8 @@ parse_string_to_word_list (s, flags, whom) ...@@ -6531,10 +6529,8 @@ parse_string_to_word_list (s, flags, whom)
last_read_token = '\n'; last_read_token = '\n';
pop_stream (); pop_stream ();
#if 0 /* TAG: bash-5.2 */
if (ea) if (ea)
parser_restore_alias (); parser_restore_alias ();
#endif
#if defined (HISTORY) #if defined (HISTORY)
remember_on_history = old_remember_on_history; remember_on_history = old_remember_on_history;
......
...@@ -361,6 +361,8 @@ static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *)) ...@@ -361,6 +361,8 @@ static WORD_LIST *expand_declaration_argument PARAMS((WORD_LIST *, WORD_LIST *))
static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int)); static WORD_LIST *shell_expand_word_list PARAMS((WORD_LIST *, int));
static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int)); static WORD_LIST *expand_word_list_internal PARAMS((WORD_LIST *, int));
static int do_assignment_statements PARAMS((WORD_LIST *, char *, int));
/* **************************************************************** */ /* **************************************************************** */
/* */ /* */
/* Utility Functions */ /* Utility Functions */
...@@ -11966,6 +11968,87 @@ shell_expand_word_list (tlist, eflags) ...@@ -11966,6 +11968,87 @@ shell_expand_word_list (tlist, eflags)
return (new_list); return (new_list);
} }
/* Perform assignment statements optionally preceding a command name COMMAND.
If COMMAND == NULL, is_nullcmd usually == 1. Follow the POSIX rules for
variable assignment errors. */
static int
do_assignment_statements (varlist, command, is_nullcmd)
WORD_LIST *varlist;
char *command;
int is_nullcmd;
{
WORD_LIST *temp_list;
char *savecmd;
sh_wassign_func_t *assign_func;
int is_special_builtin, is_builtin_or_func, tint;
/* If the remainder of the words expand to nothing, Posix.2 requires
that the variable and environment assignments affect the shell's
environment (do_word_assignment). */
assign_func = is_nullcmd ? do_word_assignment : assign_in_env;
tempenv_assign_error = 0;
is_builtin_or_func = command && (find_shell_builtin (command) || find_function (command));
/* Posix says that special builtins exit if a variable assignment error
occurs in an assignment preceding it. (XXX - this is old -- current Posix
says that any variable assignment error causes a non-interactive shell
to exit. See the STRICT_POSIX checks below. */
is_special_builtin = posixly_correct && command && find_special_builtin (command);
savecmd = this_command_name;
for (temp_list = varlist; temp_list; temp_list = temp_list->next)
{
this_command_name = (char *)NULL;
assigning_in_environment = is_nullcmd == 0;
tint = (*assign_func) (temp_list->word, is_builtin_or_func);
assigning_in_environment = 0;
this_command_name = savecmd;
/* Variable assignment errors in non-interactive shells running
in posix mode cause the shell to exit. */
if (tint == 0)
{
if (is_nullcmd) /* assignment statement */
{
last_command_exit_value = EXECUTION_FAILURE;
#if defined (STRICT_POSIX)
if (posixly_correct && interactive_shell == 0)
#else
if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
#endif
exp_jump_to_top_level (FORCE_EOF);
else
exp_jump_to_top_level (DISCARD);
}
/* In posix mode, assignment errors in the temporary environment
cause a non-interactive shell executing a special builtin to
exit and a non-interactive shell to otherwise jump back to the
top level. This is what POSIX says to do for variable assignment
errors, and POSIX says errors in assigning to the temporary
environment are treated as variable assignment errors.
(XXX - this is not what current POSIX says - look at the
STRICT_POSIX defines. */
else if (posixly_correct)
{
last_command_exit_value = EXECUTION_FAILURE;
#if defined (STRICT_POSIX)
exp_jump_to_top_level ((interactive_shell == 0) ? FORCE_EOF : DISCARD);
#else
if (interactive_shell == 0 && is_special_builtin)
exp_jump_to_top_level (FORCE_EOF);
else if (interactive_shell == 0)
exp_jump_to_top_level (DISCARD); /* XXX - maybe change later */
else
exp_jump_to_top_level (DISCARD);
#endif
}
else
tempenv_assign_error++;
}
}
return (tempenv_assign_error);
}
/* The workhorse for expand_words () and expand_words_no_vars (). /* The workhorse for expand_words () and expand_words_no_vars ().
First arg is LIST, a WORD_LIST of words. First arg is LIST, a WORD_LIST of words.
Second arg EFLAGS is a flags word controlling which expansions are Second arg EFLAGS is a flags word controlling which expansions are
...@@ -11985,8 +12068,6 @@ expand_word_list_internal (list, eflags) ...@@ -11985,8 +12068,6 @@ expand_word_list_internal (list, eflags)
int eflags; int eflags;
{ {
WORD_LIST *new_list, *temp_list; WORD_LIST *new_list, *temp_list;
int tint;
char *savecmd;
tempenv_assign_error = 0; tempenv_assign_error = 0;
if (list == 0) if (list == 0)
...@@ -11999,30 +12080,11 @@ expand_word_list_internal (list, eflags) ...@@ -11999,30 +12080,11 @@ expand_word_list_internal (list, eflags)
if (new_list == 0) if (new_list == 0)
{ {
if (subst_assign_varlist) if (subst_assign_varlist)
{ do_assignment_statements (subst_assign_varlist, (char *)NULL, 1);
/* All the words were variable assignments, so they are placed
into the shell's environment. */ dispose_words (subst_assign_varlist);
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next) subst_assign_varlist = (WORD_LIST *)NULL;
{
savecmd = this_command_name;
this_command_name = (char *)NULL; /* no arithmetic errors */
tint = do_word_assignment (temp_list->word, 0);
this_command_name = savecmd;
/* Variable assignment errors in non-interactive shells
running in Posix.2 mode cause the shell to exit, unless
they are being run by the `command' builtin. */
if (tint == 0)
{
last_command_exit_value = EXECUTION_FAILURE;
if (interactive_shell == 0 && posixly_correct && executing_command_builtin == 0)
exp_jump_to_top_level (FORCE_EOF);
else
exp_jump_to_top_level (DISCARD);
}
}
dispose_words (subst_assign_varlist);
subst_assign_varlist = (WORD_LIST *)NULL;
}
return ((WORD_LIST *)NULL); return ((WORD_LIST *)NULL);
} }
} }
...@@ -12056,49 +12118,7 @@ expand_word_list_internal (list, eflags) ...@@ -12056,49 +12118,7 @@ expand_word_list_internal (list, eflags)
if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist) if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
{ {
sh_wassign_func_t *assign_func; do_assignment_statements (subst_assign_varlist, (new_list && new_list->word) ? new_list->word->word : (char *)NULL, new_list == 0);
int is_special_builtin, is_builtin_or_func;
/* If the remainder of the words expand to nothing, Posix.2 requires
that the variable and environment assignments affect the shell's
environment. */
assign_func = new_list ? assign_in_env : do_word_assignment;
tempenv_assign_error = 0;
is_builtin_or_func = (new_list && new_list->word && (find_shell_builtin (new_list->word->word) || find_function (new_list->word->word)));
/* Posix says that special builtins exit if a variable assignment error
occurs in an assignment preceding it. */
is_special_builtin = (posixly_correct && new_list && new_list->word && find_special_builtin (new_list->word->word));
for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
{
savecmd = this_command_name;
this_command_name = (char *)NULL;
assigning_in_environment = (assign_func == assign_in_env);
tint = (*assign_func) (temp_list->word, is_builtin_or_func);
assigning_in_environment = 0;
this_command_name = savecmd;
/* Variable assignment errors in non-interactive shells running
in Posix.2 mode cause the shell to exit. */
if (tint == 0)
{
if (assign_func == do_word_assignment)
{
last_command_exit_value = EXECUTION_FAILURE;
if (interactive_shell == 0 && posixly_correct)
exp_jump_to_top_level (FORCE_EOF);
else
exp_jump_to_top_level (DISCARD);
}
else if (interactive_shell == 0 && is_special_builtin)
{
last_command_exit_value = EXECUTION_FAILURE;
exp_jump_to_top_level (FORCE_EOF);
}
else
tempenv_assign_error++;
}
}
dispose_words (subst_assign_varlist); dispose_words (subst_assign_varlist);
subst_assign_varlist = (WORD_LIST *)NULL; subst_assign_varlist = (WORD_LIST *)NULL;
......
...@@ -2,6 +2,7 @@ alias: 0 ...@@ -2,6 +2,7 @@ alias: 0
alias: 0 alias: 0
./alias.tests: line 38: qfoo: command not found ./alias.tests: line 38: qfoo: command not found
quux quux
hi
bar bar
value value
bar bar
......
...@@ -49,6 +49,14 @@ foo bar ...@@ -49,6 +49,14 @@ foo bar
unalias foo bar baz unalias foo bar baz
# post bash-5.1 problems with compound array assignment during multiline
# alias expansion
alias foo='a=() b=""
for i in 1; do echo hi; done'
foo
unalias foo
${THIS_SH} ./alias1.sub ${THIS_SH} ./alias1.sub
${THIS_SH} ./alias2.sub ${THIS_SH} ./alias2.sub
${THIS_SH} ./alias3.sub ${THIS_SH} ./alias3.sub
......
...@@ -176,12 +176,14 @@ after non-special builtin: 0 ...@@ -176,12 +176,14 @@ after non-special builtin: 0
./errors7.sub: line 25: x: readonly variable ./errors7.sub: line 25: x: readonly variable
after special builtin: 0 after special builtin: 0
./errors7.sub: line 27: x: readonly variable ./errors7.sub: line 27: x: readonly variable
./errors7.sub: line 29: x: readonly variable
./errors7.sub: line 21: x: readonly variable ./errors7.sub: line 21: x: readonly variable
after no such command: 1 after no such command: 1
./errors7.sub: line 23: x: readonly variable ./errors7.sub: line 23: x: readonly variable
after non-special builtin: 1 after non-special builtin: 1
./errors7.sub: line 25: x: readonly variable ./errors7.sub: line 25: x: readonly variable
./errors7.sub: line 27: x: readonly variable ./errors7.sub: line 27: x: readonly variable
./errors7.sub: line 29: x: readonly variable
./errors8.sub: eval: line 7: syntax error: unexpected end of file ./errors8.sub: eval: line 7: syntax error: unexpected end of file
ok 1 ok 1
./errors8.sub: line 8: v: readonly variable ./errors8.sub: line 8: v: readonly variable
......
...@@ -26,3 +26,5 @@ echo after non-special builtin: $? ...@@ -26,3 +26,5 @@ echo after non-special builtin: $?
echo after special builtin: $? ) echo after special builtin: $? )
( x=8 $nocmd ( x=8 $nocmd
echo after assignment error: $? ) echo after assignment error: $? )
( x=8
echo after assignment statement error: $? )
...@@ -21,6 +21,8 @@ cd $DIR ...@@ -21,6 +21,8 @@ cd $DIR
touch a .b touch a .b
LC_COLLATE=C # fix sort order
echo @(?|.?) echo @(?|.?)
echo @(.?|?) echo @(.?|?)
echo ? .? echo ? .?
......
...@@ -5676,7 +5676,7 @@ pop_args () ...@@ -5676,7 +5676,7 @@ pop_args ()
GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a); GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a); GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
ce = array_shift (bash_argc_a, 1, 0); ce = array_unshift_element (bash_argc_a);
if (ce == 0 || legal_number (element_value (ce), &i) == 0) if (ce == 0 || legal_number (element_value (ce), &i) == 0)
i = 0; i = 0;
...@@ -6286,8 +6286,7 @@ set_pipestatus_array (ps, nproc) ...@@ -6286,8 +6286,7 @@ set_pipestatus_array (ps, nproc)
if (array_num_elements (a) == nproc && nproc == 1) if (array_num_elements (a) == nproc && nproc == 1)
{ {
ae = element_forw (a->head); ae = element_forw (a->head);
free (element_value (ae)); ARRAY_ELEMENT_REPLACE (ae, itos (ps[0]));
set_element_value (ae, itos (ps[0]));
} }
else if (array_num_elements (a) <= nproc) else if (array_num_elements (a) <= nproc)
{ {
...@@ -6296,8 +6295,7 @@ set_pipestatus_array (ps, nproc) ...@@ -6296,8 +6295,7 @@ set_pipestatus_array (ps, nproc)
for (i = 0; i < array_num_elements (a); i++) for (i = 0; i < array_num_elements (a); i++)
{ {
ae = element_forw (ae); ae = element_forw (ae);
free (element_value (ae)); ARRAY_ELEMENT_REPLACE (ae, itos (ps[i]));
set_element_value (ae, itos (ps[i]));
} }
/* add any more */ /* add any more */
for ( ; i < nproc; i++) for ( ; i < nproc; i++)
...@@ -6310,7 +6308,7 @@ set_pipestatus_array (ps, nproc) ...@@ -6310,7 +6308,7 @@ set_pipestatus_array (ps, nproc)
{ {
/* deleting elements. it's faster to rebuild the array. */ /* deleting elements. it's faster to rebuild the array. */
array_flush (a); array_flush (a);
for (i = 0; ps[i] != -1; i++) for (i = 0; i < nproc; i++)
{ {
t = inttostr (ps[i], tbuf, sizeof (tbuf)); t = inttostr (ps[i], tbuf, sizeof (tbuf));
array_insert (a, i, t); array_insert (a, i, t);
......