source: trunk/third/bash/input.c @ 21276

Revision 21276, 14.5 KB checked in by zacheiss, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21275, which included commits to RCS files with non-trunk default branches.
Line 
1/* input.c -- functions to perform buffered input with synchronization. */
2
3/* Copyright (C) 1992 Free Software Foundation, Inc.
4
5   This file is part of GNU Bash, the Bourne Again SHell.
6
7   Bash is free software; you can redistribute it and/or modify it under
8   the terms of the GNU General Public License as published by the Free
9   Software Foundation; either version 2, or (at your option) any later
10   version.
11
12   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or
14   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15   for more details.
16
17   You should have received a copy of the GNU General Public License along
18   with Bash; see the file COPYING.  If not, write to the Free Software
19   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
20
21#include "config.h"
22
23#include "bashtypes.h"
24#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
25#  include <sys/file.h>
26#endif
27#include "filecntl.h"
28#include "posixstat.h"
29#include <stdio.h>
30#include <errno.h>
31
32#if defined (HAVE_UNISTD_H)
33#  include <unistd.h>
34#endif
35
36#include "bashansi.h"
37#include "bashintl.h"
38
39#include "command.h"
40#include "general.h"
41#include "input.h"
42#include "error.h"
43#include "externs.h"
44
45#if !defined (errno)
46extern int errno;
47#endif /* !errno */
48
49/* Functions to handle reading input on systems that don't restart read(2)
50   if a signal is received. */
51
52static char localbuf[128];
53static int local_index, local_bufused;
54
55/* Posix and USG systems do not guarantee to restart read () if it is
56   interrupted by a signal.  We do the read ourselves, and restart it
57   if it returns EINTR. */
58int
59getc_with_restart (stream)
60     FILE *stream;
61{
62  unsigned char uc;
63
64  /* Try local buffering to reduce the number of read(2) calls. */
65  if (local_index == local_bufused || local_bufused == 0)
66    {
67      while (1)
68        {
69          local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
70          if (local_bufused > 0)
71            break;
72          else if (local_bufused == 0 || errno != EINTR)
73            {
74              local_index = 0;
75              return EOF;
76            }
77        }
78      local_index = 0;
79    }
80  uc = localbuf[local_index++];
81  return uc;
82}
83
84int
85ungetc_with_restart (c, stream)
86     int c;
87     FILE *stream;
88{
89  if (local_index == 0 || c == EOF)
90    return EOF;
91  localbuf[--local_index] = c;
92  return c;
93}
94
95#if defined (BUFFERED_INPUT)
96
97/* A facility similar to stdio, but input-only. */
98
99#if defined (USING_BASH_MALLOC)
100#  define MAX_INPUT_BUFFER_SIZE 8176
101#else
102#  define MAX_INPUT_BUFFER_SIZE 8192
103#endif
104
105#if !defined (SEEK_CUR)
106#  define SEEK_CUR 1
107#endif /* !SEEK_CUR */
108
109#ifdef max
110#  undef max
111#endif
112#define max(a, b)       (((a) > (b)) ? (a) : (b))
113#ifdef min
114#  undef min
115#endif
116#define min(a, b)       ((a) > (b) ? (b) : (a))
117
118extern int interactive_shell;
119
120int bash_input_fd_changed;
121
122/* This provides a way to map from a file descriptor to the buffer
123   associated with that file descriptor, rather than just the other
124   way around.  This is needed so that buffers are managed properly
125   in constructs like 3<&4.  buffers[x]->b_fd == x -- that is how the
126   correspondence is maintained. */
127static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
128static int nbuffers;
129
130#define ALLOCATE_BUFFERS(n) \
131        do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
132
133/* Make sure `buffers' has at least N elements. */
134static void
135allocate_buffers (n)
136     int n;
137{
138  register int i, orig_nbuffers;
139
140  orig_nbuffers = nbuffers;
141  nbuffers = n + 20;
142  buffers = (BUFFERED_STREAM **)xrealloc
143    (buffers, nbuffers * sizeof (BUFFERED_STREAM *));
144
145  /* Zero out the new buffers. */
146  for (i = orig_nbuffers; i < nbuffers; i++)
147    buffers[i] = (BUFFERED_STREAM *)NULL;
148}
149
150/* Construct and return a BUFFERED_STREAM corresponding to file descriptor
151   FD, using BUFFER. */
152static BUFFERED_STREAM *
153make_buffered_stream (fd, buffer, bufsize)
154     int fd;
155     char *buffer;
156     size_t bufsize;
157{
158  BUFFERED_STREAM *bp;
159
160  bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
161  ALLOCATE_BUFFERS (fd);
162  buffers[fd] = bp;
163  bp->b_fd = fd;
164  bp->b_buffer = buffer;
165  bp->b_size = bufsize;
166  bp->b_used = bp->b_inputp = bp->b_flag = 0;
167  if (bufsize == 1)
168    bp->b_flag |= B_UNBUFF;
169  return (bp);
170}
171
172/* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
173static BUFFERED_STREAM *
174copy_buffered_stream (bp)
175     BUFFERED_STREAM *bp;
176{
177  BUFFERED_STREAM *nbp;
178
179  if (!bp)
180    return ((BUFFERED_STREAM *)NULL);
181
182  nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
183  xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM));
184  return (nbp);
185}
186
187int
188set_bash_input_fd (fd)
189     int fd;
190{
191  if (bash_input.type == st_bstream)
192    bash_input.location.buffered_fd = fd;
193  else if (interactive_shell == 0)
194    default_buffered_input = fd;
195  return 0;
196}
197
198int
199fd_is_bash_input (fd)
200     int fd;
201{
202  if (bash_input.type == st_bstream && bash_input.location.buffered_fd == fd)
203    return 1;
204  else if (interactive_shell == 0 && default_buffered_input == fd)
205    return 1;
206  return 0;
207}
208
209/* Save the buffered stream corresponding to file descriptor FD (which bash
210   is using to read input) to a buffered stream associated with NEW_FD.  If
211   NEW_FD is -1, a new file descriptor is allocated with fcntl.  The new
212   file descriptor is returned on success, -1 on error. */
213int
214save_bash_input (fd, new_fd)
215     int fd, new_fd;
216{
217  int nfd;
218
219  /* Sync the stream so we can re-read from the new file descriptor.  We
220     might be able to avoid this by copying the buffered stream verbatim
221     to the new file descriptor. */
222  if (buffers[fd])
223    sync_buffered_stream (fd);
224
225  /* Now take care of duplicating the file descriptor that bash is
226     using for input, so we can reinitialize it later. */
227  nfd = (new_fd == -1) ? fcntl (fd, F_DUPFD, 10) : new_fd;
228  if (nfd == -1)
229    {
230      if (fcntl (fd, F_GETFD, 0) == 0)
231        sys_error (_("cannot allocate new file descriptor for bash input from fd %d"), fd);
232      return -1;
233    }
234
235  if (buffers[nfd])
236    {
237      /* What's this?  A stray buffer without an associated open file
238         descriptor?  Free up the buffer and report the error. */
239      internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
240      free_buffered_stream (buffers[nfd]);
241    }
242
243  /* Reinitialize bash_input.location. */
244  if (bash_input.type == st_bstream)
245    {
246      bash_input.location.buffered_fd = nfd;
247      fd_to_buffered_stream (nfd);
248      close_buffered_fd (fd);   /* XXX */
249    }
250  else
251    /* If the current input type is not a buffered stream, but the shell
252       is not interactive and therefore using a buffered stream to read
253       input (e.g. with an `eval exec 3>output' inside a script), note
254       that the input fd has been changed.  pop_stream() looks at this
255       value and adjusts the input fd to the new value of
256       default_buffered_input accordingly. */
257    bash_input_fd_changed++;
258
259  if (default_buffered_input == fd)
260    default_buffered_input = nfd;
261
262  SET_CLOSE_ON_EXEC (nfd);
263  return nfd;
264}
265
266/* Check that file descriptor FD is not the one that bash is currently
267   using to read input from a script.  FD is about to be duplicated onto,
268   which means that the kernel will close it for us.  If FD is the bash
269   input file descriptor, we need to seek backwards in the script (if
270   possible and necessary -- scripts read from stdin are still unbuffered),
271   allocate a new file descriptor to use for bash input, and re-initialize
272   the buffered stream.  Make sure the file descriptor used to save bash
273   input is set close-on-exec. Returns 0 on success, -1 on failure.  This
274   works only if fd is > 0 -- if fd == 0 and bash is reading input from
275   fd 0, save_bash_input is used instead, to cooperate with input
276   redirection (look at redir.c:add_undo_redirect()). */
277int
278check_bash_input (fd)
279     int fd;
280{
281  if (fd_is_bash_input (fd))
282    {
283      if (fd > 0)
284        return ((save_bash_input (fd, -1) == -1) ? -1 : 0);
285      else if (fd == 0)
286        return ((sync_buffered_stream (fd) == -1) ? -1 : 0);
287    }
288  return 0;
289}
290     
291/* This is the buffered stream analogue of dup2(fd1, fd2).  The
292   BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists.
293   BUFFERS[fd1] is copied to BUFFERS[fd2].  This is called by the
294   redirect code for constructs like 4<&0 and 3</etc/rc.local. */
295int
296duplicate_buffered_stream (fd1, fd2)
297     int fd1, fd2;
298{
299  int is_bash_input, m;
300
301  if (fd1 == fd2)
302    return 0;
303
304  m = max (fd1, fd2);
305  ALLOCATE_BUFFERS (m);
306
307  /* If FD2 is the file descriptor bash is currently using for shell input,
308     we need to do some extra work to make sure that the buffered stream
309     actually exists (it might not if fd1 was not active, and the copy
310     didn't actually do anything). */
311  is_bash_input = (bash_input.type == st_bstream) &&
312                  (bash_input.location.buffered_fd == fd2);
313
314  if (buffers[fd2])
315    free_buffered_stream (buffers[fd2]);
316  buffers[fd2] = copy_buffered_stream (buffers[fd1]);
317  if (buffers[fd2])
318    buffers[fd2]->b_fd = fd2;
319
320  if (is_bash_input)
321    {
322      if (!buffers[fd2])
323        fd_to_buffered_stream (fd2);
324      buffers[fd2]->b_flag |= B_WASBASHINPUT;
325    }
326
327  return (fd2);
328}
329
330/* Return 1 if a seek on FD will succeed. */
331#ifndef __CYGWIN__
332#  define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
333#else
334#  define fd_is_seekable(fd) 0
335#endif /* __CYGWIN__ */
336
337/* Take FD, a file descriptor, and create and return a buffered stream
338   corresponding to it.  If something is wrong and the file descriptor
339   is invalid, return a NULL stream. */
340BUFFERED_STREAM *
341fd_to_buffered_stream (fd)
342     int fd;
343{
344  char *buffer;
345  size_t size;
346  struct stat sb;
347
348  if (fstat (fd, &sb) < 0)
349    {
350      close (fd);
351      return ((BUFFERED_STREAM *)NULL);
352    }
353
354  size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1;
355  if (size == 0)
356    size = 1;
357  buffer = (char *)xmalloc (size);
358
359  return (make_buffered_stream (fd, buffer, size));
360}
361
362/* Return a buffered stream corresponding to FILE, a file name. */
363BUFFERED_STREAM *
364open_buffered_stream (file)
365     char *file;
366{
367  int fd;
368
369  fd = open (file, O_RDONLY);
370  return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
371}
372
373/* Deallocate a buffered stream and free up its resources.  Make sure we
374   zero out the slot in BUFFERS that points to BP. */
375void
376free_buffered_stream (bp)
377     BUFFERED_STREAM *bp;
378{
379  int n;
380
381  if (!bp)
382    return;
383
384  n = bp->b_fd;
385  if (bp->b_buffer)
386    free (bp->b_buffer);
387  free (bp);
388  buffers[n] = (BUFFERED_STREAM *)NULL;
389}
390
391/* Close the file descriptor associated with BP, a buffered stream, and free
392   up the stream.  Return the status of closing BP's file descriptor. */
393int
394close_buffered_stream (bp)
395     BUFFERED_STREAM *bp;
396{
397  int fd;
398
399  if (!bp)
400    return (0);
401  fd = bp->b_fd;
402  free_buffered_stream (bp);
403  return (close (fd));
404}
405
406/* Deallocate the buffered stream associated with file descriptor FD, and
407   close FD.  Return the status of the close on FD. */
408int
409close_buffered_fd (fd)
410     int fd;
411{
412  if (fd < 0)
413    {
414      errno = EBADF;
415      return -1;
416    }
417  if (fd >= nbuffers || !buffers || !buffers[fd])
418    return (close (fd));
419  return (close_buffered_stream (buffers[fd]));
420}
421
422/* Make the BUFFERED_STREAM associcated with buffers[FD] be BP, and return
423   the old BUFFERED_STREAM. */
424BUFFERED_STREAM *
425set_buffered_stream (fd, bp)
426     int fd;
427     BUFFERED_STREAM *bp;
428{
429  BUFFERED_STREAM *ret;
430
431  ret = buffers[fd];
432  buffers[fd] = bp;
433  return ret;
434}
435
436/* Read a buffer full of characters from BP, a buffered stream. */
437static int
438b_fill_buffer (bp)
439     BUFFERED_STREAM *bp;
440{
441  ssize_t nr;
442
443  nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
444  if (nr <= 0)
445    {
446      bp->b_used = 0;
447      bp->b_buffer[0] = 0;
448      if (nr == 0)
449        bp->b_flag |= B_EOF;
450      else
451        bp->b_flag |= B_ERROR;
452      return (EOF);
453    }
454
455#if defined (__CYGWIN__)
456  /* If on cygwin, translate \r\n to \n. */
457  if (nr >= 2 && bp->b_buffer[nr - 2] == '\r' && bp->b_buffer[nr - 1] == '\n')
458    {
459      bp->b_buffer[nr - 2] = '\n';
460      nr--;
461    }
462#endif
463
464  bp->b_used = nr;
465  bp->b_inputp = 0;
466  return (bp->b_buffer[bp->b_inputp++] & 0xFF);
467}
468
469/* Get a character from buffered stream BP. */
470#define bufstream_getc(bp) \
471  (bp->b_inputp == bp->b_used || !bp->b_used) \
472                ? b_fill_buffer (bp) \
473                : bp->b_buffer[bp->b_inputp++] & 0xFF
474
475/* Push C back onto buffered stream BP. */
476static int
477bufstream_ungetc(c, bp)
478     int c;
479     BUFFERED_STREAM *bp;
480{
481  if (c == EOF || bp->b_inputp == 0)
482    return (EOF);
483
484  bp->b_buffer[--bp->b_inputp] = c;
485  return (c);
486}
487
488/* Seek backwards on file BFD to synchronize what we've read so far
489   with the underlying file pointer. */
490int
491sync_buffered_stream (bfd)
492     int bfd;
493{
494  BUFFERED_STREAM *bp;
495  off_t chars_left;
496
497  if (buffers == 0 || (bp = buffers[bfd]) == 0)
498    return (-1);
499
500  chars_left = bp->b_used - bp->b_inputp;
501  if (chars_left)
502    lseek (bp->b_fd, -chars_left, SEEK_CUR);
503  bp->b_used = bp->b_inputp = 0;
504  return (0);
505}
506
507int
508buffered_getchar ()
509{
510#if !defined (DJGPP)
511  return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
512#else
513  /* On DJGPP, ignore \r. */
514  int ch;
515  while ((ch = bufstream_getc (buffers[bash_input.location.buffered_fd])) == '\r')
516    ;
517  return ch;
518#endif
519}
520
521int
522buffered_ungetchar (c)
523     int c;
524{
525  return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
526}
527
528/* Make input come from file descriptor BFD through a buffered stream. */
529void
530with_input_from_buffered_stream (bfd, name)
531     int bfd;
532     char *name;
533{
534  INPUT_STREAM location;
535  BUFFERED_STREAM *bp;
536
537  location.buffered_fd = bfd;
538  /* Make sure the buffered stream exists. */
539  bp = fd_to_buffered_stream (bfd);
540  init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
541              buffered_ungetchar, st_bstream, name, location);
542}
543
544#if defined (TEST)
545void *
546xmalloc(s)
547int s;
548{
549        return (malloc (s));
550}
551
552void *
553xrealloc(s, size)
554char    *s;
555int     size;
556{
557        if (!s)
558                return(malloc (size));
559        else
560                return(realloc (s, size));
561}
562
563void
564init_yy_io ()
565{
566}
567
568process(bp)
569BUFFERED_STREAM *bp;
570{
571        int c;
572
573        while ((c = bufstream_getc(bp)) != EOF)
574                putchar(c);
575}
576
577BASH_INPUT bash_input;
578
579struct stat dsb;                /* can be used from gdb */
580
581/* imitate /bin/cat */
582main(argc, argv)
583int     argc;
584char    **argv;
585{
586        register int i;
587        BUFFERED_STREAM *bp;
588
589        if (argc == 1) {
590                bp = fd_to_buffered_stream (0);
591                process(bp);
592                exit(0);
593        }
594        for (i = 1; i < argc; i++) {
595                if (argv[i][0] == '-' && argv[i][1] == '\0') {
596                        bp = fd_to_buffered_stream (0);
597                        if (!bp)
598                                continue;
599                        process(bp);
600                        free_buffered_stream (bp);
601                } else {
602                        bp = open_buffered_stream (argv[i]);
603                        if (!bp)
604                                continue;
605                        process(bp);
606                        close_buffered_stream (bp);
607                }
608        }
609        exit(0);
610}
611#endif /* TEST */
612#endif /* BUFFERED_INPUT */
Note: See TracBrowser for help on using the repository browser.