1 /* input.c -- functions to perform buffered input with synchronization. */
3 /* Copyright (C) 1992 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
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
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
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 /* similar to stdio, but input-only. */
23 #include "bashtypes.h"
26 #include "posixstat.h"
40 #define MAX_INPUT_BUFFER_SIZE 8192
42 #if !defined (SEEK_CUR)
44 #endif /* !SEEK_CUR */
46 void free_buffered_stream ();
48 extern int interactive_shell;
50 int bash_input_fd_changed;
51 /* This provides a way to map from a file descriptor to the buffer
52 associated with that file descriptor, rather than just the other
53 way around. This is needed so that buffers are managed properly
54 in constructs like 3<&4. buffers[x]->b_fd == x -- that is how the
55 correspondence is maintained. */
56 BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
57 static int nbuffers = 0;
59 #define max(a, b) (((a) > (b)) ? (a) : (b))
61 #define ALLOCATE_BUFFERS(n) \
62 do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
64 /* Make sure `buffers' has at least N elements. */
69 register int i, orig_nbuffers;
71 orig_nbuffers = nbuffers;
73 buffers = (BUFFERED_STREAM **)xrealloc
74 (buffers, nbuffers * sizeof (BUFFERED_STREAM *));
76 /* Zero out the new buffers. */
77 for (i = orig_nbuffers; i < nbuffers; i++)
78 buffers[i] = (BUFFERED_STREAM *)NULL;
81 /* Construct and return a BUFFERED_STREAM corresponding to file descriptor
83 static BUFFERED_STREAM *
84 make_buffered_stream (fd, buffer, bufsize)
91 bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
92 ALLOCATE_BUFFERS (fd);
95 bp->b_buffer = buffer;
101 bp->b_flag |= B_UNBUFF;
105 /* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
106 static BUFFERED_STREAM *
107 copy_buffered_stream (bp)
110 BUFFERED_STREAM *nbp;
113 return ((BUFFERED_STREAM *)NULL);
115 nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
116 xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM));
120 /* Check that file descriptor FD is not the one that bash is currently
121 using to read input from a script. FD is about to be duplicated onto,
122 which means that the kernel will close it for us. If FD is the bash
123 input file descriptor, we need to seek backwards in the script (if
124 possible and necessary -- scripts read from stdin are still unbuffered),
125 allocate a new file descriptor to use for bash input, and re-initialize
126 the buffered stream. */
128 check_bash_input (fd)
133 if (fd > 0 && ((bash_input.type == st_bstream && bash_input.location.buffered_fd == fd) ||
134 (interactive_shell == 0 && default_buffered_input == fd)))
136 /* Sync the stream so we can re-read from the new file descriptor. We
137 might be able to avoid this by copying the buffered stream verbatim
138 to the new file descriptor. */
140 sync_buffered_stream (fd);
142 /* Now take care of duplicating the file descriptor that bash is
143 using for input, so we can reinitialize it later. */
144 nfd = fcntl (fd, F_DUPFD, 10);
147 if (fcntl (fd, F_GETFD, 0) == 0)
149 ("cannot allocate new file descriptor for bash input from fd %d: %s",
150 fd, strerror (errno));
156 /* What's this? A stray buffer without an associated open file
157 descriptor? Free up the buffer and report the error. */
158 report_error ("check_bash_input: buffer already exists for new fd %d", nfd);
159 free_buffered_stream (buffers[nfd]);
162 /* Reinitialize bash_input.location. */
163 if (bash_input.type == st_bstream)
165 bash_input.location.buffered_fd = nfd;
166 fd_to_buffered_stream (nfd);
167 close_buffered_fd (fd); /* XXX */
170 /* If the current input type is not a buffered stream, but the shell
171 is not interactive and therefore using a buffered stream to read
172 input (e.g. with an `eval exec 3>output' inside a script), note
173 that the input fd has been changed. pop_stream() looks at this
174 value and adjusts the input fd to the new value of
175 default_buffered_input accordingly. */
176 bash_input_fd_changed++;
178 if (default_buffered_input == fd)
179 default_buffered_input = nfd;
184 /* This is the buffered stream analogue of dup2(fd1, fd2). The
185 BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists.
186 BUFFERS[fd1] is copied to BUFFERS[fd2]. This is called by the
187 redirect code for constructs like 4<&0 and 3</etc/rc.local. */
188 duplicate_buffered_stream (fd1, fd2)
191 int is_bash_input, m;
197 ALLOCATE_BUFFERS (m);
199 /* If FD2 is the file descriptor bash is currently using for shell input,
200 we need to do some extra work to make sure that the buffered stream
201 actually exists (it might not if fd1 was not active, and the copy
202 didn't actually do anything). */
203 is_bash_input = (bash_input.type == st_bstream) &&
204 (bash_input.location.buffered_fd == fd2);
207 free_buffered_stream (buffers[fd2]);
208 buffers[fd2] = copy_buffered_stream (buffers[fd1]);
210 buffers[fd2]->b_fd = fd2;
215 fd_to_buffered_stream (fd2);
220 /* Return 1 if a seek on FD will succeed. */
221 #define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
223 /* Take FD, a file descriptor, and create and return a buffered stream
224 corresponding to it. If something is wrong and the file descriptor
225 is invalid, return a NULL stream. */
227 fd_to_buffered_stream (fd)
234 if (fstat (fd, &sb) < 0)
237 return ((BUFFERED_STREAM *)NULL);
240 if (fd_is_seekable (fd) == 0)
243 size = (sb.st_size > MAX_INPUT_BUFFER_SIZE) ? MAX_INPUT_BUFFER_SIZE
246 buffer = (char *)xmalloc (size);
248 return (make_buffered_stream (fd, buffer, size));
251 /* Return a buffered stream corresponding to FILE, a file name. */
253 open_buffered_stream (file)
258 fd = open (file, O_RDONLY);
260 return ((BUFFERED_STREAM *)NULL);
261 return (fd_to_buffered_stream (fd));
264 /* Deallocate a buffered stream and free up its resources. Make sure we
265 zero out the slot in BUFFERS that points to BP. */
267 free_buffered_stream (bp)
279 buffers[n] = (BUFFERED_STREAM *)NULL;
282 /* Close the file descriptor associated with BP, a buffered stream, and free
283 up the stream. Return the status of closing BP's file descriptor. */
285 close_buffered_stream (bp)
293 free_buffered_stream (bp);
297 /* Deallocate the buffered stream associated with file descriptor FD, and
298 close FD. Return the status of the close on FD. */
300 close_buffered_fd (fd)
303 if (fd >= nbuffers || !buffers || !buffers[fd])
305 return (close_buffered_stream (buffers[fd]));
308 /* Read a buffer full of characters from BP, a buffered stream. */
315 bp->b_used = read (bp->b_fd, bp->b_buffer, bp->b_size);
317 while (bp->b_used < 0 && errno == EINTR);
324 bp->b_flag |= B_ERROR;
328 return (bp->b_buffer[bp->b_inputp++] & 0xFF);
331 /* Get a character from buffered stream BP. */
332 #define bufstream_getc(bp) \
333 (bp->b_inputp == bp->b_used || !bp->b_used) \
334 ? b_fill_buffer (bp) \
335 : bp->b_buffer[bp->b_inputp++] & 0xFF
337 /* Push C back onto buffered stream BP. */
339 bufstream_ungetc(c, bp)
343 if (c == EOF || bp->b_inputp == 0)
346 bp->b_buffer[--bp->b_inputp] = c;
350 /* Seek backwards on file BFD to synchronize what we've read so far
351 with the underlying file pointer. */
353 sync_buffered_stream (bfd)
362 chars_left = bp->b_used - bp->b_inputp;
364 lseek (bp->b_fd, -chars_left, SEEK_CUR);
365 bp->b_used = bp->b_inputp = 0;
372 return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
376 buffered_ungetchar (c)
379 return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
382 /* Make input come from file descriptor BFD through a buffered stream. */
384 with_input_from_buffered_stream (bfd, name)
388 INPUT_STREAM location;
390 location.buffered_fd = bfd;
391 /* Make sure the buffered stream exists. */
392 fd_to_buffered_stream (bfd);
393 init_yy_io (buffered_getchar, buffered_ungetchar, st_bstream, name, location);
402 return ((char *)malloc (s));
411 return((char *)malloc (size));
413 return((char *)realloc (s, size));
426 while ((c = bufstream_getc(bp)) != EOF)
430 BASH_INPUT bash_input;
432 struct stat dsb; /* can be used from gdb */
434 /* imitate /bin/cat */
443 bp = fd_to_buffered_stream (0);
447 for (i = 1; i < argc; i++) {
448 if (argv[i][0] == '-' && argv[i][1] == '\0') {
449 bp = fd_to_buffered_stream (0);
453 free_buffered_stream (bp);
455 bp = open_buffered_stream (argv[i]);
459 close_buffered_stream (bp);