]> git.ipfire.org Git - thirdparty/bash.git/blame - input.c
commit bash-20041222 snapshot
[thirdparty/bash.git] / input.c
CommitLineData
726f6388
JA
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
bb70624e 19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
726f6388 20
ccc6cda3 21#include "config.h"
726f6388
JA
22
23#include "bashtypes.h"
d3a24ed2 24#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
cce855bc
JA
25# include <sys/file.h>
26#endif
726f6388
JA
27#include "filecntl.h"
28#include "posixstat.h"
29#include <stdio.h>
30#include <errno.h>
31
ccc6cda3
JA
32#if defined (HAVE_UNISTD_H)
33# include <unistd.h>
34#endif
35
726f6388 36#include "bashansi.h"
5e13499c
CR
37#include "bashintl.h"
38
726f6388
JA
39#include "command.h"
40#include "general.h"
41#include "input.h"
ccc6cda3
JA
42#include "error.h"
43#include "externs.h"
726f6388
JA
44
45#if !defined (errno)
46extern int errno;
47#endif /* !errno */
48
ccc6cda3
JA
49/* Functions to handle reading input on systems that don't restart read(2)
50 if a signal is received. */
51
f73dda09 52static char localbuf[128];
ccc6cda3
JA
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{
f73dda09
JA
62 unsigned char uc;
63
ccc6cda3
JA
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 }
f73dda09
JA
80 uc = localbuf[local_index++];
81 return uc;
ccc6cda3
JA
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;
f73dda09
JA
91 localbuf[--local_index] = c;
92 return c;
ccc6cda3 93}
ccc6cda3
JA
94
95#if defined (BUFFERED_INPUT)
96
97/* A facility similar to stdio, but input-only. */
98
bb70624e
JA
99#if defined (USING_BASH_MALLOC)
100# define MAX_INPUT_BUFFER_SIZE 8176
101#else
102# define MAX_INPUT_BUFFER_SIZE 8192
103#endif
726f6388
JA
104
105#if !defined (SEEK_CUR)
106# define SEEK_CUR 1
107#endif /* !SEEK_CUR */
108
28ef6c31
JA
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
726f6388
JA
118extern int interactive_shell;
119
120int bash_input_fd_changed;
ccc6cda3 121
726f6388
JA
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. */
cce855bc 127static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
ccc6cda3 128static int nbuffers;
726f6388 129
726f6388
JA
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;
cce855bc 156 size_t bufsize;
726f6388
JA
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;
ccc6cda3 166 bp->b_used = bp->b_inputp = bp->b_flag = 0;
726f6388
JA
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
28ef6c31
JA
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)
5e13499c 231 sys_error (_("cannot allocate new file descriptor for bash input from fd %d"), fd);
28ef6c31
JA
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. */
5e13499c 239 internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
28ef6c31
JA
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
726f6388
JA
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
28ef6c31
JA
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()). */
726f6388
JA
277int
278check_bash_input (fd)
279 int fd;
280{
d3a24ed2
CR
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 }
726f6388
JA
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. */
ccc6cda3 295int
726f6388
JA
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
28ef6c31
JA
320 if (is_bash_input)
321 {
322 if (!buffers[fd2])
323 fd_to_buffered_stream (fd2);
324 buffers[fd2]->b_flag |= B_WASBASHINPUT;
325 }
ccc6cda3 326
726f6388
JA
327 return (fd2);
328}
329
330/* Return 1 if a seek on FD will succeed. */
28ef6c31 331#ifndef __CYGWIN__
cce855bc
JA
332# define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
333#else
334# define fd_is_seekable(fd) 0
28ef6c31 335#endif /* __CYGWIN__ */
726f6388
JA
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;
cce855bc 345 size_t size;
726f6388
JA
346 struct stat sb;
347
348 if (fstat (fd, &sb) < 0)
349 {
350 close (fd);
351 return ((BUFFERED_STREAM *)NULL);
352 }
353
28ef6c31
JA
354 size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1;
355 if (size == 0)
726f6388 356 size = 1;
726f6388
JA
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);
ccc6cda3 370 return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
726f6388
JA
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{
f73dda09
JA
412 if (fd < 0)
413 {
414 errno = EBADF;
415 return -1;
416 }
726f6388
JA
417 if (fd >= nbuffers || !buffers || !buffers[fd])
418 return (close (fd));
419 return (close_buffered_stream (buffers[fd]));
420}
421
cce855bc
JA
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
726f6388
JA
436/* Read a buffer full of characters from BP, a buffered stream. */
437static int
438b_fill_buffer (bp)
439 BUFFERED_STREAM *bp;
440{
f73dda09
JA
441 ssize_t nr;
442
443 nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
444 if (nr <= 0)
726f6388 445 {
f73dda09 446 bp->b_used = 0;
726f6388 447 bp->b_buffer[0] = 0;
f73dda09 448 if (nr == 0)
726f6388
JA
449 bp->b_flag |= B_EOF;
450 else
451 bp->b_flag |= B_ERROR;
452 return (EOF);
453 }
f73dda09
JA
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;
726f6388
JA
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;
ccc6cda3 495 off_t chars_left;
726f6388 496
28ef6c31 497 if (buffers == 0 || (bp = buffers[bfd]) == 0)
726f6388 498 return (-1);
28ef6c31 499
726f6388
JA
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{
28ef6c31 510#if !defined (DJGPP)
726f6388 511 return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
28ef6c31
JA
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
726f6388
JA
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;
ccc6cda3 535 BUFFERED_STREAM *bp;
726f6388
JA
536
537 location.buffered_fd = bfd;
538 /* Make sure the buffered stream exists. */
ccc6cda3
JA
539 bp = fd_to_buffered_stream (bfd);
540 init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
541 buffered_ungetchar, st_bstream, name, location);
726f6388
JA
542}
543
544#if defined (TEST)
f73dda09 545void *
726f6388
JA
546xmalloc(s)
547int s;
548{
f73dda09 549 return (malloc (s));
726f6388
JA
550}
551
f73dda09 552void *
726f6388
JA
553xrealloc(s, size)
554char *s;
555int size;
556{
557 if (!s)
f73dda09 558 return(malloc (size));
726f6388 559 else
f73dda09 560 return(realloc (s, size));
726f6388
JA
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}
ccc6cda3
JA
611#endif /* TEST */
612#endif /* BUFFERED_INPUT */