]> git.ipfire.org Git - thirdparty/bash.git/blob - input.c
Imported from ../bash-2.04.tar.gz.
[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, 59 Temple Place, Suite 330, Boston, MA 02111 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 static unsigned char localbuf[128];
51 static int local_index, local_bufused;
52
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. */
56 int
57 getc_with_restart (stream)
58 FILE *stream;
59 {
60 /* Try local buffering to reduce the number of read(2) calls. */
61 if (local_index == local_bufused || local_bufused == 0)
62 {
63 while (1)
64 {
65 local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
66 if (local_bufused > 0)
67 break;
68 else if (local_bufused == 0 || errno != EINTR)
69 {
70 local_index = 0;
71 return EOF;
72 }
73 }
74 local_index = 0;
75 }
76 return (localbuf[local_index++]);
77 }
78
79 int
80 ungetc_with_restart (c, stream)
81 int c;
82 FILE *stream;
83 {
84 if (local_index == 0 || c == EOF)
85 return EOF;
86 return (localbuf[--local_index] = c);
87 }
88
89 #if defined (BUFFERED_INPUT)
90
91 /* A facility similar to stdio, but input-only. */
92
93 #if defined (USING_BASH_MALLOC)
94 # define MAX_INPUT_BUFFER_SIZE 8176
95 #else
96 # define MAX_INPUT_BUFFER_SIZE 8192
97 #endif
98
99 #if !defined (SEEK_CUR)
100 # define SEEK_CUR 1
101 #endif /* !SEEK_CUR */
102
103 extern int return_EOF ();
104
105 extern int interactive_shell;
106
107 int bash_input_fd_changed;
108
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;
115 static int nbuffers;
116
117 #define max(a, b) (((a) > (b)) ? (a) : (b))
118
119 #define ALLOCATE_BUFFERS(n) \
120 do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
121
122 /* Make sure `buffers' has at least N elements. */
123 static void
124 allocate_buffers (n)
125 int n;
126 {
127 register int i, orig_nbuffers;
128
129 orig_nbuffers = nbuffers;
130 nbuffers = n + 20;
131 buffers = (BUFFERED_STREAM **)xrealloc
132 (buffers, nbuffers * sizeof (BUFFERED_STREAM *));
133
134 /* Zero out the new buffers. */
135 for (i = orig_nbuffers; i < nbuffers; i++)
136 buffers[i] = (BUFFERED_STREAM *)NULL;
137 }
138
139 /* Construct and return a BUFFERED_STREAM corresponding to file descriptor
140 FD, using BUFFER. */
141 static BUFFERED_STREAM *
142 make_buffered_stream (fd, buffer, bufsize)
143 int fd;
144 char *buffer;
145 size_t bufsize;
146 {
147 BUFFERED_STREAM *bp;
148
149 bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
150 ALLOCATE_BUFFERS (fd);
151 buffers[fd] = bp;
152 bp->b_fd = fd;
153 bp->b_buffer = buffer;
154 bp->b_size = bufsize;
155 bp->b_used = bp->b_inputp = bp->b_flag = 0;
156 if (bufsize == 1)
157 bp->b_flag |= B_UNBUFF;
158 return (bp);
159 }
160
161 /* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
162 static BUFFERED_STREAM *
163 copy_buffered_stream (bp)
164 BUFFERED_STREAM *bp;
165 {
166 BUFFERED_STREAM *nbp;
167
168 if (!bp)
169 return ((BUFFERED_STREAM *)NULL);
170
171 nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
172 xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM));
173 return (nbp);
174 }
175
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. */
183 int
184 check_bash_input (fd)
185 int fd;
186 {
187 int nfd;
188
189 if (fd > 0 && ((bash_input.type == st_bstream && bash_input.location.buffered_fd == fd) ||
190 (interactive_shell == 0 && default_buffered_input == fd)))
191 {
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. */
195 if (buffers[fd])
196 sync_buffered_stream (fd);
197
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);
201 if (nfd == -1)
202 {
203 if (fcntl (fd, F_GETFD, 0) == 0)
204 sys_error ("cannot allocate new file descriptor for bash input from fd %d", fd);
205 return -1;
206 }
207
208 if (buffers[nfd])
209 {
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]);
214 }
215
216 /* Reinitialize bash_input.location. */
217 if (bash_input.type == st_bstream)
218 {
219 bash_input.location.buffered_fd = nfd;
220 fd_to_buffered_stream (nfd);
221 close_buffered_fd (fd); /* XXX */
222 }
223 else
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++;
231
232 if (default_buffered_input == fd)
233 default_buffered_input = nfd;
234 }
235 return 0;
236 }
237
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. */
242 int
243 duplicate_buffered_stream (fd1, fd2)
244 int fd1, fd2;
245 {
246 int is_bash_input, m;
247
248 if (fd1 == fd2)
249 return 0;
250
251 m = max (fd1, fd2);
252 ALLOCATE_BUFFERS (m);
253
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);
260
261 if (buffers[fd2])
262 free_buffered_stream (buffers[fd2]);
263 buffers[fd2] = copy_buffered_stream (buffers[fd1]);
264 if (buffers[fd2])
265 buffers[fd2]->b_fd = fd2;
266
267 if (is_bash_input && !buffers[fd2])
268 fd_to_buffered_stream (fd2);
269
270 return (fd2);
271 }
272
273 /* Return 1 if a seek on FD will succeed. */
274 #ifndef __CYGWIN32__
275 # define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
276 #else
277 # define fd_is_seekable(fd) 0
278 #endif /* __CYGWIN32__ */
279
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. */
283 BUFFERED_STREAM *
284 fd_to_buffered_stream (fd)
285 int fd;
286 {
287 char *buffer;
288 size_t size;
289 struct stat sb;
290
291 if (fstat (fd, &sb) < 0)
292 {
293 close (fd);
294 return ((BUFFERED_STREAM *)NULL);
295 }
296
297 if (fd_is_seekable (fd) == 0)
298 size = 1;
299 else
300 size = (size_t)((sb.st_size > MAX_INPUT_BUFFER_SIZE)
301 ? MAX_INPUT_BUFFER_SIZE
302 : sb.st_size);
303
304 buffer = (char *)xmalloc (size);
305
306 return (make_buffered_stream (fd, buffer, size));
307 }
308
309 /* Return a buffered stream corresponding to FILE, a file name. */
310 BUFFERED_STREAM *
311 open_buffered_stream (file)
312 char *file;
313 {
314 int fd;
315
316 fd = open (file, O_RDONLY);
317 return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
318 }
319
320 /* Deallocate a buffered stream and free up its resources. Make sure we
321 zero out the slot in BUFFERS that points to BP. */
322 void
323 free_buffered_stream (bp)
324 BUFFERED_STREAM *bp;
325 {
326 int n;
327
328 if (!bp)
329 return;
330
331 n = bp->b_fd;
332 if (bp->b_buffer)
333 free (bp->b_buffer);
334 free (bp);
335 buffers[n] = (BUFFERED_STREAM *)NULL;
336 }
337
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. */
340 int
341 close_buffered_stream (bp)
342 BUFFERED_STREAM *bp;
343 {
344 int fd;
345
346 if (!bp)
347 return (0);
348 fd = bp->b_fd;
349 free_buffered_stream (bp);
350 return (close (fd));
351 }
352
353 /* Deallocate the buffered stream associated with file descriptor FD, and
354 close FD. Return the status of the close on FD. */
355 int
356 close_buffered_fd (fd)
357 int fd;
358 {
359 if (fd >= nbuffers || !buffers || !buffers[fd])
360 return (close (fd));
361 return (close_buffered_stream (buffers[fd]));
362 }
363
364 /* Make the BUFFERED_STREAM associcated with buffers[FD] be BP, and return
365 the old BUFFERED_STREAM. */
366 BUFFERED_STREAM *
367 set_buffered_stream (fd, bp)
368 int fd;
369 BUFFERED_STREAM *bp;
370 {
371 BUFFERED_STREAM *ret;
372
373 ret = buffers[fd];
374 buffers[fd] = bp;
375 return ret;
376 }
377
378 /* Read a buffer full of characters from BP, a buffered stream. */
379 static int
380 b_fill_buffer (bp)
381 BUFFERED_STREAM *bp;
382 {
383 bp->b_used = zread (bp->b_fd, bp->b_buffer, bp->b_size);
384 if (bp->b_used <= 0)
385 {
386 bp->b_buffer[0] = 0;
387 if (bp->b_used == 0)
388 bp->b_flag |= B_EOF;
389 else
390 bp->b_flag |= B_ERROR;
391 return (EOF);
392 }
393 bp->b_inputp = 0;
394 return (bp->b_buffer[bp->b_inputp++] & 0xFF);
395 }
396
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
402
403 /* Push C back onto buffered stream BP. */
404 static int
405 bufstream_ungetc(c, bp)
406 int c;
407 BUFFERED_STREAM *bp;
408 {
409 if (c == EOF || bp->b_inputp == 0)
410 return (EOF);
411
412 bp->b_buffer[--bp->b_inputp] = c;
413 return (c);
414 }
415
416 /* Seek backwards on file BFD to synchronize what we've read so far
417 with the underlying file pointer. */
418 int
419 sync_buffered_stream (bfd)
420 int bfd;
421 {
422 BUFFERED_STREAM *bp;
423 off_t chars_left;
424
425 bp = buffers[bfd];
426 if (!bp)
427 return (-1);
428 chars_left = bp->b_used - bp->b_inputp;
429 if (chars_left)
430 lseek (bp->b_fd, -chars_left, SEEK_CUR);
431 bp->b_used = bp->b_inputp = 0;
432 return (0);
433 }
434
435 int
436 buffered_getchar ()
437 {
438 return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
439 }
440
441 int
442 buffered_ungetchar (c)
443 int c;
444 {
445 return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
446 }
447
448 /* Make input come from file descriptor BFD through a buffered stream. */
449 void
450 with_input_from_buffered_stream (bfd, name)
451 int bfd;
452 char *name;
453 {
454 INPUT_STREAM location;
455 BUFFERED_STREAM *bp;
456
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);
462 }
463
464 #if defined (TEST)
465 char *
466 xmalloc(s)
467 int s;
468 {
469 return ((char *)malloc (s));
470 }
471
472 char *
473 xrealloc(s, size)
474 char *s;
475 int size;
476 {
477 if (!s)
478 return((char *)malloc (size));
479 else
480 return((char *)realloc (s, size));
481 }
482
483 void
484 init_yy_io ()
485 {
486 }
487
488 process(bp)
489 BUFFERED_STREAM *bp;
490 {
491 int c;
492
493 while ((c = bufstream_getc(bp)) != EOF)
494 putchar(c);
495 }
496
497 BASH_INPUT bash_input;
498
499 struct stat dsb; /* can be used from gdb */
500
501 /* imitate /bin/cat */
502 main(argc, argv)
503 int argc;
504 char **argv;
505 {
506 register int i;
507 BUFFERED_STREAM *bp;
508
509 if (argc == 1) {
510 bp = fd_to_buffered_stream (0);
511 process(bp);
512 exit(0);
513 }
514 for (i = 1; i < argc; i++) {
515 if (argv[i][0] == '-' && argv[i][1] == '\0') {
516 bp = fd_to_buffered_stream (0);
517 if (!bp)
518 continue;
519 process(bp);
520 free_buffered_stream (bp);
521 } else {
522 bp = open_buffered_stream (argv[i]);
523 if (!bp)
524 continue;
525 process(bp);
526 close_buffered_stream (bp);
527 }
528 }
529 exit(0);
530 }
531 #endif /* TEST */
532 #endif /* BUFFERED_INPUT */