]>
git.ipfire.org Git - thirdparty/bash.git/blob - input.c
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, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
23 #include "bashtypes.h"
25 # include <sys/file.h>
28 #include "posixstat.h"
32 #if defined (HAVE_UNISTD_H)
47 /* Functions to handle reading input on systems that don't restart read(2)
48 if a signal is received. */
50 static unsigned char localbuf
[128];
51 static int local_index
, local_bufused
;
53 /* Posix and USG systems do not guarantee to restart read () if it is
54 interrupted by a signal. We do the read ourselves, and restart it
55 if it returns EINTR. */
57 getc_with_restart (stream
)
60 /* Try local buffering to reduce the number of read(2) calls. */
61 if (local_index
== local_bufused
|| local_bufused
== 0)
65 local_bufused
= read (fileno (stream
), localbuf
, sizeof(localbuf
));
66 if (local_bufused
> 0)
68 else if (local_bufused
== 0 || errno
!= EINTR
)
76 return (localbuf
[local_index
++]);
80 ungetc_with_restart (c
, stream
)
84 if (local_index
== 0 || c
== EOF
)
86 return (localbuf
[--local_index
] = c
);
89 #if defined (BUFFERED_INPUT)
91 /* A facility similar to stdio, but input-only. */
93 #if defined (USING_BASH_MALLOC)
94 # define MAX_INPUT_BUFFER_SIZE 8176
96 # define MAX_INPUT_BUFFER_SIZE 8192
99 #if !defined (SEEK_CUR)
101 #endif /* !SEEK_CUR */
103 extern int return_EOF ();
105 extern int interactive_shell
;
107 int bash_input_fd_changed
;
109 /* This provides a way to map from a file descriptor to the buffer
110 associated with that file descriptor, rather than just the other
111 way around. This is needed so that buffers are managed properly
112 in constructs like 3<&4. buffers[x]->b_fd == x -- that is how the
113 correspondence is maintained. */
114 static BUFFERED_STREAM
**buffers
= (BUFFERED_STREAM
**)NULL
;
117 #define max(a, b) (((a) > (b)) ? (a) : (b))
119 #define ALLOCATE_BUFFERS(n) \
120 do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
122 /* Make sure `buffers' has at least N elements. */
127 register int i
, orig_nbuffers
;
129 orig_nbuffers
= nbuffers
;
131 buffers
= (BUFFERED_STREAM
**)xrealloc
132 (buffers
, nbuffers
* sizeof (BUFFERED_STREAM
*));
134 /* Zero out the new buffers. */
135 for (i
= orig_nbuffers
; i
< nbuffers
; i
++)
136 buffers
[i
] = (BUFFERED_STREAM
*)NULL
;
139 /* Construct and return a BUFFERED_STREAM corresponding to file descriptor
141 static BUFFERED_STREAM
*
142 make_buffered_stream (fd
, buffer
, bufsize
)
149 bp
= (BUFFERED_STREAM
*)xmalloc (sizeof (BUFFERED_STREAM
));
150 ALLOCATE_BUFFERS (fd
);
153 bp
->b_buffer
= buffer
;
154 bp
->b_size
= bufsize
;
155 bp
->b_used
= bp
->b_inputp
= bp
->b_flag
= 0;
157 bp
->b_flag
|= B_UNBUFF
;
161 /* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
162 static BUFFERED_STREAM
*
163 copy_buffered_stream (bp
)
166 BUFFERED_STREAM
*nbp
;
169 return ((BUFFERED_STREAM
*)NULL
);
171 nbp
= (BUFFERED_STREAM
*)xmalloc (sizeof (BUFFERED_STREAM
));
172 xbcopy ((char *)bp
, (char *)nbp
, sizeof (BUFFERED_STREAM
));
176 /* Check that file descriptor FD is not the one that bash is currently
177 using to read input from a script. FD is about to be duplicated onto,
178 which means that the kernel will close it for us. If FD is the bash
179 input file descriptor, we need to seek backwards in the script (if
180 possible and necessary -- scripts read from stdin are still unbuffered),
181 allocate a new file descriptor to use for bash input, and re-initialize
182 the buffered stream. */
184 check_bash_input (fd
)
189 if (fd
> 0 && ((bash_input
.type
== st_bstream
&& bash_input
.location
.buffered_fd
== fd
) ||
190 (interactive_shell
== 0 && default_buffered_input
== fd
)))
192 /* Sync the stream so we can re-read from the new file descriptor. We
193 might be able to avoid this by copying the buffered stream verbatim
194 to the new file descriptor. */
196 sync_buffered_stream (fd
);
198 /* Now take care of duplicating the file descriptor that bash is
199 using for input, so we can reinitialize it later. */
200 nfd
= fcntl (fd
, F_DUPFD
, 10);
203 if (fcntl (fd
, F_GETFD
, 0) == 0)
204 sys_error ("cannot allocate new file descriptor for bash input from fd %d", fd
);
210 /* What's this? A stray buffer without an associated open file
211 descriptor? Free up the buffer and report the error. */
212 internal_error ("check_bash_input: buffer already exists for new fd %d", nfd
);
213 free_buffered_stream (buffers
[nfd
]);
216 /* Reinitialize bash_input.location. */
217 if (bash_input
.type
== st_bstream
)
219 bash_input
.location
.buffered_fd
= nfd
;
220 fd_to_buffered_stream (nfd
);
221 close_buffered_fd (fd
); /* XXX */
224 /* If the current input type is not a buffered stream, but the shell
225 is not interactive and therefore using a buffered stream to read
226 input (e.g. with an `eval exec 3>output' inside a script), note
227 that the input fd has been changed. pop_stream() looks at this
228 value and adjusts the input fd to the new value of
229 default_buffered_input accordingly. */
230 bash_input_fd_changed
++;
232 if (default_buffered_input
== fd
)
233 default_buffered_input
= nfd
;
238 /* This is the buffered stream analogue of dup2(fd1, fd2). The
239 BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists.
240 BUFFERS[fd1] is copied to BUFFERS[fd2]. This is called by the
241 redirect code for constructs like 4<&0 and 3</etc/rc.local. */
243 duplicate_buffered_stream (fd1
, fd2
)
246 int is_bash_input
, m
;
252 ALLOCATE_BUFFERS (m
);
254 /* If FD2 is the file descriptor bash is currently using for shell input,
255 we need to do some extra work to make sure that the buffered stream
256 actually exists (it might not if fd1 was not active, and the copy
257 didn't actually do anything). */
258 is_bash_input
= (bash_input
.type
== st_bstream
) &&
259 (bash_input
.location
.buffered_fd
== fd2
);
262 free_buffered_stream (buffers
[fd2
]);
263 buffers
[fd2
] = copy_buffered_stream (buffers
[fd1
]);
265 buffers
[fd2
]->b_fd
= fd2
;
267 if (is_bash_input
&& !buffers
[fd2
])
268 fd_to_buffered_stream (fd2
);
273 /* Return 1 if a seek on FD will succeed. */
275 # define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
277 # define fd_is_seekable(fd) 0
278 #endif /* __CYGWIN32__ */
280 /* Take FD, a file descriptor, and create and return a buffered stream
281 corresponding to it. If something is wrong and the file descriptor
282 is invalid, return a NULL stream. */
284 fd_to_buffered_stream (fd
)
291 if (fstat (fd
, &sb
) < 0)
294 return ((BUFFERED_STREAM
*)NULL
);
297 if (fd_is_seekable (fd
) == 0)
300 size
= (size_t)((sb
.st_size
> MAX_INPUT_BUFFER_SIZE
)
301 ? MAX_INPUT_BUFFER_SIZE
304 buffer
= (char *)xmalloc (size
);
306 return (make_buffered_stream (fd
, buffer
, size
));
309 /* Return a buffered stream corresponding to FILE, a file name. */
311 open_buffered_stream (file
)
316 fd
= open (file
, O_RDONLY
);
317 return ((fd
>= 0) ? fd_to_buffered_stream (fd
) : (BUFFERED_STREAM
*)NULL
);
320 /* Deallocate a buffered stream and free up its resources. Make sure we
321 zero out the slot in BUFFERS that points to BP. */
323 free_buffered_stream (bp
)
335 buffers
[n
] = (BUFFERED_STREAM
*)NULL
;
338 /* Close the file descriptor associated with BP, a buffered stream, and free
339 up the stream. Return the status of closing BP's file descriptor. */
341 close_buffered_stream (bp
)
349 free_buffered_stream (bp
);
353 /* Deallocate the buffered stream associated with file descriptor FD, and
354 close FD. Return the status of the close on FD. */
356 close_buffered_fd (fd
)
359 if (fd
>= nbuffers
|| !buffers
|| !buffers
[fd
])
361 return (close_buffered_stream (buffers
[fd
]));
364 /* Make the BUFFERED_STREAM associcated with buffers[FD] be BP, and return
365 the old BUFFERED_STREAM. */
367 set_buffered_stream (fd
, bp
)
371 BUFFERED_STREAM
*ret
;
378 /* Read a buffer full of characters from BP, a buffered stream. */
383 bp
->b_used
= zread (bp
->b_fd
, bp
->b_buffer
, bp
->b_size
);
390 bp
->b_flag
|= B_ERROR
;
394 return (bp
->b_buffer
[bp
->b_inputp
++] & 0xFF);
397 /* Get a character from buffered stream BP. */
398 #define bufstream_getc(bp) \
399 (bp->b_inputp == bp->b_used || !bp->b_used) \
400 ? b_fill_buffer (bp) \
401 : bp->b_buffer[bp->b_inputp++] & 0xFF
403 /* Push C back onto buffered stream BP. */
405 bufstream_ungetc(c
, bp
)
409 if (c
== EOF
|| bp
->b_inputp
== 0)
412 bp
->b_buffer
[--bp
->b_inputp
] = c
;
416 /* Seek backwards on file BFD to synchronize what we've read so far
417 with the underlying file pointer. */
419 sync_buffered_stream (bfd
)
428 chars_left
= bp
->b_used
- bp
->b_inputp
;
430 lseek (bp
->b_fd
, -chars_left
, SEEK_CUR
);
431 bp
->b_used
= bp
->b_inputp
= 0;
438 return (bufstream_getc (buffers
[bash_input
.location
.buffered_fd
]));
442 buffered_ungetchar (c
)
445 return (bufstream_ungetc (c
, buffers
[bash_input
.location
.buffered_fd
]));
448 /* Make input come from file descriptor BFD through a buffered stream. */
450 with_input_from_buffered_stream (bfd
, name
)
454 INPUT_STREAM location
;
457 location
.buffered_fd
= bfd
;
458 /* Make sure the buffered stream exists. */
459 bp
= fd_to_buffered_stream (bfd
);
460 init_yy_io (bp
== 0 ? return_EOF
: buffered_getchar
,
461 buffered_ungetchar
, st_bstream
, name
, location
);
469 return ((char *)malloc (s
));
478 return((char *)malloc (size
));
480 return((char *)realloc (s
, size
));
493 while ((c
= bufstream_getc(bp
)) != EOF
)
497 BASH_INPUT bash_input
;
499 struct stat dsb
; /* can be used from gdb */
501 /* imitate /bin/cat */
510 bp
= fd_to_buffered_stream (0);
514 for (i
= 1; i
< argc
; i
++) {
515 if (argv
[i
][0] == '-' && argv
[i
][1] == '\0') {
516 bp
= fd_to_buffered_stream (0);
520 free_buffered_stream (bp
);
522 bp
= open_buffered_stream (argv
[i
]);
526 close_buffered_stream (bp
);
532 #endif /* BUFFERED_INPUT */