1/*
2 * io.c --- routines for dealing with input and output and records
3 */
4
5/*
6 * Copyright (C) 1986, 1988, 1989, 1991-2003 the Free Software Foundation, Inc.
7 *
8 * This file is part of GAWK, the GNU implementation of the
9 * AWK Programming 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 this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
24 */
25
26#include "awk.h"
27
28#ifdef HAVE_SYS_PARAM_H
29#undef RE_DUP_MAX	/* avoid spurious conflict w/regex.h */
30#include <sys/param.h>
31#endif /* HAVE_SYS_PARAM_H */
32
33#ifndef O_RDONLY
34#include <fcntl.h>
35#endif
36#ifndef O_ACCMODE
37#define O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)
38#endif
39
40#ifdef HAVE_TERMIOS_H
41#include <termios.h>
42#endif
43#ifdef HAVE_STROPTS_H
44#include <stropts.h>
45#endif
46
47#ifdef HAVE_SOCKETS
48#ifdef HAVE_SYS_SOCKET_H
49#include <sys/socket.h>
50#else
51#include <socket.h>
52#endif /* HAVE_SYS_SOCKET_H */
53#ifdef HAVE_NETINET_IN_H
54#include <netinet/in.h>
55#else
56#include <in.h>
57#endif /* HAVE_NETINET_IN_H */
58#ifdef HAVE_NETDB_H
59#include <netdb.h>
60#endif /* HAVE_NETDB_H */
61#endif /* HAVE_SOCKETS */
62
63#ifdef __EMX__
64#include <process.h>
65#endif
66
67#ifndef ENFILE
68#define ENFILE EMFILE
69#endif
70
71extern int MRL;
72
73#ifdef HAVE_SOCKETS
74enum inet_prot { INET_NONE, INET_TCP, INET_UDP, INET_RAW };
75
76#ifndef SHUT_RD
77#define SHUT_RD		0
78#endif
79
80#ifndef SHUT_WR
81#define SHUT_WR		1
82#endif
83
84#ifndef SHUT_RDWR
85#define SHUT_RDWR	2
86#endif
87
88#endif /* HAVE_SOCKETS */
89
90#ifdef atarist
91#include <stddef.h>
92#endif
93
94#if defined(GAWK_AIX)
95#undef TANDEM	/* AIX defines this in one of its header files */
96#undef MSDOS	/* For good measure, */
97#undef WIN32	/* yes, I'm paranoid */
98#endif
99
100#if defined(MSDOS) || defined(WIN32) || defined(TANDEM)
101#define PIPES_SIMULATED
102#endif
103
104typedef enum { CLOSE_ALL, CLOSE_TO, CLOSE_FROM } two_way_close_type;
105
106/* Several macros make the code a bit clearer:                              */
107/*                                                                          */
108/*                                                                          */
109/* <defines and enums>=                                                     */
110#define at_eof(iop)     ((iop->flag & IOP_AT_EOF) != 0)
111#define has_no_data(iop)        (iop->dataend == NULL)
112#define no_data_left(iop)	(iop->off >= iop->dataend)
113/* The key point to the design is to split out the code that searches through */
114/* a buffer looking for the record and the terminator into separate routines, */
115/* with a higher-level routine doing the reading of data and buffer management. */
116/* This makes the code easier to manage; the buffering code is the same independent */
117/* of how we find a record.  Communication is via the return value:         */
118/*                                                                          */
119/*                                                                          */
120/* <defines and enums>=                                                     */
121typedef enum recvalues {
122        REC_OK,         /* record and terminator found, recmatch struct filled in */
123        NOTERM,         /* no terminator found, give me more input data */
124        TERMATEND,      /* found terminator at end of buffer */
125        TERMNEAREND,    /* found terminator close to end of buffer, for RE might be bigger */
126} RECVALUE;
127/* Between calls to a scanning routine, the state is stored in              */
128/* an [[enum scanstate]] variable.  Not all states apply to all             */
129/* variants, but the higher code doesn't really care.                       */
130/*                                                                          */
131/*                                                                          */
132/* <defines and enums>=                                                     */
133typedef enum scanstate {
134        NOSTATE,        /* scanning not started yet (all) */
135        INLEADER,       /* skipping leading data (RS = "") */
136        INDATA,         /* in body of record (all) */
137        INTERM,         /* scanning terminator (RS = "", RS = regexp) */
138} SCANSTATE;
139/* When a record is seen ([[REC_OK]] or [[TERMATEND]]), the following       */
140/* structure is filled in.                                                  */
141/*                                                                          */
142/*                                                                          */
143/* <recmatch>=                                                              */
144struct recmatch {
145        char *start;    /* record start */
146        size_t len;     /* length of record */
147        char *rt_start; /* start of terminator */
148        size_t rt_len;  /* length of terminator */
149};
150
151static IOBUF *nextfile P((int skipping));
152static int inrec P((IOBUF *iop));
153static int iop_close P((IOBUF *iop));
154struct redirect *redirect P((NODE *tree, int *errflg));
155static void close_one P((void));
156static int close_redir P((struct redirect *rp, int exitwarn, two_way_close_type how));
157#ifndef PIPES_SIMULATED
158static int wait_any P((int interesting));
159#endif
160static IOBUF *gawk_popen P((const char *cmd, struct redirect *rp));
161static IOBUF *iop_open P((const char *file, const char *how, IOBUF *buf));
162static IOBUF *iop_alloc P((int fd, const char *name, IOBUF *buf));
163static int gawk_pclose P((struct redirect *rp));
164static int do_pathopen P((const char *file));
165static int str2mode P((const char *mode));
166static void spec_setup P((IOBUF *iop, int len, int allocate));
167static int specfdopen P((IOBUF *iop, const char *name, const char *mode));
168static int pidopen P((IOBUF *iop, const char *name, const char *mode));
169static int useropen P((IOBUF *iop, const char *name, const char *mode));
170static int two_way_open P((const char *str, struct redirect *rp));
171static int pty_vs_pipe P((const char *command));
172
173static RECVALUE rs1scan P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state));
174static RECVALUE rsnullscan P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state));
175static RECVALUE rsrescan P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state));
176
177static RECVALUE (*matchrec) P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state)) = rs1scan;
178
179static int get_a_record P((char **out, IOBUF *iop, int *errcode));
180
181#if defined(HAVE_POPEN_H)
182#include "popen.h"
183#endif
184
185static struct redirect *red_head = NULL;
186static NODE *RS;
187static Regexp *RS_re_yes_case;
188static Regexp *RS_re_no_case;
189static Regexp *RS_regexp;
190
191int RS_is_null;
192
193extern int output_is_tty;
194extern NODE *ARGC_node;
195extern NODE *ARGV_node;
196extern NODE *ARGIND_node;
197extern NODE *ERRNO_node;
198extern NODE **fields_arr;
199
200static jmp_buf filebuf;		/* for do_nextfile() */
201
202#if defined(MSDOS) || defined(OS2) || defined(WIN32) \
203 || defined(__EMX__) || defined(__CYGWIN__)
204static const char *
205binmode(const char *mode)
206{
207	switch (mode[0]) {
208	case 'r':
209		if ((BINMODE & 1) != 0)
210			mode = "rb";
211		break;
212	case 'w':
213	case 'a':
214		if ((BINMODE & 2) != 0)
215			mode = (mode[0] == 'w' ? "wb" : "ab");
216		break;
217	}
218	return mode;
219}
220#else
221#define binmode(mode)	(mode)
222#endif
223
224#ifdef VMS
225/* File pointers have an extra level of indirection, and there are cases where
226   `stdin' can be null.  That can crash gawk if fileno() is used as-is.  */
227static int vmsrtl_fileno P((FILE *));
228static int vmsrtl_fileno(fp) FILE *fp; { return fileno(fp); }
229#undef fileno
230#define fileno(FP) (((FP) && *(FP)) ? vmsrtl_fileno(FP) : -1)
231#endif	/* VMS */
232
233/* do_nextfile --- implement gawk "nextfile" extension */
234
235void
236do_nextfile()
237{
238	(void) nextfile(TRUE);
239	longjmp(filebuf, 1);
240}
241
242/* nextfile --- move to the next input data file */
243
244static IOBUF *
245nextfile(int skipping)
246{
247	static long i = 1;
248	static int files = 0;
249	NODE *arg;
250	static IOBUF *curfile = NULL;
251	static IOBUF mybuf;
252	const char *fname;
253
254	if (skipping) {
255		if (curfile != NULL)
256			iop_close(curfile);
257		curfile = NULL;
258		return NULL;
259	}
260	if (curfile != NULL) {
261		if (at_eof(curfile)) {
262			(void) iop_close(curfile);
263			curfile = NULL;
264		} else
265			return curfile;
266	}
267	for (; i < (long) (ARGC_node->lnode->numbr); i++) {
268		arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i), FALSE);
269		if (arg->stlen == 0)
270			continue;
271		arg->stptr[arg->stlen] = '\0';
272		if (! do_traditional) {
273			unref(ARGIND_node->var_value);
274			ARGIND_node->var_value = make_number((AWKNUM) i);
275		}
276		if (! arg_assign(arg->stptr, FALSE)) {
277			files++;
278			fname = arg->stptr;
279			curfile = iop_open(fname, binmode("r"), &mybuf);
280			if (curfile == NULL)
281				goto give_up;
282			curfile->flag |= IOP_NOFREE_OBJ;
283			/* This is a kludge.  */
284			unref(FILENAME_node->var_value);
285			FILENAME_node->var_value = dupnode(arg);
286			FNR = 0;
287			i++;
288			break;
289		}
290	}
291	if (files == 0) {
292		files++;
293		/* no args. -- use stdin */
294		/* FNR is init'ed to 0 */
295		FILENAME_node->var_value = make_string("-", 1);
296		fname = "-";
297		curfile = iop_open(fname, binmode("r"), &mybuf);
298		if (curfile == NULL)
299			goto give_up;
300		curfile->flag |= IOP_NOFREE_OBJ;
301	}
302	return curfile;
303
304 give_up:
305	fatal(_("cannot open file `%s' for reading (%s)"),
306		fname, strerror(errno));
307	/* NOTREACHED */
308	return 0;
309}
310
311/* set_FNR --- update internal FNR from awk variable */
312
313void
314set_FNR()
315{
316	FNR = (long) FNR_node->var_value->numbr;
317}
318
319/* set_NR --- update internal NR from awk variable */
320
321void
322set_NR()
323{
324	NR = (long) NR_node->var_value->numbr;
325}
326
327/* inrec --- This reads in a record from the input file */
328
329static int
330inrec(IOBUF *iop)
331{
332	char *begin;
333	register int cnt;
334	int retval = 0;
335
336        if (at_eof(iop) && no_data_left(iop))
337		cnt = EOF;
338	else if ((iop->flag & IOP_CLOSED) != 0)
339		cnt = EOF;
340	else
341		cnt = get_a_record(&begin, iop, NULL);
342
343	if (cnt == EOF) {
344		cnt = 0;
345		retval = 1;
346	} else {
347		NR += 1;
348		FNR += 1;
349		set_record(begin, cnt);
350	}
351
352	return retval;
353}
354
355/* iop_close --- close an open IOP */
356
357static int
358iop_close(IOBUF *iop)
359{
360	int ret;
361
362	if (iop == NULL)
363		return 0;
364	errno = 0;
365
366	iop->flag &= ~IOP_AT_EOF;
367	iop->flag |= IOP_CLOSED;	/* there may be dangling pointers */
368	iop->dataend = NULL;
369#ifdef _CRAY
370	/* Work around bug in UNICOS popen */
371	if (iop->fd < 3)
372		ret = 0;
373	else
374#endif
375	/* save these for re-use; don't free the storage */
376	if ((iop->flag & IOP_IS_INTERNAL) != 0) {
377		iop->off = iop->buf;
378		iop->end = iop->buf + strlen(iop->buf);
379		iop->count = 0;
380		return 0;
381	}
382
383	/* Don't close standard files or else crufty code elsewhere will lose */
384	if (iop->fd == fileno(stdin)
385	    || iop->fd == fileno(stdout)
386	    || iop->fd == fileno(stderr))
387		ret = 0;
388	else
389		ret = close(iop->fd);
390
391	if (ret == -1)
392		warning(_("close of fd %d (`%s') failed (%s)"), iop->fd,
393				iop->name, strerror(errno));
394	if ((iop->flag & IOP_NO_FREE) == 0) {
395		/*
396		 * Be careful -- $0 may still reference the buffer even though
397		 * an explicit close is being done; in the future, maybe we
398		 * can do this a bit better.
399		 */
400		if (iop->buf) {
401			if ((fields_arr[0]->stptr >= iop->buf)
402			    && (fields_arr[0]->stptr < (iop->buf + iop->size))) {
403				NODE *t;
404
405				t = make_string(fields_arr[0]->stptr,
406						fields_arr[0]->stlen);
407				unref(fields_arr[0]);
408				fields_arr[0] = t;
409				/*
410				 * 1/27/2003: This used to be here:
411				 *
412				 * reset_record();
413				 *
414				 * Don't do that; reset_record() throws away all fields,
415				 * saves FS etc.  We just need to make sure memory isn't
416				 * corrupted and that references to $0 and fields work.
417				 */
418			}
419			free(iop->buf);
420			iop->buf = NULL;
421		}
422		if ((iop->flag & IOP_NOFREE_OBJ) == 0)
423			free((char *) iop);
424	}
425	return ret == -1 ? 1 : 0;
426}
427
428/* do_input --- the main input processing loop */
429
430void
431do_input()
432{
433	IOBUF *iop;
434	extern int exiting;
435	int rval1, rval2, rval3;
436
437	(void) setjmp(filebuf);	/* for `nextfile' */
438
439	while ((iop = nextfile(FALSE)) != NULL) {
440		/*
441		 * This was:
442		if (inrec(iop) == 0)
443			while (interpret(expression_value) && inrec(iop) == 0)
444				continue;
445		 * Now expand it out for ease of debugging.
446		 */
447		rval1 = inrec(iop);
448		if (rval1 == 0) {
449			for (;;) {
450				rval2 = rval3 = -1;	/* for debugging */
451				rval2 = interpret(expression_value);
452				if (rval2 != 0)
453					rval3 = inrec(iop);
454				if (rval2 == 0 || rval3 != 0)
455					break;
456			}
457		}
458		if (exiting)
459			break;
460	}
461}
462
463/* redflags2str --- turn redirection flags into a string, for debugging */
464
465const char *
466redflags2str(int flags)
467{
468	static const struct flagtab redtab[] = {
469		{ RED_FILE,	"RED_FILE" },
470		{ RED_PIPE,	"RED_PIPE" },
471		{ RED_READ,	"RED_READ" },
472		{ RED_WRITE,	"RED_WRITE" },
473		{ RED_APPEND,	"RED_APPEND" },
474		{ RED_NOBUF,	"RED_NOBUF" },
475		{ RED_EOF,	"RED_EOF" },
476		{ RED_TWOWAY,	"RED_TWOWAY" },
477		{ RED_PTY,	"RED_PTY" },
478		{ RED_SOCKET,	"RED_SOCKET" },
479		{ RED_TCP,	"RED_TCP" },
480		{ 0, NULL }
481	};
482
483	return genflags2str(flags, redtab);
484}
485
486/* redirect --- Redirection for printf and print commands */
487
488struct redirect *
489redirect(NODE *tree, int *errflg)
490{
491	register NODE *tmp;
492	register struct redirect *rp;
493	register char *str;
494	int tflag = 0;
495	int outflag = 0;
496	const char *direction = "to";
497	const char *mode;
498	int fd;
499	const char *what = NULL;
500
501	switch (tree->type) {
502	case Node_redirect_append:
503		tflag = RED_APPEND;
504		/* FALL THROUGH */
505	case Node_redirect_output:
506		outflag = (RED_FILE|RED_WRITE);
507		tflag |= outflag;
508		if (tree->type == Node_redirect_output)
509			what = ">";
510		else
511			what = ">>";
512		break;
513	case Node_redirect_pipe:
514		tflag = (RED_PIPE|RED_WRITE);
515		what = "|";
516		break;
517	case Node_redirect_pipein:
518		tflag = (RED_PIPE|RED_READ);
519		what = "|";
520		break;
521	case Node_redirect_input:
522		tflag = (RED_FILE|RED_READ);
523		what = "<";
524		break;
525	case Node_redirect_twoway:
526		tflag = (RED_READ|RED_WRITE|RED_TWOWAY);
527		what = "|&";
528		break;
529	default:
530		fatal(_("invalid tree type %s in redirect()"),
531					nodetype2str(tree->type));
532		break;
533	}
534	tmp = tree_eval(tree->subnode);
535	if (do_lint && (tmp->flags & STRCUR) == 0)
536		lintwarn(_("expression in `%s' redirection only has numeric value"),
537			what);
538	tmp = force_string(tmp);
539	str = tmp->stptr;
540
541	if (str == NULL || *str == '\0')
542		fatal(_("expression for `%s' redirection has null string value"),
543			what);
544
545	if (do_lint
546	    && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen)))
547		lintwarn(_("filename `%s' for `%s' redirection may be result of logical expression"), str, what);
548
549#ifdef HAVE_SOCKETS
550	if (STREQN(str, "/inet/", 6)) {
551		tflag |= RED_SOCKET;
552		if (STREQN(str + 6, "tcp/", 4))
553			tflag |= RED_TCP;	/* use shutdown when closing */
554	}
555#endif /* HAVE_SOCKETS */
556
557	for (rp = red_head; rp != NULL; rp = rp->next) {
558		if (strlen(rp->value) == tmp->stlen
559		    && STREQN(rp->value, str, tmp->stlen)
560		    && ((rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY)) == tflag
561			|| (outflag != 0
562			    && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) {
563
564			int rpflag = (rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY));
565			int newflag = (tflag & ~(RED_NOBUF|RED_EOF|RED_PTY));
566
567			if (do_lint && rpflag != newflag)
568				lintwarn(
569		_("unnecessary mixing of `>' and `>>' for file `%.*s'"),
570					tmp->stlen, rp->value);
571
572			break;
573		}
574	}
575
576	if (rp == NULL) {
577		emalloc(rp, struct redirect *, sizeof(struct redirect),
578			"redirect");
579		emalloc(str, char *, tmp->stlen+1, "redirect");
580		memcpy(str, tmp->stptr, tmp->stlen);
581		str[tmp->stlen] = '\0';
582		rp->value = str;
583		rp->flag = tflag;
584		rp->fp = NULL;
585		rp->iop = NULL;
586		rp->pid = 0;	/* unlikely that we're worried about init */
587		rp->status = 0;
588		/* maintain list in most-recently-used first order */
589		if (red_head != NULL)
590			red_head->prev = rp;
591		rp->prev = NULL;
592		rp->next = red_head;
593		red_head = rp;
594	} else
595		str = rp->value;	/* get \0 terminated string */
596
597	while (rp->fp == NULL && rp->iop == NULL) {
598		if (rp->flag & RED_EOF)
599			/*
600			 * encountered EOF on file or pipe -- must be cleared
601			 * by explicit close() before reading more
602			 */
603			return rp;
604		mode = NULL;
605		errno = 0;
606		switch (tree->type) {
607		case Node_redirect_output:
608			mode = binmode("w");
609			if ((rp->flag & RED_USED) != 0)
610				mode = (rp->mode[1] == 'b') ? "ab" : "a";
611			break;
612		case Node_redirect_append:
613			mode = binmode("a");
614			break;
615		case Node_redirect_pipe:
616			/* synchronize output before new pipe */
617			(void) flush_io();
618
619			os_restore_mode(fileno(stdin));
620			if ((rp->fp = popen(str, binmode("w"))) == NULL)
621				fatal(_("can't open pipe `%s' for output (%s)"),
622					str, strerror(errno));
623			/* set close-on-exec */
624			os_close_on_exec(fileno(rp->fp), str, "pipe", "to");
625			rp->flag |= RED_NOBUF;
626			break;
627		case Node_redirect_pipein:
628			direction = "from";
629			if (gawk_popen(str, rp) == NULL)
630				fatal(_("can't open pipe `%s' for input (%s)"),
631					str, strerror(errno));
632			break;
633		case Node_redirect_input:
634			direction = "from";
635			rp->iop = iop_open(str, binmode("r"), NULL);
636			break;
637		case Node_redirect_twoway:
638			direction = "to/from";
639			if (! two_way_open(str, rp)) {
640#ifdef HAVE_SOCKETS
641				/* multiple messages make life easier for translators */
642				if (STREQN(str, "/inet/", 6))
643					fatal(_("can't open two way socket `%s' for input/output (%s)"),
644						str, strerror(errno));
645				else
646#endif
647					fatal(_("can't open two way pipe `%s' for input/output (%s)"),
648						str, strerror(errno));
649			}
650			break;
651		default:
652			cant_happen();
653		}
654		if (mode != NULL) {
655			errno = 0;
656			fd = devopen(str, mode);
657			if (fd > INVALID_HANDLE) {
658				if (fd == fileno(stdin))
659					rp->fp = stdin;
660				else if (fd == fileno(stdout))
661					rp->fp = stdout;
662				else if (fd == fileno(stderr))
663					rp->fp = stderr;
664				else {
665#if defined(F_GETFL) && defined(O_APPEND)
666					int fd_flags;
667
668					fd_flags = fcntl(fd, F_GETFL);
669					if (fd_flags != -1 && (fd_flags & O_APPEND) == O_APPEND)
670						rp->fp = fdopen(fd, binmode("a"));
671					else
672#endif
673						rp->fp = fdopen(fd, (const char *) mode);
674					rp->mode = (const char *) mode;
675					/* don't leak file descriptors */
676					if (rp->fp == NULL)
677						close(fd);
678				}
679				if (rp->fp != NULL && isatty(fd))
680					rp->flag |= RED_NOBUF;
681				/* Move rp to the head of the list. */
682				if (red_head != rp) {
683					if ((rp->prev->next = rp->next) != NULL)
684						rp->next->prev = rp->prev;
685					red_head->prev = rp;
686					rp->prev = NULL;
687					rp->next = red_head;
688					red_head = rp;
689				}
690			}
691		}
692		if (rp->fp == NULL && rp->iop == NULL) {
693			/* too many files open -- close one and try again */
694			if (errno == EMFILE || errno == ENFILE)
695				close_one();
696#if defined __MINGW32__ || defined __sun
697			else if (errno == 0)    /* HACK! */
698				close_one();
699#endif
700#ifdef VMS
701			/* Alpha/VMS V7.1's C RTL is returning this instead
702			   of EMFILE (haven't tried other post-V6.2 systems) */
703#define SS$_EXQUOTA 0x001C
704			else if (errno == EIO && vaxc$errno == SS$_EXQUOTA)
705				close_one();
706#endif
707			else {
708				/*
709				 * Some other reason for failure.
710				 *
711				 * On redirection of input from a file,
712				 * just return an error, so e.g. getline
713				 * can return -1.  For output to file,
714				 * complain. The shell will complain on
715				 * a bad command to a pipe.
716				 */
717				if (errflg != NULL)
718					*errflg = errno;
719				if (tree->type == Node_redirect_output
720				    || tree->type == Node_redirect_append) {
721					/* multiple messages make life easier for translators */
722					if (*direction == 'f')
723						fatal(_("can't redirect from `%s' (%s)"),
724					    		str, strerror(errno));
725					else
726						fatal(_("can't redirect to `%s' (%s)"),
727							str, strerror(errno));
728				} else {
729					free_temp(tmp);
730					return NULL;
731				}
732			}
733		}
734	}
735	free_temp(tmp);
736	return rp;
737}
738
739/* getredirect --- find the struct redirect for this file or pipe */
740
741struct redirect *
742getredirect(const char *str, int len)
743{
744	struct redirect *rp;
745
746	for (rp = red_head; rp != NULL; rp = rp->next)
747		if (strlen(rp->value) == len && STREQN(rp->value, str, len))
748			return rp;
749
750	return NULL;
751}
752
753/* close_one --- temporarily close an open file to re-use the fd */
754
755static void
756close_one()
757{
758	register struct redirect *rp;
759	register struct redirect *rplast = NULL;
760
761	static short warned = FALSE;
762
763	if (do_lint && ! warned) {
764		warned = TRUE;
765		lintwarn(_("reached system limit for open files: starting to multiplex file descriptors"));
766	}
767
768	/* go to end of list first, to pick up least recently used entry */
769	for (rp = red_head; rp != NULL; rp = rp->next)
770		rplast = rp;
771	/* now work back up through the list */
772	for (rp = rplast; rp != NULL; rp = rp->prev)
773		if (rp->fp != NULL && (rp->flag & RED_FILE) != 0) {
774			rp->flag |= RED_USED;
775			errno = 0;
776			if (/* do_lint && */ fclose(rp->fp) != 0)
777				warning(_("close of `%s' failed (%s)."),
778					rp->value, strerror(errno));
779			rp->fp = NULL;
780			break;
781		}
782	if (rp == NULL)
783		/* surely this is the only reason ??? */
784		fatal(_("too many pipes or input files open"));
785}
786
787/* do_close --- completely close an open file or pipe */
788
789NODE *
790do_close(NODE *tree)
791{
792	NODE *tmp, *tmp2;
793	register struct redirect *rp;
794	two_way_close_type how = CLOSE_ALL;	/* default */
795
796	tmp = force_string(tree_eval(tree->lnode));	/* 1st arg: redir to close */
797
798	if (tree->rnode != NULL) {
799		/* 2nd arg if present: "to" or "from" for two-way pipe */
800		/* DO NOT use _() on the strings here! */
801		tmp2 = force_string(tree->rnode->lnode);
802		if (strcasecmp(tmp2->stptr, "to") == 0)
803			how = CLOSE_TO;
804		else if (strcasecmp(tmp2->stptr, "from") == 0)
805			how = CLOSE_FROM;
806		else
807			fatal(_("close: second argument must be `to' or `from'"));
808		free_temp(tmp2);
809	}
810
811	for (rp = red_head; rp != NULL; rp = rp->next) {
812		if (strlen(rp->value) == tmp->stlen
813		    && STREQN(rp->value, tmp->stptr, tmp->stlen))
814			break;
815	}
816
817	if (rp == NULL) {	/* no match, return -1 */
818		char *cp;
819
820		if (do_lint)
821			lintwarn(_("close: `%.*s' is not an open file, pipe or co-process"),
822				tmp->stlen, tmp->stptr);
823
824		/* update ERRNO manually, using errno = ENOENT is a stretch. */
825		cp = _("close of redirection that was never opened");
826		unref(ERRNO_node->var_value);
827		ERRNO_node->var_value = make_string(cp, strlen(cp));
828
829		free_temp(tmp);
830		return tmp_number((AWKNUM) -1.0);
831	}
832	free_temp(tmp);
833	fflush(stdout);	/* synchronize regular output */
834	tmp = tmp_number((AWKNUM) close_redir(rp, FALSE, how));
835	rp = NULL;
836	/*
837	 * POSIX says close() returns 0 on success, non-zero otherwise.
838	 * For POSIX, at this point we just return 0.  Otherwise we
839	 * return the exit status of the process or of pclose(), depending.
840	 * This whole business is a mess.
841	 */
842	if (do_posix) {
843		free_temp(tmp);
844		return tmp_number((AWKNUM) 0);
845	}
846	return tmp;
847}
848
849/* close_redir --- close an open file or pipe */
850
851static int
852close_redir(register struct redirect *rp, int exitwarn, two_way_close_type how)
853{
854	int status = 0;
855
856	if (rp == NULL)
857		return 0;
858	if (rp->fp == stdout || rp->fp == stderr)
859		return 0;
860
861	if (do_lint && (rp->flag & RED_TWOWAY) == 0 && how != CLOSE_ALL)
862		lintwarn(_("close: redirection `%s' not opened with `|&', second argument ignored"),
863				rp->value);
864
865	errno = 0;
866	if ((rp->flag & RED_TWOWAY) != 0) {	/* two-way pipe */
867		/* write end: */
868		if ((how == CLOSE_ALL || how == CLOSE_TO) && rp->fp != NULL) {
869#ifdef HAVE_SOCKETS
870			if ((rp->flag & RED_TCP) != 0)
871				(void) shutdown(fileno(rp->fp), SHUT_WR);
872#endif /* HAVE_SOCKETS */
873
874			if ((rp->flag & RED_PTY) != 0) {
875				fwrite("\004\n", sizeof("\004\n") - 1, 1, rp->fp);
876				fflush(rp->fp);
877			}
878			status = fclose(rp->fp);
879			rp->fp = NULL;
880		}
881
882		/* read end: */
883		if (how == CLOSE_ALL || how == CLOSE_FROM) {
884			if ((rp->flag & RED_SOCKET) != 0 && rp->iop != NULL) {
885#ifdef HAVE_SOCKETS
886				if ((rp->flag & RED_TCP) != 0)
887					(void) shutdown(rp->iop->fd, SHUT_RD);
888#endif /* HAVE_SOCKETS */
889				(void) iop_close(rp->iop);
890			} else
891				status = gawk_pclose(rp);
892
893			rp->iop = NULL;
894		}
895	} else if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) { /* write to pipe */
896		status = pclose(rp->fp);
897#ifdef O_BINARY
898		if ((BINMODE & 1) != 0)
899			os_setbinmode(fileno(stdin), O_BINARY);
900#endif
901		rp->fp = NULL;
902	} else if (rp->fp != NULL) {	/* write to file */
903		status = fclose(rp->fp);
904		rp->fp = NULL;
905	} else if (rp->iop != NULL) {	/* read from pipe/file */
906		if ((rp->flag & RED_PIPE) != 0)		/* read from pipe */
907			status = gawk_pclose(rp);
908			/* gawk_pclose sets rp->iop to null */
909		else {					/* read from file */
910			status = iop_close(rp->iop);
911			rp->iop = NULL;
912		}
913	}
914
915	/* SVR4 awk checks and warns about status of close */
916	if (status != 0) {
917		char *s = strerror(errno);
918
919		/*
920		 * Too many people have complained about this.
921		 * As of 2.15.6, it is now under lint control.
922		 */
923		if (do_lint) {
924			if ((rp->flag & RED_PIPE) != 0)
925				lintwarn(_("failure status (%d) on pipe close of `%s' (%s)"),
926					 status, rp->value, s);
927			else
928				lintwarn(_("failure status (%d) on file close of `%s' (%s)"),
929					 status, rp->value, s);
930		}
931
932		if (! do_traditional) {
933			/* set ERRNO too so that program can get at it */
934			update_ERRNO();
935		}
936	}
937
938	if (exitwarn) {
939		/*
940		 * Don't use lintwarn() here.  If lint warnings are fatal,
941		 * doing so prevents us from closing other open redirections.
942		 *
943		 * Using multiple full messages instead of string parameters
944		 * for the types makes message translation easier.
945		 */
946		if ((rp->flag & RED_SOCKET) != 0)
947			warning(_("no explicit close of socket `%s' provided"),
948				rp->value);
949		else if ((rp->flag & RED_TWOWAY) != 0)
950			warning(_("no explicit close of co-process `%s' provided"),
951				rp->value);
952		else if ((rp->flag & RED_PIPE) != 0)
953			warning(_("no explicit close of pipe `%s' provided"),
954				rp->value);
955		else
956			warning(_("no explicit close of file `%s' provided"),
957				rp->value);
958	}
959
960	/* remove it from the list if closing both or both ends have been closed */
961	if (how == CLOSE_ALL || (rp->iop == NULL && rp->fp == NULL)) {
962		if (rp->next != NULL)
963			rp->next->prev = rp->prev;
964		if (rp->prev != NULL)
965			rp->prev->next = rp->next;
966		else
967			red_head = rp->next;
968		free(rp->value);
969		free((char *) rp);
970	}
971
972	return status;
973}
974
975/* flush_io --- flush all open output files */
976
977int
978flush_io()
979{
980	register struct redirect *rp;
981	int status = 0;
982
983	errno = 0;
984	if (fflush(stdout)) {
985		warning(_("error writing standard output (%s)"), strerror(errno));
986		status++;
987	}
988	if (fflush(stderr)) {
989		warning(_("error writing standard error (%s)"), strerror(errno));
990		status++;
991	}
992	for (rp = red_head; rp != NULL; rp = rp->next)
993		/* flush both files and pipes, what the heck */
994		if ((rp->flag & RED_WRITE) && rp->fp != NULL) {
995			if (fflush(rp->fp)) {
996				if (rp->flag  & RED_PIPE)
997					warning(_("pipe flush of `%s' failed (%s)."),
998						rp->value, strerror(errno));
999				else if (rp->flag & RED_TWOWAY)
1000					warning(_("co-process flush of pipe to `%s' failed (%s)."),
1001						rp->value, strerror(errno));
1002				else
1003					warning(_("file flush of `%s' failed (%s)."),
1004						rp->value, strerror(errno));
1005				status++;
1006			}
1007		}
1008	if (status != 0)
1009		status = -1;	/* canonicalize it */
1010	return status;
1011}
1012
1013/* close_io --- close all open files, called when exiting */
1014
1015int
1016close_io()
1017{
1018	register struct redirect *rp;
1019	register struct redirect *next;
1020	int status = 0;
1021
1022	errno = 0;
1023	for (rp = red_head; rp != NULL; rp = next) {
1024		next = rp->next;
1025		/*
1026		 * close_redir() will print a message if needed
1027		 * if do_lint, warn about lack of explicit close
1028		 */
1029		if (close_redir(rp, do_lint, CLOSE_ALL))
1030			status++;
1031		rp = NULL;
1032	}
1033	/*
1034	 * Some of the non-Unix os's have problems doing an fclose
1035	 * on stdout and stderr.  Since we don't really need to close
1036	 * them, we just flush them, and do that across the board.
1037	 */
1038	if (fflush(stdout)) {
1039		warning(_("error writing standard output (%s)"), strerror(errno));
1040		status++;
1041	}
1042	if (fflush(stderr)) {
1043		warning(_("error writing standard error (%s)"), strerror(errno));
1044		status++;
1045	}
1046	return status;
1047}
1048
1049/* str2mode --- convert a string mode to an integer mode */
1050
1051static int
1052str2mode(const char *mode)
1053{
1054	int ret;
1055	const char *second = & mode[1];
1056
1057	if (*second == 'b')
1058		second++;
1059
1060	switch(mode[0]) {
1061	case 'r':
1062		ret = O_RDONLY;
1063		if (*second == '+' || *second == 'w')
1064			ret = O_RDWR;
1065		break;
1066
1067	case 'w':
1068		ret = O_WRONLY|O_CREAT|O_TRUNC;
1069		if (*second == '+' || *second == 'r')
1070			ret = O_RDWR|O_CREAT|O_TRUNC;
1071		break;
1072
1073	case 'a':
1074		ret = O_WRONLY|O_APPEND|O_CREAT;
1075		if (*second == '+')
1076			ret = O_RDWR|O_APPEND|O_CREAT;
1077		break;
1078
1079	default:
1080		ret = 0;		/* lint */
1081		cant_happen();
1082	}
1083#ifdef O_BINARY
1084	if (strchr(mode, 'b') != NULL)
1085		ret |= O_BINARY;
1086#endif
1087	return ret;
1088}
1089
1090#ifdef HAVE_SOCKETS
1091/* socketopen --- open a socket and set it into connected state */
1092
1093static int
1094socketopen(enum inet_prot type, int localport, int remoteport, const char *remotehostname)
1095{
1096	struct hostent *hp = gethostbyname(remotehostname);
1097	struct sockaddr_in local_addr, remote_addr;
1098	int socket_fd;
1099	int any_remote_host = strcmp(remotehostname, "0");
1100
1101	socket_fd = INVALID_HANDLE;
1102	switch (type) {
1103	case INET_TCP:
1104		if (localport != 0 || remoteport != 0) {
1105			int on = 1;
1106#ifdef SO_LINGER
1107			struct linger linger;
1108
1109			memset(& linger, '\0', sizeof(linger));
1110#endif
1111			socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1112			setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR,
1113				(char *) & on, sizeof(on));
1114#ifdef SO_LINGER
1115			linger.l_onoff = 1;
1116			linger.l_linger = 30;    /* linger for 30/100 second */
1117			setsockopt(socket_fd, SOL_SOCKET, SO_LINGER,
1118				(char *) & linger, sizeof(linger));
1119#endif
1120		}
1121		break;
1122	case INET_UDP:
1123		if (localport != 0 || remoteport != 0)
1124			socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1125		break;
1126	case INET_RAW:
1127#ifdef SOCK_RAW
1128		if (localport == 0 && remoteport == 0)
1129			socket_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1130#endif
1131		break;
1132	case INET_NONE:
1133		/* fall through */
1134	default:
1135		cant_happen();
1136		break;
1137	}
1138
1139	if (socket_fd < 0 || socket_fd == INVALID_HANDLE
1140	    || (hp == NULL && any_remote_host != 0))
1141		return INVALID_HANDLE;
1142
1143	local_addr.sin_family = remote_addr.sin_family = AF_INET;
1144	local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1145	remote_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1146	local_addr.sin_port  = htons(localport);
1147	remote_addr.sin_port = htons(remoteport);
1148	if (bind(socket_fd, (struct sockaddr *) &local_addr, sizeof(local_addr)) == 0) {
1149		if (any_remote_host != 0) { /* not ANY => create a client */
1150			if (type == INET_TCP || type == INET_UDP) {
1151				memcpy(&remote_addr.sin_addr, hp->h_addr,
1152					sizeof(remote_addr.sin_addr));
1153				if (connect(socket_fd,
1154						(struct sockaddr *) &remote_addr,
1155						sizeof(remote_addr)) != 0) {
1156					close(socket_fd);
1157					if (localport == 0)
1158						socket_fd = INVALID_HANDLE;
1159					else
1160						socket_fd = socketopen(type, localport, 0, "0");
1161				}
1162			} else {
1163				/* /inet/raw client not ready yet */
1164				fatal(_("/inet/raw client not ready yet, sorry"));
1165				if (geteuid() != 0)
1166					fatal(_("only root may use `/inet/raw'."));
1167			}
1168		} else { /* remote host is ANY => create a server */
1169			if (type == INET_TCP) {
1170				int clientsocket_fd = INVALID_HANDLE;
1171				int namelen = sizeof(remote_addr);
1172
1173				if (listen(socket_fd, 1) >= 0
1174				    && (clientsocket_fd = accept(socket_fd,
1175						(struct sockaddr *) &remote_addr,
1176						&namelen)) >= 0) {
1177					close(socket_fd);
1178					socket_fd = clientsocket_fd;
1179				} else {
1180					close(socket_fd);
1181					socket_fd = INVALID_HANDLE;
1182				}
1183			} else if (type == INET_UDP) {
1184				char buf[10];
1185				int readle;
1186
1187#ifdef MSG_PEEK
1188				if (recvfrom(socket_fd, buf, 1, MSG_PEEK,
1189					(struct sockaddr *) & remote_addr,
1190					& readle) < 1
1191						|| readle != sizeof(remote_addr)
1192				    || connect(socket_fd,
1193					(struct sockaddr *)& remote_addr,
1194						readle) != 0) {
1195					close(socket_fd);
1196					socket_fd = INVALID_HANDLE;
1197				}
1198#endif
1199			} else {
1200				/* /inet/raw server not ready yet */
1201				fatal(_("/inet/raw server not ready yet, sorry"));
1202				if (geteuid() != 0)
1203					fatal(_("only root may use `/inet/raw'."));
1204			}
1205		}
1206	} else {
1207		close(socket_fd);
1208		socket_fd = INVALID_HANDLE;
1209	}
1210
1211	return socket_fd;
1212}
1213#endif /* HAVE_SOCKETS */
1214
1215/* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
1216
1217/*
1218 * This separate version is still needed for output, since file and pipe
1219 * output is done with stdio. iop_open() handles input with IOBUFs of
1220 * more "special" files.  Those files are not handled here since it makes
1221 * no sense to use them for output.
1222 */
1223
1224/*
1225 * Strictly speaking, "name" is not a "const char *" because we temporarily
1226 * change the string.
1227 */
1228
1229int
1230devopen(const char *name, const char *mode)
1231{
1232	int openfd;
1233	char *cp;
1234	char *ptr;
1235	int flag = 0;
1236	extern double strtod();
1237
1238	flag = str2mode(mode);
1239
1240	if (STREQ(name, "-"))
1241		return fileno(stdin);
1242
1243	openfd = INVALID_HANDLE;
1244
1245	if (do_traditional)
1246		goto strictopen;
1247
1248	if ((openfd = os_devopen(name, flag)) != INVALID_HANDLE) {
1249		os_close_on_exec(openfd, name, "file", "");
1250		return openfd;
1251	}
1252
1253	if (STREQN(name, "/dev/", 5)) {
1254		cp = (char *) name + 5;
1255
1256		if (STREQ(cp, "stdin") && (flag & O_ACCMODE) == O_RDONLY)
1257			openfd = fileno(stdin);
1258		else if (STREQ(cp, "stdout") && (flag & O_ACCMODE) == O_WRONLY)
1259			openfd = fileno(stdout);
1260		else if (STREQ(cp, "stderr") && (flag & O_ACCMODE) == O_WRONLY)
1261			openfd = fileno(stderr);
1262		else if (STREQN(cp, "fd/", 3)) {
1263			cp += 3;
1264			openfd = (int) strtod(cp, &ptr);
1265			if (openfd <= INVALID_HANDLE || ptr == cp)
1266				openfd = INVALID_HANDLE;
1267		}
1268		/* do not set close-on-exec for inherited fd's */
1269		if (openfd != INVALID_HANDLE)
1270			return openfd;
1271	} else if (STREQN(name, "/inet/", 6)) {
1272#ifdef HAVE_SOCKETS
1273		/* /inet/protocol/localport/hostname/remoteport */
1274		enum inet_prot protocol = INET_NONE;
1275		int localport, remoteport;
1276		char *hostname;
1277		char *hostnameslastcharp;
1278		char *localpname;
1279		char proto[4];
1280		struct servent *service;
1281
1282		cp = (char *) name + 6;
1283		/* which protocol? */
1284		if (STREQN(cp, "tcp/", 4))
1285			protocol = INET_TCP;
1286		else if (STREQN(cp, "udp/", 4))
1287			protocol = INET_UDP;
1288		else if (STREQN(cp, "raw/", 4))
1289			protocol = INET_RAW;
1290		else
1291			fatal(_("no (known) protocol supplied in special filename `%s'"),
1292				name);
1293
1294		proto[0] = cp[0];
1295		proto[1] = cp[1];
1296		proto[2] = cp[2];
1297		proto[3] =  '\0';
1298		cp += 4;
1299
1300		/* which localport? */
1301		localpname = cp;
1302		while (*cp != '/' && *cp != '\0')
1303			cp++;
1304		/*
1305		 * Require a port, let them explicitly put 0 if
1306		 * they don't care.
1307		 */
1308		if (*cp != '/' || cp == localpname)
1309			fatal(_("special file name `%s' is incomplete"), name);
1310		/* We change the special file name temporarily because we
1311		 * need a 0-terminated string here for conversion with atoi().
1312		 * By using atoi() the use of decimal numbers is enforced.
1313		 */
1314		*cp = '\0';
1315
1316		localport = atoi(localpname);
1317		if (strcmp(localpname, "0") != 0
1318		    && (localport <= 0 || localport > 65535)) {
1319			service = getservbyname(localpname, proto);
1320			if (service == NULL)
1321				fatal(_("local port invalid in `%s'"), name);
1322			else
1323				localport = ntohs(service->s_port);
1324		}
1325		*cp = '/';
1326
1327		/* which hostname? */
1328		cp++;
1329		hostname = cp;
1330		while (*cp != '/' && *cp != '\0')
1331			cp++;
1332		if (*cp != '/' || cp == hostname)
1333			fatal(_("must supply a remote hostname to `/inet'"));
1334		*cp = '\0';
1335		hostnameslastcharp = cp;
1336
1337		/* which remoteport? */
1338		cp++;
1339		/*
1340		 * The remote port ends the special file name.
1341		 * This means there already is a 0 at the end of the string.
1342		 * Therefore no need to patch any string ending.
1343		 *
1344		 * Here too, require a port, let them explicitly put 0 if
1345		 * they don't care.
1346		 */
1347		if (*cp == '\0')
1348			fatal(_("must supply a remote port to `/inet'"));
1349		remoteport = atoi(cp);
1350		if (strcmp(cp, "0") != 0
1351		    && (remoteport <= 0 || remoteport > 65535)) {
1352			service = getservbyname(cp, proto);
1353			if (service == NULL)
1354				 fatal(_("remote port invalid in `%s'"), name);
1355			else
1356				remoteport = ntohs(service->s_port);
1357		}
1358
1359		/* Open Sesame! */
1360		openfd = socketopen(protocol, localport, remoteport, hostname);
1361		*hostnameslastcharp = '/';
1362
1363#else /* ! HAVE_SOCKETS */
1364		fatal(_("TCP/IP communications are not supported"));
1365#endif /* HAVE_SOCKETS */
1366	}
1367
1368strictopen:
1369	if (openfd == INVALID_HANDLE)
1370		openfd = open(name, flag, 0666);
1371	if (openfd != INVALID_HANDLE) {
1372		if (os_isdir(openfd))
1373			fatal(_("file `%s' is a directory"), name);
1374
1375		os_close_on_exec(openfd, name, "file", "");
1376	}
1377	return openfd;
1378}
1379
1380
1381/* spec_setup --- setup an IOBUF for a special internal file */
1382
1383static void
1384spec_setup(IOBUF *iop, int len, int allocate)
1385{
1386	char *cp;
1387
1388	if (allocate) {
1389		emalloc(cp, char *, len+2, "spec_setup");
1390		iop->buf = cp;
1391	} else {
1392		len = strlen(iop->buf);
1393		iop->buf[len++] = '\n';	/* get_a_record clobbered it */
1394		iop->buf[len] = '\0';	/* just in case */
1395	}
1396	iop->off = iop->buf;
1397	iop->count = 0;
1398	iop->size = len;
1399	iop->end = iop->buf + len;
1400	iop->dataend = iop->end;
1401	iop->fd = -1;
1402	iop->flag = IOP_IS_INTERNAL;
1403}
1404
1405/* specfdopen --- open an fd special file */
1406
1407static int
1408specfdopen(IOBUF *iop, const char *name, const char *mode)
1409{
1410	int fd;
1411	IOBUF *tp;
1412
1413	fd = devopen(name, mode);
1414	if (fd == INVALID_HANDLE)
1415		return INVALID_HANDLE;
1416	tp = iop_alloc(fd, name, NULL);
1417	if (tp == NULL) {
1418		/* don't leak fd's */
1419		close(fd);
1420		return INVALID_HANDLE;
1421	}
1422	*iop = *tp;
1423	iop->flag |= IOP_NO_FREE;
1424	free(tp);
1425	return 0;
1426}
1427
1428#ifdef GETPGRP_VOID
1429#define getpgrp_arg() /* nothing */
1430#else
1431#define getpgrp_arg() getpid()
1432#endif
1433
1434/* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */
1435
1436static int
1437pidopen(IOBUF *iop, const char *name, const char *mode ATTRIBUTE_UNUSED)
1438{
1439	char tbuf[BUFSIZ];
1440	int i;
1441	const char *cp = name + 5;
1442
1443	warning(_("use `PROCINFO[\"%s\"]' instead of `%s'"), cp, name);
1444
1445	if (name[6] == 'g')
1446		sprintf(tbuf, "%d\n", (int) getpgrp(getpgrp_arg()));
1447	else if (name[6] == 'i')
1448		sprintf(tbuf, "%d\n", (int) getpid());
1449	else
1450		sprintf(tbuf, "%d\n", (int) getppid());
1451	i = strlen(tbuf);
1452	spec_setup(iop, i, TRUE);
1453	strcpy(iop->buf, tbuf);
1454	return 0;
1455}
1456
1457/* useropen --- "open" /dev/user */
1458
1459/*
1460 * /dev/user creates a record as follows:
1461 *	$1 = getuid()
1462 *	$2 = geteuid()
1463 *	$3 = getgid()
1464 *	$4 = getegid()
1465 * If multiple groups are supported, then $5 through $NF are the
1466 * supplementary group set.
1467 */
1468
1469static int
1470useropen(IOBUF *iop, const char *name ATTRIBUTE_UNUSED, const char *mode ATTRIBUTE_UNUSED)
1471{
1472	char tbuf[BUFSIZ], *cp;
1473	int i;
1474
1475	warning(_("use `PROCINFO[...]' instead of `/dev/user'"));
1476
1477	sprintf(tbuf, "%d %d %d %d", (int) getuid(), (int) geteuid(), (int) getgid(), (int) getegid());
1478
1479	cp = tbuf + strlen(tbuf);
1480#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
1481	for (i = 0; i < ngroups; i++) {
1482		*cp++ = ' ';
1483		sprintf(cp, "%d", (int) groupset[i]);
1484		cp += strlen(cp);
1485	}
1486#endif
1487	*cp++ = '\n';
1488	*cp++ = '\0';
1489
1490	i = strlen(tbuf);
1491	spec_setup(iop, i, TRUE);
1492	strcpy(iop->buf, tbuf);
1493	return 0;
1494}
1495
1496/* iop_open --- handle special and regular files for input */
1497
1498static IOBUF *
1499iop_open(const char *name, const char *mode, IOBUF *iop)
1500{
1501	int openfd = INVALID_HANDLE;
1502	int flag = 0;
1503	static struct internal {
1504		const char *name;
1505		int compare;
1506		int (*fp) P((IOBUF *, const char *, const char *));
1507		IOBUF iob;
1508	} table[] = {
1509		{ "/dev/fd/",		8,	specfdopen },
1510		{ "/dev/stdin",		10,	specfdopen },
1511		{ "/dev/stdout",	11,	specfdopen },
1512		{ "/dev/stderr",	11,	specfdopen },
1513		{ "/inet/",		6,	specfdopen },
1514		{ "/dev/pid",		8,	pidopen },
1515		{ "/dev/ppid",		9,	pidopen },
1516		{ "/dev/pgrpid",	11,	pidopen },
1517		{ "/dev/user",		9,	useropen },
1518	};
1519	int devcount = sizeof(table) / sizeof(table[0]);
1520
1521	flag = str2mode(mode);
1522
1523	if (STREQ(name, "-"))
1524		openfd = fileno(stdin);
1525	else if (do_traditional)
1526		goto strictopen;
1527	else if (STREQN(name, "/dev/", 5) || STREQN(name, "/inet/", 6)) {
1528		int i;
1529
1530		for (i = 0; i < devcount; i++) {
1531			if (STREQN(name, table[i].name, table[i].compare)) {
1532				iop = & table[i].iob;
1533
1534				if (iop->buf != NULL) {
1535					spec_setup(iop, 0, FALSE);
1536					return iop;
1537				} else if ((*table[i].fp)(iop, name, mode) == 0)
1538					return iop;
1539				else {
1540					warning(_("could not open `%s', mode `%s'"),
1541						name, mode);
1542					return NULL;
1543				}
1544			}
1545		}
1546		/* not in table, fall through to regular code */
1547	}
1548
1549strictopen:
1550	if (openfd == INVALID_HANDLE)
1551		openfd = open(name, flag, 0666);
1552	if (openfd != INVALID_HANDLE) {
1553		if (os_isdir(openfd))
1554			fatal(_("file `%s' is a directory"), name);
1555
1556		if (openfd > fileno(stderr))
1557			os_close_on_exec(openfd, name, "file", "");
1558	}
1559	return iop_alloc(openfd, name, iop);
1560}
1561
1562/* two_way_open --- open a two way communications channel */
1563
1564static int
1565two_way_open(const char *str, struct redirect *rp)
1566{
1567	static int no_ptys = FALSE;
1568
1569#ifdef HAVE_SOCKETS
1570	/* case 1: socket */
1571	if (STREQN(str, "/inet/", 6)) {
1572		int fd, newfd;
1573
1574		fd = devopen(str, "rw");
1575		if (fd == INVALID_HANDLE)
1576			return FALSE;
1577		rp->fp = fdopen(fd, "w");
1578		if (rp->fp == NULL) {
1579			close(fd);
1580			return FALSE;
1581		}
1582		newfd = dup(fd);
1583		if (newfd < 0) {
1584			fclose(rp->fp);
1585			return FALSE;
1586		}
1587		os_close_on_exec(newfd, str, "socket", "to/from");
1588		rp->iop = iop_alloc(newfd, str, NULL);
1589		if (rp->iop == NULL) {
1590			fclose(rp->fp);
1591			return FALSE;
1592		}
1593		rp->flag |= RED_SOCKET;
1594		return TRUE;
1595	}
1596#endif /* HAVE_SOCKETS */
1597
1598#ifdef HAVE_PORTALS
1599	/* case 1.5: portal */
1600	if (STREQN(str, "/p/", 3)) {
1601		int fd, newfd;
1602
1603		fd = open(str, O_RDWR);
1604		if (fd == INVALID_HANDLE)
1605			return FALSE;
1606		rp->fp = fdopen(fd, "w");
1607		if (rp->fp == NULL) {
1608			close(fd);
1609			return FALSE;
1610		}
1611		newfd = dup(fd);
1612		if (newfd < 0) {
1613			fclose(rp->fp);
1614			return FALSE;
1615		}
1616		os_close_on_exec(newfd, str, "portal", "to/from");
1617		rp->iop = iop_alloc(newfd, str, NULL);
1618		if (rp->iop == NULL) {
1619			fclose(rp->fp);
1620			return FALSE;
1621		}
1622		rp->flag |= RED_SOCKET;
1623		return TRUE;
1624	}
1625#endif /* HAVE_PORTALS */
1626
1627#ifdef HAVE_TERMIOS_H
1628	/* case 2: use ptys for two-way communications to child */
1629	if (! no_ptys && pty_vs_pipe(str)) {
1630		static int initialized = FALSE;
1631		static char first_pty_letter;
1632#ifdef HAVE_GRANTPT
1633		static int have_dev_ptmx;
1634#endif
1635		char slavenam[32];
1636		char c;
1637		int master, dup_master;
1638		int slave;
1639		int save_errno;
1640		pid_t pid;
1641		struct stat statb;
1642		struct termios st;
1643
1644		if (! initialized) {
1645			initialized = TRUE;
1646#ifdef HAVE_GRANTPT
1647			have_dev_ptmx = (stat("/dev/ptmx", &statb) >= 0);
1648#endif
1649			c = 'p';
1650			do {
1651				sprintf(slavenam, "/dev/pty%c0", c);
1652				if (stat(slavenam, &statb) >= 0) {
1653					first_pty_letter = c;
1654					break;
1655				}
1656				if (++c > 'z')
1657					c = 'a';
1658			} while (c != 'p');
1659		}
1660
1661#ifdef HAVE_GRANTPT
1662		if (have_dev_ptmx) {
1663			master = open("/dev/ptmx", O_RDWR);
1664			if (master >= 0) {
1665				char *tem;
1666
1667				grantpt(master);
1668				unlockpt(master);
1669				tem = ptsname(master);
1670				if (tem != NULL) {
1671					strcpy(slavenam, tem);
1672					goto got_the_pty;
1673				}
1674				(void) close(master);
1675			}
1676		}
1677#endif
1678
1679		if (first_pty_letter) {
1680			/*
1681			 * Assume /dev/ptyXNN and /dev/ttyXN naming system.
1682			 * The FIRST_PTY_LETTER gives the first X to try. We try in the
1683			 * sequence FIRST_PTY_LETTER, .., 'z', 'a', .., FIRST_PTY_LETTER.
1684			 * Is this worthwhile, or just over-zealous?
1685			 */
1686			c = first_pty_letter;
1687			do {
1688				int i;
1689				for (i = 0; i < 16; i++) {
1690					sprintf(slavenam, "/dev/pty%c%x", c, i);
1691					if (stat(slavenam, &statb) < 0) {
1692						no_ptys = TRUE;	/* bypass all this next time */
1693						goto use_pipes;
1694					}
1695
1696					if ((master = open(slavenam, O_RDWR)) >= 0) {
1697						slavenam[sizeof("/dev/") - 1] = 't';
1698						if (access(slavenam, R_OK | W_OK) == 0)
1699							goto got_the_pty;
1700						close(master);
1701					}
1702				}
1703				if (++c > 'z')
1704				c = 'a';
1705			} while (c != first_pty_letter);
1706		} else
1707			no_ptys = TRUE;
1708
1709		/* Couldn't find a pty. Fall back to using pipes. */
1710		goto use_pipes;
1711
1712	got_the_pty:
1713		if ((slave = open(slavenam, O_RDWR)) < 0) {
1714			fatal(_("could not open `%s', mode `%s'"),
1715				slavenam, "r+");
1716		}
1717
1718#ifdef I_PUSH
1719		/*
1720		 * Push the necessary modules onto the slave to
1721		 * get terminal semantics.
1722		 */
1723		ioctl(slave, I_PUSH, "ptem");
1724		ioctl(slave, I_PUSH, "ldterm");
1725#endif
1726
1727#ifdef TIOCSCTTY
1728		ioctl(slave, TIOCSCTTY, 0);
1729#endif
1730		tcgetattr(slave, &st);
1731		st.c_iflag &= ~(ISTRIP | IGNCR | INLCR | IXOFF);
1732		st.c_iflag |= (ICRNL | IGNPAR | BRKINT | IXON);
1733		st.c_oflag &= ~OPOST;
1734		st.c_cflag &= ~CSIZE;
1735		st.c_cflag |= CREAD | CS8 | CLOCAL;
1736		st.c_lflag &= ~(ECHO | ECHOE | ECHOK | NOFLSH | TOSTOP);
1737		st.c_lflag |= ISIG;
1738#if 0
1739		st.c_cc[VMIN] = 1;
1740		st.c_cc[VTIME] = 0;
1741#endif
1742
1743		/* Set some control codes to default values */
1744#ifdef VINTR
1745		st.c_cc[VINTR] = '\003';        /* ^c */
1746#endif
1747#ifdef VQUIT
1748		st.c_cc[VQUIT] = '\034';        /* ^| */
1749#endif
1750#ifdef VERASE
1751		st.c_cc[VERASE] = '\177';       /* ^? */
1752#endif
1753#ifdef VKILL
1754		st.c_cc[VKILL] = '\025';        /* ^u */
1755#endif
1756#ifdef VEOF
1757		st.c_cc[VEOF] = '\004'; /* ^d */
1758#endif
1759		tcsetattr(slave, TCSANOW, &st);
1760
1761		switch (pid = fork ()) {
1762		case 0:
1763			/* Child process */
1764			if (close(master) == -1)
1765				fatal(_("close of master pty failed (%s)"), strerror(errno));
1766			if (close(1) == -1)
1767				fatal(_("close of stdout in child failed (%s)"),
1768					strerror(errno));
1769			if (dup(slave) != 1)
1770				fatal(_("moving slave pty to stdout in child failed (dup: %s)"), strerror(errno));
1771			if (close(0) == -1)
1772				fatal(_("close of stdin in child failed (%s)"),
1773					strerror(errno));
1774			if (dup(slave) != 0)
1775				fatal(_("moving slave pty to stdin in child failed (dup: %s)"), strerror(errno));
1776			if (close(slave))
1777				fatal(_("close of slave pty failed (%s)"), strerror(errno));
1778
1779			/* stderr does NOT get dup'ed onto child's stdout */
1780
1781			signal(SIGPIPE, SIG_DFL);
1782
1783			execl("/bin/sh", "sh", "-c", str, NULL);
1784			_exit(127);
1785
1786		case -1:
1787			save_errno = errno;
1788			close(master);
1789			errno = save_errno;
1790			return FALSE;
1791
1792		}
1793
1794		/* parent */
1795		if (close(slave))
1796			fatal(_("close of slave pty failed (%s)"), strerror(errno));
1797
1798		rp->pid = pid;
1799		rp->iop = iop_alloc(master, str, NULL);
1800		if (rp->iop == NULL) {
1801			(void) close(master);
1802			(void) kill(pid, SIGKILL);      /* overkill? (pardon pun) */
1803			return FALSE;
1804		}
1805
1806		/*
1807		 * Force read and write ends of two-way connection to
1808		 * be different fd's so they can be closed independently.
1809		 */
1810		if ((dup_master = dup(master)) < 0
1811		    || (rp->fp = fdopen(dup_master, "w")) == NULL) {
1812			iop_close(rp->iop);
1813			rp->iop = NULL;
1814			(void) close(master);
1815			(void) kill(pid, SIGKILL);      /* overkill? (pardon pun) */
1816			if (dup_master > 0)
1817				(void) close(dup_master);
1818			return FALSE;
1819		}
1820		rp->flag |= RED_PTY;
1821		os_close_on_exec(master, str, "pipe", "from");
1822		os_close_on_exec(dup_master, str, "pipe", "to");
1823		first_pty_letter = '\0';	/* reset for next command */
1824		return TRUE;
1825	}
1826#endif /* HAVE_TERMIOS_H */
1827
1828use_pipes:
1829#ifndef PIPES_SIMULATED		/* real pipes */
1830	/* case 3: two way pipe to a child process */
1831    {
1832	int ptoc[2], ctop[2];
1833	int pid;
1834	int save_errno;
1835#ifdef __EMX__
1836	int save_stdout, save_stdin;
1837#endif
1838
1839	if (pipe(ptoc) < 0)
1840		return FALSE;	/* errno set, diagnostic from caller */
1841
1842	if (pipe(ctop) < 0) {
1843		save_errno = errno;
1844		close(ptoc[0]);
1845		close(ptoc[1]);
1846		errno = save_errno;
1847		return FALSE;
1848	}
1849
1850#ifdef __EMX__
1851	save_stdin = dup(0);	/* duplicate stdin */
1852	save_stdout = dup(1);	/* duplicate stdout */
1853
1854	if (save_stdout == -1 || save_stdin == -1) {
1855		/* if an error occurrs close all open file handles */
1856		save_errno = errno;
1857		if (save_stdin != -1)
1858			close(save_stdin);
1859		if (save_stdout != -1)
1860			close(save_stdout);
1861		close(ptoc[0]); close(ptoc[1]);
1862		close(ctop[0]); close(ctop[1]);
1863		errno = save_errno;
1864		return FALSE;
1865	}
1866
1867	/* connect pipes to stdin and stdout */
1868	close(1);	/* close stdout */
1869	if (dup(ctop[1]) != 1)	/* connect pipe input to stdout */
1870		fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
1871
1872	close(0);	/* close stdin */
1873	if (dup(ptoc[0]) != 0)	/* connect pipe output to stdin */
1874		fatal(_("moving pipe to stdin in child failed (dup: %s)"), strerror(errno));
1875
1876	/* none of these handles must be inherited by the child process */
1877	(void) close(ptoc[0]);	/* close pipe output, child will use stdin instead */
1878	(void) close(ctop[1]);	/* close pipe input, child will use stdout instead */
1879
1880	os_close_on_exec(ptoc[1], str, "pipe", "from"); /* pipe input: output of the parent process */
1881	os_close_on_exec(ctop[0], str, "pipe", "from"); /* pipe output: input of the parent process */
1882	os_close_on_exec(save_stdin, str, "pipe", "from"); /* saved stdin of the parent process */
1883	os_close_on_exec(save_stdout, str, "pipe", "from"); /* saved stdout of the parent process */
1884
1885	/* stderr does NOT get dup'ed onto child's stdout */
1886	pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", str, NULL);
1887
1888	/* restore stdin and stdout */
1889	close(1);
1890	if (dup(save_stdout) != 1)
1891		fatal(_("restoring stdout in parent process failed\n"));
1892	close(save_stdout);
1893
1894	close(0);
1895	if (dup(save_stdin) != 0)
1896		fatal(_("restoring stdin in parent process failed\n"));
1897	close(save_stdin);
1898
1899	if (pid < 0) { /* spawnl() failed */
1900		save_errno = errno;
1901		close(ptoc[1]);
1902		close(ctop[0]);
1903
1904		errno = save_errno;
1905		return FALSE;
1906	}
1907
1908#else /* NOT __EMX__ */
1909	if ((pid = fork()) < 0) {
1910		save_errno = errno;
1911		close(ptoc[0]); close(ptoc[1]);
1912		close(ctop[0]); close(ctop[1]);
1913		errno = save_errno;
1914		return FALSE;
1915	}
1916
1917	if (pid == 0) {	/* child */
1918		if (close(1) == -1)
1919			fatal(_("close of stdout in child failed (%s)"),
1920				strerror(errno));
1921		if (dup(ctop[1]) != 1)
1922			fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
1923		if (close(0) == -1)
1924			fatal(_("close of stdin in child failed (%s)"),
1925				strerror(errno));
1926		if (dup(ptoc[0]) != 0)
1927			fatal(_("moving pipe to stdin in child failed (dup: %s)"), strerror(errno));
1928		if (   close(ptoc[0]) == -1 || close(ptoc[1]) == -1
1929		    || close(ctop[0]) == -1 || close(ctop[1]) == -1)
1930			fatal(_("close of pipe failed (%s)"), strerror(errno));
1931		/* stderr does NOT get dup'ed onto child's stdout */
1932		execl("/bin/sh", "sh", "-c", str, NULL);
1933		_exit(errno == ENOENT ? 127 : 126);
1934	}
1935#endif /* NOT __EMX__ */
1936
1937	/* parent */
1938	rp->pid = pid;
1939	rp->iop = iop_alloc(ctop[0], str, NULL);
1940	if (rp->iop == NULL) {
1941		(void) close(ctop[0]);
1942		(void) close(ctop[1]);
1943		(void) close(ptoc[0]);
1944		(void) close(ptoc[1]);
1945		(void) kill(pid, SIGKILL);	/* overkill? (pardon pun) */
1946
1947		return FALSE;
1948	}
1949	rp->fp = fdopen(ptoc[1], "w");
1950	if (rp->fp == NULL) {
1951		iop_close(rp->iop);
1952		rp->iop = NULL;
1953		(void) close(ctop[0]);
1954		(void) close(ctop[1]);
1955		(void) close(ptoc[0]);
1956		(void) close(ptoc[1]);
1957		(void) kill(pid, SIGKILL);	/* overkill? (pardon pun) */
1958
1959		return FALSE;
1960	}
1961
1962#ifndef __EMX__
1963	os_close_on_exec(ctop[0], str, "pipe", "from");
1964	os_close_on_exec(ptoc[1], str, "pipe", "from");
1965
1966	(void) close(ptoc[0]);
1967	(void) close(ctop[1]);
1968#endif
1969
1970	return TRUE;
1971    }
1972
1973#else	/*PIPES_SIMULATED*/
1974
1975	fatal(_("`|&' not supported"));
1976	/*NOTREACHED*/
1977	return FALSE;
1978
1979#endif
1980}
1981
1982#ifndef PIPES_SIMULATED		/* real pipes */
1983
1984/* wait_any --- wait for a child process, close associated pipe */
1985
1986static int
1987wait_any(int interesting)	/* pid of interest, if any */
1988{
1989	RETSIGTYPE (*hstat) P((int)), (*istat) P((int)), (*qstat) P((int));
1990	int pid;
1991	int status = 0;
1992	struct redirect *redp;
1993	extern int errno;
1994
1995	hstat = signal(SIGHUP, SIG_IGN);
1996	istat = signal(SIGINT, SIG_IGN);
1997	qstat = signal(SIGQUIT, SIG_IGN);
1998	for (;;) {
1999#ifdef HAVE_SYS_WAIT_H	/* Posix compatible sys/wait.h */
2000		pid = wait(&status);
2001#else
2002		pid = wait((union wait *)&status);
2003#endif /* NeXT */
2004		if (interesting && pid == interesting) {
2005			break;
2006		} else if (pid != -1) {
2007			for (redp = red_head; redp != NULL; redp = redp->next)
2008				if (pid == redp->pid) {
2009					redp->pid = -1;
2010					redp->status = status;
2011					break;
2012				}
2013		}
2014		if (pid == -1 && errno == ECHILD)
2015			break;
2016	}
2017	signal(SIGHUP, hstat);
2018	signal(SIGINT, istat);
2019	signal(SIGQUIT, qstat);
2020	return(status);
2021}
2022
2023/* gawk_popen --- open an IOBUF on a child process */
2024
2025static IOBUF *
2026gawk_popen(const char *cmd, struct redirect *rp)
2027{
2028	int p[2];
2029	register int pid;
2030#ifdef __EMX__
2031	int save_stdout;
2032#endif
2033
2034	/*
2035	 * used to wait for any children to synchronize input and output,
2036	 * but this could cause gawk to hang when it is started in a pipeline
2037	 * and thus has a child process feeding it input (shell dependant)
2038	 */
2039	/*(void) wait_any(0);*/	/* wait for outstanding processes */
2040
2041	if (pipe(p) < 0)
2042		fatal(_("cannot open pipe `%s' (%s)"), cmd, strerror(errno));
2043
2044#ifdef __EMX__
2045	save_stdout = dup(1); /* save stdout */
2046	rp->iop = NULL;
2047	if (save_stdout == -1)
2048		return rp->iop; /* failed */
2049
2050	close(1); /* close stdout */
2051	if (dup(p[1]) != 1)
2052		fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
2053
2054	/* none of these handles must be inherited by the child process */
2055	close(p[1]); /* close pipe input */
2056
2057	os_close_on_exec(p[0], cmd, "pipe", "from"); /* pipe output: input of the parent process */
2058	os_close_on_exec(save_stdout, cmd, "pipe", "from"); /* saved stdout of the parent process */
2059
2060	pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", cmd, NULL);
2061
2062	/* restore stdout */
2063	close(1);
2064	if (dup(save_stdout) != 1)
2065		fatal(_("restoring stdout in parent process failed\n"));
2066	close(save_stdout);
2067
2068#else /* NOT __EMX__ */
2069	if ((pid = fork()) == 0) {
2070		if (close(1) == -1)
2071			fatal(_("close of stdout in child failed (%s)"),
2072				strerror(errno));
2073		if (dup(p[1]) != 1)
2074			fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
2075		if (close(p[0]) == -1 || close(p[1]) == -1)
2076			fatal(_("close of pipe failed (%s)"), strerror(errno));
2077		execl("/bin/sh", "sh", "-c", cmd, NULL);
2078		_exit(errno == ENOENT ? 127 : 126);
2079	}
2080#endif /* NOT __EMX__ */
2081
2082	if (pid == -1)
2083		fatal(_("cannot create child process for `%s' (fork: %s)"), cmd, strerror(errno));
2084	rp->pid = pid;
2085#ifndef __EMX__
2086	if (close(p[1]) == -1)
2087		fatal(_("close of pipe failed (%s)"), strerror(errno));
2088#endif
2089	os_close_on_exec(p[0], cmd, "pipe", "from");
2090	rp->iop = iop_alloc(p[0], cmd, NULL);
2091	if (rp->iop == NULL)
2092		(void) close(p[0]);
2093
2094	return (rp->iop);
2095}
2096
2097/* gawk_pclose --- close an open child pipe */
2098
2099static int
2100gawk_pclose(struct redirect *rp)
2101{
2102	if (rp->iop != NULL)
2103		(void) iop_close(rp->iop);
2104	rp->iop = NULL;
2105
2106	/* process previously found, return stored status */
2107	if (rp->pid == -1)
2108		return rp->status;
2109	rp->status = wait_any(rp->pid);
2110	rp->pid = -1;
2111	return rp->status;
2112}
2113
2114#else	/* PIPES_SIMULATED */
2115
2116/*
2117 * use temporary file rather than pipe
2118 * except if popen() provides real pipes too
2119 */
2120
2121#if defined(VMS) || defined(OS2) || defined (MSDOS) || defined(WIN32) || defined(TANDEM) || defined(__EMX__)
2122
2123/* gawk_popen --- open an IOBUF on a child process */
2124
2125static IOBUF *
2126gawk_popen(const char *cmd, struct redirect *rp)
2127{
2128	FILE *current;
2129
2130	os_restore_mode(fileno(stdin));
2131	current = popen(cmd, binmode("r"));
2132#ifdef O_BINARY
2133	if ((BINMODE & 1) != 0)
2134		os_setbinmode(fileno(stdin), O_BINARY);
2135#endif
2136	if (current == NULL)
2137		return NULL;
2138	os_close_on_exec(fileno(current), cmd, "pipe", "from");
2139	rp->iop = iop_alloc(fileno(current), cmd, NULL);
2140	if (rp->iop == NULL) {
2141		(void) pclose(current);
2142		current = NULL;
2143	}
2144	rp->ifp = current;
2145	return (rp->iop);
2146}
2147
2148/* gawk_pclose --- close an open child pipe */
2149
2150static int
2151gawk_pclose(struct redirect *rp)
2152{
2153	int rval, aval, fd = rp->iop->fd;
2154
2155	if (rp->iop != NULL) {
2156		rp->iop->fd = dup(fd);	  /* kludge to allow close() + pclose() */
2157		rval = iop_close(rp->iop);
2158	}
2159	rp->iop = NULL;
2160	aval = pclose(rp->ifp);
2161	rp->ifp = NULL;
2162	return (rval < 0 ? rval : aval);
2163}
2164#else	/* not (VMS || OS2 || MSDOS || TANDEM) */
2165
2166static struct pipeinfo {
2167	char *command;
2168	char *name;
2169} pipes[_NFILE];
2170
2171/* gawk_popen --- open an IOBUF on a child process */
2172
2173static IOBUF *
2174gawk_popen(const char *cmd, struct redirect *rp)
2175{
2176	extern char *strdup P((const char *));
2177	int current;
2178	char *name;
2179	static char cmdbuf[256];
2180
2181	/* get a name to use */
2182	if ((name = tempnam(".", "pip")) == NULL)
2183		return NULL;
2184	sprintf(cmdbuf, "%s > %s", cmd, name);
2185	system(cmdbuf);
2186	if ((current = open(name, O_RDONLY)) == INVALID_HANDLE)
2187		return NULL;
2188	pipes[current].name = name;
2189	pipes[current].command = strdup(cmd);
2190	os_close_on_exec(current, cmd, "pipe", "from");
2191	rp->iop = iop_alloc(current, name, NULL);
2192	if (rp->iop == NULL)
2193		(void) close(current);
2194	return (rp->iop);
2195}
2196
2197/* gawk_pclose --- close an open child pipe */
2198
2199static int
2200gawk_pclose(struct redirect *rp)
2201{
2202	int cur = rp->iop->fd;
2203	int rval = 0;
2204
2205	if (rp->iop != NULL)
2206		rval = iop_close(rp->iop);
2207	rp->iop = NULL;
2208
2209	/* check for an open file  */
2210	if (pipes[cur].name == NULL)
2211		return -1;
2212	unlink(pipes[cur].name);
2213	free(pipes[cur].name);
2214	pipes[cur].name = NULL;
2215	free(pipes[cur].command);
2216	return rval;
2217}
2218#endif	/* not (VMS || OS2 || MSDOS || TANDEM) */
2219
2220#endif	/* PIPES_SIMULATED */
2221
2222/* do_getline --- read in a line, into var and with redirection, as needed */
2223
2224NODE *
2225do_getline(NODE *tree)
2226{
2227	struct redirect *rp = NULL;
2228	IOBUF *iop;
2229	int cnt = EOF;
2230	char *s = NULL;
2231	int errcode;
2232
2233	while (cnt == EOF) {
2234		if (tree->rnode == NULL) {	 /* no redirection */
2235			iop = nextfile(FALSE);
2236			if (iop == NULL)		/* end of input */
2237				return tmp_number((AWKNUM) 0.0);
2238		} else {
2239			int redir_error = 0;
2240
2241			rp = redirect(tree->rnode, &redir_error);
2242			if (rp == NULL && redir_error) { /* failed redirect */
2243				if (! do_traditional)
2244					update_ERRNO();
2245
2246				return tmp_number((AWKNUM) -1.0);
2247			}
2248			iop = rp->iop;
2249			if (iop == NULL)		/* end of input */
2250				return tmp_number((AWKNUM) 0.0);
2251		}
2252		errcode = 0;
2253		cnt = get_a_record(&s, iop, &errcode);
2254		if (errcode != 0) {
2255			if (! do_traditional)
2256				update_ERRNO();
2257
2258			return tmp_number((AWKNUM) -1.0);
2259		}
2260		if (cnt == EOF) {
2261			if (rp != NULL) {
2262				/*
2263				 * Don't do iop_close() here if we are
2264				 * reading from a pipe; otherwise
2265				 * gawk_pclose will not be called.
2266				 */
2267				if ((rp->flag & (RED_PIPE|RED_TWOWAY)) == 0) {
2268					(void) iop_close(iop);
2269					rp->iop = NULL;
2270				}
2271				rp->flag |= RED_EOF;	/* sticky EOF */
2272				return tmp_number((AWKNUM) 0.0);
2273			} else
2274				continue;	/* try another file */
2275		}
2276		if (rp == NULL) {
2277			NR++;
2278			FNR++;
2279		}
2280		if (tree->lnode == NULL)	/* no optional var. */
2281			set_record(s, cnt);
2282		else {			/* assignment to variable */
2283			Func_ptr after_assign = NULL;
2284			NODE **lhs;
2285
2286			lhs = get_lhs(tree->lnode, &after_assign, FALSE);
2287			unref(*lhs);
2288			*lhs = make_string(s, cnt);
2289			(*lhs)->flags |= MAYBE_NUM;
2290			/* we may have to regenerate $0 here! */
2291			if (after_assign != NULL)
2292				(*after_assign)();
2293		}
2294	}
2295	return tmp_number((AWKNUM) 1.0);
2296}
2297
2298/* pathopen --- pathopen with default file extension handling */
2299
2300int
2301pathopen(const char *file)
2302{
2303	int fd = do_pathopen(file);
2304
2305#ifdef DEFAULT_FILETYPE
2306	if (! do_traditional && fd <= INVALID_HANDLE) {
2307		char *file_awk;
2308		int save = errno;
2309#ifdef VMS
2310		int vms_save = vaxc$errno;
2311#endif
2312
2313		/* append ".awk" and try again */
2314		emalloc(file_awk, char *, strlen(file) +
2315			sizeof(DEFAULT_FILETYPE) + 1, "pathopen");
2316		sprintf(file_awk, "%s%s", file, DEFAULT_FILETYPE);
2317		fd = do_pathopen(file_awk);
2318		free(file_awk);
2319		if (fd <= INVALID_HANDLE) {
2320			errno = save;
2321#ifdef VMS
2322			vaxc$errno = vms_save;
2323#endif
2324		}
2325	}
2326#endif	/*DEFAULT_FILETYPE*/
2327
2328	return fd;
2329}
2330
2331/* do_pathopen --- search $AWKPATH for source file */
2332
2333static int
2334do_pathopen(const char *file)
2335{
2336	static const char *savepath = NULL;
2337	static int first = TRUE;
2338	const char *awkpath;
2339	char *cp, *trypath;
2340	int fd;
2341	int len;
2342
2343	if (STREQ(file, "-"))
2344		return (0);
2345
2346	if (do_traditional)
2347		return (devopen(file, "r"));
2348
2349	if (first) {
2350		first = FALSE;
2351		if ((awkpath = getenv("AWKPATH")) != NULL && *awkpath)
2352			savepath = awkpath;	/* used for restarting */
2353		else
2354			savepath = defpath;
2355	}
2356	awkpath = savepath;
2357
2358	/* some kind of path name, no search */
2359	if (ispath(file))
2360		return (devopen(file, "r"));
2361
2362	/* no arbitrary limits: */
2363	len = strlen(awkpath) + strlen(file) + 2;
2364	emalloc(trypath, char *, len, "do_pathopen");
2365
2366	do {
2367		trypath[0] = '\0';
2368
2369		for (cp = trypath; *awkpath && *awkpath != envsep; )
2370			*cp++ = *awkpath++;
2371
2372		if (cp != trypath) {	/* nun-null element in path */
2373			/* add directory punctuation only if needed */
2374			if (! isdirpunct(*(cp-1)))
2375				*cp++ = '/';
2376			/* append filename */
2377			strcpy(cp, file);
2378		} else
2379			strcpy(trypath, file);
2380		if ((fd = devopen(trypath, "r")) > INVALID_HANDLE) {
2381			free(trypath);
2382			return (fd);
2383		}
2384
2385		/* no luck, keep going */
2386		if(*awkpath == envsep && awkpath[1] != '\0')
2387			awkpath++;	/* skip colon */
2388	} while (*awkpath != '\0');
2389	free(trypath);
2390
2391	/*
2392	 * You might have one of the awk paths defined, WITHOUT the current
2393	 * working directory in it. Therefore try to open the file in the
2394	 * current directory.
2395	 */
2396	return (devopen(file, "r"));
2397}
2398
2399#ifdef TEST
2400int bufsize = 8192;
2401
2402void
2403fatal(const char *s)
2404{
2405	printf("%s\n", s);
2406	exit(1);
2407}
2408#endif
2409
2410/* iop_alloc --- allocate an IOBUF structure for an open fd */
2411
2412static IOBUF *
2413iop_alloc(int fd, const char *name, IOBUF *iop)
2414{
2415        struct stat sbuf;
2416
2417        if (fd == INVALID_HANDLE)
2418                return NULL;
2419        if (iop == NULL)
2420                emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
2421	memset(iop, '\0', sizeof(IOBUF));
2422        iop->flag = 0;
2423        if (isatty(fd))
2424                iop->flag |= IOP_IS_TTY;
2425        iop->readsize = iop->size = optimal_bufsize(fd, & sbuf);
2426        iop->sbuf = sbuf;
2427        if (do_lint && S_ISREG(sbuf.st_mode) && sbuf.st_size == 0)
2428                lintwarn(_("data file `%s' is empty"), name);
2429        errno = 0;
2430        iop->fd = fd;
2431        iop->count = iop->scanoff = 0;
2432        iop->name = name;
2433        emalloc(iop->buf, char *, iop->size += 2, "iop_alloc");
2434        iop->off = iop->buf;
2435        iop->dataend = NULL;
2436        iop->end = iop->buf + iop->size;
2437	iop->flag = 0;
2438        return iop;
2439}
2440
2441#define set_RT_to_null() \
2442	(void)(! do_traditional && (unref(RT_node->var_value), \
2443			   RT_node->var_value = Nnull_string))
2444
2445#define set_RT(str, len) \
2446	(void)(! do_traditional && (unref(RT_node->var_value), \
2447			   RT_node->var_value = make_string(str, len)))
2448
2449/* grow must increase size of buffer, set end, make sure off and dataend point at */
2450/* right spot.                                                              */
2451/*                                                                          */
2452/*                                                                          */
2453/* <growbuffer>=                                                            */
2454/* grow_iop_buffer --- grow the buffer */
2455
2456static void
2457grow_iop_buffer(IOBUF *iop)
2458{
2459        size_t valid = iop->dataend - iop->off;
2460        size_t off = iop->off - iop->buf;
2461	size_t newsize;
2462
2463	/*
2464	 * Lop off original extra two bytes, double the size,
2465	 * add them back.
2466	 */
2467        newsize = ((iop->size - 2) * 2) + 2;
2468
2469	/* Check for overflow */
2470	if (newsize <= iop->size)
2471		fatal(_("could not allocate more input memory"));
2472
2473	/* Make sure there's room for a disk block */
2474        if (newsize - valid < iop->readsize)
2475                newsize += iop->readsize + 2;
2476
2477	/* Check for overflow, again */
2478	if (newsize <= iop->size)
2479		fatal(_("could not allocate more input memory"));
2480
2481	iop->size = newsize;
2482        erealloc(iop->buf, char *, iop->size, "grow_iop_buffer");
2483        iop->off = iop->buf + off;
2484        iop->dataend = iop->off + valid;
2485        iop->end = iop->buf + iop->size;
2486}
2487
2488/* Here are the routines.                                                   */
2489/*                                                                          */
2490/*                                                                          */
2491/* <rs1scan>=                                                               */
2492/* rs1scan --- scan for a single character record terminator */
2493
2494static RECVALUE
2495rs1scan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state)
2496{
2497        register char *bp;
2498        register char rs;
2499#ifdef MBS_SUPPORT
2500        size_t mbclen = 0;
2501        mbstate_t mbs;
2502#endif
2503
2504        memset(recm, '\0', sizeof(struct recmatch));
2505        rs = RS->stptr[0];
2506        *(iop->dataend) = rs;   /* set sentinel */
2507        recm->start = iop->off; /* beginning of record */
2508
2509        bp = iop->off;
2510        if (*state == INDATA)   /* skip over data we've already seen */
2511                bp += iop->scanoff;
2512
2513#ifdef MBS_SUPPORT
2514	/*
2515	 * From: Bruno Haible <bruno@clisp.org>
2516	 * To: Aharon Robbins <arnold@skeeve.com>, gnits@gnits.org
2517	 * Subject: Re: multibyte locales: any way to find if a character isn't multibyte?
2518	 * Date: Mon, 23 Jun 2003 12:20:16 +0200
2519	 * Cc: isamu@yamato.ibm.com
2520	 *
2521	 * Hi,
2522	 *
2523	 * > Is there any way to make the following query to the current locale?
2524	 * >
2525	 * > 	Given an 8-bit value, can this value ever appear as part of
2526	 * > 	a multibyte character?
2527	 *
2528	 * There is no simple answer here. The easiest solution I see is to
2529	 * get the current locale's codeset (via locale_charset() which is a
2530	 * wrapper around nl_langinfo(CODESET)), and then perform a case-by-case
2531	 * treatment of the known multibyte encodings, from GB2312 to EUC-JISX0213;
2532	 * for the unibyte encodings, a single btowc() call will tell you.
2533	 *
2534	 * > This is particularly critical for me for ASCII newline ('\n').  If I
2535	 * > can be guaranteed that it never shows up as part of a multibyte character,
2536	 * > I can speed up gawk considerably in mulitbyte locales.
2537	 *
2538	 * This is much simpler to answer!
2539	 * In all ASCII based multibyte encodings used for locales today (this
2540	 * excludes EBCDIC based doublebyte encodings from IBM, and also excludes
2541	 * ISO-2022-JP which is used for email exchange but not as a locale encoding)
2542	 * ALL bytes in the range 0x00..0x2F occur only as a single character, not
2543	 * as part of a multibyte character.
2544	 *
2545	 * So it's safe to assume, but deserves a comment in the source.
2546	 *
2547	 * Bruno
2548	 ***************************************************************
2549	 * From: Bruno Haible <bruno@clisp.org>
2550	 * To: Aharon Robbins <arnold@skeeve.com>
2551	 * Subject: Re: multibyte locales: any way to find if a character isn't multibyte?
2552	 * Date: Mon, 23 Jun 2003 14:27:49 +0200
2553	 *
2554	 * On Monday 23 June 2003 14:11, you wrote:
2555	 *
2556	 * >       if (rs != '\n' && MB_CUR_MAX > 1) {
2557	 *
2558	 * If you assume ASCII, you can even write
2559	 *
2560	 *         if (rs >= 0x30 && MB_CUR_MAX > 1) {
2561	 *
2562	 * (this catches also the space character) but if portability to EBCDIC
2563	 * systems is desired, your code is fine as is.
2564	 *
2565	 * Bruno
2566	 */
2567	/* Thus, the check for \n here; big speedup ! */
2568        if (rs != '\n' && gawk_mb_cur_max > 1) {
2569                int len = iop->dataend - bp;
2570                int found = 0;
2571                memset(&mbs, 0, sizeof(mbstate_t));
2572                do {
2573                        if (*bp == rs)
2574                                found = 1;
2575                        mbclen = mbrlen(bp, len, &mbs);
2576                        if ((mbclen == 1) || (mbclen == (size_t) -1)
2577                                || (mbclen == (size_t) -2) || (mbclen == 0)) {
2578                                /* We treat it as a singlebyte character.  */
2579                                mbclen = 1;
2580                        }
2581                        len -= mbclen;
2582                        bp += mbclen;
2583                } while (len > 0 && ! found);
2584
2585		/* Check that newline found isn't the sentinel. */
2586                if (found && (bp - mbclen) < iop->dataend) {
2587                	/*
2588			 * set len to what we have so far, in case this is
2589			 * all there is
2590			 */
2591                	recm->len = bp - recm->start - mbclen;
2592                        recm->rt_start = bp - mbclen;
2593                        recm->rt_len = mbclen;
2594                        *state = NOSTATE;
2595                        return REC_OK;
2596                } else {
2597			/* also set len */
2598                	recm->len = bp - recm->start;
2599                        *state = INDATA;
2600                        iop->scanoff = bp - iop->off;
2601                        return NOTERM;
2602                }
2603        }
2604#endif
2605        while (*bp != rs)
2606                bp++;
2607
2608        /* set len to what we have so far, in case this is all there is */
2609        recm->len = bp - recm->start;
2610
2611        if (bp < iop->dataend) {        /* found it in the buffer */
2612                recm->rt_start = bp;
2613                recm->rt_len = 1;
2614                *state = NOSTATE;
2615                return REC_OK;
2616        } else {
2617                *state = INDATA;
2618                iop->scanoff = bp - iop->off;
2619                return NOTERM;
2620        }
2621}
2622
2623/* <rsrescan>=                                                              */
2624/* rsrescan --- search for a regex match in the buffer */
2625
2626static RECVALUE
2627rsrescan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state)
2628{
2629        register char *bp;
2630        size_t restart = 0, reend = 0;
2631        Regexp *RSre = RS_regexp;
2632
2633        memset(recm, '\0', sizeof(struct recmatch));
2634        recm->start = iop->off;
2635
2636        bp = iop->off;
2637        if (*state == INDATA)
2638                bp += iop->scanoff;
2639
2640again:
2641        /* case 1, no match */
2642        if (research(RSre, bp, 0, iop->dataend - bp, TRUE) == -1) {
2643                /* set len, in case this all there is. */
2644                recm->len = iop->dataend - iop->off - 1;
2645                return NOTERM;
2646        }
2647
2648        /* ok, we matched within the buffer, set start and end */
2649        restart = RESTART(RSre, iop->off);
2650        reend = REEND(RSre, iop->off);
2651
2652        /* case 2, null regex match, grow buffer, try again */
2653        if (restart == reend) {
2654                *state = INDATA;
2655                iop->scanoff = reend + 1;
2656                /*
2657                 * If still room in buffer, skip over null match
2658                 * and restart search. Otherwise, return.
2659                 */
2660                if (bp + iop->scanoff < iop->dataend) {
2661                        bp += iop->scanoff;
2662                        goto again;
2663                }
2664                recm->len = (bp - iop->off) + restart;
2665                return NOTERM;
2666        }
2667
2668        /*
2669         * At this point, we have a non-empty match.
2670         *
2671         * First, fill in rest of data. The rest of the cases return
2672         * a record and terminator.
2673         */
2674        recm->len = restart;
2675        recm->rt_start = bp + restart;
2676        recm->rt_len = reend - restart;
2677        *state = NOSTATE;
2678
2679        /*
2680         * 3. Match exactly at end:
2681         *      if re is a simple string match
2682         *              found a simple string match at end, return REC_OK
2683         *      else
2684         *              grow buffer, add more data, try again
2685         *      fi
2686         */
2687        if (iop->off + reend >= iop->dataend) {
2688                if (reisstring(RS->stptr, RS->stlen, RSre, iop->off))
2689                        return REC_OK;
2690                else
2691                        return TERMATEND;
2692        }
2693
2694        /*
2695         * 4. Match within xxx bytes of end & maybe islong re:
2696         *      return TERMNEAREND
2697         */
2698
2699        /*
2700         * case 4, match succeeded, but there may be more in
2701         * the next input buffer.
2702         *
2703         * Consider an RS of   xyz(abc)?   where the
2704         * exact end of the buffer is   xyza  and the
2705         * next two, unread, characters are bc.
2706         *
2707         * This matches the "xyz" and ends up putting the
2708         * "abc" into the front of the next record. Ooops.
2709         *
2710         * The remaybelong() function looks to see if the
2711         * regex contains one of: + * ? |.  This is a very
2712         * simple heuristic, but in combination with the
2713         * "end of match within a few bytes of end of buffer"
2714         * check, should keep things reasonable.
2715         */
2716
2717        /*
2718         * XXX: The reisstring and remaybelong tests should
2719         * really be done once when RS is assigned to and
2720         * then tested as flags here.  Maybe one day.
2721         */
2722
2723        /* succession of tests is easier to trace in GDB. */
2724        if (remaybelong(RS->stptr, RS->stlen)) {
2725                char *matchend = iop->off + reend;
2726
2727                if (iop->dataend - matchend < RS->stlen)
2728                        return TERMNEAREND;
2729        }
2730
2731        return REC_OK;
2732}
2733
2734/* <rsnullscan>=                                                            */
2735/* rsnullscan --- handle RS = "" */
2736
2737static RECVALUE
2738rsnullscan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state)
2739{
2740        register char *bp;
2741
2742        if (*state == NOSTATE || *state == INLEADER)
2743                memset(recm, '\0', sizeof(struct recmatch));
2744
2745        recm->start = iop->off;
2746
2747        bp = iop->off;
2748        if (*state != NOSTATE)
2749                bp += iop->scanoff;
2750
2751        /* set sentinel */
2752        *(iop->dataend) = '\n';
2753
2754        if (*state == INTERM)
2755                goto find_longest_terminator;
2756        else if (*state == INDATA)
2757                goto scan_data;
2758        /* else
2759                fall into things from beginning,
2760                either NOSTATE or INLEADER */
2761
2762/* skip_leading: */
2763        /* leading newlines are ignored */
2764        while (*bp == '\n' && bp < iop->dataend)
2765                bp++;
2766
2767        if (bp >= iop->dataend) {       /* LOTS of leading newlines, sheesh. */
2768                *state = INLEADER;
2769                iop->scanoff = bp - iop->off;
2770                return NOTERM;
2771        }
2772
2773        iop->off = recm->start = bp;    /* real start of record */
2774scan_data:
2775        while (*bp++ != '\n')
2776                continue;
2777
2778        if (bp >= iop->dataend) {       /* no terminator */
2779                iop->scanoff = recm->len = bp - iop->off - 1;
2780                *state = INDATA;
2781                return NOTERM;
2782        }
2783
2784        /* found one newline before end of buffer, check next char */
2785        if (*bp != '\n')
2786                goto scan_data;
2787
2788        /* we've now seen at least two newlines */
2789        *state = INTERM;
2790        recm->len = bp - iop->off - 1;
2791        recm->rt_start = bp - 1;
2792
2793find_longest_terminator:
2794        /* find as many newlines as we can, to set RT */
2795        while (*bp == '\n' && bp < iop->dataend)
2796                bp++;
2797
2798        recm->rt_len = bp - recm->rt_start;
2799        iop->scanoff = bp - iop->off;
2800
2801        if (bp >= iop->dataend)
2802                return TERMATEND;
2803
2804        return REC_OK;
2805}
2806
2807/* <getarecord>=                                                            */
2808/* get_a_record --- read a record from IOP into out, return length of EOF, set RT */
2809
2810int
2811get_a_record(char **out,        /* pointer to pointer to data */
2812        IOBUF *iop,             /* input IOP */
2813        int *errcode)           /* pointer to error variable */
2814{
2815        struct recmatch recm;
2816        SCANSTATE state;
2817        RECVALUE ret;
2818        int retval;
2819        NODE *rtval = NULL;
2820	static RECVALUE (*lastmatchrec)P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state)) = NULL;
2821
2822        if (at_eof(iop) && no_data_left(iop))
2823                return EOF;
2824
2825        /* <fill initial buffer>=                                                   */
2826        if (has_no_data(iop) || no_data_left(iop)) {
2827                iop->count = read(iop->fd, iop->buf, iop->readsize);
2828                if (iop->count == 0) {
2829                        iop->flag |= IOP_AT_EOF;
2830                        return EOF;
2831                } else if (iop->count == -1) {
2832                        if (! do_traditional && errcode != NULL) {
2833                                *errcode = errno;
2834                                iop->flag |= IOP_AT_EOF;
2835                                return EOF;
2836                        } else
2837                                fatal(_("error reading input file `%s': %s"),
2838                                        iop->name, strerror(errno));
2839                } else {
2840                        iop->dataend = iop->buf + iop->count;
2841                        iop->off = iop->buf;
2842                }
2843        }
2844
2845
2846
2847        /* <loop through file to find a record>=                                    */
2848        state = NOSTATE;
2849        for (;;) {
2850                size_t dataend_off;
2851
2852                ret = (*matchrec)(iop, & recm, & state);
2853
2854                if (ret == REC_OK)
2855                        break;
2856
2857                /* need to add more data to buffer */
2858                /* <shift data down in buffer>=                                             */
2859                dataend_off = iop->dataend - iop->off;
2860                memmove(iop->buf, iop->off, dataend_off);
2861                iop->off = iop->buf;
2862                iop->dataend = iop->buf + dataend_off;
2863
2864                /* <adjust recm contents>=                                                  */
2865                recm.start = iop->off;
2866                if (recm.rt_start != NULL)
2867                        recm.rt_start = iop->off + recm.len;
2868
2869                /* <read more data, break if EOF>=                                          */
2870                if ((iop->flag & IOP_IS_INTERNAL) != 0) {
2871                        iop->flag |= IOP_AT_EOF;
2872                        break;
2873                } else {
2874#define min(x, y) (x < y ? x : y)
2875                        /* subtract one in read count to leave room for sentinel */
2876                        size_t room_left = iop->end - iop->dataend - 1;
2877                        size_t amt_to_read = min(iop->readsize, room_left);
2878
2879                        if (amt_to_read < iop->readsize) {
2880                                grow_iop_buffer(iop);
2881                                /* <adjust recm contents>=                                                  */
2882                                recm.start = iop->off;
2883                                if (recm.rt_start != NULL)
2884                                        recm.rt_start = iop->off + recm.len;
2885
2886                                /* recalculate amt_to_read */
2887                                room_left = iop->end - iop->dataend - 1;
2888                                amt_to_read = min(iop->readsize, room_left);
2889                        }
2890                        while (amt_to_read + iop->readsize < room_left)
2891                                amt_to_read += iop->readsize;
2892
2893                        iop->count = read(iop->fd, iop->dataend, amt_to_read);
2894                        if (iop->count == -1) {
2895                                if (! do_traditional && errcode != NULL) {
2896                                        *errcode = errno;
2897                                        iop->flag |= IOP_AT_EOF;
2898                                        break;
2899                                } else
2900                                        fatal(_("error reading input file `%s': %s"),
2901                                                iop->name, strerror(errno));
2902                        } else if (iop->count == 0) {
2903                                /*
2904                                 * hit EOF before matching RS, so end
2905                                 * the record and set RT to ""
2906                                 */
2907                                iop->flag |= IOP_AT_EOF;
2908                                break;
2909                        } else
2910                                iop->dataend += iop->count;
2911                }
2912
2913
2914        }
2915
2916
2917
2918        /* <set record, RT, return right value>=                                    */
2919
2920        /*
2921         * rtval is not a static pointer to avoid dangling pointer problems
2922         * in case awk code assigns to RT.  A remote possibility, to be sure,
2923         * but Bitter Experience teaches us not to make ``that'll never
2924         * happen'' kinds of assumptions.
2925         */
2926        rtval = RT_node->var_value;
2927
2928        if (recm.rt_len == 0) {
2929                set_RT_to_null();
2930		lastmatchrec = NULL;
2931	} else {
2932                assert(recm.rt_start != NULL);
2933                /*
2934                 * Optimization. For rs1 case, don't set RT if
2935                 * character is same as last time.  This knocks a
2936                 * chunk of time off something simple like
2937                 *
2938                 *      gawk '{ print }' /some/big/file
2939                 *
2940                 * Similarly, for rsnull case, if length of new RT is
2941                 * shorter than current RT, just bump length down in RT.
2942		 *
2943		 * Make sure that matchrec didn't change since the last
2944		 * check.  (Ugh, details, details, details.)
2945                 */
2946		if (lastmatchrec == NULL || lastmatchrec != matchrec) {
2947			lastmatchrec = matchrec;
2948			set_RT(recm.rt_start, recm.rt_len);
2949		} else if (matchrec == rs1scan) {
2950                        if (rtval->stlen != 1 || rtval->stptr[0] != recm.rt_start[0])
2951                                set_RT(recm.rt_start, recm.rt_len);
2952                        /* else
2953                                leave it alone */
2954                } else if (matchrec == rsnullscan) {
2955                        if (rtval->stlen <= recm.rt_len)
2956                                rtval->stlen = recm.rt_len;
2957                        else
2958                                set_RT(recm.rt_start, recm.rt_len);
2959                } else
2960                        set_RT(recm.rt_start, recm.rt_len);
2961        }
2962
2963        if (recm.len == 0) {
2964                *out = NULL;
2965                retval = 0;
2966        } else {
2967                assert(recm.start != NULL);
2968                *out = recm.start;
2969                retval = recm.len;
2970        }
2971
2972	iop->off += recm.len + recm.rt_len;
2973
2974        if (recm.len == 0 && recm.rt_len == 0 && at_eof(iop))
2975                return EOF;
2976        else
2977                return retval;
2978
2979}
2980
2981/* set_RS --- update things as appropriate when RS is set */
2982
2983void
2984set_RS()
2985{
2986	static NODE *save_rs = NULL;
2987
2988	/*
2989	 * Don't use cmp_nodes(), which pays attention to IGNORECASE.
2990	 */
2991	if (save_rs
2992		&& RS_node->var_value->stlen == save_rs->stlen
2993		&& STREQN(RS_node->var_value->stptr, save_rs->stptr, save_rs->stlen)) {
2994		/*
2995		 * It could be that just IGNORECASE changed.  If so,
2996		 * update the regex and then do the same for FS.
2997		 * set_IGNORECASE() relies on this routine to call
2998		 * set_FS().
2999		 */
3000		RS_regexp = (IGNORECASE ? RS_re_no_case : RS_re_yes_case);
3001		goto set_FS;
3002	}
3003	unref(save_rs);
3004	save_rs = dupnode(RS_node->var_value);
3005	RS_is_null = FALSE;
3006	RS = force_string(RS_node->var_value);
3007	if (RS_regexp != NULL) {
3008		refree(RS_re_yes_case);
3009		refree(RS_re_no_case);
3010		RS_re_yes_case = RS_re_no_case = RS_regexp = NULL;
3011	}
3012	if (RS->stlen == 0) {
3013		RS_is_null = TRUE;
3014		matchrec = rsnullscan;
3015	} else if (RS->stlen > 1) {
3016		static int warned = FALSE;
3017
3018		RS_re_yes_case = make_regexp(RS->stptr, RS->stlen, FALSE);
3019		RS_re_no_case = make_regexp(RS->stptr, RS->stlen, TRUE);
3020		RS_regexp = (IGNORECASE ? RS_re_no_case : RS_re_yes_case);
3021
3022		matchrec = rsrescan;
3023
3024		if (do_lint && ! warned) {
3025			lintwarn(_("multicharacter value of `RS' is a gawk extension"));
3026			warned = TRUE;
3027		}
3028	} else
3029		matchrec = rs1scan;
3030set_FS:
3031	if (! using_fieldwidths())
3032		set_FS();
3033}
3034
3035/* pty_vs_pipe --- return true if should use pty instead of pipes for `|&' */
3036
3037/*
3038 * This works by checking if PROCINFO["command", "pty"] exists and is true.
3039 */
3040
3041static int
3042pty_vs_pipe(const char *command)
3043{
3044#ifdef HAVE_TERMIOS_H
3045	char *full_index;
3046	size_t full_len;
3047	NODE *val;
3048	NODE *sub;
3049
3050	if (PROCINFO_node == NULL)
3051		return FALSE;
3052
3053	full_len = strlen(command)
3054			+ SUBSEP_node->var_value->stlen
3055			+ 3	/* strlen("pty") */
3056			+ 1;	/* string terminator */
3057	emalloc(full_index, char *, full_len, "pty_vs_pipe");
3058	sprintf(full_index, "%s%.*spty", command,
3059		(int) SUBSEP_node->var_value->stlen, SUBSEP_node->var_value->stptr);
3060
3061	sub = tmp_string(full_index, strlen(full_index));
3062	val = in_array(PROCINFO_node, sub);
3063	free_temp(sub);
3064	free(full_index);
3065
3066	if (val) {
3067		if (val->flags & MAYBE_NUM)
3068			(void) force_number(val);
3069		if (val->flags & NUMBER)
3070			return (val->numbr != 0.0);
3071		else
3072			return (val->stlen != 0);
3073	}
3074#endif /* HAVE_TERMIOS_H */
3075	return FALSE;
3076}
3077
3078/* iopflags2str --- make IOP flags printable */
3079
3080const char *
3081iopflags2str(int flag)
3082{
3083	static const struct flagtab values[] = {
3084		{ IOP_IS_TTY, "IOP_IS_TTY" },
3085		{ IOP_IS_INTERNAL, "IOP_IS_INTERNAL" },
3086		{ IOP_NO_FREE, "IOP_NO_FREE" },
3087		{ IOP_NOFREE_OBJ, "IOP_NOFREE_OBJ" },
3088		{ IOP_AT_EOF,  "IOP_AT_EOF" },
3089		{ 0, NULL }
3090	};
3091
3092	return genflags2str(flag, values);
3093}
3094