/* 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
{
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;
}
/* 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
#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
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);
}
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]);
}
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)
/* 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]);
}
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
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));
}
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)
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;
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);
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;
{
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