]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - input.c
Bash-4.3 patch 15
[thirdparty/bash.git] / input.c
diff --git a/input.c b/input.c
index 9cb5401dea53df45a83a91189f3f7975b862f030..14c6f4e0794e022eae6d96a64c7a7f147eb5563b 100644 (file)
--- a/input.c
+++ b/input.c
@@ -1,27 +1,27 @@
 /* input.c -- functions to perform buffered input with synchronization. */
 
-/* Copyright (C) 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1992-2009 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 "bashtypes.h"
-#ifndef _MINIX
+#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
 #  include <sys/file.h>
 #endif
 #include "filecntl.h"
 #endif
 
 #include "bashansi.h"
+#include "bashintl.h"
+
 #include "command.h"
 #include "general.h"
 #include "input.h"
 #include "error.h"
 #include "externs.h"
+#include "quit.h"
+#include "trap.h"
 
 #if !defined (errno)
 extern int errno;
 #endif /* !errno */
 
+#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 __P((int));
+
 /* Functions to handle reading input on systems that don't restart read(2)
    if a signal is received. */
 
 static char localbuf[128];
-static int local_index, local_bufused;
+static int local_index = 0, local_bufused = 0;
 
 /* Posix and USG systems do not guarantee to restart read () if it is
    interrupted by a signal.  We do the read ourselves, and restart it
@@ -59,19 +77,41 @@ getc_with_restart (stream)
 {
   unsigned char uc;
 
+  CHECK_TERMSIG;
+
   /* Try local buffering to reduce the number of read(2) calls. */
   if (local_index == local_bufused || local_bufused == 0)
     {
       while (1)
        {
+         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;
     }
@@ -164,6 +204,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 |= O_TEXT;
   return (bp);
 }
 
@@ -226,7 +268,7 @@ save_bash_input (fd, new_fd)
   if (nfd == -1)
     {
       if (fcntl (fd, F_GETFD, 0) == 0)
-       sys_error ("cannot allocate new file descriptor for bash input from fd %d", fd);
+       sys_error (_("cannot allocate new file descriptor for bash input from fd %d"), fd);
       return -1;
     }
 
@@ -234,7 +276,7 @@ save_bash_input (fd, new_fd)
     {
       /* What's this?  A stray buffer without an associated open file
         descriptor?  Free up the buffer and report the error. */
-      internal_error ("check_bash_input: buffer already exists for new fd %d", nfd);
+      internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
       free_buffered_stream (buffers[nfd]);
     }
 
@@ -270,14 +312,19 @@ 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)
      int fd;
 {
-  if (fd > 0 && fd_is_bash_input (fd))
-    return ((save_bash_input (fd, -1) == -1) ? -1 : 0);
+  if (fd_is_bash_input (fd))
+    {
+      if (fd > 0)
+       return ((save_bash_input (fd, -1) == -1) ? -1 : 0);
+      else if (fd == 0)
+        return ((sync_buffered_stream (fd) == -1) ? -1 : 0);
+    }
   return 0;
 }
       
@@ -305,7 +352,13 @@ duplicate_buffered_stream (fd1, fd2)
                  (bash_input.location.buffered_fd == fd2);
 
   if (buffers[fd2])
-    free_buffered_stream (buffers[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;
+      else
+       free_buffered_stream (buffers[fd2]);
+    }
   buffers[fd2] = copy_buffered_stream (buffers[fd1]);
   if (buffers[fd2])
     buffers[fd2]->b_fd = fd2;
@@ -321,11 +374,7 @@ duplicate_buffered_stream (fd1, 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
@@ -412,7 +461,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)
@@ -432,8 +481,27 @@ b_fill_buffer (bp)
      BUFFERED_STREAM *bp;
 {
   ssize_t nr;
-
-  nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
+  off_t o;
+
+  CHECK_TERMSIG;
+  /* 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;
@@ -445,15 +513,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);
@@ -500,6 +559,8 @@ sync_buffered_stream (bfd)
 int
 buffered_getchar ()
 {
+  CHECK_TERMSIG;
+
 #if !defined (DJGPP)
   return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
 #else