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