]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - input.c
Bash-5.1 patch 4: fix key-value pair associative array assignment word expansions
[thirdparty/bash.git] / input.c
diff --git a/input.c b/input.c
index 7933da2f2ee3a5e385817e3b98b337c8dd7bac19..c57e81c362f9514b07aedf6d4c8d5d5d06635b45 100644 (file)
--- a/input.c
+++ b/input.c
@@ -1,22 +1,22 @@
 /* input.c -- functions to perform buffered input with synchronization. */
 
-/* Copyright (C) 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1992-2020 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
-   Bash 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 2, or (at your option) any later
-   version.
+   Bash 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.
 
-   Bash 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.
+   Bash 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 Bash; see the file COPYING.  If not, write to the Free Software
-   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+   You should have received a copy of the GNU General Public License
+   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
+*/
 
 #include "config.h"
 
 #include "bashansi.h"
 #include "bashintl.h"
 
-#include "command.h"
-#include "general.h"
+#include "shell.h"
 #include "input.h"
-#include "error.h"
 #include "externs.h"
-#include "quit.h"
+#include "trap.h"
 
 #if !defined (errno)
 extern int errno;
 #endif /* !errno */
 
-extern void termsig_handler __P((int));
+#if defined (EAGAIN)
+#  define X_EAGAIN EAGAIN
+#else
+#  define X_EAGAIN -99
+#endif
+
+#if defined (EWOULDBLOCK)
+#  define X_EWOULDBLOCK EWOULDBLOCK
+#else
+#  define X_EWOULDBLOCK -99
+#endif
+
+extern void termsig_handler PARAMS((int));
 
 /* Functions to handle reading input on systems that don't restart read(2)
    if a signal is received. */
 
-static char localbuf[128];
+static char localbuf[1024];
 static int local_index = 0, local_bufused = 0;
 
 /* Posix and USG systems do not guarantee to restart read () if it is
@@ -71,15 +81,34 @@ getc_with_restart (stream)
     {
       while (1)
        {
-         CHECK_TERMSIG;
+         QUIT;
+         run_pending_traps ();
+
          local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
          if (local_bufused > 0)
            break;
-         else if (local_bufused == 0 || errno != EINTR)
+         else if (local_bufused == 0)
            {
              local_index = 0;
              return EOF;
            }
+         else if (errno == X_EAGAIN || errno == X_EWOULDBLOCK)
+           {
+             if (sh_unset_nodelay_mode (fileno (stream)) < 0)
+               {
+                 sys_error (_("cannot reset nodelay mode for fd %d"), fileno (stream));
+                 local_index = local_bufused = 0;
+                 return EOF;
+               }
+             continue;
+           }
+         else if (errno != EINTR)
+           {
+             local_index = local_bufused = 0;
+             return EOF;
+           }
+         else if (interrupt_state || terminating_signal)       /* QUIT; */
+           local_index = local_bufused = 0;
        }
       local_index = 0;
     }
@@ -103,7 +132,7 @@ ungetc_with_restart (c, stream)
 /* A facility similar to stdio, but input-only. */
 
 #if defined (USING_BASH_MALLOC)
-#  define MAX_INPUT_BUFFER_SIZE        8176
+#  define MAX_INPUT_BUFFER_SIZE        8172
 #else
 #  define MAX_INPUT_BUFFER_SIZE        8192
 #endif
@@ -121,8 +150,6 @@ ungetc_with_restart (c, stream)
 #endif
 #define min(a, b)      ((a) > (b) ? (b) : (a))
 
-extern int interactive_shell;
-
 int bash_input_fd_changed;
 
 /* This provides a way to map from a file descriptor to the buffer
@@ -172,6 +199,8 @@ make_buffered_stream (fd, buffer, bufsize)
   bp->b_used = bp->b_inputp = bp->b_flag = 0;
   if (bufsize == 1)
     bp->b_flag |= B_UNBUFF;
+  if (O_TEXT && (fcntl (fd, F_GETFL) & O_TEXT) != 0)
+    bp->b_flag |= B_TEXT;
   return (bp);
 }
 
@@ -238,11 +267,13 @@ save_bash_input (fd, new_fd)
       return -1;
     }
 
-  if (buffers[nfd])
+  if (nfd < nbuffers && buffers[nfd])
     {
       /* What's this?  A stray buffer without an associated open file
         descriptor?  Free up the buffer and report the error. */
       internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
+      if (buffers[nfd]->b_flag & B_SHAREDBUF)
+       buffers[nfd]->b_buffer = (char *)NULL;
       free_buffered_stream (buffers[nfd]);
     }
 
@@ -278,7 +309,7 @@ save_bash_input (fd, new_fd)
    the buffered stream.  Make sure the file descriptor used to save bash
    input is set close-on-exec. Returns 0 on success, -1 on failure.  This
    works only if fd is > 0 -- if fd == 0 and bash is reading input from
-   fd 0, save_bash_input is used instead, to cooperate with input
+   fd 0, sync_buffered_stream is used instead, to cooperate with input
    redirection (look at redir.c:add_undo_redirect()). */
 int
 check_bash_input (fd)
@@ -322,6 +353,12 @@ duplicate_buffered_stream (fd1, fd2)
       /* If the two objects share the same b_buffer, don't free it. */
       if (buffers[fd1] && buffers[fd1]->b_buffer && buffers[fd1]->b_buffer == buffers[fd2]->b_buffer)
        buffers[fd2] = (BUFFERED_STREAM *)NULL;
+      /* If this buffer is shared with another fd, don't free the buffer */
+      else if (buffers[fd2]->b_flag & B_SHAREDBUF)
+       {
+         buffers[fd2]->b_buffer = (char *)NULL;
+         free_buffered_stream (buffers[fd2]);
+       }
       else
        free_buffered_stream (buffers[fd2]);
     }
@@ -336,15 +373,14 @@ duplicate_buffered_stream (fd1, fd2)
       buffers[fd2]->b_flag |= B_WASBASHINPUT;
     }
 
+  if (fd_is_bash_input (fd1) || (buffers[fd1] && (buffers[fd1]->b_flag & B_SHAREDBUF)))
+    buffers[fd2]->b_flag |= B_SHAREDBUF;
+
   return (fd2);
 }
 
 /* Return 1 if a seek on FD will succeed. */
-#ifndef __CYGWIN__
-#  define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
-#else
-#  define fd_is_seekable(fd) 0
-#endif /* __CYGWIN__ */
+#define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
 
 /* Take FD, a file descriptor, and create and return a buffered stream
    corresponding to it.  If something is wrong and the file descriptor
@@ -411,6 +447,8 @@ close_buffered_stream (bp)
   if (!bp)
     return (0);
   fd = bp->b_fd;
+  if (bp->b_flag & B_SHAREDBUF)
+    bp->b_buffer = (char *)NULL;
   free_buffered_stream (bp);
   return (close (fd));
 }
@@ -431,7 +469,7 @@ close_buffered_fd (fd)
   return (close_buffered_stream (buffers[fd]));
 }
 
-/* Make the BUFFERED_STREAM associcated with buffers[FD] be BP, and return
+/* Make the BUFFERED_STREAM associated with buffers[FD] be BP, and return
    the old BUFFERED_STREAM. */
 BUFFERED_STREAM *
 set_buffered_stream (fd, bp)
@@ -451,12 +489,30 @@ b_fill_buffer (bp)
      BUFFERED_STREAM *bp;
 {
   ssize_t nr;
+  off_t o;
 
   CHECK_TERMSIG;
-  nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
+  /* In an environment where text and binary files are treated differently,
+     compensate for lseek() on text files returning an offset different from
+     the count of characters read() returns.  Text-mode streams have to be
+     treated as unbuffered. */
+  if ((bp->b_flag & (B_TEXT | B_UNBUFF)) == B_TEXT)
+    {
+      o = lseek (bp->b_fd, 0, SEEK_CUR);
+      nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
+      if (nr > 0 && nr < lseek (bp->b_fd, 0, SEEK_CUR) - o)
+       {
+         lseek (bp->b_fd, o, SEEK_SET);
+         bp->b_flag |= B_UNBUFF;
+         bp->b_size = 1;
+         nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
+       }
+    }
+  else
+    nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
   if (nr <= 0)
     {
-      bp->b_used = 0;
+      bp->b_used = bp->b_inputp = 0;
       bp->b_buffer[0] = 0;
       if (nr == 0)
        bp->b_flag |= B_EOF;
@@ -465,15 +521,6 @@ b_fill_buffer (bp)
       return (EOF);
     }
 
-#if defined (__CYGWIN__)
-  /* If on cygwin, translate \r\n to \n. */
-  if (nr >= 2 && bp->b_buffer[nr - 2] == '\r' && bp->b_buffer[nr - 1] == '\n')
-    {
-      bp->b_buffer[nr - 2] = '\n';
-      nr--;
-    }
-#endif
-
   bp->b_used = nr;
   bp->b_inputp = 0;
   return (bp->b_buffer[bp->b_inputp++] & 0xFF);
@@ -491,7 +538,7 @@ bufstream_ungetc(c, bp)
      int c;
      BUFFERED_STREAM *bp;
 {
-  if (c == EOF || bp->b_inputp == 0)
+  if (c == EOF || bp == 0 || bp->b_inputp == 0)
     return (EOF);
 
   bp->b_buffer[--bp->b_inputp] = c;
@@ -522,6 +569,9 @@ buffered_getchar ()
 {
   CHECK_TERMSIG;
 
+  if (bash_input.location.buffered_fd < 0 || buffers[bash_input.location.buffered_fd] == 0)
+    return EOF;
+
 #if !defined (DJGPP)
   return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
 #else