source: vendor/bash/3.1-p17/input.c

Last change on this file was 3231, checked in by bird, 18 years ago

eol style.

  • Property svn:eol-style set to native
File size: 14.7 KB
Line 
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#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
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 "bashintl.h"
38
39#include "command.h"
40#include "general.h"
41#include "input.h"
42#include "error.h"
43#include "externs.h"
44
45#if !defined (errno)
46extern int errno;
47#endif /* !errno */
48
49/* Functions to handle reading input on systems that don't restart read(2)
50 if a signal is received. */
51
52static char localbuf[128];
53static int local_index = 0, local_bufused = 0;
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{
62 unsigned char uc;
63
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 }
80 uc = localbuf[local_index++];
81 return uc;
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;
91 localbuf[--local_index] = c;
92 return c;
93}
94
95#if defined (BUFFERED_INPUT)
96
97/* A facility similar to stdio, but input-only. */
98
99#if defined (USING_BASH_MALLOC)
100# define MAX_INPUT_BUFFER_SIZE 8176
101#else
102# define MAX_INPUT_BUFFER_SIZE 8192
103#endif
104
105#if !defined (SEEK_CUR)
106# define SEEK_CUR 1
107#endif /* !SEEK_CUR */
108
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
118extern int interactive_shell;
119
120int bash_input_fd_changed;
121
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. */
127static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
128static int nbuffers;
129
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;
156 size_t bufsize;
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;
166 bp->b_used = bp->b_inputp = bp->b_flag = 0;
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
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)
231 sys_error (_("cannot allocate new file descriptor for bash input from fd %d"), fd);
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. */
239 internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
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
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
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()). */
277int
278check_bash_input (fd)
279 int fd;
280{
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 }
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. */
295int
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 {
316 /* If the two objects share the same b_buffer, don't free it. */
317 if (buffers[fd1] && buffers[fd1]->b_buffer && buffers[fd1]->b_buffer == buffers[fd2]->b_buffer)
318 buffers[fd2] = (BUFFERED_STREAM *)NULL;
319 else
320 free_buffered_stream (buffers[fd2]);
321 }
322 buffers[fd2] = copy_buffered_stream (buffers[fd1]);
323 if (buffers[fd2])
324 buffers[fd2]->b_fd = fd2;
325
326 if (is_bash_input)
327 {
328 if (!buffers[fd2])
329 fd_to_buffered_stream (fd2);
330 buffers[fd2]->b_flag |= B_WASBASHINPUT;
331 }
332
333 return (fd2);
334}
335
336/* Return 1 if a seek on FD will succeed. */
337#ifndef __CYGWIN__
338# define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
339#else
340# define fd_is_seekable(fd) 0
341#endif /* __CYGWIN__ */
342
343/* Take FD, a file descriptor, and create and return a buffered stream
344 corresponding to it. If something is wrong and the file descriptor
345 is invalid, return a NULL stream. */
346BUFFERED_STREAM *
347fd_to_buffered_stream (fd)
348 int fd;
349{
350 char *buffer;
351 size_t size;
352 struct stat sb;
353
354 if (fstat (fd, &sb) < 0)
355 {
356 close (fd);
357 return ((BUFFERED_STREAM *)NULL);
358 }
359
360 size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1;
361 if (size == 0)
362 size = 1;
363 buffer = (char *)xmalloc (size);
364
365 return (make_buffered_stream (fd, buffer, size));
366}
367
368/* Return a buffered stream corresponding to FILE, a file name. */
369BUFFERED_STREAM *
370open_buffered_stream (file)
371 char *file;
372{
373 int fd;
374
375 fd = open (file, O_RDONLY);
376 return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
377}
378
379/* Deallocate a buffered stream and free up its resources. Make sure we
380 zero out the slot in BUFFERS that points to BP. */
381void
382free_buffered_stream (bp)
383 BUFFERED_STREAM *bp;
384{
385 int n;
386
387 if (!bp)
388 return;
389
390 n = bp->b_fd;
391 if (bp->b_buffer)
392 free (bp->b_buffer);
393 free (bp);
394 buffers[n] = (BUFFERED_STREAM *)NULL;
395}
396
397/* Close the file descriptor associated with BP, a buffered stream, and free
398 up the stream. Return the status of closing BP's file descriptor. */
399int
400close_buffered_stream (bp)
401 BUFFERED_STREAM *bp;
402{
403 int fd;
404
405 if (!bp)
406 return (0);
407 fd = bp->b_fd;
408 free_buffered_stream (bp);
409 return (close (fd));
410}
411
412/* Deallocate the buffered stream associated with file descriptor FD, and
413 close FD. Return the status of the close on FD. */
414int
415close_buffered_fd (fd)
416 int fd;
417{
418 if (fd < 0)
419 {
420 errno = EBADF;
421 return -1;
422 }
423 if (fd >= nbuffers || !buffers || !buffers[fd])
424 return (close (fd));
425 return (close_buffered_stream (buffers[fd]));
426}
427
428/* Make the BUFFERED_STREAM associcated with buffers[FD] be BP, and return
429 the old BUFFERED_STREAM. */
430BUFFERED_STREAM *
431set_buffered_stream (fd, bp)
432 int fd;
433 BUFFERED_STREAM *bp;
434{
435 BUFFERED_STREAM *ret;
436
437 ret = buffers[fd];
438 buffers[fd] = bp;
439 return ret;
440}
441
442/* Read a buffer full of characters from BP, a buffered stream. */
443static int
444b_fill_buffer (bp)
445 BUFFERED_STREAM *bp;
446{
447 ssize_t nr;
448
449 nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
450 if (nr <= 0)
451 {
452 bp->b_used = 0;
453 bp->b_buffer[0] = 0;
454 if (nr == 0)
455 bp->b_flag |= B_EOF;
456 else
457 bp->b_flag |= B_ERROR;
458 return (EOF);
459 }
460
461#if defined (__CYGWIN__)
462 /* If on cygwin, translate \r\n to \n. */
463 if (nr >= 2 && bp->b_buffer[nr - 2] == '\r' && bp->b_buffer[nr - 1] == '\n')
464 {
465 bp->b_buffer[nr - 2] = '\n';
466 nr--;
467 }
468#endif
469
470 bp->b_used = nr;
471 bp->b_inputp = 0;
472 return (bp->b_buffer[bp->b_inputp++] & 0xFF);
473}
474
475/* Get a character from buffered stream BP. */
476#define bufstream_getc(bp) \
477 (bp->b_inputp == bp->b_used || !bp->b_used) \
478 ? b_fill_buffer (bp) \
479 : bp->b_buffer[bp->b_inputp++] & 0xFF
480
481/* Push C back onto buffered stream BP. */
482static int
483bufstream_ungetc(c, bp)
484 int c;
485 BUFFERED_STREAM *bp;
486{
487 if (c == EOF || bp->b_inputp == 0)
488 return (EOF);
489
490 bp->b_buffer[--bp->b_inputp] = c;
491 return (c);
492}
493
494/* Seek backwards on file BFD to synchronize what we've read so far
495 with the underlying file pointer. */
496int
497sync_buffered_stream (bfd)
498 int bfd;
499{
500 BUFFERED_STREAM *bp;
501 off_t chars_left;
502
503 if (buffers == 0 || (bp = buffers[bfd]) == 0)
504 return (-1);
505
506 chars_left = bp->b_used - bp->b_inputp;
507 if (chars_left)
508 lseek (bp->b_fd, -chars_left, SEEK_CUR);
509 bp->b_used = bp->b_inputp = 0;
510 return (0);
511}
512
513int
514buffered_getchar ()
515{
516#if !defined (DJGPP)
517 return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
518#else
519 /* On DJGPP, ignore \r. */
520 int ch;
521 while ((ch = bufstream_getc (buffers[bash_input.location.buffered_fd])) == '\r')
522 ;
523 return ch;
524#endif
525}
526
527int
528buffered_ungetchar (c)
529 int c;
530{
531 return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
532}
533
534/* Make input come from file descriptor BFD through a buffered stream. */
535void
536with_input_from_buffered_stream (bfd, name)
537 int bfd;
538 char *name;
539{
540 INPUT_STREAM location;
541 BUFFERED_STREAM *bp;
542
543 location.buffered_fd = bfd;
544 /* Make sure the buffered stream exists. */
545 bp = fd_to_buffered_stream (bfd);
546 init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
547 buffered_ungetchar, st_bstream, name, location);
548}
549
550#if defined (TEST)
551void *
552xmalloc(s)
553int s;
554{
555 return (malloc (s));
556}
557
558void *
559xrealloc(s, size)
560char *s;
561int size;
562{
563 if (!s)
564 return(malloc (size));
565 else
566 return(realloc (s, size));
567}
568
569void
570init_yy_io ()
571{
572}
573
574process(bp)
575BUFFERED_STREAM *bp;
576{
577 int c;
578
579 while ((c = bufstream_getc(bp)) != EOF)
580 putchar(c);
581}
582
583BASH_INPUT bash_input;
584
585struct stat dsb; /* can be used from gdb */
586
587/* imitate /bin/cat */
588main(argc, argv)
589int argc;
590char **argv;
591{
592 register int i;
593 BUFFERED_STREAM *bp;
594
595 if (argc == 1) {
596 bp = fd_to_buffered_stream (0);
597 process(bp);
598 exit(0);
599 }
600 for (i = 1; i < argc; i++) {
601 if (argv[i][0] == '-' && argv[i][1] == '\0') {
602 bp = fd_to_buffered_stream (0);
603 if (!bp)
604 continue;
605 process(bp);
606 free_buffered_stream (bp);
607 } else {
608 bp = open_buffered_stream (argv[i]);
609 if (!bp)
610 continue;
611 process(bp);
612 close_buffered_stream (bp);
613 }
614 }
615 exit(0);
616}
617#endif /* TEST */
618#endif /* BUFFERED_INPUT */
Note: See TracBrowser for help on using the repository browser.