]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
local variables no longer modify external variables if the variable is supplied as...
authorChet Ramey <chet.ramey@case.edu>
Mon, 27 Feb 2023 15:55:06 +0000 (10:55 -0500)
committerChet Ramey <chet.ramey@case.edu>
Mon, 27 Feb 2023 15:55:06 +0000 (10:55 -0500)
22 files changed:
CWRU/CWRU.chlog
MANIFEST
builtins/declare.def
builtins/exec.def
builtins/read.def
builtins/setattr.def
config-top.h
doc/bash.1
doc/bashref.texi
execute_cmd.c
input.c
input.h
jobs.c
nojobs.c
parse.y
quit.h
redir.c
shell.c
tests/varenv.right
tests/varenv.tests
tests/varenv23.sub [new file with mode: 0644]
variables.c

index 34539b3be17021ea383c999cd292094b0cb09e61..d05a91f4cef33624e198b044d65bb16aab40f0a0 100644 (file)
@@ -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
index 1e9685d3bc04d989cc4c620dbe7db094000cc911..436947247c668ade0cec39a0d26bf974cdd14058 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -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
index 28100de1b858e8204626b395504edfcf3867a076..41c11e1f80158589b450baf506a600d569b93e8b 100644 (file)
@@ -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. */
index b0638dac303e8c19fe8a7c8fa8b82683c9badf7e..54dc6645903c1b9cd550e7329a3b91ed0ac26de5 100644 (file)
@@ -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);
 
index 7e122c3bd04d323efa46aa991be835fa42f2bf8a..e0f73749ee231038a4927a312c6150dd76bb9709 100644 (file)
@@ -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);
index 0f0dbf2c79a55cff9df94931d235ea1d05ed6a45..4520c9e55e187cc88f94901371319c0e73f52d60 100644 (file)
@@ -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);
        }
     }
index 05b78a359ead3898d9a838dd58e31914d240e187..f2ebc6716e246eaee882a1de0a539b92c9a2d845 100644 (file)
    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
index 587a94d7710a28fea3957b9dfd40ef645c3dc0a3..80b5b63e228292f8394ec78a9bdfcae30c93b652 100644 (file)
@@ -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
index 9eeab73594e5233d55dd94f07616153dfba35aa5..727d23772bdd136e4ee3cc4b41dcf6b0b0a31e22 100644 (file)
@@ -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,
index 18540409968977dc156c315fd101639c4a86f922..16d5328ad8901bb43a64898477e23962caec4535 100644 (file)
@@ -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
diff --git a/input.c b/input.c
index 73ffa3ec7d301e3276752d317b5c124f5fe74dfe..155fd36991e893e5250708465772282e9453eb6d 100644 (file)
--- a/input.c
+++ b/input.c
@@ -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 */
diff --git a/input.h b/input.h
index 09a42119ffd2d42dc04068c9276a6d7870f12e51..a1fa7219a0f1ec8ec6c91288705662d2eff99960 100644 (file)
--- a/input.h
+++ b/input.h
@@ -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_ */
diff --git a/jobs.c b/jobs.c
index c0cae92df7ba678140b189dd46dd1aaeafbf21eb..1c225aa6c544bd0afcfd884a8c8ae4ce784f78f5 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -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 ();
 
index 4374d263079b772b8c7285322cad7b19027e3aea..6ca05ba1bb3de81e42f1c6275b0fe9ea2ce8a934 100644 (file)
--- a/nojobs.c
+++ b/nojobs.c
@@ -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 */
 
diff --git a/parse.y b/parse.y
index 2bfc0c6661fea19f0980fd171f8f007927e2c724..231cde6d23d68e56bfea6f1f25b239836f3fb536 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -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;
        }
     }
 
diff --git a/quit.h b/quit.h
index 2d6dca4e320d39b7e4b315127ed1ed11c2e81a42..44d9082837122889f81c7f42c724eca31cf43cca 100644 (file)
--- a/quit.h
+++ b/quit.h
@@ -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_ */
diff --git a/redir.c b/redir.c
index f3407c69ada7ba42f0358af3a97c5c857bd4a33d..804d9b8274e0b4ccdba6c744e5f1ec9d3cc3054b 100644 (file)
--- a/redir.c
+++ b/redir.c
@@ -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);
diff --git a/shell.c b/shell.c
index a64e8e0035b235b47abdf7da97ab2314c04a1e20..28940ad134f3ebe8f3c48301d85bc031103762fb 100644 (file)
--- a/shell.c
+++ b/shell.c
@@ -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 */
 }
       
 
index f6bd1b5bd4d0ee42b395a79fd9529333127bca9c..48b0abd28c780958f01e927a4fcef13d970a7c11 100644 (file)
@@ -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
index 68c619ec767f42e2d53b1fb4fc43dda46dffc5db..9a111c1f9a545a55f90fa2b96a87c5c98d3b7d3f 100644 (file)
@@ -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
diff --git a/tests/varenv23.sub b/tests/varenv23.sub
new file mode 100644 (file)
index 0000000..03202ad
--- /dev/null
@@ -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
+
+
index a643185dc3ca8a414f7882b65105b15a52675363..9f9440673fe60cefe5e3db6ff02b5461e142b5f4 100644 (file)
@@ -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);