xref: /csrg-svn/contrib/gawk-2.15.2/io.c (revision 60886)
1 /*
2  * io.c --- routines for dealing with input and output and records
3  */
4 
5 /*
6  * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
7  *
8  * This file is part of GAWK, the GNU implementation of the
9  * AWK Progamming Language.
10  *
11  * GAWK is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * GAWK is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with GAWK; see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25 
26 #include "awk.h"
27 
28 #ifndef O_RDONLY
29 #include <fcntl.h>
30 #endif
31 
32 #if !defined(S_ISDIR) && defined(S_IFDIR)
33 #define	S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
34 #endif
35 
36 #ifndef atarist
37 #define INVALID_HANDLE (-1)
38 #else
39 #define INVALID_HANDLE  (__SMALLEST_VALID_HANDLE - 1)
40 #endif
41 
42 #if defined(MSDOS) || defined(atarist)
43 #define PIPES_SIMULATED
44 #endif
45 
46 static IOBUF *nextfile P((int skipping));
47 static int inrec P((IOBUF *iop));
48 static int iop_close P((IOBUF *iop));
49 struct redirect *redirect P((NODE *tree, int *errflg));
50 static void close_one P((void));
51 static int close_redir P((struct redirect *rp));
52 #ifndef PIPES_SIMULATED
53 static int wait_any P((int interesting));
54 #endif
55 static IOBUF *gawk_popen P((char *cmd, struct redirect *rp));
56 static IOBUF *iop_open P((char *file, char *how));
57 static int gawk_pclose P((struct redirect *rp));
58 static int do_pathopen P((char *file));
59 
60 extern FILE	*fdopen();
61 extern FILE	*popen();
62 
63 static struct redirect *red_head = NULL;
64 
65 extern int output_is_tty;
66 extern NODE *ARGC_node;
67 extern NODE *ARGV_node;
68 extern NODE *ARGIND_node;
69 extern NODE *ERRNO_node;
70 extern NODE **fields_arr;
71 
72 static jmp_buf filebuf;		/* for do_nextfile() */
73 
74 /* do_nextfile --- implement gawk "next file" extension */
75 
76 void
77 do_nextfile()
78 {
79 	(void) nextfile(1);
80 	longjmp(filebuf, 1);
81 }
82 
83 static IOBUF *
84 nextfile(skipping)
85 int skipping;
86 {
87 	static int i = 1;
88 	static int files = 0;
89 	NODE *arg;
90 	int fd = INVALID_HANDLE;
91 	static IOBUF *curfile = NULL;
92 
93 	if (skipping) {
94 		if (curfile != NULL)
95 			iop_close(curfile);
96 		curfile = NULL;
97 		return NULL;
98 	}
99 	if (curfile != NULL) {
100 		if (curfile->cnt == EOF) {
101 			(void) iop_close(curfile);
102 			curfile = NULL;
103 		} else
104 			return curfile;
105 	}
106 	for (; i < (int) (ARGC_node->lnode->numbr); i++) {
107 		arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i));
108 		if (arg->stptr[0] == '\0')
109 			continue;
110 		arg->stptr[arg->stlen] = '\0';
111 		if (! do_unix) {
112 			ARGIND_node->var_value->numbr = i;
113 			ARGIND_node->var_value->flags = NUM|NUMBER;
114 		}
115 		if (!arg_assign(arg->stptr)) {
116 			files++;
117 			curfile = iop_open(arg->stptr, "r");
118 			if (curfile == NULL)
119 				fatal("cannot open file `%s' for reading (%s)",
120 					arg->stptr, strerror(errno));
121 				/* NOTREACHED */
122 			/* This is a kludge.  */
123 			unref(FILENAME_node->var_value);
124 			FILENAME_node->var_value =
125 				dupnode(arg);
126 			FNR = 0;
127 			i++;
128 			break;
129 		}
130 	}
131 	if (files == 0) {
132 		files++;
133 		/* no args. -- use stdin */
134 		/* FILENAME is init'ed to "-" */
135 		/* FNR is init'ed to 0 */
136 		curfile = iop_alloc(fileno(stdin));
137 	}
138 	return curfile;
139 }
140 
141 void
142 set_FNR()
143 {
144 	FNR = (int) FNR_node->var_value->numbr;
145 }
146 
147 void
148 set_NR()
149 {
150 	NR = (int) NR_node->var_value->numbr;
151 }
152 
153 /*
154  * This reads in a record from the input file
155  */
156 static int
157 inrec(iop)
158 IOBUF *iop;
159 {
160 	char *begin;
161 	register int cnt;
162 	int retval = 0;
163 
164 	cnt = get_a_record(&begin, iop, *RS, NULL);
165 	if (cnt == EOF) {
166 		cnt = 0;
167 		retval = 1;
168 	} else {
169 		    NR += 1;
170 		    FNR += 1;
171 	}
172 	set_record(begin, cnt, 1);
173 
174 	return retval;
175 }
176 
177 static int
178 iop_close(iop)
179 IOBUF *iop;
180 {
181 	int ret;
182 
183 	if (iop == NULL)
184 		return 0;
185 	errno = 0;
186 
187 #ifdef _CRAY
188 	/* Work around bug in UNICOS popen */
189 	if (iop->fd < 3)
190 		ret = 0;
191 	else
192 #endif
193 	/* save these for re-use; don't free the storage */
194 	if ((iop->flag & IOP_IS_INTERNAL) != 0) {
195 		iop->off = iop->buf;
196 		iop->end = iop->buf + strlen(iop->buf);
197 		iop->cnt = 0;
198 		iop->secsiz = 0;
199 		return 0;
200 	}
201 
202 	/* Don't close standard files or else crufty code elsewhere will lose */
203 	if (iop->fd == fileno(stdin) ||
204 	    iop->fd == fileno(stdout) ||
205 	    iop->fd == fileno(stderr))
206 		ret = 0;
207 	else
208 		ret = close(iop->fd);
209 	if (ret == -1)
210 		warning("close of fd %d failed (%s)", iop->fd, strerror(errno));
211 	if ((iop->flag & IOP_NO_FREE) == 0) {
212 		/*
213 		 * be careful -- $0 may still reference the buffer even though
214 		 * an explicit close is being done; in the future, maybe we
215 		 * can do this a bit better
216 		 */
217 		if (iop->buf) {
218 			if ((fields_arr[0]->stptr >= iop->buf)
219 			    && (fields_arr[0]->stptr < iop->end)) {
220 				NODE *t;
221 
222 				t = make_string(fields_arr[0]->stptr,
223 						fields_arr[0]->stlen);
224 				unref(fields_arr[0]);
225 				fields_arr [0] = t;
226 				reset_record ();
227 			}
228   			free(iop->buf);
229 		}
230 		free((char *)iop);
231 	}
232 	return ret == -1 ? 1 : 0;
233 }
234 
235 void
236 do_input()
237 {
238 	IOBUF *iop;
239 	extern int exiting;
240 
241 	if (setjmp(filebuf) != 0) {
242 	}
243 	while ((iop = nextfile(0)) != NULL) {
244 		if (inrec(iop) == 0)
245 			while (interpret(expression_value) && inrec(iop) == 0)
246 				;
247 		if (exiting)
248 			break;
249 	}
250 }
251 
252 /* Redirection for printf and print commands */
253 struct redirect *
254 redirect(tree, errflg)
255 NODE *tree;
256 int *errflg;
257 {
258 	register NODE *tmp;
259 	register struct redirect *rp;
260 	register char *str;
261 	int tflag = 0;
262 	int outflag = 0;
263 	char *direction = "to";
264 	char *mode;
265 	int fd;
266 	char *what = NULL;
267 
268 	switch (tree->type) {
269 	case Node_redirect_append:
270 		tflag = RED_APPEND;
271 		/* FALL THROUGH */
272 	case Node_redirect_output:
273 		outflag = (RED_FILE|RED_WRITE);
274 		tflag |= outflag;
275 		if (tree->type == Node_redirect_output)
276 			what = ">";
277 		else
278 			what = ">>";
279 		break;
280 	case Node_redirect_pipe:
281 		tflag = (RED_PIPE|RED_WRITE);
282 		what = "|";
283 		break;
284 	case Node_redirect_pipein:
285 		tflag = (RED_PIPE|RED_READ);
286 		what = "|";
287 		break;
288 	case Node_redirect_input:
289 		tflag = (RED_FILE|RED_READ);
290 		what = "<";
291 		break;
292 	default:
293 		fatal ("invalid tree type %d in redirect()", tree->type);
294 		break;
295 	}
296 	tmp = tree_eval(tree->subnode);
297 	if (do_lint && ! (tmp->flags & STR))
298 		warning("expression in `%s' redirection only has numeric value",
299 			what);
300 	tmp = force_string(tmp);
301 	str = tmp->stptr;
302 	if (str == NULL || *str == '\0')
303 		fatal("expression for `%s' redirection has null string value",
304 			what);
305 	if (do_lint
306 	    && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen)))
307 		warning("filename `%s' for `%s' redirection may be result of logical expression", str, what);
308 	for (rp = red_head; rp != NULL; rp = rp->next)
309 		if (strlen(rp->value) == tmp->stlen
310 		    && STREQN(rp->value, str, tmp->stlen)
311 		    && ((rp->flag & ~(RED_NOBUF|RED_EOF)) == tflag
312 			|| (outflag
313 			    && (rp->flag & (RED_FILE|RED_WRITE)) == outflag)))
314 			break;
315 	if (rp == NULL) {
316 		emalloc(rp, struct redirect *, sizeof(struct redirect),
317 			"redirect");
318 		emalloc(str, char *, tmp->stlen+1, "redirect");
319 		memcpy(str, tmp->stptr, tmp->stlen);
320 		str[tmp->stlen] = '\0';
321 		rp->value = str;
322 		rp->flag = tflag;
323 		rp->fp = NULL;
324 		rp->iop = NULL;
325 		rp->pid = 0;	/* unlikely that we're worried about init */
326 		rp->status = 0;
327 		/* maintain list in most-recently-used first order */
328 		if (red_head)
329 			red_head->prev = rp;
330 		rp->prev = NULL;
331 		rp->next = red_head;
332 		red_head = rp;
333 	}
334 	while (rp->fp == NULL && rp->iop == NULL) {
335 		if (rp->flag & RED_EOF)
336 			/* encountered EOF on file or pipe -- must be cleared
337 			 * by explicit close() before reading more
338 			 */
339 			return rp;
340 		mode = NULL;
341 		errno = 0;
342 		switch (tree->type) {
343 		case Node_redirect_output:
344 			mode = "w";
345 			if (rp->flag & RED_USED)
346 				mode = "a";
347 			break;
348 		case Node_redirect_append:
349 			mode = "a";
350 			break;
351 		case Node_redirect_pipe:
352 			if ((rp->fp = popen(str, "w")) == NULL)
353 				fatal("can't open pipe (\"%s\") for output (%s)",
354 					str, strerror(errno));
355 			rp->flag |= RED_NOBUF;
356 			break;
357 		case Node_redirect_pipein:
358 			direction = "from";
359 			if (gawk_popen(str, rp) == NULL)
360 				fatal("can't open pipe (\"%s\") for input (%s)",
361 					str, strerror(errno));
362 			break;
363 		case Node_redirect_input:
364 			direction = "from";
365 			rp->iop = iop_open(str, "r");
366 			break;
367 		default:
368 			cant_happen();
369 		}
370 		if (mode != NULL) {
371 			fd = devopen(str, mode);
372 			if (fd > INVALID_HANDLE) {
373 				if (fd == fileno(stdin))
374 					rp->fp = stdin;
375 				else if (fd == fileno(stdout))
376 					rp->fp = stdout;
377 				else if (fd == fileno(stderr))
378 					rp->fp = stderr;
379 				else
380 					rp->fp = fdopen(fd, mode);
381 				if (isatty(fd))
382 					rp->flag |= RED_NOBUF;
383 			}
384 		}
385 		if (rp->fp == NULL && rp->iop == NULL) {
386 			/* too many files open -- close one and try again */
387 			if (errno == EMFILE)
388 				close_one();
389 			else {
390 				/*
391 				 * Some other reason for failure.
392 				 *
393 				 * On redirection of input from a file,
394 				 * just return an error, so e.g. getline
395 				 * can return -1.  For output to file,
396 				 * complain. The shell will complain on
397 				 * a bad command to a pipe.
398 				 */
399 				*errflg = errno;
400 				if (tree->type == Node_redirect_output
401 				    || tree->type == Node_redirect_append)
402 					fatal("can't redirect %s `%s' (%s)",
403 					    direction, str, strerror(errno));
404 				else {
405 					free_temp(tmp);
406 					return NULL;
407 				}
408 			}
409 		}
410 	}
411 	free_temp(tmp);
412 	return rp;
413 }
414 
415 static void
416 close_one()
417 {
418 	register struct redirect *rp;
419 	register struct redirect *rplast = NULL;
420 
421 	/* go to end of list first, to pick up least recently used entry */
422 	for (rp = red_head; rp != NULL; rp = rp->next)
423 		rplast = rp;
424 	/* now work back up through the list */
425 	for (rp = rplast; rp != NULL; rp = rp->prev)
426 		if (rp->fp && (rp->flag & RED_FILE)) {
427 			rp->flag |= RED_USED;
428 			errno = 0;
429 			if (fclose(rp->fp))
430 				warning("close of \"%s\" failed (%s).",
431 					rp->value, strerror(errno));
432 			rp->fp = NULL;
433 			break;
434 		}
435 	if (rp == NULL)
436 		/* surely this is the only reason ??? */
437 		fatal("too many pipes or input files open");
438 }
439 
440 NODE *
441 do_close(tree)
442 NODE *tree;
443 {
444 	NODE *tmp;
445 	register struct redirect *rp;
446 
447 	tmp = force_string(tree_eval(tree->subnode));
448 	for (rp = red_head; rp != NULL; rp = rp->next) {
449 		if (strlen(rp->value) == tmp->stlen
450 		    && STREQN(rp->value, tmp->stptr, tmp->stlen))
451 			break;
452 	}
453 	free_temp(tmp);
454 	if (rp == NULL) /* no match */
455 		return tmp_number((AWKNUM) 0.0);
456 	fflush(stdout);	/* synchronize regular output */
457 	tmp = tmp_number((AWKNUM)close_redir(rp));
458 	rp = NULL;
459 	return tmp;
460 }
461 
462 static int
463 close_redir(rp)
464 register struct redirect *rp;
465 {
466 	int status = 0;
467 
468 	if (rp == NULL)
469 		return 0;
470 	if (rp->fp == stdout || rp->fp == stderr)
471 		return 0;
472 	errno = 0;
473 	if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE))
474 		status = pclose(rp->fp);
475 	else if (rp->fp)
476 		status = fclose(rp->fp);
477 	else if (rp->iop) {
478 		if (rp->flag & RED_PIPE)
479 			status = gawk_pclose(rp);
480 		else {
481 			status = iop_close(rp->iop);
482 			rp->iop = NULL;
483 		}
484 	}
485 	/* SVR4 awk checks and warns about status of close */
486 	if (status) {
487 		char *s = strerror(errno);
488 
489 		warning("failure status (%d) on %s close of \"%s\" (%s).",
490 			status,
491 			(rp->flag & RED_PIPE) ? "pipe" :
492 			"file", rp->value, s);
493 
494 		if (! do_unix) {
495 			/* set ERRNO too so that program can get at it */
496 			unref(ERRNO_node->var_value);
497 			ERRNO_node->var_value = make_string(s, strlen(s));
498 		}
499 	}
500 	if (rp->next)
501 		rp->next->prev = rp->prev;
502 	if (rp->prev)
503 		rp->prev->next = rp->next;
504 	else
505 		red_head = rp->next;
506 	free(rp->value);
507 	free((char *)rp);
508 	return status;
509 }
510 
511 int
512 flush_io ()
513 {
514 	register struct redirect *rp;
515 	int status = 0;
516 
517 	errno = 0;
518 	if (fflush(stdout)) {
519 		warning("error writing standard output (%s).", strerror(errno));
520 		status++;
521 	}
522 	if (fflush(stderr)) {
523 		warning("error writing standard error (%s).", strerror(errno));
524 		status++;
525 	}
526 	for (rp = red_head; rp != NULL; rp = rp->next)
527 		/* flush both files and pipes, what the heck */
528 		if ((rp->flag & RED_WRITE) && rp->fp != NULL) {
529 			if (fflush(rp->fp)) {
530 				warning("%s flush of \"%s\" failed (%s).",
531 				    (rp->flag  & RED_PIPE) ? "pipe" :
532 				    "file", rp->value, strerror(errno));
533 				status++;
534 			}
535 		}
536 	return status;
537 }
538 
539 int
540 close_io ()
541 {
542 	register struct redirect *rp;
543 	register struct redirect *next;
544 	int status = 0;
545 
546 	errno = 0;
547 	if (fclose(stdout)) {
548 		warning("error writing standard output (%s).", strerror(errno));
549 		status++;
550 	}
551 	if (fclose(stderr)) {
552 		warning("error writing standard error (%s).", strerror(errno));
553 		status++;
554 	}
555 	for (rp = red_head; rp != NULL; rp = next) {
556 		next = rp->next;
557 		if (close_redir(rp))
558 			status++;
559 		rp = NULL;
560 	}
561 	return status;
562 }
563 
564 /* str2mode --- convert a string mode to an integer mode */
565 
566 static int
567 str2mode(mode)
568 char *mode;
569 {
570 	int ret;
571 
572 	switch(mode[0]) {
573 	case 'r':
574 		ret = O_RDONLY;
575 		break;
576 
577 	case 'w':
578 		ret = O_WRONLY|O_CREAT|O_TRUNC;
579 		break;
580 
581 	case 'a':
582 		ret = O_WRONLY|O_APPEND|O_CREAT;
583 		break;
584 	default:
585 		cant_happen();
586 	}
587 	return ret;
588 }
589 
590 /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
591 
592 /*
593  * This separate version is still needed for output, since file and pipe
594  * output is done with stdio. iop_open() handles input with IOBUFs of
595  * more "special" files.  Those files are not handled here since it makes
596  * no sense to use them for output.
597  */
598 
599 int
600 devopen(name, mode)
601 char *name, *mode;
602 {
603 	int openfd = INVALID_HANDLE;
604 	char *cp, *ptr;
605 	int flag = 0;
606 	struct stat buf;
607 	extern double strtod();
608 
609 	flag = str2mode(mode);
610 
611 	if (do_unix)
612 		goto strictopen;
613 
614 #ifdef VMS
615 	if ((openfd = vms_devopen(name, flag)) >= 0)
616 		return openfd;
617 #endif /* VMS */
618 
619 	if (STREQ(name, "-"))
620 		openfd = fileno(stdin);
621 	else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) {
622 		cp = name + 5;
623 
624 		if (STREQ(cp, "stdin") && (flag & O_RDONLY) == O_RDONLY)
625 			openfd = fileno(stdin);
626 		else if (STREQ(cp, "stdout") && (flag & O_WRONLY) == O_WRONLY)
627 			openfd = fileno(stdout);
628 		else if (STREQ(cp, "stderr") && (flag & O_WRONLY) == O_WRONLY)
629 			openfd = fileno(stderr);
630 		else if (STREQN(cp, "fd/", 3)) {
631 			cp += 3;
632 			openfd = (int)strtod(cp, &ptr);
633 			if (openfd <= INVALID_HANDLE || ptr == cp)
634 				openfd = INVALID_HANDLE;
635 		}
636 	}
637 
638 strictopen:
639 	if (openfd == INVALID_HANDLE)
640 		openfd = open(name, flag, 0666);
641 	if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0)
642 		if (S_ISDIR(buf.st_mode))
643 			fatal("file `%s' is a directory", name);
644 	return openfd;
645 }
646 
647 
648 /* spec_setup --- setup an IOBUF for a special internal file */
649 
650 void
651 spec_setup(iop, len, allocate)
652 IOBUF *iop;
653 int len;
654 int allocate;
655 {
656 	char *cp;
657 
658 	if (allocate) {
659 		emalloc(cp, char *, len+2, "spec_setup");
660 		iop->buf = cp;
661 	} else {
662 		len = strlen(iop->buf);
663 		iop->buf[len++] = '\n';	/* get_a_record clobbered it */
664 		iop->buf[len] = '\0';	/* just in case */
665 	}
666 	iop->off = iop->buf;
667 	iop->cnt = 0;
668 	iop->secsiz = 0;
669 	iop->size = len;
670 	iop->end = iop->buf + len;
671 	iop->fd = -1;
672 	iop->flag = IOP_IS_INTERNAL;
673 }
674 
675 /* specfdopen --- open a fd special file */
676 
677 int
678 specfdopen(iop, name, mode)
679 IOBUF *iop;
680 char *name, *mode;
681 {
682 	int fd;
683 	IOBUF *tp;
684 
685 	fd = devopen(name, mode);
686 	if (fd == INVALID_HANDLE)
687 		return INVALID_HANDLE;
688 	tp = iop_alloc(fd);
689 	if (tp == NULL)
690 		return INVALID_HANDLE;
691 	*iop = *tp;
692 	iop->flag |= IOP_NO_FREE;
693 	free(tp);
694 	return 0;
695 }
696 
697 /* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */
698 
699 int
700 pidopen(iop, name, mode)
701 IOBUF *iop;
702 char *name, *mode;
703 {
704 	char tbuf[BUFSIZ];
705 	int i;
706 
707 	if (name[6] == 'g')
708 /* following #if will improve in 2.16 */
709 #if defined(__svr4__) || defined(i860) || defined(_AIX) || defined(BSD4_4)
710 		sprintf(tbuf, "%d\n", getpgrp());
711 #else
712 		sprintf(tbuf, "%d\n", getpgrp(getpid()));
713 #endif
714 	else if (name[6] == 'i')
715 		sprintf(tbuf, "%d\n", getpid());
716 	else
717 		sprintf(tbuf, "%d\n", getppid());
718 	i = strlen(tbuf);
719 	spec_setup(iop, i, 1);
720 	strcpy(iop->buf, tbuf);
721 	return 0;
722 }
723 
724 /* useropen --- "open" /dev/user */
725 
726 /*
727  * /dev/user creates a record as follows:
728  *	$1 = getuid()
729  *	$2 = geteuid()
730  *	$3 = getgid()
731  *	$4 = getegid()
732  * If multiple groups are supported, the $5 through $NF are the
733  * supplementary group set.
734  */
735 
736 int
737 useropen(iop, name, mode)
738 IOBUF *iop;
739 char *name, *mode;
740 {
741 	char tbuf[BUFSIZ], *cp;
742 	int i;
743 #if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
744 	int groupset[NGROUPS_MAX];
745 	int ngroups;
746 #endif
747 
748 	sprintf(tbuf, "%d %d %d %d", getuid(), geteuid(), getgid(), getegid());
749 
750 	cp = tbuf + strlen(tbuf);
751 #if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
752 	ngroups = getgroups(NGROUPS_MAX, groupset);
753 	if (ngroups == -1)
754 		fatal("could not find groups: %s", strerror(errno));
755 
756 	for (i = 0; i < ngroups; i++) {
757 		*cp++ = ' ';
758 		sprintf(cp, "%d", groupset[i]);
759 		cp += strlen(cp);
760 	}
761 #endif
762 	*cp++ = '\n';
763 	*cp++ = '\0';
764 
765 
766 	i = strlen(tbuf);
767 	spec_setup(iop, i, 1);
768 	strcpy(iop->buf, tbuf);
769 	return 0;
770 }
771 
772 /* iop_open --- handle special and regular files for input */
773 
774 static IOBUF *
775 iop_open(name, mode)
776 char *name, *mode;
777 {
778 	int openfd = INVALID_HANDLE;
779 	char *cp, *ptr;
780 	int flag = 0;
781 	int i;
782 	struct stat buf;
783 	IOBUF *iop;
784 	static struct internal {
785 		char *name;
786 		int compare;
787 		int (*fp)();
788 		IOBUF iob;
789 	} table[] = {
790 		{ "/dev/fd/",		8,	specfdopen },
791 		{ "/dev/stdin",		10,	specfdopen },
792 		{ "/dev/stdout",	11,	specfdopen },
793 		{ "/dev/stderr",	11,	specfdopen },
794 		{ "/dev/pid",		8,	pidopen },
795 		{ "/dev/ppid",		9,	pidopen },
796 		{ "/dev/pgrpid",	11,	pidopen },
797 		{ "/dev/user",		9,	useropen },
798 	};
799 	int devcount = sizeof(table) / sizeof(table[0]);
800 
801 	flag = str2mode(mode);
802 
803 	if (do_unix)
804 		goto strictopen;
805 
806 	if (STREQ(name, "-"))
807 		openfd = fileno(stdin);
808 	else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) {
809 		int i;
810 
811 		for (i = 0; i < devcount; i++) {
812 			if (STREQN(name, table[i].name, table[i].compare)) {
813 				IOBUF *iop = & table[i].iob;
814 
815 				if (iop->buf != NULL) {
816 					spec_setup(iop, 0, 0);
817 					return iop;
818 				} else if ((*table[i].fp)(iop, name, mode) == 0)
819 					return iop;
820 				else {
821 					warning("could not open %s, mode `%s'",
822 						name, mode);
823 					return NULL;
824 				}
825 			}
826 		}
827 	}
828 
829 strictopen:
830 	if (openfd == INVALID_HANDLE)
831 		openfd = open(name, flag, 0666);
832 	if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0)
833 		if ((buf.st_mode & S_IFMT) == S_IFDIR)
834 			fatal("file `%s' is a directory", name);
835 	iop = iop_alloc(openfd);
836 	return iop;
837 }
838 
839 #ifndef PIPES_SIMULATED
840 	/* real pipes */
841 static int
842 wait_any(interesting)
843 int interesting;	/* pid of interest, if any */
844 {
845 	SIGTYPE (*hstat)(), (*istat)(), (*qstat)();
846 	int pid;
847 	int status = 0;
848 	struct redirect *redp;
849 	extern int errno;
850 
851 	hstat = signal(SIGHUP, SIG_IGN);
852 	istat = signal(SIGINT, SIG_IGN);
853 	qstat = signal(SIGQUIT, SIG_IGN);
854 	for (;;) {
855 #ifdef NeXT
856 		pid = wait((union wait *)&status);
857 #else
858 		pid = wait(&status);
859 #endif /* NeXT */
860 		if (interesting && pid == interesting) {
861 			break;
862 		} else if (pid != -1) {
863 			for (redp = red_head; redp != NULL; redp = redp->next)
864 				if (pid == redp->pid) {
865 					redp->pid = -1;
866 					redp->status = status;
867 					if (redp->fp) {
868 						pclose(redp->fp);
869 						redp->fp = 0;
870 					}
871 					if (redp->iop) {
872 						(void) iop_close(redp->iop);
873 						redp->iop = 0;
874 					}
875 					break;
876 				}
877 		}
878 		if (pid == -1 && errno == ECHILD)
879 			break;
880 	}
881 	signal(SIGHUP, hstat);
882 	signal(SIGINT, istat);
883 	signal(SIGQUIT, qstat);
884 	return(status);
885 }
886 
887 static IOBUF *
888 gawk_popen(cmd, rp)
889 char *cmd;
890 struct redirect *rp;
891 {
892 	int p[2];
893 	register int pid;
894 
895 	/* used to wait for any children to synchronize input and output,
896 	 * but this could cause gawk to hang when it is started in a pipeline
897 	 * and thus has a child process feeding it input (shell dependant)
898 	 */
899 	/*(void) wait_any(0);*/	/* wait for outstanding processes */
900 
901 	if (pipe(p) < 0)
902 		fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno));
903 	if ((pid = fork()) == 0) {
904 		if (close(1) == -1)
905 			fatal("close of stdout in child failed (%s)",
906 				strerror(errno));
907 		if (dup(p[1]) != 1)
908 			fatal("dup of pipe failed (%s)", strerror(errno));
909 		if (close(p[0]) == -1 || close(p[1]) == -1)
910 			fatal("close of pipe failed (%s)", strerror(errno));
911 		if (close(0) == -1)
912 			fatal("close of stdin in child failed (%s)",
913 				strerror(errno));
914 		execl("/bin/sh", "sh", "-c", cmd, 0);
915 		_exit(127);
916 	}
917 	if (pid == -1)
918 		fatal("cannot fork for \"%s\" (%s)", cmd, strerror(errno));
919 	rp->pid = pid;
920 	if (close(p[1]) == -1)
921 		fatal("close of pipe failed (%s)", strerror(errno));
922 	return (rp->iop = iop_alloc(p[0]));
923 }
924 
925 static int
926 gawk_pclose(rp)
927 struct redirect *rp;
928 {
929 	(void) iop_close(rp->iop);
930 	rp->iop = NULL;
931 
932 	/* process previously found, return stored status */
933 	if (rp->pid == -1)
934 		return (rp->status >> 8) & 0xFF;
935 	rp->status = wait_any(rp->pid);
936 	rp->pid = -1;
937 	return (rp->status >> 8) & 0xFF;
938 }
939 
940 #else	/* PIPES_SIMULATED */
941 	/* use temporary file rather than pipe */
942 
943 #ifdef VMS
944 static IOBUF *
945 gawk_popen(cmd, rp)
946 char *cmd;
947 struct redirect *rp;
948 {
949 	FILE *current;
950 
951 	if ((current = popen(cmd, "r")) == NULL)
952 		return NULL;
953 	return (rp->iop = iop_alloc(fileno(current)));
954 }
955 
956 static int
957 gawk_pclose(rp)
958 struct redirect *rp;
959 {
960 	int rval, aval, fd = rp->iop->fd;
961 	FILE *kludge = fdopen(fd, "r"); /* pclose needs FILE* w/ right fileno */
962 
963 	rp->iop->fd = dup(fd);	  /* kludge to allow close() + pclose() */
964 	rval = iop_close(rp->iop);
965 	rp->iop = NULL;
966 	aval = pclose(kludge);
967 	return (rval < 0 ? rval : aval);
968 }
969 #else	/* VMS */
970 
971 static
972 struct {
973 	char *command;
974 	char *name;
975 } pipes[_NFILE];
976 
977 static IOBUF *
978 gawk_popen(cmd, rp)
979 char *cmd;
980 struct redirect *rp;
981 {
982 	extern char *strdup(const char *);
983 	int current;
984 	char *name;
985 	static char cmdbuf[256];
986 
987 	/* get a name to use.  */
988 	if ((name = tempnam(".", "pip")) == NULL)
989 		return NULL;
990 	sprintf(cmdbuf,"%s > %s", cmd, name);
991 	system(cmdbuf);
992 	if ((current = open(name,O_RDONLY)) == INVALID_HANDLE)
993 		return NULL;
994 	pipes[current].name = name;
995 	pipes[current].command = strdup(cmd);
996 	rp->iop = iop_alloc(current);
997 	return (rp->iop = iop_alloc(current));
998 }
999 
1000 static int
1001 gawk_pclose(rp)
1002 struct redirect *rp;
1003 {
1004 	int cur = rp->iop->fd;
1005 	int rval;
1006 
1007 	rval = iop_close(rp->iop);
1008 	rp->iop = NULL;
1009 
1010 	/* check for an open file  */
1011 	if (pipes[cur].name == NULL)
1012 		return -1;
1013 	unlink(pipes[cur].name);
1014 	free(pipes[cur].name);
1015 	pipes[cur].name = NULL;
1016 	free(pipes[cur].command);
1017 	return rval;
1018 }
1019 #endif	/* VMS */
1020 
1021 #endif	/* PIPES_SIMULATED */
1022 
1023 NODE *
1024 do_getline(tree)
1025 NODE *tree;
1026 {
1027 	struct redirect *rp = NULL;
1028 	IOBUF *iop;
1029 	int cnt = EOF;
1030 	char *s = NULL;
1031 	int errcode;
1032 
1033 	while (cnt == EOF) {
1034 		if (tree->rnode == NULL) {	 /* no redirection */
1035 			iop = nextfile(0);
1036 			if (iop == NULL)		/* end of input */
1037 				return tmp_number((AWKNUM) 0.0);
1038 		} else {
1039 			int redir_error = 0;
1040 
1041 			rp = redirect(tree->rnode, &redir_error);
1042 			if (rp == NULL && redir_error) { /* failed redirect */
1043 				if (! do_unix) {
1044 					char *s = strerror(redir_error);
1045 
1046 					unref(ERRNO_node->var_value);
1047 					ERRNO_node->var_value =
1048 						make_string(s, strlen(s));
1049 				}
1050 				return tmp_number((AWKNUM) -1.0);
1051 			}
1052 			iop = rp->iop;
1053 			if (iop == NULL)		/* end of input */
1054 				return tmp_number((AWKNUM) 0.0);
1055 		}
1056 		errcode = 0;
1057 		cnt = get_a_record(&s, iop, *RS, & errcode);
1058 		if (! do_unix && errcode != 0) {
1059 			char *s = strerror(errcode);
1060 
1061 			unref(ERRNO_node->var_value);
1062 			ERRNO_node->var_value = make_string(s, strlen(s));
1063 			return tmp_number((AWKNUM) -1.0);
1064 		}
1065 		if (cnt == EOF) {
1066 			if (rp) {
1067 				/*
1068 				 * Don't do iop_close() here if we are
1069 				 * reading from a pipe; otherwise
1070 				 * gawk_pclose will not be called.
1071 				 */
1072 				if (!(rp->flag & RED_PIPE)) {
1073 					(void) iop_close(iop);
1074 					rp->iop = NULL;
1075 				}
1076 				rp->flag |= RED_EOF;	/* sticky EOF */
1077 				return tmp_number((AWKNUM) 0.0);
1078 			} else
1079 				continue;	/* try another file */
1080 		}
1081 		if (!rp) {
1082 			NR += 1;
1083 			FNR += 1;
1084 		}
1085 		if (tree->lnode == NULL)	/* no optional var. */
1086 			set_record(s, cnt, 1);
1087 		else {			/* assignment to variable */
1088 			Func_ptr after_assign = NULL;
1089 			NODE **lhs;
1090 
1091 			lhs = get_lhs(tree->lnode, &after_assign);
1092 			unref(*lhs);
1093 			*lhs = make_string(s, strlen(s));
1094 			(*lhs)->flags |= MAYBE_NUM;
1095 			/* we may have to regenerate $0 here! */
1096 			if (after_assign)
1097 				(*after_assign)();
1098 		}
1099 	}
1100 	return tmp_number((AWKNUM) 1.0);
1101 }
1102 
1103 int
1104 pathopen (file)
1105 char *file;
1106 {
1107 	int fd = do_pathopen(file);
1108 
1109 #ifdef DEFAULT_FILETYPE
1110 	if (! do_unix && fd <= INVALID_HANDLE) {
1111 		char *file_awk;
1112 		int save = errno;
1113 #ifdef VMS
1114 		int vms_save = vaxc$errno;
1115 #endif
1116 
1117 		/* append ".awk" and try again */
1118 		emalloc(file_awk, char *, strlen(file) +
1119 			sizeof(DEFAULT_FILETYPE) + 1, "pathopen");
1120 		sprintf(file_awk, "%s%s", file, DEFAULT_FILETYPE);
1121 		fd = do_pathopen(file_awk);
1122 		free(file_awk);
1123 		if (fd <= INVALID_HANDLE) {
1124 			errno = save;
1125 #ifdef VMS
1126 			vaxc$errno = vms_save;
1127 #endif
1128 		}
1129 	}
1130 #endif	/*DEFAULT_FILETYPE*/
1131 
1132 	return fd;
1133 }
1134 
1135 static int
1136 do_pathopen (file)
1137 char *file;
1138 {
1139 	static char *savepath = DEFPATH;	/* defined in config.h */
1140 	static int first = 1;
1141 	char *awkpath, *cp;
1142 	char trypath[BUFSIZ];
1143 	int fd;
1144 
1145 	if (STREQ(file, "-"))
1146 		return (0);
1147 
1148 	if (do_unix)
1149 		return (devopen(file, "r"));
1150 
1151 	if (first) {
1152 		first = 0;
1153 		if ((awkpath = getenv ("AWKPATH")) != NULL && *awkpath)
1154 			savepath = awkpath;	/* used for restarting */
1155 	}
1156 	awkpath = savepath;
1157 
1158 	/* some kind of path name, no search */
1159 #ifdef VMS	/* (strchr not equal implies either or both not NULL) */
1160 	if (strchr(file, ':') != strchr(file, ']')
1161 	 || strchr(file, '>') != strchr(file, '/'))
1162 #else /*!VMS*/
1163 #ifdef MSDOS
1164 	if (strchr(file, '/') != strchr(file, '\\')
1165 	 || strchr(file, ':') != NULL)
1166 #else
1167 	if (strchr(file, '/') != NULL)
1168 #endif	/*MSDOS*/
1169 #endif	/*VMS*/
1170 		return (devopen(file, "r"));
1171 
1172 	do {
1173 		trypath[0] = '\0';
1174 		/* this should take into account limits on size of trypath */
1175 		for (cp = trypath; *awkpath && *awkpath != ENVSEP; )
1176 			*cp++ = *awkpath++;
1177 
1178 		if (cp != trypath) {	/* nun-null element in path */
1179 			/* add directory punctuation only if needed */
1180 #ifdef VMS
1181 			if (strchr(":]>/", *(cp-1)) == NULL)
1182 #else
1183 #ifdef MSDOS
1184 			if (strchr(":\\/", *(cp-1)) == NULL)
1185 #else
1186 			if (*(cp-1) != '/')
1187 #endif
1188 #endif
1189 				*cp++ = '/';
1190 			/* append filename */
1191 			strcpy (cp, file);
1192 		} else
1193 			strcpy (trypath, file);
1194 		if ((fd = devopen(trypath, "r")) >= 0)
1195 			return (fd);
1196 
1197 		/* no luck, keep going */
1198 		if(*awkpath == ENVSEP && awkpath[1] != '\0')
1199 			awkpath++;	/* skip colon */
1200 	} while (*awkpath);
1201 	/*
1202 	 * You might have one of the awk
1203 	 * paths defined, WITHOUT the current working directory in it.
1204 	 * Therefore try to open the file in the current directory.
1205 	 */
1206 	return (devopen(file, "r"));
1207 }
1208