]> git.ipfire.org Git - thirdparty/bash.git/blob - input.c
6ca49a80b6cee7e6bc008e658ecbe452e0e8be43
[thirdparty/bash.git] / input.c
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #include "config.h"
22
23 #include "bashtypes.h"
24 #ifndef _MINIX
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 "command.h"
38 #include "general.h"
39 #include "input.h"
40 #include "error.h"
41 #include "externs.h"
42
43 #if !defined (errno)
44 extern int errno;
45 #endif /* !errno */
46
47 /* Functions to handle reading input on systems that don't restart read(2)
48 if a signal is received. */
49
50 #if !defined (HAVE_RESTARTABLE_SYSCALLS)
51 static unsigned char localbuf[128];
52 static int local_index, local_bufused;
53
54 /* Posix and USG systems do not guarantee to restart read () if it is
55 interrupted by a signal. We do the read ourselves, and restart it
56 if it returns EINTR. */
57 int
58 getc_with_restart (stream)
59 FILE *stream;
60 {
61 /* Try local buffering to reduce the number of read(2) calls. */
62 if (local_index == local_bufused || local_bufused == 0)
63 {
64 while (1)
65 {
66 local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
67 if (local_bufused > 0)
68 break;
69 else if (local_bufused == 0 || errno != EINTR)
70 {
71 local_index = 0;
72 return EOF;
73 }
74 }
75 local_index = 0;
76 }
77 return (localbuf[local_index++]);
78 }
79
80 int
81 ungetc_with_restart (c, stream)
82 int c;
83 FILE *stream;
84 {
85 if (local_index == 0 || c == EOF)
86 return EOF;
87 return (localbuf[--local_index] = c);
88 }
89 #endif /* !HAVE_RESTARTABLE_SYSCALLS */
90
91 #if defined (BUFFERED_INPUT)
92
93 /* A facility similar to stdio, but input-only. */
94
95 #define MAX_INPUT_BUFFER_SIZE 8192
96
97 #if !defined (SEEK_CUR)
98 # define SEEK_CUR 1
99 #endif /* !SEEK_CUR */
100
101 extern int return_EOF ();
102
103 extern int interactive_shell;
104
105 int bash_input_fd_changed;
106
107 /* This provides a way to map from a file descriptor to the buffer
108 associated with that file descriptor, rather than just the other
109 way around. This is needed so that buffers are managed properly
110 in constructs like 3<&4. buffers[x]->b_fd == x -- that is how the
111 correspondence is maintained. */
112 static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
113 static int nbuffers;
114
115 #define max(a, b) (((a) > (b)) ? (a) : (b))
116
117 #define ALLOCATE_BUFFERS(n) \
118 do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
119
120 /* Make sure `buffers' has at least N elements. */
121 static void
122 allocate_buffers (n)
123 int n;
124 {
125 register int i, orig_nbuffers;
126
127 orig_nbuffers = nbuffers;
128 nbuffers = n + 20;
129 buffers = (BUFFERED_STREAM **)xrealloc
130 (buffers, nbuffers * sizeof (BUFFERED_STREAM *));
131
132 /* Zero out the new buffers. */
133 for (i = orig_nbuffers; i < nbuffers; i++)
134 buffers[i] = (BUFFERED_STREAM *)NULL;
135 }
136
137 /* Construct and return a BUFFERED_STREAM corresponding to file descriptor
138 FD, using BUFFER. */
139 static BUFFERED_STREAM *
140 make_buffered_stream (fd, buffer, bufsize)
141 int fd;
142 char *buffer;
143 size_t bufsize;
144 {
145 BUFFERED_STREAM *bp;
146
147 bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
148 ALLOCATE_BUFFERS (fd);
149 buffers[fd] = bp;
150 bp->b_fd = fd;
151 bp->b_buffer = buffer;
152 bp->b_size = bufsize;
153 bp->b_used = bp->b_inputp = bp->b_flag = 0;
154 if (bufsize == 1)
155 bp->b_flag |= B_UNBUFF;
156 return (bp);
157 }
158
159 /* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
160 static BUFFERED_STREAM *
161 copy_buffered_stream (bp)
162 BUFFERED_STREAM *bp;
163 {
164 BUFFERED_STREAM *nbp;
165
166 if (!bp)
167 return ((BUFFERED_STREAM *)NULL);
168
169 nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
170 xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM));
171 return (nbp);
172 }
173
174 /* Check that file descriptor FD is not the one that bash is currently
175 using to read input from a script. FD is about to be duplicated onto,
176 which means that the kernel will close it for us. If FD is the bash
177 input file descriptor, we need to seek backwards in the script (if
178 possible and necessary -- scripts read from stdin are still unbuffered),
179 allocate a new file descriptor to use for bash input, and re-initialize
180 the buffered stream. */
181 int
182 check_bash_input (fd)
183 int fd;
184 {
185 int nfd;
186
187 if (fd > 0 && ((bash_input.type == st_bstream && bash_input.location.buffered_fd == fd) ||
188 (interactive_shell == 0 && default_buffered_input == fd)))
189 {
190 /* Sync the stream so we can re-read from the new file descriptor. We
191 might be able to avoid this by copying the buffered stream verbatim
192 to the new file descriptor. */
193 if (buffers[fd])
194 sync_buffered_stream (fd);
195
196 /* Now take care of duplicating the file descriptor that bash is
197 using for input, so we can reinitialize it later. */
198 nfd = fcntl (fd, F_DUPFD, 10);
199 if (nfd == -1)
200 {
201 if (fcntl (fd, F_GETFD, 0) == 0)
202 sys_error ("cannot allocate new file descriptor for bash input from fd %d", fd);
203 return -1;
204 }
205
206 if (buffers[nfd])
207 {
208 /* What's this? A stray buffer without an associated open file
209 descriptor? Free up the buffer and report the error. */
210 internal_error ("check_bash_input: buffer already exists for new fd %d", nfd);
211 free_buffered_stream (buffers[nfd]);
212 }
213
214 /* Reinitialize bash_input.location. */
215 if (bash_input.type == st_bstream)
216 {
217 bash_input.location.buffered_fd = nfd;
218 fd_to_buffered_stream (nfd);
219 close_buffered_fd (fd); /* XXX */
220 }
221 else
222 /* If the current input type is not a buffered stream, but the shell
223 is not interactive and therefore using a buffered stream to read
224 input (e.g. with an `eval exec 3>output' inside a script), note
225 that the input fd has been changed. pop_stream() looks at this
226 value and adjusts the input fd to the new value of
227 default_buffered_input accordingly. */
228 bash_input_fd_changed++;
229
230 if (default_buffered_input == fd)
231 default_buffered_input = nfd;
232 }
233 return 0;
234 }
235
236 /* This is the buffered stream analogue of dup2(fd1, fd2). The
237 BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists.
238 BUFFERS[fd1] is copied to BUFFERS[fd2]. This is called by the
239 redirect code for constructs like 4<&0 and 3</etc/rc.local. */
240 int
241 duplicate_buffered_stream (fd1, fd2)
242 int fd1, fd2;
243 {
244 int is_bash_input, m;
245
246 if (fd1 == fd2)
247 return 0;
248
249 m = max (fd1, fd2);
250 ALLOCATE_BUFFERS (m);
251
252 /* If FD2 is the file descriptor bash is currently using for shell input,
253 we need to do some extra work to make sure that the buffered stream
254 actually exists (it might not if fd1 was not active, and the copy
255 didn't actually do anything). */
256 is_bash_input = (bash_input.type == st_bstream) &&
257 (bash_input.location.buffered_fd == fd2);
258
259 if (buffers[fd2])
260 free_buffered_stream (buffers[fd2]);
261 buffers[fd2] = copy_buffered_stream (buffers[fd1]);
262 if (buffers[fd2])
263 buffers[fd2]->b_fd = fd2;
264
265 if (is_bash_input && !buffers[fd2])
266 fd_to_buffered_stream (fd2);
267
268 return (fd2);
269 }
270
271 /* Return 1 if a seek on FD will succeed. */
272 #ifndef __CYGWIN32__
273 # define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
274 #else
275 # define fd_is_seekable(fd) 0
276 #endif /* __CYGWIN32__ */
277
278 /* Take FD, a file descriptor, and create and return a buffered stream
279 corresponding to it. If something is wrong and the file descriptor
280 is invalid, return a NULL stream. */
281 BUFFERED_STREAM *
282 fd_to_buffered_stream (fd)
283 int fd;
284 {
285 char *buffer;
286 size_t size;
287 struct stat sb;
288
289 if (fstat (fd, &sb) < 0)
290 {
291 close (fd);
292 return ((BUFFERED_STREAM *)NULL);
293 }
294
295 if (fd_is_seekable (fd) == 0)
296 size = 1;
297 else
298 size = (size_t)((sb.st_size > MAX_INPUT_BUFFER_SIZE)
299 ? MAX_INPUT_BUFFER_SIZE
300 : sb.st_size);
301
302 buffer = (char *)xmalloc (size);
303
304 return (make_buffered_stream (fd, buffer, size));
305 }
306
307 /* Return a buffered stream corresponding to FILE, a file name. */
308 BUFFERED_STREAM *
309 open_buffered_stream (file)
310 char *file;
311 {
312 int fd;
313
314 fd = open (file, O_RDONLY);
315 return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
316 }
317
318 /* Deallocate a buffered stream and free up its resources. Make sure we
319 zero out the slot in BUFFERS that points to BP. */
320 void
321 free_buffered_stream (bp)
322 BUFFERED_STREAM *bp;
323 {
324 int n;
325
326 if (!bp)
327 return;
328
329 n = bp->b_fd;
330 if (bp->b_buffer)
331 free (bp->b_buffer);
332 free (bp);
333 buffers[n] = (BUFFERED_STREAM *)NULL;
334 }
335
336 /* Close the file descriptor associated with BP, a buffered stream, and free
337 up the stream. Return the status of closing BP's file descriptor. */
338 int
339 close_buffered_stream (bp)
340 BUFFERED_STREAM *bp;
341 {
342 int fd;
343
344 if (!bp)
345 return (0);
346 fd = bp->b_fd;
347 free_buffered_stream (bp);
348 return (close (fd));
349 }
350
351 /* Deallocate the buffered stream associated with file descriptor FD, and
352 close FD. Return the status of the close on FD. */
353 int
354 close_buffered_fd (fd)
355 int fd;
356 {
357 if (fd >= nbuffers || !buffers || !buffers[fd])
358 return (close (fd));
359 return (close_buffered_stream (buffers[fd]));
360 }
361
362 /* Make the BUFFERED_STREAM associcated with buffers[FD] be BP, and return
363 the old BUFFERED_STREAM. */
364 BUFFERED_STREAM *
365 set_buffered_stream (fd, bp)
366 int fd;
367 BUFFERED_STREAM *bp;
368 {
369 BUFFERED_STREAM *ret;
370
371 ret = buffers[fd];
372 buffers[fd] = bp;
373 return ret;
374 }
375
376 /* Read a buffer full of characters from BP, a buffered stream. */
377 static int
378 b_fill_buffer (bp)
379 BUFFERED_STREAM *bp;
380 {
381 do
382 {
383 bp->b_used = read (bp->b_fd, bp->b_buffer, bp->b_size);
384 }
385 while (bp->b_used < 0 && errno == EINTR);
386 if (bp->b_used <= 0)
387 {
388 bp->b_buffer[0] = 0;
389 if (bp->b_used == 0)
390 bp->b_flag |= B_EOF;
391 else
392 bp->b_flag |= B_ERROR;
393 return (EOF);
394 }
395 bp->b_inputp = 0;
396 return (bp->b_buffer[bp->b_inputp++] & 0xFF);
397 }
398
399 /* Get a character from buffered stream BP. */
400 #define bufstream_getc(bp) \
401 (bp->b_inputp == bp->b_used || !bp->b_used) \
402 ? b_fill_buffer (bp) \
403 : bp->b_buffer[bp->b_inputp++] & 0xFF
404
405 /* Push C back onto buffered stream BP. */
406 static int
407 bufstream_ungetc(c, bp)
408 int c;
409 BUFFERED_STREAM *bp;
410 {
411 if (c == EOF || bp->b_inputp == 0)
412 return (EOF);
413
414 bp->b_buffer[--bp->b_inputp] = c;
415 return (c);
416 }
417
418 /* Seek backwards on file BFD to synchronize what we've read so far
419 with the underlying file pointer. */
420 int
421 sync_buffered_stream (bfd)
422 int bfd;
423 {
424 BUFFERED_STREAM *bp;
425 off_t chars_left;
426
427 bp = buffers[bfd];
428 if (!bp)
429 return (-1);
430 chars_left = bp->b_used - bp->b_inputp;
431 if (chars_left)
432 lseek (bp->b_fd, -chars_left, SEEK_CUR);
433 bp->b_used = bp->b_inputp = 0;
434 return (0);
435 }
436
437 int
438 buffered_getchar ()
439 {
440 return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
441 }
442
443 int
444 buffered_ungetchar (c)
445 int c;
446 {
447 return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
448 }
449
450 /* Make input come from file descriptor BFD through a buffered stream. */
451 void
452 with_input_from_buffered_stream (bfd, name)
453 int bfd;
454 char *name;
455 {
456 INPUT_STREAM location;
457 BUFFERED_STREAM *bp;
458
459 location.buffered_fd = bfd;
460 /* Make sure the buffered stream exists. */
461 bp = fd_to_buffered_stream (bfd);
462 init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
463 buffered_ungetchar, st_bstream, name, location);
464 }
465
466 #if defined (TEST)
467 char *
468 xmalloc(s)
469 int s;
470 {
471 return ((char *)malloc (s));
472 }
473
474 char *
475 xrealloc(s, size)
476 char *s;
477 int size;
478 {
479 if (!s)
480 return((char *)malloc (size));
481 else
482 return((char *)realloc (s, size));
483 }
484
485 void
486 init_yy_io ()
487 {
488 }
489
490 process(bp)
491 BUFFERED_STREAM *bp;
492 {
493 int c;
494
495 while ((c = bufstream_getc(bp)) != EOF)
496 putchar(c);
497 }
498
499 BASH_INPUT bash_input;
500
501 struct stat dsb; /* can be used from gdb */
502
503 /* imitate /bin/cat */
504 main(argc, argv)
505 int argc;
506 char **argv;
507 {
508 register int i;
509 BUFFERED_STREAM *bp;
510
511 if (argc == 1) {
512 bp = fd_to_buffered_stream (0);
513 process(bp);
514 exit(0);
515 }
516 for (i = 1; i < argc; i++) {
517 if (argv[i][0] == '-' && argv[i][1] == '\0') {
518 bp = fd_to_buffered_stream (0);
519 if (!bp)
520 continue;
521 process(bp);
522 free_buffered_stream (bp);
523 } else {
524 bp = open_buffered_stream (argv[i]);
525 if (!bp)
526 continue;
527 process(bp);
528 close_buffered_stream (bp);
529 }
530 }
531 exit(0);
532 }
533 #endif /* TEST */
534 #endif /* BUFFERED_INPUT */