c543ce75fbed406bb18b507be67b8eb75f9916c6
[platform/upstream/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 #include <sys/file.h>
25 #include "filecntl.h"
26 #include "posixstat.h"
27 #include <stdio.h>
28 #include <errno.h>
29
30 #if defined (HAVE_UNISTD_H)
31 #  include <unistd.h>
32 #endif
33
34 #include "bashansi.h"
35 #include "command.h"
36 #include "general.h"
37 #include "input.h"
38 #include "error.h"
39 #include "externs.h"
40
41 #if !defined (errno)
42 extern int errno;
43 #endif /* !errno */
44
45 /* Functions to handle reading input on systems that don't restart read(2)
46    if a signal is received. */
47
48 #if !defined (HAVE_RESTARTABLE_SYSCALLS)
49 static unsigned char localbuf[128];
50 static int local_index, local_bufused;
51
52 /* Posix and USG systems do not guarantee to restart read () if it is
53    interrupted by a signal.  We do the read ourselves, and restart it
54    if it returns EINTR. */
55 int
56 getc_with_restart (stream)
57      FILE *stream;
58 {
59   /* Try local buffering to reduce the number of read(2) calls. */
60   if (local_index == local_bufused || local_bufused == 0)
61     {
62       while (1)
63         {
64           local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
65           if (local_bufused > 0)
66             break;
67           else if (local_bufused == 0 || errno != EINTR)
68             {
69               local_index = 0;
70               return EOF;
71             }
72         }
73       local_index = 0;
74     }
75   return (localbuf[local_index++]);
76 }
77
78 int
79 ungetc_with_restart (c, stream)
80      int c;
81      FILE *stream;
82 {
83   if (local_index == 0 || c == EOF)
84     return EOF;
85   return (localbuf[--local_index] = c);
86 }
87 #endif /* !HAVE_RESTARTABLE_SYSCALLS */
88
89 #if defined (BUFFERED_INPUT)
90
91 /* A facility similar to stdio, but input-only. */
92
93 #define MAX_INPUT_BUFFER_SIZE   8192
94
95 #if !defined (SEEK_CUR)
96 #  define SEEK_CUR 1
97 #endif /* !SEEK_CUR */
98
99 void free_buffered_stream ();
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 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      int 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 #define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
273
274 /* Take FD, a file descriptor, and create and return a buffered stream
275    corresponding to it.  If something is wrong and the file descriptor
276    is invalid, return a NULL stream. */
277 BUFFERED_STREAM *
278 fd_to_buffered_stream (fd)
279      int fd;
280 {
281   char *buffer;
282   int size;
283   struct stat sb;
284
285   if (fstat (fd, &sb) < 0)
286     {
287       close (fd);
288       return ((BUFFERED_STREAM *)NULL);
289     }
290
291   if (fd_is_seekable (fd) == 0)
292     size = 1;
293   else
294     size = (sb.st_size > MAX_INPUT_BUFFER_SIZE) ? MAX_INPUT_BUFFER_SIZE
295                                                 : sb.st_size;
296       
297   buffer = (char *)xmalloc (size);
298
299   return (make_buffered_stream (fd, buffer, size));
300 }
301
302 /* Return a buffered stream corresponding to FILE, a file name. */
303 BUFFERED_STREAM *
304 open_buffered_stream (file)
305      char *file;
306 {
307   int fd;
308
309   fd = open (file, O_RDONLY);
310   return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
311 }
312
313 /* Deallocate a buffered stream and free up its resources.  Make sure we
314    zero out the slot in BUFFERS that points to BP. */
315 void
316 free_buffered_stream (bp)
317      BUFFERED_STREAM *bp;
318 {
319   int n;
320
321   if (!bp)
322     return;
323
324   n = bp->b_fd;
325   if (bp->b_buffer)
326     free (bp->b_buffer);
327   free (bp);
328   buffers[n] = (BUFFERED_STREAM *)NULL;
329 }
330
331 /* Close the file descriptor associated with BP, a buffered stream, and free
332    up the stream.  Return the status of closing BP's file descriptor. */
333 int
334 close_buffered_stream (bp)
335      BUFFERED_STREAM *bp;
336 {
337   int fd;
338
339   if (!bp)
340     return (0);
341   fd = bp->b_fd;
342   free_buffered_stream (bp);
343   return (close (fd));
344 }
345
346 /* Deallocate the buffered stream associated with file descriptor FD, and
347    close FD.  Return the status of the close on FD. */
348 int
349 close_buffered_fd (fd)
350      int fd;
351 {
352   if (fd >= nbuffers || !buffers || !buffers[fd])
353     return (close (fd));
354   return (close_buffered_stream (buffers[fd]));
355 }
356
357 /* Read a buffer full of characters from BP, a buffered stream. */
358 static int
359 b_fill_buffer (bp)
360      BUFFERED_STREAM *bp;
361 {
362   do
363     {
364       bp->b_used = read (bp->b_fd, bp->b_buffer, bp->b_size);
365     }
366   while (bp->b_used < 0 && errno == EINTR);
367   if (bp->b_used <= 0)
368     {
369       bp->b_buffer[0] = 0;
370       if (bp->b_used == 0)
371         bp->b_flag |= B_EOF;
372       else
373         bp->b_flag |= B_ERROR;
374       return (EOF);
375     }
376   bp->b_inputp = 0;
377   return (bp->b_buffer[bp->b_inputp++] & 0xFF);
378 }
379
380 /* Get a character from buffered stream BP. */
381 #define bufstream_getc(bp) \
382   (bp->b_inputp == bp->b_used || !bp->b_used) \
383                 ? b_fill_buffer (bp) \
384                 : bp->b_buffer[bp->b_inputp++] & 0xFF
385
386 /* Push C back onto buffered stream BP. */
387 static int
388 bufstream_ungetc(c, bp)
389      int c;
390      BUFFERED_STREAM *bp;
391 {
392   if (c == EOF || bp->b_inputp == 0)
393     return (EOF);
394
395   bp->b_buffer[--bp->b_inputp] = c;
396   return (c);
397 }
398
399 /* Seek backwards on file BFD to synchronize what we've read so far
400    with the underlying file pointer. */
401 int
402 sync_buffered_stream (bfd)
403      int bfd;
404 {
405   BUFFERED_STREAM *bp;
406   off_t chars_left;
407
408   bp = buffers[bfd];
409   if (!bp)
410     return (-1);
411   chars_left = bp->b_used - bp->b_inputp;
412   if (chars_left)
413     lseek (bp->b_fd, -chars_left, SEEK_CUR);
414   bp->b_used = bp->b_inputp = 0;
415   return (0);
416 }
417
418 int
419 buffered_getchar ()
420 {
421   return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
422 }
423
424 int
425 buffered_ungetchar (c)
426      int c;
427 {
428   return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
429 }
430
431 /* Make input come from file descriptor BFD through a buffered stream. */
432 void
433 with_input_from_buffered_stream (bfd, name)
434      int bfd;
435      char *name;
436 {
437   INPUT_STREAM location;
438   BUFFERED_STREAM *bp;
439
440   location.buffered_fd = bfd;
441   /* Make sure the buffered stream exists. */
442   bp = fd_to_buffered_stream (bfd);
443   init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
444               buffered_ungetchar, st_bstream, name, location);
445 }
446
447 #if defined (TEST)
448 char *
449 xmalloc(s)
450 int s;
451 {
452         return ((char *)malloc (s));
453 }
454
455 char *
456 xrealloc(s, size)
457 char    *s;
458 int     size;
459 {
460         if (!s)
461                 return((char *)malloc (size));
462         else
463                 return((char *)realloc (s, size));
464 }
465
466 void
467 init_yy_io ()
468 {
469 }
470
471 process(bp)
472 BUFFERED_STREAM *bp;
473 {
474         int c;
475
476         while ((c = bufstream_getc(bp)) != EOF)
477                 putchar(c);
478 }
479
480 BASH_INPUT bash_input;
481
482 struct stat dsb;                /* can be used from gdb */
483
484 /* imitate /bin/cat */
485 main(argc, argv)
486 int     argc;
487 char    **argv;
488 {
489         register int i;
490         BUFFERED_STREAM *bp;
491
492         if (argc == 1) {
493                 bp = fd_to_buffered_stream (0);
494                 process(bp);
495                 exit(0);
496         }
497         for (i = 1; i < argc; i++) {
498                 if (argv[i][0] == '-' && argv[i][1] == '\0') {
499                         bp = fd_to_buffered_stream (0);
500                         if (!bp)
501                                 continue;
502                         process(bp);
503                         free_buffered_stream (bp);
504                 } else {
505                         bp = open_buffered_stream (argv[i]);
506                         if (!bp)
507                                 continue;
508                         process(bp);
509                         close_buffered_stream (bp);
510                 }
511         }
512         exit(0);
513 }
514 #endif /* TEST */
515 #endif /* BUFFERED_INPUT */