mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-08-05 17:52:30 +02:00
local variables no longer modify external variables if the variable is supplied as a variable assignment preceding a function call; assignments in compound assignment statements don't undergo brace expansion
This commit is contained in:
@@ -5437,3 +5437,40 @@ jobs.c
|
||||
- wait_for: if we're checking for window size changes, allow checks
|
||||
during trap commands while readline is active or `bind -x' command
|
||||
execution. Fix from Koichi Murase <myoga.murase@gmail.com>
|
||||
|
||||
2/22
|
||||
----
|
||||
jobs.c
|
||||
- wait_for: check for window size changes during programmable completion
|
||||
|
||||
2/23
|
||||
----
|
||||
execute_cmd.c,input.c,jobs.c,nojobs.c,parse.y,redir.c,shell.c
|
||||
builtins/{exec.def,read.def}
|
||||
input.h
|
||||
- BUFFERED_INPUT: preprocessor #define is gone, this code is now
|
||||
unconditional
|
||||
|
||||
2/24
|
||||
----
|
||||
builtins/declare.def
|
||||
- declare_internal: set the att_propagate flag on a variable that is
|
||||
marked as att_tempvar only if it's *not* marked att_local. The
|
||||
effect is that local variables with the same name as variables in
|
||||
the temporary environment are not propagated to the previous scope.
|
||||
From a report by Voldemar Lazarev <voldemar.lazarev@alludo.com>
|
||||
that prompted a bug-bash discussion
|
||||
|
||||
builtins/setattr.def
|
||||
- set_var_attribute: don't set local variables for which we are setting
|
||||
export or readonly to propagate back to the previous context, but
|
||||
make sure we preserve posix semantics
|
||||
|
||||
parse.y
|
||||
- read_token_word: if we're parsing the words of a compound assignment
|
||||
(parser_state & PST_COMPASSIGN), and we have a valid assignment
|
||||
statement as a word ([sub]=value), set W_NOBRACE in the word so we
|
||||
don't try and perform brace expansion on it. This makes ( [sub]=word )
|
||||
closer to name[sub]=word.
|
||||
From a report by Ilkka Virta <itvirta@iki.fi> back in July, 2020:
|
||||
https://lists.gnu.org/archive/html/bug-bash/2020-07/msg00133.html
|
||||
|
||||
@@ -1540,6 +1540,7 @@ tests/varenv19.sub f
|
||||
tests/varenv20.sub f
|
||||
tests/varenv21.sub f
|
||||
tests/varenv22.sub f
|
||||
tests/varenv23.sub f
|
||||
tests/version f
|
||||
tests/version.mini f
|
||||
tests/vredir.tests f
|
||||
|
||||
+10
-3
@@ -990,7 +990,10 @@ restart_new_var_name:
|
||||
/* If we found this variable in the temporary environment, as with
|
||||
`var=value declare -x var', make sure it is treated identically
|
||||
to `var=value export var'. Do the same for `declare -r' and
|
||||
`readonly'. Preserve the attributes, except for att_tempvar. */
|
||||
`readonly'. Preserve the attributes, except for att_tempvar.
|
||||
This doesn't happen in functions, since declare in shell functions
|
||||
always creates local variables (that inherit their value from the
|
||||
tempenv variable). We don't check variable_context; maybe we should. */
|
||||
/* XXX -- should this create a variable in the global scope, or
|
||||
modify the local variable flags? ksh93 has it modify the
|
||||
global scope.
|
||||
@@ -1001,6 +1004,7 @@ restart_new_var_name:
|
||||
SHELL_VAR *tv;
|
||||
char *tvalue;
|
||||
|
||||
/* Temporary environment? Or in the local variable context? */
|
||||
tv = find_tempenv_variable (name_cell (var));
|
||||
if (tv)
|
||||
{
|
||||
@@ -1009,12 +1013,15 @@ restart_new_var_name:
|
||||
if (tv)
|
||||
{
|
||||
tv->attributes |= var->attributes & ~att_tempvar;
|
||||
if (tv->context > 0)
|
||||
if (tv->context > 0 && local_p (var) == 0) /* just paranoia here */
|
||||
VSETATTR (tv, att_propagate);
|
||||
}
|
||||
free (tvalue);
|
||||
}
|
||||
VSETATTR (var, att_propagate);
|
||||
/* XXX - don't propagate local variables back to a previous scope,
|
||||
even in posix mode. */
|
||||
if (local_p (var) == 0)
|
||||
VSETATTR (var, att_propagate);
|
||||
}
|
||||
|
||||
/* Turn on nameref attribute we deferred above. */
|
||||
|
||||
@@ -223,10 +223,8 @@ exec_builtin (WORD_LIST *list)
|
||||
default_tty_job_signals (); /* undo initialize_job_signals */
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
if (default_buffered_input >= 0)
|
||||
sync_buffered_stream (default_buffered_input);
|
||||
#endif
|
||||
|
||||
exit_value = shell_execve (command, args, env);
|
||||
|
||||
|
||||
+1
-5
@@ -103,9 +103,7 @@ $END
|
||||
#include <readline/readline.h>
|
||||
#endif
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
# include "input.h"
|
||||
#endif
|
||||
#include "input.h"
|
||||
|
||||
#include "shmbutil.h"
|
||||
#include "timer.h"
|
||||
@@ -425,10 +423,8 @@ read_builtin (WORD_LIST *list)
|
||||
|
||||
begin_unwind_frame ("read_builtin");
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
if (interactive == 0 && default_buffered_input >= 0 && fd_is_bash_input (fd))
|
||||
sync_buffered_stream (default_buffered_input);
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
input_is_tty = isatty (fd);
|
||||
|
||||
@@ -574,6 +574,8 @@ show_func_attributes (char *name, int nodefs)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* This is only called by readonly/export, so we can implement posix-mode
|
||||
semantics for special variables. */
|
||||
void
|
||||
set_var_attribute (char *name, int attribute, int undo)
|
||||
{
|
||||
@@ -584,6 +586,7 @@ set_var_attribute (char *name, int attribute, int undo)
|
||||
var = find_variable (name);
|
||||
else
|
||||
{
|
||||
/* var=value readonly var */
|
||||
tv = find_tempenv_variable (name);
|
||||
/* XXX -- need to handle case where tv is a temp variable in a
|
||||
function-scope context, since function_env has been merged into
|
||||
@@ -645,7 +648,7 @@ set_var_attribute (char *name, int attribute, int undo)
|
||||
if (var)
|
||||
VSETATTR (var, att_invisible);
|
||||
}
|
||||
else if (var->context != 0)
|
||||
else if (var->context != 0 && local_p (var) == 0)
|
||||
VSETATTR (var, att_propagate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,6 @@
|
||||
error messages about multiple directory arguments to `cd'. */
|
||||
#define CD_COMPLAINS
|
||||
|
||||
/* Define BUFFERED_INPUT if you want the shell to do its own input
|
||||
buffering, rather than using stdio. Do not undefine this; it's
|
||||
required to preserve semantics required by POSIX. */
|
||||
#define BUFFERED_INPUT
|
||||
|
||||
/* Define ONESHOT if you want sh -c 'command' to avoid forking to execute
|
||||
`command' whenever possible. This is a big efficiency improvement. */
|
||||
#define ONESHOT
|
||||
|
||||
+6
-2
@@ -2754,10 +2754,14 @@ Arrays are assigned to using compound assignments of the form
|
||||
\fIname\fP=\fB(\fPvalue\fI1\fP ... value\fIn\fP\fB)\fP, where each
|
||||
\fIvalue\fP may be of the form [\fIsubscript\fP]=\fIstring\fP.
|
||||
Indexed array assignments do not require anything but \fIstring\fP.
|
||||
Each \fIvalue\fP in the list is expanded using all the shell expansions
|
||||
Each \fIvalue\fP in the list is expanded using the shell expansions
|
||||
described below under
|
||||
.SM
|
||||
.BR EXPANSION .
|
||||
.BR EXPANSION ,
|
||||
but \fIvalue\fPs that are valid variable assignments
|
||||
including the brackets and subscript do not undergo
|
||||
brace expansion and word splitting, as with individual
|
||||
variable assignments.
|
||||
When assigning to indexed arrays, if the optional brackets and subscript
|
||||
are supplied, that index is assigned to;
|
||||
otherwise the index of the element assigned is the last index assigned
|
||||
|
||||
+6
-2
@@ -7741,8 +7741,12 @@ the optional subscript is supplied, that index is assigned to;
|
||||
otherwise the index of the element assigned is the last index assigned
|
||||
to by the statement plus one. Indexing starts at zero.
|
||||
|
||||
Each @var{value} in the list undergoes all the shell expansions
|
||||
described above (@pxref{Shell Expansions}).
|
||||
Each @var{value} in the list undergoes the shell expansions
|
||||
described above (@pxref{Shell Expansions}),
|
||||
but @var{value}s that are valid variable assignments
|
||||
including the brackets and subscript do not undergo
|
||||
brace expansion and word splitting, as with individual
|
||||
variable assignments.
|
||||
|
||||
When assigning to an associative array, the words in a compound assignment
|
||||
may be either assignment statements, for which the subscript is required,
|
||||
|
||||
+2
-6
@@ -1,6 +1,6 @@
|
||||
/* execute_cmd.c -- Execute a COMMAND structure. */
|
||||
|
||||
/* Copyright (C) 1987-2022 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -90,9 +90,7 @@ extern int errno;
|
||||
#include <glob/strmatch.h>
|
||||
#include <tilde/tilde.h>
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
# include "input.h"
|
||||
#endif
|
||||
#include "input.h"
|
||||
|
||||
#if defined (ALIAS)
|
||||
# include "alias.h"
|
||||
@@ -1626,10 +1624,8 @@ execute_in_subshell (COMMAND *command, int asynchronous, int pipe_in, int pipe_o
|
||||
if (should_redir_stdin && stdin_redir == 0)
|
||||
async_redirect_stdin ();
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
/* In any case, we are not reading our command input from stdin. */
|
||||
default_buffered_input = -1;
|
||||
#endif
|
||||
|
||||
/* We can't optimize away forks if one of the commands executed by the
|
||||
subshell sets an exit trap, so we set CMD_NO_FORK for simple commands
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* input.c -- functions to perform buffered input with synchronization. */
|
||||
|
||||
/* Copyright (C) 1992-2022 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1992-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -124,8 +124,6 @@ ungetc_with_restart (int c, FILE *stream)
|
||||
return c;
|
||||
}
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
|
||||
/* A facility similar to stdio, but input-only. */
|
||||
|
||||
#if defined (USING_BASH_MALLOC)
|
||||
@@ -653,4 +651,3 @@ main(int argc, char **argv)
|
||||
exit(0);
|
||||
}
|
||||
#endif /* TEST */
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* input.h -- Structures and unions used for reading input. */
|
||||
|
||||
/* Copyright (C) 1993-2022 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1993-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -28,8 +28,6 @@ typedef int sh_cunget_func_t (int); /* sh_intfunc_t */
|
||||
|
||||
enum stream_type {st_none, st_stdin, st_stream, st_string, st_bstream};
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
|
||||
/* Possible values for b_flag. */
|
||||
#undef B_EOF
|
||||
#undef B_ERROR /* There are some systems with this define */
|
||||
@@ -71,14 +69,10 @@ extern int bash_input_fd_changed;
|
||||
|
||||
#define bclearerror(bp) ((bp)->b_flag &= ~(B_ERROR|B_EOF))
|
||||
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
typedef union {
|
||||
FILE *file;
|
||||
char *string;
|
||||
#if defined (BUFFERED_INPUT)
|
||||
int buffered_fd;
|
||||
#endif
|
||||
} INPUT_STREAM;
|
||||
|
||||
typedef struct {
|
||||
@@ -114,7 +108,6 @@ extern void restore_token_state (int *);
|
||||
extern int getc_with_restart (FILE *);
|
||||
extern int ungetc_with_restart (int, FILE *);
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
/* Functions from input.c. */
|
||||
extern int fd_is_bash_input (int);
|
||||
extern int set_bash_input_fd (int);
|
||||
@@ -132,6 +125,5 @@ extern int sync_buffered_stream (int);
|
||||
extern int buffered_getchar (void);
|
||||
extern int buffered_ungetchar (int);
|
||||
extern void with_input_from_buffered_stream (int, char *);
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
#endif /* _INPUT_H_ */
|
||||
|
||||
@@ -49,9 +49,7 @@
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
# include "input.h"
|
||||
#endif
|
||||
#include "input.h"
|
||||
|
||||
/* Need to include this up here for *_TTY_DRIVER definitions. */
|
||||
#include "shtty.h"
|
||||
@@ -2091,15 +2089,12 @@ make_child (char *command, int flags)
|
||||
async_p = (flags & FORK_ASYNC);
|
||||
forksleep = 1;
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
/* If default_buffered_input is active, we are reading a script. If
|
||||
the command is asynchronous, we have already duplicated /dev/null
|
||||
as fd 0, but have not changed the buffered stream corresponding to
|
||||
the old fd 0. We don't want to sync the stream in this case. */
|
||||
if (default_buffered_input != -1 &&
|
||||
(!async_p || default_buffered_input > 0))
|
||||
if (default_buffered_input != -1 && (!async_p || default_buffered_input > 0))
|
||||
sync_buffered_stream (default_buffered_input);
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
/* Create the child, handle severe errors. Retry on EAGAIN. */
|
||||
while ((pid = fork ()) < 0 && errno == EAGAIN && forksleep < FORKSLEEP_MAX)
|
||||
@@ -2153,12 +2148,11 @@ make_child (char *command, int flags)
|
||||
child process, go back and change callers who free `command' in
|
||||
the child process when this returns. */
|
||||
mypid = getpid ();
|
||||
#if defined (BUFFERED_INPUT)
|
||||
|
||||
/* Close default_buffered_input if it's > 0. We don't close it if it's
|
||||
0 because that's the file descriptor used when redirecting input,
|
||||
and it's wrong to close the file in that case. */
|
||||
unset_bash_input (0);
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
CLRINTERRUPT; /* XXX - children have their own interrupt state */
|
||||
|
||||
@@ -3057,17 +3051,17 @@ if (job == NO_JOB)
|
||||
}
|
||||
else
|
||||
#if defined (READLINE)
|
||||
/* We don't want to do this if we are running a process during
|
||||
programmable completion, but we do want to handle window size
|
||||
changes for traps while readline is active or a command bound
|
||||
to `bind -x'. */
|
||||
if (RL_ISSTATE (RL_STATE_COMPLETING) == 0)
|
||||
if (RL_ISSTATE(RL_STATE_DISPATCHING|RL_STATE_TERMPREPPED) != 0)
|
||||
{
|
||||
if (check_window_size)
|
||||
get_new_window_size (0, (int *)0, (int *)0);
|
||||
}
|
||||
else
|
||||
/* We don't want to get the entire tty state if we are running
|
||||
while readline is active or has changed the terminal, but we
|
||||
can handle window size changes during programmable completion,
|
||||
traps while readline is active, or a command bound using
|
||||
`bind -x'. */
|
||||
if (RL_ISSTATE(RL_STATE_COMPLETING|RL_STATE_DISPATCHING|RL_STATE_TERMPREPPED) != 0)
|
||||
{
|
||||
if (check_window_size)
|
||||
get_new_window_size (0, (int *)0, (int *)0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
get_tty_state ();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/* This file works under BSD, System V, minix, and Posix systems. It does
|
||||
not implement job control. */
|
||||
|
||||
/* Copyright (C) 1987-2022 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -34,9 +34,7 @@
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
# include "input.h"
|
||||
#endif
|
||||
#include "input.h"
|
||||
|
||||
/* Need to include this up here for *_TTY_DRIVER definitions. */
|
||||
#include "shtty.h"
|
||||
@@ -485,14 +483,12 @@ make_child (char *command, int flags)
|
||||
async_p = (flags & FORK_ASYNC);
|
||||
start_pipeline ();
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
/* If default_buffered_input is active, we are reading a script. If
|
||||
the command is asynchronous, we have already duplicated /dev/null
|
||||
as fd 0, but have not changed the buffered stream corresponding to
|
||||
the old fd 0. We don't want to sync the stream in this case. */
|
||||
if (default_buffered_input != -1 && (!async_p || default_buffered_input > 0))
|
||||
sync_buffered_stream (default_buffered_input);
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
/* Block SIGTERM here and unblock in child after fork resets the
|
||||
set of pending signals */
|
||||
@@ -540,9 +536,7 @@ make_child (char *command, int flags)
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
#if defined (BUFFERED_INPUT)
|
||||
unset_bash_input (0);
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
CLRINTERRUPT; /* XXX - children have their own interrupt state */
|
||||
|
||||
|
||||
@@ -1509,7 +1509,6 @@ yy_ungetc (int c)
|
||||
return (*(bash_input.ungetter)) (c);
|
||||
}
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
#ifdef INCLUDE_UNUSED
|
||||
int
|
||||
input_file_descriptor (void)
|
||||
@@ -1526,7 +1525,6 @@ input_file_descriptor (void)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
@@ -1756,9 +1754,7 @@ typedef struct stream_saver {
|
||||
struct stream_saver *next;
|
||||
BASH_INPUT bash_input;
|
||||
int line;
|
||||
#if defined (BUFFERED_INPUT)
|
||||
BUFFERED_STREAM *bstream;
|
||||
#endif /* BUFFERED_INPUT */
|
||||
} STREAM_SAVER;
|
||||
|
||||
/* The globally known line number. */
|
||||
@@ -1781,13 +1777,11 @@ push_stream (int reset_lineno)
|
||||
|
||||
xbcopy ((char *)&bash_input, (char *)&(saver->bash_input), sizeof (BASH_INPUT));
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
saver->bstream = (BUFFERED_STREAM *)NULL;
|
||||
/* If we have a buffered stream, clear out buffers[fd]. */
|
||||
if (bash_input.type == st_bstream && bash_input.location.buffered_fd >= 0)
|
||||
saver->bstream = set_buffered_stream (bash_input.location.buffered_fd,
|
||||
(BUFFERED_STREAM *)NULL);
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
saver->line = line_number;
|
||||
bash_input.name = (char *)NULL;
|
||||
@@ -1816,7 +1810,6 @@ pop_stream (void)
|
||||
saver->bash_input.name,
|
||||
saver->bash_input.location);
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
/* If we have a buffered stream, restore buffers[fd]. */
|
||||
/* If the input file descriptor was changed while this was on the
|
||||
save stack, update the buffered fd to the new file descriptor and
|
||||
@@ -1836,7 +1829,6 @@ pop_stream (void)
|
||||
/* XXX could free buffered stream returned as result here. */
|
||||
set_buffered_stream (bash_input.location.buffered_fd, saver->bstream);
|
||||
}
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
line_number = saver->line;
|
||||
|
||||
@@ -2334,11 +2326,7 @@ shell_getc (int remove_quoted_newline)
|
||||
QUIT;
|
||||
|
||||
last_was_backslash = 0;
|
||||
if (sigwinch_received)
|
||||
{
|
||||
sigwinch_received = 0;
|
||||
get_new_window_size (0, (int *)0, (int *)0);
|
||||
}
|
||||
CHECK_WINCH;
|
||||
|
||||
if (eol_ungetc_lookahead)
|
||||
{
|
||||
@@ -2458,7 +2446,6 @@ shell_getc (int remove_quoted_newline)
|
||||
if (i == 0)
|
||||
shell_input_line_terminator = EOF;
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
if (i == 0 && bash_input.type == st_bstream)
|
||||
{
|
||||
BUFFERED_STREAM *bp;
|
||||
@@ -2467,9 +2454,8 @@ shell_getc (int remove_quoted_newline)
|
||||
shell_input_line_terminator = READERR;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i == 0 && interactive_shell == 0 && bash_input.type == st_stream && ferror (stdin))
|
||||
shell_input_line_terminator = READERR;
|
||||
if (i == 0 && interactive_shell == 0 && bash_input.type == st_stream && ferror (stdin))
|
||||
shell_input_line_terminator = READERR;
|
||||
|
||||
/* If we want to make read errors cancel execution of any partial
|
||||
line, take out the checks for i == 0 above and set i = 0 if
|
||||
@@ -5456,7 +5442,7 @@ got_token:
|
||||
{
|
||||
the_word->flags |= W_NOSPLIT;
|
||||
if (parser_state & PST_COMPASSIGN)
|
||||
the_word->flags |= W_NOGLOB; /* XXX - W_NOBRACE? */
|
||||
the_word->flags |= W_NOGLOB|W_NOBRACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,4 +73,14 @@ extern volatile sig_atomic_t terminating_signal;
|
||||
do { \
|
||||
if (sigterm_received) termsig_handler (SIGTERM); \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_WINCH \
|
||||
do { \
|
||||
if (sigwinch_received) \
|
||||
{ \
|
||||
sigwinch_received = 0; \
|
||||
get_new_window_size (0, (int *)0, (int *)0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* _QUIT_H_ */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* redir.c -- Functions to perform input and output redirection. */
|
||||
|
||||
/* Copyright (C) 1997-2022 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1997-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -54,9 +54,7 @@ extern int errno;
|
||||
#include "redir.h"
|
||||
#include "trap.h"
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
# include "input.h"
|
||||
#endif
|
||||
#include "input.h"
|
||||
|
||||
#include "builtins/pipesize.h"
|
||||
|
||||
@@ -936,11 +934,9 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp)
|
||||
REDIRECTION_ERROR (r, errno, fd);
|
||||
}
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
/* inhibit call to sync_buffered_stream() for async processes */
|
||||
if (redirector != 0 || (subshell_environment & SUBSHELL_ASYNC) == 0)
|
||||
check_bash_input (redirector);
|
||||
#endif
|
||||
|
||||
/* Make sure there is no pending output before we change the state
|
||||
of the underlying file descriptor, since the builtins use stdio
|
||||
@@ -971,13 +967,11 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp)
|
||||
return (errno);
|
||||
}
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
/* Do not change the buffered stream for an implicit redirection
|
||||
of /dev/null to fd 0 for asynchronous commands without job
|
||||
control (r_inputa_direction). */
|
||||
if (ri == r_input_direction || ri == r_input_output)
|
||||
duplicate_buffered_stream (fd, redirector);
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
/*
|
||||
* If we're remembering, then this is the result of a while, for
|
||||
@@ -995,11 +989,9 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp)
|
||||
|
||||
if (fd != redirector)
|
||||
{
|
||||
#if defined (BUFFERED_INPUT)
|
||||
if (INPUT_REDIRECT (ri))
|
||||
close_buffered_fd (fd);
|
||||
else
|
||||
#endif /* !BUFFERED_INPUT */
|
||||
close (fd); /* Don't close what we just opened! */
|
||||
}
|
||||
|
||||
@@ -1057,9 +1049,8 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp)
|
||||
REDIRECTION_ERROR (r, errno, fd);
|
||||
}
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
check_bash_input (redirector);
|
||||
#endif
|
||||
|
||||
if (redirect->rflags & REDIR_VARASSIGN)
|
||||
{
|
||||
if ((r = redir_varassign (redirect, redirector)) < 0)
|
||||
@@ -1076,20 +1067,14 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp)
|
||||
return (r);
|
||||
}
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
duplicate_buffered_stream (fd, redirector);
|
||||
#endif
|
||||
|
||||
if ((flags & RX_CLEXEC) && (redirector > 2))
|
||||
SET_CLOSE_ON_EXEC (redirector);
|
||||
}
|
||||
|
||||
if (fd != redirector)
|
||||
#if defined (BUFFERED_INPUT)
|
||||
close_buffered_fd (fd);
|
||||
#else
|
||||
close (fd);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1131,11 +1116,11 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp)
|
||||
REDIRECTION_ERROR (r, errno, -1);
|
||||
}
|
||||
}
|
||||
#if defined (BUFFERED_INPUT)
|
||||
|
||||
/* inhibit call to sync_buffered_stream() for async processes */
|
||||
if (redirector != 0 || (subshell_environment & SUBSHELL_ASYNC) == 0)
|
||||
check_bash_input (redirector);
|
||||
#endif
|
||||
|
||||
if (redirect->rflags & REDIR_VARASSIGN)
|
||||
{
|
||||
if ((r = redir_varassign (redirect, redirector)) < 0)
|
||||
@@ -1148,10 +1133,8 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp)
|
||||
else if (dup2 (redir_fd, redirector) < 0)
|
||||
return (errno);
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
if (ri == r_duplicating_input || ri == r_move_input)
|
||||
duplicate_buffered_stream (redir_fd, redirector);
|
||||
#endif /* BUFFERED_INPUT */
|
||||
|
||||
/* First duplicate the close-on-exec state of redirectee. dup2
|
||||
leaves the flag unset on the new descriptor, which means it
|
||||
@@ -1218,14 +1201,10 @@ do_redirection_internal (REDIRECT *redirect, int flags, char **fnp)
|
||||
#endif
|
||||
xtrace_fdchk (redirector);
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
/* inhibit call to sync_buffered_stream() for async processes */
|
||||
if (redirector != 0 || (subshell_environment & SUBSHELL_ASYNC) == 0)
|
||||
check_bash_input (redirector);
|
||||
r = close_buffered_fd (redirector);
|
||||
#else /* !BUFFERED_INPUT */
|
||||
r = close (redirector);
|
||||
#endif /* !BUFFERED_INPUT */
|
||||
|
||||
if (r < 0 && (flags & RX_INTERNAL) && (errno == EIO || errno == ENOSPC))
|
||||
REDIRECTION_ERROR (r, errno, -1);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* shell.c -- GNU's idea of the POSIX shell specification. */
|
||||
|
||||
/* Copyright (C) 1987-2022 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -288,10 +288,8 @@ char **subshell_envp;
|
||||
|
||||
char *exec_argv0;
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
/* The file descriptor from which the shell is reading input. */
|
||||
int default_buffered_input = -1;
|
||||
#endif
|
||||
|
||||
/* The following two variables are not static so they can show up in $-. */
|
||||
int read_from_stdin; /* -s flag supplied */
|
||||
@@ -438,9 +436,7 @@ main (int argc, char **argv, char **env)
|
||||
command_execution_string = shell_script_filename = NULL;
|
||||
want_pending_command = locally_skip_execution = read_from_stdin = 0;
|
||||
default_input = stdin;
|
||||
#if defined (BUFFERED_INPUT)
|
||||
default_buffered_input = -1;
|
||||
#endif
|
||||
|
||||
/* Fix for the `infinite process creation' bug when running shell scripts
|
||||
from startup files on System V. */
|
||||
@@ -772,11 +768,7 @@ main (int argc, char **argv, char **env)
|
||||
{
|
||||
/* In this mode, bash is reading a script from stdin, which is a
|
||||
pipe or redirected file. */
|
||||
#if defined (BUFFERED_INPUT)
|
||||
default_buffered_input = fileno (stdin); /* == 0 */
|
||||
#else
|
||||
setbuf (default_input, NULL);
|
||||
#endif /* !BUFFERED_INPUT */
|
||||
read_from_stdin = 1;
|
||||
}
|
||||
else if (top_level_arg_index == argc) /* arg index before startup files */
|
||||
@@ -1672,22 +1664,8 @@ open_shell_script (char *script_name)
|
||||
not match with ours. */
|
||||
fd = move_to_high_fd (fd, 1, -1);
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
default_buffered_input = fd;
|
||||
SET_CLOSE_ON_EXEC (default_buffered_input);
|
||||
#else /* !BUFFERED_INPUT */
|
||||
default_input = fdopen (fd, "r");
|
||||
|
||||
if (default_input == 0)
|
||||
{
|
||||
file_error (filename);
|
||||
exit (EX_NOTFOUND);
|
||||
}
|
||||
|
||||
SET_CLOSE_ON_EXEC (fd);
|
||||
if (fileno (default_input) != fd)
|
||||
SET_CLOSE_ON_EXEC (fileno (default_input));
|
||||
#endif /* !BUFFERED_INPUT */
|
||||
|
||||
/* Just about the only way for this code to be executed is if something
|
||||
like `bash -i /dev/stdin' is executed. */
|
||||
@@ -1696,12 +1674,7 @@ open_shell_script (char *script_name)
|
||||
dup2 (fd, 0);
|
||||
close (fd);
|
||||
fd = 0;
|
||||
#if defined (BUFFERED_INPUT)
|
||||
default_buffered_input = 0;
|
||||
#else
|
||||
fclose (default_input);
|
||||
default_input = stdin;
|
||||
#endif
|
||||
}
|
||||
else if (forced_interactive && fd_is_tty == 0)
|
||||
/* But if a script is called with something like `bash -i scriptname',
|
||||
@@ -1721,20 +1694,16 @@ set_bash_input (void)
|
||||
{
|
||||
/* Make sure the fd from which we are reading input is not in
|
||||
no-delay mode. */
|
||||
#if defined (BUFFERED_INPUT)
|
||||
if (interactive == 0)
|
||||
sh_unset_nodelay_mode (default_buffered_input);
|
||||
else
|
||||
#endif /* !BUFFERED_INPUT */
|
||||
sh_unset_nodelay_mode (fileno (stdin));
|
||||
|
||||
/* with_input_from_stdin really means `with_input_from_readline' */
|
||||
if (interactive && no_line_editing == 0)
|
||||
with_input_from_stdin ();
|
||||
#if defined (BUFFERED_INPUT)
|
||||
else if (interactive == 0)
|
||||
with_input_from_buffered_stream (default_buffered_input, dollar_vars[0]);
|
||||
#endif /* BUFFERED_INPUT */
|
||||
else
|
||||
with_input_from_stream (default_input, dollar_vars[0]);
|
||||
}
|
||||
@@ -1746,7 +1715,6 @@ set_bash_input (void)
|
||||
void
|
||||
unset_bash_input (int check_zero)
|
||||
{
|
||||
#if defined (BUFFERED_INPUT)
|
||||
if ((check_zero && default_buffered_input >= 0) ||
|
||||
(check_zero == 0 && default_buffered_input > 0))
|
||||
{
|
||||
@@ -1754,13 +1722,6 @@ unset_bash_input (int check_zero)
|
||||
default_buffered_input = bash_input.location.buffered_fd = -1;
|
||||
bash_input.type = st_none; /* XXX */
|
||||
}
|
||||
#else /* !BUFFERED_INPUT */
|
||||
if (default_input)
|
||||
{
|
||||
fclose (default_input);
|
||||
default_input = (FILE *)NULL;
|
||||
}
|
||||
#endif /* !BUFFERED_INPUT */
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -272,6 +272,32 @@ trap -- 'echo trap:$FUNCNAME' EXIT
|
||||
trap:f
|
||||
trap -- 'echo trap:$FUNCNAME' EXIT
|
||||
trap:f
|
||||
declare -rx x="4"
|
||||
declare -rx y="5"
|
||||
f:3
|
||||
f1:3
|
||||
global1:bcde
|
||||
f:3
|
||||
f1:3
|
||||
global2:bcde
|
||||
f:3
|
||||
f1:3
|
||||
global:bcde
|
||||
f:3
|
||||
f1:3
|
||||
global:bcde
|
||||
f:3
|
||||
bcde
|
||||
f:3
|
||||
bcde
|
||||
f1:3
|
||||
global: bcde
|
||||
f1:3
|
||||
global: 3
|
||||
f: 3
|
||||
global: declare -rx c="3"
|
||||
f1: 4
|
||||
global: declare -- b="8"
|
||||
a=z
|
||||
a=b
|
||||
a=z
|
||||
|
||||
@@ -260,6 +260,7 @@ ${THIS_SH} ./varenv19.sub
|
||||
${THIS_SH} ./varenv20.sub
|
||||
${THIS_SH} ./varenv21.sub
|
||||
${THIS_SH} ./varenv22.sub
|
||||
${THIS_SH} ./varenv23.sub
|
||||
|
||||
# make sure variable scoping is done right
|
||||
tt() { typeset a=b;echo a=$a; };a=z;echo a=$a;tt;echo a=$a
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# posix rules for assignments preceding export/readonly in functions, using
|
||||
# local and global vars; default rules for assignments preceding declare/local
|
||||
# in functions, always using local vars.
|
||||
#
|
||||
# changes to local variables should never propagate upward from the function
|
||||
# to its caller, even in posix mode
|
||||
|
||||
x=1
|
||||
x=4 declare -r x
|
||||
declare -p x
|
||||
y=2
|
||||
y=5 readonly y
|
||||
declare -p y
|
||||
# can't use x and y from here on
|
||||
|
||||
f() { local -r a=3; echo f:$a; }
|
||||
f1() { declare -r b=3; echo f1:$b; }
|
||||
|
||||
a=4 f
|
||||
b=4 f1
|
||||
echo global1:$a $b
|
||||
|
||||
set -o posix
|
||||
a=4 f
|
||||
b=4 f1
|
||||
echo global2:$a $b
|
||||
set +o posix
|
||||
|
||||
unset -f f f1
|
||||
|
||||
f() { local a=3; readonly a; echo f:$a; }
|
||||
f1() { local b=3; declare -r b; echo f1:$b; }
|
||||
|
||||
a=4 f
|
||||
b=4 f1
|
||||
echo global:$a $b
|
||||
|
||||
set -o posix
|
||||
a=4 f
|
||||
b=4 f1
|
||||
echo global:$a $b
|
||||
set +o posix
|
||||
|
||||
unset -f f f1
|
||||
|
||||
f() { local a; a=3 readonly a; echo f:$a; }
|
||||
|
||||
a=4 f
|
||||
echo $a
|
||||
set -o posix
|
||||
a=4 f
|
||||
echo $a
|
||||
set +o posix
|
||||
|
||||
f1() { a=3 readonly a; echo f1:$a; }
|
||||
|
||||
a=7 f1
|
||||
echo global: $a
|
||||
|
||||
set -o posix
|
||||
a=7 f1
|
||||
echo global: $a
|
||||
set +o posix
|
||||
|
||||
unset -f f f1
|
||||
# can't use a from here on
|
||||
|
||||
c=7 b=8
|
||||
f() { c=3 readonly c; echo f: $c; }
|
||||
f1() { b=4 declare -r b; echo f1: $b; }
|
||||
|
||||
f
|
||||
echo global: $(declare -p c)
|
||||
|
||||
f1
|
||||
echo global: $(declare -p b)
|
||||
|
||||
unset -f f f1
|
||||
|
||||
# can't use c from here on
|
||||
|
||||
|
||||
+2
-2
@@ -4504,7 +4504,7 @@ propagate_temp_var (PTR_T data)
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = (SHELL_VAR *)data;
|
||||
if (tempvar_p (var) && (var->attributes & att_propagate))
|
||||
if (tempvar_p (var) && propagate_p (var))
|
||||
push_temp_var (data);
|
||||
else
|
||||
{
|
||||
@@ -5307,7 +5307,7 @@ push_exported_var (PTR_T data)
|
||||
propagated, bind it in the previous scope before disposing it. */
|
||||
/* XXX - This isn't exactly right, because all tempenv variables have the
|
||||
export attribute set. */
|
||||
if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate))
|
||||
if (tempvar_p (var) && exported_p (var) && propagate_p (var))
|
||||
{
|
||||
var->attributes &= ~att_tempvar; /* XXX */
|
||||
v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
|
||||
|
||||
Reference in New Issue
Block a user