Blame input.c

Packit b5e560
/* input.c -- functions to perform buffered input with synchronization. */
Packit b5e560
Packit b5e560
/* Copyright (C) 1992-2009 Free Software Foundation, Inc.
Packit b5e560
Packit b5e560
   This file is part of GNU Bash, the Bourne Again SHell.
Packit b5e560
Packit b5e560
   Bash is free software: you can redistribute it and/or modify
Packit b5e560
   it under the terms of the GNU General Public License as published by
Packit b5e560
   the Free Software Foundation, either version 3 of the License, or
Packit b5e560
   (at your option) any later version.
Packit b5e560
Packit b5e560
   Bash is distributed in the hope that it will be useful,
Packit b5e560
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b5e560
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit b5e560
   GNU General Public License for more details.
Packit b5e560
Packit b5e560
   You should have received a copy of the GNU General Public License
Packit b5e560
   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
Packit b5e560
*/
Packit b5e560
Packit b5e560
#include "config.h"
Packit b5e560
Packit b5e560
#include "bashtypes.h"
Packit b5e560
#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
Packit b5e560
#  include <sys/file.h>
Packit b5e560
#endif
Packit b5e560
#include "filecntl.h"
Packit b5e560
#include "posixstat.h"
Packit b5e560
#include <stdio.h>
Packit b5e560
#include <errno.h>
Packit b5e560
Packit b5e560
#if defined (HAVE_UNISTD_H)
Packit b5e560
#  include <unistd.h>
Packit b5e560
#endif
Packit b5e560
Packit b5e560
#include "bashansi.h"
Packit b5e560
#include "bashintl.h"
Packit b5e560
Packit b5e560
#include "command.h"
Packit b5e560
#include "general.h"
Packit b5e560
#include "input.h"
Packit b5e560
#include "error.h"
Packit b5e560
#include "externs.h"
Packit b5e560
#include "quit.h"
Packit b5e560
#include "trap.h"
Packit b5e560
Packit b5e560
#if !defined (errno)
Packit b5e560
extern int errno;
Packit b5e560
#endif /* !errno */
Packit b5e560
Packit b5e560
#if defined (EAGAIN)
Packit b5e560
#  define X_EAGAIN EAGAIN
Packit b5e560
#else
Packit b5e560
#  define X_EAGAIN -99
Packit b5e560
#endif
Packit b5e560
Packit b5e560
#if defined (EWOULDBLOCK)
Packit b5e560
#  define X_EWOULDBLOCK EWOULDBLOCK
Packit b5e560
#else
Packit b5e560
#  define X_EWOULDBLOCK -99
Packit b5e560
#endif
Packit b5e560
Packit b5e560
extern void termsig_handler __P((int));
Packit b5e560
Packit b5e560
/* Functions to handle reading input on systems that don't restart read(2)
Packit b5e560
   if a signal is received. */
Packit b5e560
Packit b5e560
static char localbuf[128];
Packit b5e560
static int local_index = 0, local_bufused = 0;
Packit b5e560
Packit b5e560
/* Posix and USG systems do not guarantee to restart read () if it is
Packit b5e560
   interrupted by a signal.  We do the read ourselves, and restart it
Packit b5e560
   if it returns EINTR. */
Packit b5e560
int
Packit b5e560
getc_with_restart (stream)
Packit b5e560
     FILE *stream;
Packit b5e560
{
Packit b5e560
  unsigned char uc;
Packit b5e560
Packit b5e560
  CHECK_TERMSIG;
Packit b5e560
Packit b5e560
  /* Try local buffering to reduce the number of read(2) calls. */
Packit b5e560
  if (local_index == local_bufused || local_bufused == 0)
Packit b5e560
    {
Packit b5e560
      while (1)
Packit b5e560
	{
Packit b5e560
	  QUIT;
Packit b5e560
	  run_pending_traps ();
Packit b5e560
Packit b5e560
	  local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
Packit b5e560
	  if (local_bufused > 0)
Packit b5e560
	    break;
Packit b5e560
	  else if (local_bufused == 0)
Packit b5e560
	    {
Packit b5e560
	      local_index = 0;
Packit b5e560
	      return EOF;
Packit b5e560
	    }
Packit b5e560
	  else if (errno == X_EAGAIN || errno == X_EWOULDBLOCK)
Packit b5e560
	    {
Packit b5e560
	      if (sh_unset_nodelay_mode (fileno (stream)) < 0)
Packit b5e560
		{
Packit b5e560
		  sys_error (_("cannot reset nodelay mode for fd %d"), fileno (stream));
Packit b5e560
		  local_index = local_bufused = 0;
Packit b5e560
		  return EOF;
Packit b5e560
		}
Packit b5e560
	      continue;
Packit b5e560
	    }
Packit b5e560
	  else if (errno != EINTR)
Packit b5e560
	    {
Packit b5e560
	      local_index = local_bufused = 0;
Packit b5e560
	      return EOF;
Packit b5e560
	    }
Packit b5e560
	  else if (interrupt_state || terminating_signal)	/* QUIT; */
Packit b5e560
	    local_index = local_bufused = 0;
Packit b5e560
	}
Packit b5e560
      local_index = 0;
Packit b5e560
    }
Packit b5e560
  uc = localbuf[local_index++];
Packit b5e560
  return uc;
Packit b5e560
}
Packit b5e560
Packit b5e560
int
Packit b5e560
ungetc_with_restart (c, stream)
Packit b5e560
     int c;
Packit b5e560
     FILE *stream;
Packit b5e560
{
Packit b5e560
  if (local_index == 0 || c == EOF)
Packit b5e560
    return EOF;
Packit b5e560
  localbuf[--local_index] = c;
Packit b5e560
  return c;
Packit b5e560
}
Packit b5e560
Packit b5e560
#if defined (BUFFERED_INPUT)
Packit b5e560
Packit b5e560
/* A facility similar to stdio, but input-only. */
Packit b5e560
Packit b5e560
#if defined (USING_BASH_MALLOC)
Packit b5e560
#  define MAX_INPUT_BUFFER_SIZE	8176
Packit b5e560
#else
Packit b5e560
#  define MAX_INPUT_BUFFER_SIZE	8192
Packit b5e560
#endif
Packit b5e560
Packit b5e560
#if !defined (SEEK_CUR)
Packit b5e560
#  define SEEK_CUR 1
Packit b5e560
#endif /* !SEEK_CUR */
Packit b5e560
Packit b5e560
#ifdef max
Packit b5e560
#  undef max
Packit b5e560
#endif
Packit b5e560
#define max(a, b)	(((a) > (b)) ? (a) : (b))
Packit b5e560
#ifdef min
Packit b5e560
#  undef min
Packit b5e560
#endif
Packit b5e560
#define min(a, b)	((a) > (b) ? (b) : (a))
Packit b5e560
Packit b5e560
extern int interactive_shell;
Packit b5e560
Packit b5e560
int bash_input_fd_changed;
Packit b5e560
Packit b5e560
/* This provides a way to map from a file descriptor to the buffer
Packit b5e560
   associated with that file descriptor, rather than just the other
Packit b5e560
   way around.  This is needed so that buffers are managed properly
Packit b5e560
   in constructs like 3<&4.  buffers[x]->b_fd == x -- that is how the
Packit b5e560
   correspondence is maintained. */
Packit b5e560
static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
Packit b5e560
static int nbuffers;
Packit b5e560
Packit b5e560
#define ALLOCATE_BUFFERS(n) \
Packit b5e560
	do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
Packit b5e560
Packit b5e560
/* Make sure `buffers' has at least N elements. */
Packit b5e560
static void
Packit b5e560
allocate_buffers (n)
Packit b5e560
     int n;
Packit b5e560
{
Packit b5e560
  register int i, orig_nbuffers;
Packit b5e560
Packit b5e560
  orig_nbuffers = nbuffers;
Packit b5e560
  nbuffers = n + 20;
Packit b5e560
  buffers = (BUFFERED_STREAM **)xrealloc
Packit b5e560
    (buffers, nbuffers * sizeof (BUFFERED_STREAM *));
Packit b5e560
Packit b5e560
  /* Zero out the new buffers. */
Packit b5e560
  for (i = orig_nbuffers; i < nbuffers; i++)
Packit b5e560
    buffers[i] = (BUFFERED_STREAM *)NULL;
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Construct and return a BUFFERED_STREAM corresponding to file descriptor
Packit b5e560
   FD, using BUFFER. */
Packit b5e560
static BUFFERED_STREAM *
Packit b5e560
make_buffered_stream (fd, buffer, bufsize)
Packit b5e560
     int fd;
Packit b5e560
     char *buffer;
Packit b5e560
     size_t bufsize;
Packit b5e560
{
Packit b5e560
  BUFFERED_STREAM *bp;
Packit b5e560
Packit b5e560
  bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
Packit b5e560
  ALLOCATE_BUFFERS (fd);
Packit b5e560
  buffers[fd] = bp;
Packit b5e560
  bp->b_fd = fd;
Packit b5e560
  bp->b_buffer = buffer;
Packit b5e560
  bp->b_size = bufsize;
Packit b5e560
  bp->b_used = bp->b_inputp = bp->b_flag = 0;
Packit b5e560
  if (bufsize == 1)
Packit b5e560
    bp->b_flag |= B_UNBUFF;
Packit b5e560
  if (O_TEXT && (fcntl (fd, F_GETFL) & O_TEXT) != 0)
Packit b5e560
    bp->b_flag |= B_TEXT;
Packit b5e560
  return (bp);
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
Packit b5e560
static BUFFERED_STREAM *
Packit b5e560
copy_buffered_stream (bp)
Packit b5e560
     BUFFERED_STREAM *bp;
Packit b5e560
{
Packit b5e560
  BUFFERED_STREAM *nbp;
Packit b5e560
Packit b5e560
  if (!bp)
Packit b5e560
    return ((BUFFERED_STREAM *)NULL);
Packit b5e560
Packit b5e560
  nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
Packit b5e560
  xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM));
Packit b5e560
  return (nbp);
Packit b5e560
}
Packit b5e560
Packit b5e560
int
Packit b5e560
set_bash_input_fd (fd)
Packit b5e560
     int fd;
Packit b5e560
{
Packit b5e560
  if (bash_input.type == st_bstream)
Packit b5e560
    bash_input.location.buffered_fd = fd;
Packit b5e560
  else if (interactive_shell == 0)
Packit b5e560
    default_buffered_input = fd;
Packit b5e560
  return 0;
Packit b5e560
}
Packit b5e560
Packit b5e560
int
Packit b5e560
fd_is_bash_input (fd)
Packit b5e560
     int fd;
Packit b5e560
{
Packit b5e560
  if (bash_input.type == st_bstream && bash_input.location.buffered_fd == fd)
Packit b5e560
    return 1;
Packit b5e560
  else if (interactive_shell == 0 && default_buffered_input == fd)
Packit b5e560
    return 1;
Packit b5e560
  return 0;
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Save the buffered stream corresponding to file descriptor FD (which bash
Packit b5e560
   is using to read input) to a buffered stream associated with NEW_FD.  If
Packit b5e560
   NEW_FD is -1, a new file descriptor is allocated with fcntl.  The new
Packit b5e560
   file descriptor is returned on success, -1 on error. */
Packit b5e560
int
Packit b5e560
save_bash_input (fd, new_fd)
Packit b5e560
     int fd, new_fd;
Packit b5e560
{
Packit b5e560
  int nfd;
Packit b5e560
Packit b5e560
  /* Sync the stream so we can re-read from the new file descriptor.  We
Packit b5e560
     might be able to avoid this by copying the buffered stream verbatim
Packit b5e560
     to the new file descriptor. */
Packit b5e560
  if (buffers[fd])
Packit b5e560
    sync_buffered_stream (fd);
Packit b5e560
Packit b5e560
  /* Now take care of duplicating the file descriptor that bash is
Packit b5e560
     using for input, so we can reinitialize it later. */
Packit b5e560
  nfd = (new_fd == -1) ? fcntl (fd, F_DUPFD, 10) : new_fd;
Packit b5e560
  if (nfd == -1)
Packit b5e560
    {
Packit b5e560
      if (fcntl (fd, F_GETFD, 0) == 0)
Packit b5e560
	sys_error (_("cannot allocate new file descriptor for bash input from fd %d"), fd);
Packit b5e560
      return -1;
Packit b5e560
    }
Packit b5e560
Packit b5e560
  if (nfd < nbuffers && buffers[nfd])
Packit b5e560
    {
Packit b5e560
      /* What's this?  A stray buffer without an associated open file
Packit b5e560
	 descriptor?  Free up the buffer and report the error. */
Packit b5e560
      internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
Packit b5e560
      free_buffered_stream (buffers[nfd]);
Packit b5e560
    }
Packit b5e560
Packit b5e560
  /* Reinitialize bash_input.location. */
Packit b5e560
  if (bash_input.type == st_bstream)
Packit b5e560
    {
Packit b5e560
      bash_input.location.buffered_fd = nfd;
Packit b5e560
      fd_to_buffered_stream (nfd);
Packit b5e560
      close_buffered_fd (fd);	/* XXX */
Packit b5e560
    }
Packit b5e560
  else
Packit b5e560
    /* If the current input type is not a buffered stream, but the shell
Packit b5e560
       is not interactive and therefore using a buffered stream to read
Packit b5e560
       input (e.g. with an `eval exec 3>output' inside a script), note
Packit b5e560
       that the input fd has been changed.  pop_stream() looks at this
Packit b5e560
       value and adjusts the input fd to the new value of
Packit b5e560
       default_buffered_input accordingly. */
Packit b5e560
    bash_input_fd_changed++;
Packit b5e560
Packit b5e560
  if (default_buffered_input == fd)
Packit b5e560
    default_buffered_input = nfd;
Packit b5e560
Packit b5e560
  SET_CLOSE_ON_EXEC (nfd);
Packit b5e560
  return nfd;
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Check that file descriptor FD is not the one that bash is currently
Packit b5e560
   using to read input from a script.  FD is about to be duplicated onto,
Packit b5e560
   which means that the kernel will close it for us.  If FD is the bash
Packit b5e560
   input file descriptor, we need to seek backwards in the script (if
Packit b5e560
   possible and necessary -- scripts read from stdin are still unbuffered),
Packit b5e560
   allocate a new file descriptor to use for bash input, and re-initialize
Packit b5e560
   the buffered stream.  Make sure the file descriptor used to save bash
Packit b5e560
   input is set close-on-exec. Returns 0 on success, -1 on failure.  This
Packit b5e560
   works only if fd is > 0 -- if fd == 0 and bash is reading input from
Packit b5e560
   fd 0, sync_buffered_stream is used instead, to cooperate with input
Packit b5e560
   redirection (look at redir.c:add_undo_redirect()). */
Packit b5e560
int
Packit b5e560
check_bash_input (fd)
Packit b5e560
     int fd;
Packit b5e560
{
Packit b5e560
  if (fd_is_bash_input (fd))
Packit b5e560
    {
Packit b5e560
      if (fd > 0)
Packit b5e560
	return ((save_bash_input (fd, -1) == -1) ? -1 : 0);
Packit b5e560
      else if (fd == 0)
Packit b5e560
        return ((sync_buffered_stream (fd) == -1) ? -1 : 0);
Packit b5e560
    }
Packit b5e560
  return 0;
Packit b5e560
}
Packit b5e560
      
Packit b5e560
/* This is the buffered stream analogue of dup2(fd1, fd2).  The
Packit b5e560
   BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists.
Packit b5e560
   BUFFERS[fd1] is copied to BUFFERS[fd2].  This is called by the
Packit b5e560
   redirect code for constructs like 4<&0 and 3
Packit b5e560
int
Packit b5e560
duplicate_buffered_stream (fd1, fd2)
Packit b5e560
     int fd1, fd2;
Packit b5e560
{
Packit b5e560
  int is_bash_input, m;
Packit b5e560
Packit b5e560
  if (fd1 == fd2)
Packit b5e560
    return 0;
Packit b5e560
Packit b5e560
  m = max (fd1, fd2);
Packit b5e560
  ALLOCATE_BUFFERS (m);
Packit b5e560
Packit b5e560
  /* If FD2 is the file descriptor bash is currently using for shell input,
Packit b5e560
     we need to do some extra work to make sure that the buffered stream
Packit b5e560
     actually exists (it might not if fd1 was not active, and the copy
Packit b5e560
     didn't actually do anything). */
Packit b5e560
  is_bash_input = (bash_input.type == st_bstream) &&
Packit b5e560
		  (bash_input.location.buffered_fd == fd2);
Packit b5e560
Packit b5e560
  if (buffers[fd2])
Packit b5e560
    {
Packit b5e560
      /* If the two objects share the same b_buffer, don't free it. */
Packit b5e560
      if (buffers[fd1] && buffers[fd1]->b_buffer && buffers[fd1]->b_buffer == buffers[fd2]->b_buffer)
Packit b5e560
	buffers[fd2] = (BUFFERED_STREAM *)NULL;
Packit b5e560
      else
Packit b5e560
	free_buffered_stream (buffers[fd2]);
Packit b5e560
    }
Packit b5e560
  buffers[fd2] = copy_buffered_stream (buffers[fd1]);
Packit b5e560
  if (buffers[fd2])
Packit b5e560
    buffers[fd2]->b_fd = fd2;
Packit b5e560
Packit b5e560
  if (is_bash_input)
Packit b5e560
    {
Packit b5e560
      if (!buffers[fd2])
Packit b5e560
	fd_to_buffered_stream (fd2);
Packit b5e560
      buffers[fd2]->b_flag |= B_WASBASHINPUT;
Packit b5e560
    }
Packit b5e560
Packit b5e560
  return (fd2);
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Return 1 if a seek on FD will succeed. */
Packit b5e560
#define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
Packit b5e560
Packit b5e560
/* Take FD, a file descriptor, and create and return a buffered stream
Packit b5e560
   corresponding to it.  If something is wrong and the file descriptor
Packit b5e560
   is invalid, return a NULL stream. */
Packit b5e560
BUFFERED_STREAM *
Packit b5e560
fd_to_buffered_stream (fd)
Packit b5e560
     int fd;
Packit b5e560
{
Packit b5e560
  char *buffer;
Packit b5e560
  size_t size;
Packit b5e560
  struct stat sb;
Packit b5e560
Packit b5e560
  if (fstat (fd, &sb) < 0)
Packit b5e560
    {
Packit b5e560
      close (fd);
Packit b5e560
      return ((BUFFERED_STREAM *)NULL);
Packit b5e560
    }
Packit b5e560
Packit b5e560
  size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1;
Packit b5e560
  if (size == 0)
Packit b5e560
    size = 1;
Packit b5e560
  buffer = (char *)xmalloc (size);
Packit b5e560
Packit b5e560
  return (make_buffered_stream (fd, buffer, size));
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Return a buffered stream corresponding to FILE, a file name. */
Packit b5e560
BUFFERED_STREAM *
Packit b5e560
open_buffered_stream (file)
Packit b5e560
     char *file;
Packit b5e560
{
Packit b5e560
  int fd;
Packit b5e560
Packit b5e560
  fd = open (file, O_RDONLY);
Packit b5e560
  return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Deallocate a buffered stream and free up its resources.  Make sure we
Packit b5e560
   zero out the slot in BUFFERS that points to BP. */
Packit b5e560
void
Packit b5e560
free_buffered_stream (bp)
Packit b5e560
     BUFFERED_STREAM *bp;
Packit b5e560
{
Packit b5e560
  int n;
Packit b5e560
Packit b5e560
  if (!bp)
Packit b5e560
    return;
Packit b5e560
Packit b5e560
  n = bp->b_fd;
Packit b5e560
  if (bp->b_buffer)
Packit b5e560
    free (bp->b_buffer);
Packit b5e560
  free (bp);
Packit b5e560
  buffers[n] = (BUFFERED_STREAM *)NULL;
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Close the file descriptor associated with BP, a buffered stream, and free
Packit b5e560
   up the stream.  Return the status of closing BP's file descriptor. */
Packit b5e560
int
Packit b5e560
close_buffered_stream (bp)
Packit b5e560
     BUFFERED_STREAM *bp;
Packit b5e560
{
Packit b5e560
  int fd;
Packit b5e560
Packit b5e560
  if (!bp)
Packit b5e560
    return (0);
Packit b5e560
  fd = bp->b_fd;
Packit b5e560
  free_buffered_stream (bp);
Packit b5e560
  return (close (fd));
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Deallocate the buffered stream associated with file descriptor FD, and
Packit b5e560
   close FD.  Return the status of the close on FD. */
Packit b5e560
int
Packit b5e560
close_buffered_fd (fd)
Packit b5e560
     int fd;
Packit b5e560
{
Packit b5e560
  if (fd < 0)
Packit b5e560
    {
Packit b5e560
      errno = EBADF;
Packit b5e560
      return -1;
Packit b5e560
    }
Packit b5e560
  if (fd >= nbuffers || !buffers || !buffers[fd])
Packit b5e560
    return (close (fd));
Packit b5e560
  return (close_buffered_stream (buffers[fd]));
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Make the BUFFERED_STREAM associated with buffers[FD] be BP, and return
Packit b5e560
   the old BUFFERED_STREAM. */
Packit b5e560
BUFFERED_STREAM *
Packit b5e560
set_buffered_stream (fd, bp)
Packit b5e560
     int fd;
Packit b5e560
     BUFFERED_STREAM *bp;
Packit b5e560
{
Packit b5e560
  BUFFERED_STREAM *ret;
Packit b5e560
Packit b5e560
  ret = buffers[fd];
Packit b5e560
  buffers[fd] = bp;
Packit b5e560
  return ret;
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Read a buffer full of characters from BP, a buffered stream. */
Packit b5e560
static int
Packit b5e560
b_fill_buffer (bp)
Packit b5e560
     BUFFERED_STREAM *bp;
Packit b5e560
{
Packit b5e560
  ssize_t nr;
Packit b5e560
  off_t o;
Packit b5e560
Packit b5e560
  CHECK_TERMSIG;
Packit b5e560
  /* In an environment where text and binary files are treated differently,
Packit b5e560
     compensate for lseek() on text files returning an offset different from
Packit b5e560
     the count of characters read() returns.  Text-mode streams have to be
Packit b5e560
     treated as unbuffered. */
Packit b5e560
  if ((bp->b_flag & (B_TEXT | B_UNBUFF)) == B_TEXT)
Packit b5e560
    {
Packit b5e560
      o = lseek (bp->b_fd, 0, SEEK_CUR);
Packit b5e560
      nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
Packit b5e560
      if (nr > 0 && nr < lseek (bp->b_fd, 0, SEEK_CUR) - o)
Packit b5e560
	{
Packit b5e560
	  lseek (bp->b_fd, o, SEEK_SET);
Packit b5e560
	  bp->b_flag |= B_UNBUFF;
Packit b5e560
	  bp->b_size = 1;
Packit b5e560
	  nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
Packit b5e560
	}
Packit b5e560
    }
Packit b5e560
  else
Packit b5e560
    nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
Packit b5e560
  if (nr <= 0)
Packit b5e560
    {
Packit b5e560
      bp->b_used = 0;
Packit b5e560
      bp->b_buffer[0] = 0;
Packit b5e560
      if (nr == 0)
Packit b5e560
	bp->b_flag |= B_EOF;
Packit b5e560
      else
Packit b5e560
	bp->b_flag |= B_ERROR;
Packit b5e560
      return (EOF);
Packit b5e560
    }
Packit b5e560
Packit b5e560
  bp->b_used = nr;
Packit b5e560
  bp->b_inputp = 0;
Packit b5e560
  return (bp->b_buffer[bp->b_inputp++] & 0xFF);
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Get a character from buffered stream BP. */
Packit b5e560
#define bufstream_getc(bp) \
Packit b5e560
  (bp->b_inputp == bp->b_used || !bp->b_used) \
Packit b5e560
  		? b_fill_buffer (bp) \
Packit b5e560
		: bp->b_buffer[bp->b_inputp++] & 0xFF
Packit b5e560
Packit b5e560
/* Push C back onto buffered stream BP. */
Packit b5e560
static int
Packit b5e560
bufstream_ungetc(c, bp)
Packit b5e560
     int c;
Packit b5e560
     BUFFERED_STREAM *bp;
Packit b5e560
{
Packit b5e560
  if (c == EOF || bp->b_inputp == 0)
Packit b5e560
    return (EOF);
Packit b5e560
Packit b5e560
  bp->b_buffer[--bp->b_inputp] = c;
Packit b5e560
  return (c);
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Seek backwards on file BFD to synchronize what we've read so far
Packit b5e560
   with the underlying file pointer. */
Packit b5e560
int
Packit b5e560
sync_buffered_stream (bfd)
Packit b5e560
     int bfd;
Packit b5e560
{
Packit b5e560
  BUFFERED_STREAM *bp;
Packit b5e560
  off_t chars_left;
Packit b5e560
Packit b5e560
  if (buffers == 0 || (bp = buffers[bfd]) == 0)
Packit b5e560
    return (-1);
Packit b5e560
Packit b5e560
  chars_left = bp->b_used - bp->b_inputp;
Packit b5e560
  if (chars_left)
Packit b5e560
    lseek (bp->b_fd, -chars_left, SEEK_CUR);
Packit b5e560
  bp->b_used = bp->b_inputp = 0;
Packit b5e560
  return (0);
Packit b5e560
}
Packit b5e560
Packit b5e560
int
Packit b5e560
buffered_getchar ()
Packit b5e560
{
Packit b5e560
  CHECK_TERMSIG;
Packit b5e560
Packit b5e560
#if !defined (DJGPP)
Packit b5e560
  return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
Packit b5e560
#else
Packit b5e560
  /* On DJGPP, ignore \r. */
Packit b5e560
  int ch;
Packit b5e560
  while ((ch = bufstream_getc (buffers[bash_input.location.buffered_fd])) == '\r')
Packit b5e560
    ;
Packit b5e560
  return ch;
Packit b5e560
#endif
Packit b5e560
}
Packit b5e560
Packit b5e560
int
Packit b5e560
buffered_ungetchar (c)
Packit b5e560
     int c;
Packit b5e560
{
Packit b5e560
  return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
Packit b5e560
}
Packit b5e560
Packit b5e560
/* Make input come from file descriptor BFD through a buffered stream. */
Packit b5e560
void
Packit b5e560
with_input_from_buffered_stream (bfd, name)
Packit b5e560
     int bfd;
Packit b5e560
     char *name;
Packit b5e560
{
Packit b5e560
  INPUT_STREAM location;
Packit b5e560
  BUFFERED_STREAM *bp;
Packit b5e560
Packit b5e560
  location.buffered_fd = bfd;
Packit b5e560
  /* Make sure the buffered stream exists. */
Packit b5e560
  bp = fd_to_buffered_stream (bfd);
Packit b5e560
  init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
Packit b5e560
	      buffered_ungetchar, st_bstream, name, location);
Packit b5e560
}
Packit b5e560
Packit b5e560
#if defined (TEST)
Packit b5e560
void *
Packit b5e560
xmalloc(s)
Packit b5e560
int s;
Packit b5e560
{
Packit b5e560
	return (malloc (s));
Packit b5e560
}
Packit b5e560
Packit b5e560
void *
Packit b5e560
xrealloc(s, size)
Packit b5e560
char	*s;
Packit b5e560
int	size;
Packit b5e560
{
Packit b5e560
	if (!s)
Packit b5e560
		return(malloc (size));
Packit b5e560
	else
Packit b5e560
		return(realloc (s, size));
Packit b5e560
}
Packit b5e560
Packit b5e560
void
Packit b5e560
init_yy_io ()
Packit b5e560
{
Packit b5e560
}
Packit b5e560
Packit b5e560
process(bp)
Packit b5e560
BUFFERED_STREAM *bp;
Packit b5e560
{
Packit b5e560
	int c;
Packit b5e560
Packit b5e560
	while ((c = bufstream_getc(bp)) != EOF)
Packit b5e560
		putchar(c);
Packit b5e560
}
Packit b5e560
Packit b5e560
BASH_INPUT bash_input;
Packit b5e560
Packit b5e560
struct stat dsb;		/* can be used from gdb */
Packit b5e560
Packit b5e560
/* imitate /bin/cat */
Packit b5e560
main(argc, argv)
Packit b5e560
int	argc;
Packit b5e560
char	**argv;
Packit b5e560
{
Packit b5e560
	register int i;
Packit b5e560
	BUFFERED_STREAM *bp;
Packit b5e560
Packit b5e560
	if (argc == 1) {
Packit b5e560
		bp = fd_to_buffered_stream (0);
Packit b5e560
		process(bp);
Packit b5e560
		exit(0);
Packit b5e560
	}
Packit b5e560
	for (i = 1; i < argc; i++) {
Packit b5e560
		if (argv[i][0] == '-' && argv[i][1] == '\0') {
Packit b5e560
			bp = fd_to_buffered_stream (0);
Packit b5e560
			if (!bp)
Packit b5e560
				continue;
Packit b5e560
			process(bp);
Packit b5e560
			free_buffered_stream (bp);
Packit b5e560
		} else {
Packit b5e560
			bp = open_buffered_stream (argv[i]);
Packit b5e560
			if (!bp)
Packit b5e560
				continue;
Packit b5e560
			process(bp);
Packit b5e560
			close_buffered_stream (bp);
Packit b5e560
		}
Packit b5e560
	}
Packit b5e560
	exit(0);
Packit b5e560
}
Packit b5e560
#endif /* TEST */
Packit b5e560
#endif /* BUFFERED_INPUT */