blob: 314a1f5375716f72dcf89c8860ec3789d8402716 [file] [log] [blame]
Jari Aalto726f6381996-08-26 18:22:31 +00001/* 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
Jari Aaltobb706242000-03-17 21:46:59 +000019 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
Jari Aalto726f6381996-08-26 18:22:31 +000020
Jari Aaltoccc6cda1996-12-23 17:02:34 +000021#include "config.h"
Jari Aalto726f6381996-08-26 18:22:31 +000022
23#include "bashtypes.h"
Jari Aaltob80f6442004-07-27 13:29:18 +000024#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
Jari Aaltocce855b1998-04-17 19:52:44 +000025# include <sys/file.h>
26#endif
Jari Aalto726f6381996-08-26 18:22:31 +000027#include "filecntl.h"
28#include "posixstat.h"
29#include <stdio.h>
30#include <errno.h>
31
Jari Aaltoccc6cda1996-12-23 17:02:34 +000032#if defined (HAVE_UNISTD_H)
33# include <unistd.h>
34#endif
35
Jari Aalto726f6381996-08-26 18:22:31 +000036#include "bashansi.h"
Jari Aaltob80f6442004-07-27 13:29:18 +000037#include "bashintl.h"
38
Jari Aalto726f6381996-08-26 18:22:31 +000039#include "command.h"
40#include "general.h"
41#include "input.h"
Jari Aaltoccc6cda1996-12-23 17:02:34 +000042#include "error.h"
43#include "externs.h"
Jari Aalto726f6381996-08-26 18:22:31 +000044
45#if !defined (errno)
46extern int errno;
47#endif /* !errno */
48
Jari Aaltoccc6cda1996-12-23 17:02:34 +000049/* Functions to handle reading input on systems that don't restart read(2)
50 if a signal is received. */
51
Jari Aaltof73dda02001-11-13 17:56:06 +000052static char localbuf[128];
Jari Aalto95732b42005-12-07 14:08:12 +000053static int local_index = 0, local_bufused = 0;
Jari Aaltoccc6cda1996-12-23 17:02:34 +000054
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{
Jari Aaltof73dda02001-11-13 17:56:06 +000062 unsigned char uc;
63
Jari Aaltoccc6cda1996-12-23 17:02:34 +000064 /* 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 }
Jari Aaltof73dda02001-11-13 17:56:06 +000080 uc = localbuf[local_index++];
81 return uc;
Jari Aaltoccc6cda1996-12-23 17:02:34 +000082}
83
84int
85ungetc_with_restart (c, stream)
86 int c;
87 FILE *stream;
88{
89 if (local_index == 0 || c == EOF)
90 return EOF;
Jari Aaltof73dda02001-11-13 17:56:06 +000091 localbuf[--local_index] = c;
92 return c;
Jari Aaltoccc6cda1996-12-23 17:02:34 +000093}
Jari Aaltoccc6cda1996-12-23 17:02:34 +000094
95#if defined (BUFFERED_INPUT)
96
97/* A facility similar to stdio, but input-only. */
98
Jari Aaltobb706242000-03-17 21:46:59 +000099#if defined (USING_BASH_MALLOC)
100# define MAX_INPUT_BUFFER_SIZE 8176
101#else
102# define MAX_INPUT_BUFFER_SIZE 8192
103#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000104
105#if !defined (SEEK_CUR)
106# define SEEK_CUR 1
107#endif /* !SEEK_CUR */
108
Jari Aalto28ef6c32001-04-06 19:14:31 +0000109#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
Jari Aalto726f6381996-08-26 18:22:31 +0000118extern int interactive_shell;
119
120int bash_input_fd_changed;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000121
Jari Aalto726f6381996-08-26 18:22:31 +0000122/* 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. */
Jari Aaltocce855b1998-04-17 19:52:44 +0000127static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000128static int nbuffers;
Jari Aalto726f6381996-08-26 18:22:31 +0000129
Jari Aalto726f6381996-08-26 18:22:31 +0000130#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;
Jari Aaltocce855b1998-04-17 19:52:44 +0000156 size_t bufsize;
Jari Aalto726f6381996-08-26 18:22:31 +0000157{
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;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000166 bp->b_used = bp->b_inputp = bp->b_flag = 0;
Jari Aalto726f6381996-08-26 18:22:31 +0000167 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
Jari Aalto28ef6c32001-04-06 19:14:31 +0000187int
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)
Jari Aaltob80f6442004-07-27 13:29:18 +0000231 sys_error (_("cannot allocate new file descriptor for bash input from fd %d"), fd);
Jari Aalto28ef6c32001-04-06 19:14:31 +0000232 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. */
Jari Aaltob80f6442004-07-27 13:29:18 +0000239 internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
Jari Aalto28ef6c32001-04-06 19:14:31 +0000240 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
Jari Aalto726f6381996-08-26 18:22:31 +0000266/* 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
Jari Aalto28ef6c32001-04-06 19:14:31 +0000272 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()). */
Jari Aalto726f6381996-08-26 18:22:31 +0000277int
278check_bash_input (fd)
279 int fd;
280{
Jari Aaltob80f6442004-07-27 13:29:18 +0000281 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 }
Jari Aalto726f6381996-08-26 18:22:31 +0000288 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. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000295int
Jari Aalto726f6381996-08-26 18:22:31 +0000296duplicate_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])
Jari Aalto95732b42005-12-07 14:08:12 +0000315 {
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 }
Jari Aalto726f6381996-08-26 18:22:31 +0000322 buffers[fd2] = copy_buffered_stream (buffers[fd1]);
323 if (buffers[fd2])
324 buffers[fd2]->b_fd = fd2;
325
Jari Aalto28ef6c32001-04-06 19:14:31 +0000326 if (is_bash_input)
327 {
328 if (!buffers[fd2])
329 fd_to_buffered_stream (fd2);
330 buffers[fd2]->b_flag |= B_WASBASHINPUT;
331 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000332
Jari Aalto726f6381996-08-26 18:22:31 +0000333 return (fd2);
334}
335
336/* Return 1 if a seek on FD will succeed. */
Jari Aalto28ef6c32001-04-06 19:14:31 +0000337#ifndef __CYGWIN__
Jari Aaltocce855b1998-04-17 19:52:44 +0000338# define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
339#else
340# define fd_is_seekable(fd) 0
Jari Aalto28ef6c32001-04-06 19:14:31 +0000341#endif /* __CYGWIN__ */
Jari Aalto726f6381996-08-26 18:22:31 +0000342
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;
Jari Aaltocce855b1998-04-17 19:52:44 +0000351 size_t size;
Jari Aalto726f6381996-08-26 18:22:31 +0000352 struct stat sb;
353
354 if (fstat (fd, &sb) < 0)
355 {
356 close (fd);
357 return ((BUFFERED_STREAM *)NULL);
358 }
359
Jari Aalto28ef6c32001-04-06 19:14:31 +0000360 size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1;
361 if (size == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000362 size = 1;
Jari Aalto726f6381996-08-26 18:22:31 +0000363 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);
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000376 return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
Jari Aalto726f6381996-08-26 18:22:31 +0000377}
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{
Jari Aaltof73dda02001-11-13 17:56:06 +0000418 if (fd < 0)
419 {
420 errno = EBADF;
421 return -1;
422 }
Jari Aalto726f6381996-08-26 18:22:31 +0000423 if (fd >= nbuffers || !buffers || !buffers[fd])
424 return (close (fd));
425 return (close_buffered_stream (buffers[fd]));
426}
427
Jari Aaltocce855b1998-04-17 19:52:44 +0000428/* 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
Jari Aalto726f6381996-08-26 18:22:31 +0000442/* Read a buffer full of characters from BP, a buffered stream. */
443static int
444b_fill_buffer (bp)
445 BUFFERED_STREAM *bp;
446{
Jari Aaltof73dda02001-11-13 17:56:06 +0000447 ssize_t nr;
448
449 nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
450 if (nr <= 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000451 {
Jari Aaltof73dda02001-11-13 17:56:06 +0000452 bp->b_used = 0;
Jari Aalto726f6381996-08-26 18:22:31 +0000453 bp->b_buffer[0] = 0;
Jari Aaltof73dda02001-11-13 17:56:06 +0000454 if (nr == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000455 bp->b_flag |= B_EOF;
456 else
457 bp->b_flag |= B_ERROR;
458 return (EOF);
459 }
Jari Aaltof73dda02001-11-13 17:56:06 +0000460
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;
Jari Aalto726f6381996-08-26 18:22:31 +0000471 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;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000501 off_t chars_left;
Jari Aalto726f6381996-08-26 18:22:31 +0000502
Jari Aalto28ef6c32001-04-06 19:14:31 +0000503 if (buffers == 0 || (bp = buffers[bfd]) == 0)
Jari Aalto726f6381996-08-26 18:22:31 +0000504 return (-1);
Jari Aalto28ef6c32001-04-06 19:14:31 +0000505
Jari Aalto726f6381996-08-26 18:22:31 +0000506 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{
Jari Aalto28ef6c32001-04-06 19:14:31 +0000516#if !defined (DJGPP)
Jari Aalto726f6381996-08-26 18:22:31 +0000517 return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
Jari Aalto28ef6c32001-04-06 19:14:31 +0000518#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
Jari Aalto726f6381996-08-26 18:22:31 +0000525}
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;
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000541 BUFFERED_STREAM *bp;
Jari Aalto726f6381996-08-26 18:22:31 +0000542
543 location.buffered_fd = bfd;
544 /* Make sure the buffered stream exists. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000545 bp = fd_to_buffered_stream (bfd);
546 init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
547 buffered_ungetchar, st_bstream, name, location);
Jari Aalto726f6381996-08-26 18:22:31 +0000548}
549
550#if defined (TEST)
Jari Aaltof73dda02001-11-13 17:56:06 +0000551void *
Jari Aalto726f6381996-08-26 18:22:31 +0000552xmalloc(s)
553int s;
554{
Jari Aaltof73dda02001-11-13 17:56:06 +0000555 return (malloc (s));
Jari Aalto726f6381996-08-26 18:22:31 +0000556}
557
Jari Aaltof73dda02001-11-13 17:56:06 +0000558void *
Jari Aalto726f6381996-08-26 18:22:31 +0000559xrealloc(s, size)
560char *s;
561int size;
562{
563 if (!s)
Jari Aaltof73dda02001-11-13 17:56:06 +0000564 return(malloc (size));
Jari Aalto726f6381996-08-26 18:22:31 +0000565 else
Jari Aaltof73dda02001-11-13 17:56:06 +0000566 return(realloc (s, size));
Jari Aalto726f6381996-08-26 18:22:31 +0000567}
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}
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000617#endif /* TEST */
618#endif /* BUFFERED_INPUT */