2 /********************************************
4 copyright 1991-94. Michael D. Brennan
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
14 * Revision 1.9 1996/01/14 17:14:10 mike
17 * Revision 1.8 1995/06/06 00:18:27 mike
18 * change mawk_exit(1) to mawk_exit(2)
20 * Revision 1.7 1994/12/11 20:48:50 mike
23 * Revision 1.6 1994/10/08 19:15:40 mike
26 * Revision 1.5 1994/04/17 20:01:37 mike
27 * recognize filename "/dev/stdout"
29 * Revision 1.4 1994/02/21 00:11:07 mike
32 * Revision 1.3 1993/07/16 01:00:36 mike
35 * Revision 5.5 1992/12/17 02:48:01 mike
36 * 1.1.2d changes for DOS
38 * Revision 5.4 1992/07/10 16:10:30 brennan
40 * MsDOS: remove useless NO_BINMODE macro
41 * get process exit code on in pipes
43 * Revision 5.3 1992/04/07 20:21:17 brennan
45 * unbuffered output to a tty
47 * Revision 5.2 1992/04/07 16:03:08 brennan
49 * allow same filename for output and input, but use different descriptors
50 * E.g. < "/dev/tty" and > "/dev/tty"
52 * Revision 5.1 91/12/05 07:56:00 brennan
64 static FILE *PROTO(tfopen, (char *, char *)) ;
65 static void PROTO(efflush, (FILE*)) ;
66 static void PROTO(add_to_child_list, (int, int)) ;
67 static struct child *PROTO(remove_from_child_list, (int)) ;
68 extern int PROTO(isatty, (int)) ;
71 #include <sgtty.h> /* defines FIOCLEX */
78 #define CLOSE_ON_EXEC(fd) fcntl(fd, F_SETFD, 1)
81 #define CLOSE_ON_EXEC(fd) ioctl(fd, FIOCLEX, (PTR) 0)
85 /* We store dynamically created files on a linked linear
86 list with move to the front (big surprise) */
93 int pid ; /* we need to wait() when we close a pipe */
94 /* holds temp file index under MSDOS */
100 PTR ptr ; /* FIN* or FILE* */
104 static FILE_NODE *file_list ;
107 /* find a file on file_list */
109 file_find(sval, type)
113 register FILE_NODE *p = file_list ;
114 FILE_NODE *q = (FILE_NODE *) 0 ;
115 char *name = sval->str ;
123 p = ZMALLOC(FILE_NODE) ;
125 switch (p->type = type)
129 ostr = (binmode() & 2) ? "wb" : "w" ;
133 if (!(p->ptr = (PTR) tfopen(name, ostr)))
139 ostr = (binmode() & 2) ? "ab" : "a" ;
143 if (!(p->ptr = (PTR) tfopen(name, ostr)))
148 if (!(p->ptr = (PTR) FINopen(name, 0)))
150 zfree(p, sizeof(FILE_NODE)) ;
158 #if HAVE_REAL_PIPES || HAVE_FAKE_PIPES
160 if (!(p->ptr = get_pipe(name, type, &p->pid)))
162 if (type == PIPE_OUT) goto out_failure ;
165 zfree(p, sizeof(FILE_NODE)) ;
170 rt_error("pipes not supported") ;
176 bozo("bad file type") ;
179 /* successful open */
182 break ; /* while loop */
185 /* search is by name and type */
186 if (strcmp(name, p->name->str) == 0 &&
188 /* no distinction between F_APPEND and F_TRUNC here */
189 p->type >= F_APPEND && type >= F_APPEND))
193 if (!q) /*at front of list */
195 /* delete from list for move to front */
197 break ; /* while loop */
200 q = p ; p = p->link ;
201 } /* end while loop */
203 /* put p at the front of the list */
204 p->link = file_list ;
205 return (PTR) (file_list = p)->ptr ;
208 errmsg(errno, "cannot open \"%s\" for output", name) ;
214 /* Close a file and delete it's node from the file_list.
215 Walk the whole list, in case a name has two nodes,
216 e.g. < "/dev/tty" and > "/dev/tty"
224 register FILE_NODE *p ;
225 FILE_NODE *q = &dummy ; /* trails p */
227 char *name = sval->str ;
230 dummy.link = p = file_list ;
233 if (strcmp(name, p->name->str) == 0)
240 fclose((FILE *) p->ptr) ;
245 fclose((FILE *) p->ptr) ;
248 retval = wait_for(p->pid) ;
251 retval = close_fake_outpipe(p->name->str, p->pid) ;
256 FINclose((FIN *) p->ptr) ;
261 FINclose((FIN *) p->ptr) ;
264 retval = wait_for(p->pid) ;
269 unlink(tmp_file_name(p->pid, xbuff)) ;
270 retval = p->inpipe_exit ;
276 free_STRING(p->name) ;
278 q->link = p = p->link ;
283 q = p ; p = p->link ;
287 file_list = dummy.link ;
292 find an output file with name == sval and fflush it
300 register FILE_NODE *p = file_list ;
301 unsigned len = sval->len ;
302 char *str = sval->str ;
306 /* for consistency with gawk */
313 if ( IS_OUTPUT(p->type) &&
314 len == p->name->len &&
315 strcmp(str,p->name->str) == 0 )
318 efflush((FILE*)p->ptr) ;
319 /* it's possible for a command and a file to have the same
320 name -- so keep looking */
332 for(p=file_list; p ; p = p->link)
333 if (IS_OUTPUT(p->type)) efflush((FILE*)p->ptr) ;
342 errmsg(errno, "unexpected write error") ;
348 /* When we exit, we need to close and wait for all output pipes */
352 /* work around for bug in AIX 4.1 -- If there are exactly 16 or
353 32 or 48 ..., open files then the last one doesn't get flushed on
354 exit. So the following is now a misnomer as we'll really close
361 register FILE_NODE *p = file_list ;
365 if (IS_OUTPUT(p->type))
367 fclose((FILE *) p->ptr) ;
368 if (p->type == PIPE_OUT) wait_for(p->pid) ;
376 #if HAVE_FAKE_PIPES /* pipes are faked with temp files */
381 register FILE_NODE *p = file_list ;
384 /* close input pipes first to free descriptors for children */
387 if (p->type == PIPE_IN)
389 FINclose((FIN *) p->ptr) ;
390 unlink(tmp_file_name(p->pid, xbuff)) ;
398 if (p->type == PIPE_OUT)
401 close_fake_outpipe(p->name->str, p->pid) ;
406 #endif /* HAVE_FAKE_PIPES */
407 #endif /* ! HAVE_REAL_PIPES */
409 /* hardwire to /bin/sh for portability of programs */
410 char *shell = "/bin/sh" ;
415 get_pipe(name, type, pid_ptr)
420 int the_pipe[2], local_fd, remote_fd ;
422 if (pipe(the_pipe) == -1) return (PTR) 0 ;
423 local_fd = the_pipe[type == PIPE_OUT] ;
424 remote_fd = the_pipe[type == PIPE_IN] ;
425 /* to keep output ordered correctly */
426 fflush(stdout) ; fflush(stderr) ;
428 switch (*pid_ptr = vfork())
437 close(type == PIPE_IN) ;
440 execl(shell, shell, "-c", name, (char *) 0) ;
442 errmsg(errno, "failed to exec %s -c %s", shell, name) ;
449 /* we could deadlock if future child inherit the local fd ,
450 set close on exec flag */
451 CLOSE_ON_EXEC(local_fd) ;
455 return type == PIPE_IN ? (PTR) FINdopen(local_fd, 0) :
456 (PTR) fdopen(local_fd, "w") ;
461 /*------------ children ------------------*/
463 /* we need to wait for children at the end of output pipes to
464 complete so we know any files they have created are complete */
466 /* dead children are kept on this list */
476 add_to_child_list(pid, exit_status)
477 int pid, exit_status ;
479 register struct child *p = ZMALLOC(struct child) ;
481 p->pid = pid ; p->exit_status = exit_status ;
482 p->link = child_list ; child_list = p ;
485 static struct child *
486 remove_from_child_list(pid)
490 register struct child *p ;
491 struct child *q = &dummy ;
493 dummy.link = p = child_list ;
503 q = p ; p = p->link ;
507 child_list = dummy.link ;
509 /* null return if not in the list */
513 /* wait for a specific child to complete and return its
516 If pid is zero, wait for any single child and
517 put it on the dead children list
530 id = wait(&exit_status) ;
531 add_to_child_list(id, exit_status) ;
533 /* see if an earlier wait() caught our child */
534 else if (p = remove_from_child_list(pid))
536 exit_status = p->exit_status ;
541 /* need to really wait */
542 while ((id = wait(&exit_status)) != pid)
544 if (id == -1) /* can't happen */
548 /* we got the exit status of another child
549 put it on the child list and try again */
550 add_to_child_list(id, exit_status) ;
555 if (exit_status & 0xff) exit_status = 128 + (exit_status & 0xff) ;
556 else exit_status = (exit_status & 0xff00) >> 8 ;
561 #endif /* HAVE_REAL_PIPES */
565 set_stderr() /* and stdout */
569 p = ZMALLOC(FILE_NODE) ;
570 p->link = (FILE_NODE*) 0 ;
572 p->name = new_STRING("/dev/stdout") ;
573 p->ptr = (PTR) stdout ;
574 q = ZMALLOC(FILE_NODE);
577 q->name = new_STRING("/dev/stderr") ;
578 q->ptr = (PTR) stderr ;
582 /* fopen() but no buffering to ttys */
587 FILE *retval = fopen(name, mode) ;
591 if (isatty(fileno(retval))) setbuf(retval, (char *) 0) ;
595 enlarge_output_buffer(retval) ;
604 enlarge_output_buffer(fp)
607 if (setvbuf(fp, (char *) 0, _IOFBF, BUFFSZ) < 0)
609 errmsg(errno, "setvbuf failed on fileno %d", fileno(fp)) ;
617 if (!isatty(1)) enlarge_output_buffer(stdout) ;
620 setmode(1,O_BINARY) ; setmode(2,O_BINARY) ;