"Fossies" - the Fresh Open Source Software Archive

Member "gawk-5.1.0/io.c" (20 Mar 2020, 112107 Bytes) of package /linux/misc/gawk-5.1.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "io.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.0.1_vs_5.1.0.

    1 /*
    2  * io.c --- routines for dealing with input and output and records
    3  */
    4 
    5 /*
    6  * Copyright (C) 1986, 1988, 1989, 1991-2020,
    7  * the Free Software Foundation, Inc.
    8  *
    9  * This file is part of GAWK, the GNU implementation of the
   10  * AWK Programming Language.
   11  *
   12  * GAWK is free software; you can redistribute it and/or modify
   13  * it under the terms of the GNU General Public License as published by
   14  * the Free Software Foundation; either version 3 of the License, or
   15  * (at your option) any later version.
   16  *
   17  * GAWK is distributed in the hope that it will be useful,
   18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   20  * GNU General Public License for more details.
   21  *
   22  * You should have received a copy of the GNU General Public License
   23  * along with this program; if not, write to the Free Software
   24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
   25  */
   26 
   27 /* For OSF/1 to get struct sockaddr_storage */
   28 #if defined(__osf__) && !defined(_OSF_SOURCE)
   29 #define _OSF_SOURCE
   30 #endif
   31 
   32 #include "awk.h"
   33 
   34 #ifdef HAVE_SYS_PARAM_H
   35 #undef RE_DUP_MAX   /* avoid spurious conflict w/regex.h */
   36 #include <sys/param.h>
   37 #endif /* HAVE_SYS_PARAM_H */
   38 #ifdef HAVE_SYS_IOCTL_H
   39 #include <sys/ioctl.h>
   40 #endif /* HAVE_SYS_IOCTL_H */
   41 
   42 #ifndef O_ACCMODE
   43 #define O_ACCMODE   (O_RDONLY|O_WRONLY|O_RDWR)
   44 #endif
   45 
   46 #if ! defined(S_ISREG) && defined(S_IFREG)
   47 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
   48 #endif
   49 
   50 #ifdef HAVE_TERMIOS_H
   51 #include <termios.h>
   52 #endif
   53 #ifdef HAVE_STROPTS_H
   54 #include <stropts.h>
   55 #endif
   56 
   57 #ifdef HAVE_SOCKETS
   58 
   59 #ifdef HAVE_SYS_SOCKET_H
   60 #include <sys/socket.h>
   61 #else
   62 #include <socket.h>
   63 #endif /* HAVE_SYS_SOCKET_H */
   64 
   65 #ifdef HAVE_NETINET_IN_H
   66 #include <netinet/in.h>
   67 
   68 #ifdef HAVE_ARPA_INET_H
   69 #include <arpa/inet.h>
   70 #endif
   71 
   72 #else /* ! HAVE_NETINET_IN_H */
   73 #include <in.h>
   74 #endif /* HAVE_NETINET_IN_H */
   75 
   76 #ifdef HAVE_NETDB_H
   77 #include <netdb.h>
   78 #endif /* HAVE_NETDB_H */
   79 
   80 #ifdef HAVE_SYS_SELECT_H
   81 #include <sys/select.h>
   82 #endif  /* HAVE_SYS_SELECT_H */
   83 
   84 #ifndef HAVE_GETADDRINFO
   85 #include "missing_d/getaddrinfo.h"
   86 #endif
   87 
   88 #ifndef AI_ADDRCONFIG   /* not everyone has this symbol */
   89 #define AI_ADDRCONFIG 0
   90 #endif /* AI_ADDRCONFIG */
   91 
   92 #ifndef HAVE_SOCKADDR_STORAGE
   93 #define sockaddr_storage sockaddr   /* for older systems */
   94 #endif /* HAVE_SOCKADDR_STORAGE */
   95 
   96 #endif /* HAVE_SOCKETS */
   97 
   98 #ifndef AF_UNSPEC
   99 #define AF_UNSPEC 0
  100 #endif
  101 #ifndef AF_INET
  102 #define AF_INET 2
  103 #endif
  104 #ifndef AF_INET6
  105 #define AF_INET6 10
  106 #endif
  107 
  108 #ifdef HAVE_LIMITS_H
  109 #include <limits.h>
  110 #endif
  111 
  112 #if defined(HAVE_POPEN_H)
  113 #include "popen.h"
  114 #endif
  115 
  116 #ifdef __EMX__
  117 #include <process.h>
  118 
  119 #if !defined(_S_IFDIR) && defined(S_IFDIR)
  120 #define _S_IFDIR    S_IFDIR
  121 #endif
  122 
  123 #if !defined(_S_IRWXU) && defined(S_IRWXU)
  124 #define _S_IRWXU    S_IRWXU
  125 #endif
  126 #endif
  127 
  128 #ifndef ENFILE
  129 #define ENFILE EMFILE
  130 #endif
  131 
  132 #if defined(__DJGPP__)
  133 #define closemaybesocket(fd)    close(fd)
  134 #endif
  135 
  136 #if defined(VMS)
  137 #include <ssdef.h>
  138 #ifndef SS$_EXBYTLM
  139 #define SS$_EXBYTLM 0x2a14  /* VMS 8.4 seen */
  140 #endif
  141 #include <rmsdef.h>
  142 #define closemaybesocket(fd)    close(fd)
  143 #endif
  144 
  145 #ifdef HAVE_SOCKETS
  146 
  147 #ifndef SHUT_RD
  148 # ifdef SD_RECEIVE
  149 #  define SHUT_RD   SD_RECEIVE
  150 # else
  151 #  define SHUT_RD   0
  152 # endif
  153 #endif
  154 
  155 #ifndef SHUT_WR
  156 # ifdef SD_SEND
  157 #  define SHUT_WR   SD_SEND
  158 # else
  159 #  define SHUT_WR   1
  160 # endif
  161 #endif
  162 
  163 #ifndef SHUT_RDWR
  164 # ifdef SD_BOTH
  165 #  define SHUT_RDWR SD_BOTH
  166 # else
  167 #  define SHUT_RDWR 2
  168 # endif
  169 #endif
  170 
  171 /* MinGW defines non-trivial macros on pc/socket.h.  */
  172 #ifndef FD_TO_SOCKET
  173 # define FD_TO_SOCKET(fd)   (fd)
  174 # define closemaybesocket(fd)   close(fd)
  175 #endif
  176 
  177 #ifndef SOCKET_TO_FD
  178 # define SOCKET_TO_FD(s)    (s)
  179 # define SOCKET         int
  180 #endif
  181 
  182 #else /* HAVE_SOCKETS */
  183 
  184 #ifndef closemaybesocket
  185 # define closemaybesocket(fd)   close(fd)
  186 #endif
  187 
  188 #endif /* HAVE_SOCKETS */
  189 
  190 #ifndef HAVE_SETSID
  191 #define setsid()    /* nothing */
  192 #endif /* HAVE_SETSID */
  193 
  194 #if defined(_AIX)
  195 #undef TANDEM   /* AIX defines this in one of its header files */
  196 #endif
  197 
  198 #ifdef __DJGPP__
  199 #define PIPES_SIMULATED
  200 #endif
  201 
  202 #ifdef __MINGW32__
  203 # ifndef PIPES_SIMULATED
  204 #  define pipe(fds) _pipe(fds, 0, O_NOINHERIT)
  205 # endif
  206 #endif
  207 
  208 #ifdef HAVE_MPFR
  209 /* increment NR or FNR */
  210 #define INCREMENT_REC(X)    (do_mpfr && X == (LONG_MAX - 1)) ? \
  211                 (mpz_add_ui(M##X, M##X, 1), X = 0) : X++
  212 #else
  213 #define INCREMENT_REC(X)    X++
  214 #endif
  215 
  216 /* Several macros to make the code a bit clearer. */
  217 #define at_eof(iop)     (((iop)->flag & IOP_AT_EOF) != 0)
  218 #define has_no_data(iop)        ((iop)->dataend == NULL)
  219 #define no_data_left(iop)   ((iop)->off >= (iop)->dataend)
  220 #define buffer_has_all_data(iop) ((iop)->dataend - (iop)->off == (iop)->public.sbuf.st_size)
  221 
  222 /*
  223  * The key point to the design is to split out the code that searches through
  224  * a buffer looking for the record and the terminator into separate routines,
  225  * with a higher-level routine doing the reading of data and buffer management.
  226  * This makes the code easier to manage; the buffering code is the same
  227  * independent of how we find a record.  Communication is via the return
  228  * value:
  229  */
  230 
  231 typedef enum recvalues {
  232         REC_OK,         /* record and terminator found, recmatch struct filled in */
  233         NOTERM,         /* no terminator found, give me more input data */
  234         TERMATEND,      /* found terminator at end of buffer */
  235         TERMNEAREND     /* found terminator close to end of buffer, for when
  236                the RE might be match more data further in
  237                the file. */
  238 } RECVALUE;
  239 
  240 /*
  241  * Between calls to a scanning routine, the state is stored in
  242  * an enum scanstate variable.  Not all states apply to all
  243  * variants, but the higher code doesn't really care.
  244  */
  245 
  246 typedef enum scanstate {
  247         NOSTATE,        /* scanning not started yet (all) */
  248         INLEADER,       /* skipping leading data (RS = "") */
  249         INDATA,         /* in body of record (all) */
  250         INTERM          /* scanning terminator (RS = "", RS = regexp) */
  251 } SCANSTATE;
  252 
  253 /*
  254  * When a record is seen (REC_OK or TERMATEND), the following
  255  * structure is filled in.
  256  */
  257 
  258 struct recmatch {
  259         char *start;    /* record start */
  260         size_t len;     /* length of record */
  261         char *rt_start; /* start of terminator */
  262         size_t rt_len;  /* length of terminator */
  263 };
  264 
  265 
  266 static int iop_close(IOBUF *iop);
  267 static void close_one(void);
  268 static int close_redir(struct redirect *rp, bool exitwarn, two_way_close_type how);
  269 #ifndef PIPES_SIMULATED
  270 static int wait_any(int interesting);
  271 #endif
  272 static IOBUF *gawk_popen(const char *cmd, struct redirect *rp);
  273 static IOBUF *iop_alloc(int fd, const char *name, int errno_val);
  274 static IOBUF *iop_finish(IOBUF *iop);
  275 static int gawk_pclose(struct redirect *rp);
  276 static int str2mode(const char *mode);
  277 static int two_way_open(const char *str, struct redirect *rp, int extfd);
  278 static bool pty_vs_pipe(const char *command);
  279 static void find_input_parser(IOBUF *iop);
  280 static bool find_output_wrapper(awk_output_buf_t *outbuf);
  281 static void init_output_wrapper(awk_output_buf_t *outbuf);
  282 static bool find_two_way_processor(const char *name, struct redirect *rp);
  283 
  284 static RECVALUE rs1scan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state);
  285 static RECVALUE rsnullscan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state);
  286 static RECVALUE rsrescan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state);
  287 
  288 static RECVALUE (*matchrec)(IOBUF *iop, struct recmatch *recm, SCANSTATE *state) = rs1scan;
  289 
  290 static int get_a_record(char **out, IOBUF *iop, int *errcode, const awk_fieldwidth_info_t **field_width);
  291 
  292 static void free_rp(struct redirect *rp);
  293 
  294 struct inet_socket_info {
  295     int family;     /* AF_UNSPEC, AF_INET, or AF_INET6 */
  296     int protocol;       /* SOCK_STREAM or SOCK_DGRAM */
  297     /*
  298      * N.B. If we used 'char *' or 'const char *' pointers to the
  299      * substrings, it would trigger compiler warnings about the casts
  300      * in either inetfile() or devopen().  So we use offset/len to
  301      * avoid that.
  302      */
  303     struct {
  304         int offset;
  305         int len;
  306     } localport, remotehost, remoteport;
  307 };
  308 
  309 static bool inetfile(const char *str, size_t len, struct inet_socket_info *isn);
  310 
  311 static NODE *in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx);
  312 static long get_read_timeout(IOBUF *iop);
  313 static ssize_t read_with_timeout(int fd, char *buf, size_t size);
  314 
  315 static bool read_can_timeout = false;
  316 static long read_timeout;
  317 static long read_default_timeout;
  318 
  319 static struct redirect *red_head = NULL;
  320 static NODE *RS = NULL;
  321 static Regexp *RS_re[2];    /* index 0 - don't ignore case, index 1, do */
  322 static Regexp *RS_regexp;
  323 
  324 static const char nonfatal[] = "NONFATAL";
  325 
  326 bool RS_is_null;
  327 
  328 extern NODE *ARGC_node;
  329 extern NODE *ARGV_node;
  330 extern NODE *ARGIND_node;
  331 extern NODE **fields_arr;
  332 
  333 /* init_io --- set up timeout related variables */
  334 
  335 void
  336 init_io()
  337 {
  338     long tmout;
  339 
  340     /* Only MinGW has a non-trivial implementation of this.  */
  341     init_sockets();
  342 
  343     /*
  344      * N.B.: all these hacks are to minimize the effect
  345      * on programs that do not care about timeout.
  346      */
  347 
  348     /* Parse the env. variable only once */
  349     tmout = getenv_long("GAWK_READ_TIMEOUT");
  350     if (tmout > 0) {
  351         read_default_timeout = tmout;
  352         read_can_timeout = true;
  353     }
  354 
  355     /*
  356      * PROCINFO entries for timeout are dynamic;
  357      * We can't be any more specific than this.
  358      */
  359     if (PROCINFO_node != NULL)
  360         read_can_timeout = true;
  361 }
  362 
  363 
  364 #if defined(__DJGPP__) || defined(__MINGW32__) || defined(__EMX__) || defined(__CYGWIN__)
  365 /* binmode --- convert BINMODE to string for fopen */
  366 
  367 static const char *
  368 binmode(const char *mode)
  369 {
  370     switch (mode[0]) {
  371     case 'r':
  372         if ((BINMODE & BINMODE_INPUT) != 0)
  373             mode = "rb";
  374         break;
  375     case 'w':
  376     case 'a':
  377         if ((BINMODE & BINMODE_OUTPUT) != 0)
  378             mode = (mode[0] == 'w' ? "wb" : "ab");
  379         break;
  380     }
  381     return mode;
  382 }
  383 #else
  384 #define binmode(mode)   (mode)
  385 #endif
  386 
  387 #ifdef VMS
  388 /* File pointers have an extra level of indirection, and there are cases where
  389    `stdin' can be null.  That can crash gawk if fileno() is used as-is.  */
  390 static int vmsrtl_fileno(FILE *);
  391 static int vmsrtl_fileno(fp) FILE *fp; { return fileno(fp); }
  392 #undef fileno
  393 #define fileno(FP) (((FP) && *(FP)) ? vmsrtl_fileno(FP) : -1)
  394 #endif  /* VMS */
  395 
  396 /* after_beginfile --- reset necessary state after BEGINFILE has run */
  397 
  398 void
  399 after_beginfile(IOBUF **curfile)
  400 {
  401     IOBUF *iop;
  402 
  403     iop = *curfile;
  404     assert(iop != NULL);
  405 
  406     /*
  407      * Input parsers could have been changed by BEGINFILE,
  408      * so delay check until now.
  409      */
  410 
  411     find_input_parser(iop);
  412 
  413     if (! iop->valid) {
  414         const char *fname;
  415         int errcode;
  416         bool valid;
  417 
  418         fname = iop->public.name;
  419         errcode = iop->errcode;
  420         valid = iop->valid;
  421         errno = 0;
  422         update_ERRNO_int(errcode);
  423         iop_close(iop);
  424         *curfile = NULL;
  425         if (! valid && errcode == EISDIR && ! do_traditional) {
  426             warning(_("command line argument `%s' is a directory: skipped"), fname);
  427             return;     /* read next file */
  428         }
  429         fatal(_("cannot open file `%s' for reading: %s"),
  430                 fname, strerror(errcode));
  431     }
  432 }
  433 
  434 /* nextfile --- move to the next input data file */
  435 /*
  436  * Return value > 0 ----> run BEGINFILE block
  437  * *curfile = NULL  ----> hit EOF, run ENDFILE block
  438  */
  439 
  440 int
  441 nextfile(IOBUF **curfile, bool skipping)
  442 {
  443     static long i = 1;
  444     static bool files = false;
  445     NODE *arg, *tmp;
  446     const char *fname;
  447     int fd = INVALID_HANDLE;
  448     int errcode = 0;
  449     IOBUF *iop = *curfile;
  450     long argc;
  451 
  452     if (skipping) {         /* for 'nextfile' call */
  453         errcode = 0;
  454         if (iop != NULL) {
  455             errcode = iop->errcode;
  456             (void) iop_close(iop);
  457         }
  458         *curfile = NULL;
  459         return (errcode == 0);
  460     }
  461 
  462     if (iop != NULL) {
  463         if (at_eof(iop)) {
  464             assert(iop->public.fd != INVALID_HANDLE);
  465             (void) iop_close(iop);
  466             *curfile = NULL;
  467             return 1;   /* run endfile block */
  468         } else
  469             return 0;
  470     }
  471 
  472     argc = get_number_si(ARGC_node->var_value);
  473 
  474     for (; i < argc; i++) {
  475         tmp = make_number((AWKNUM) i);
  476         (void) force_string(tmp);
  477         arg = in_array(ARGV_node, tmp);
  478         unref(tmp);
  479         if (arg == NULL || arg->stlen == 0)
  480             continue;
  481         arg = force_string(arg);
  482         if (! do_traditional) {
  483             unref(ARGIND_node->var_value);
  484             ARGIND_node->var_value = make_number((AWKNUM) i);
  485         }
  486 
  487         if (! arg_assign(arg->stptr, false)) {
  488             files = true;
  489             fname = arg->stptr;
  490 
  491             /* manage the awk variables: */
  492             unref(FILENAME_node->var_value);
  493             FILENAME_node->var_value = dupnode(arg);
  494 #ifdef HAVE_MPFR
  495             if (is_mpg_number(FNR_node->var_value))
  496                 mpz_set_ui(MFNR, 0);
  497 #endif
  498             FNR = 0;
  499 
  500             /* IOBUF management: */
  501             errno = 0;
  502             fd = devopen(fname, binmode("r"));
  503             if (fd == INVALID_HANDLE && errno == EMFILE) {
  504                 close_one();
  505                 close_one();
  506                 fd = devopen(fname, binmode("r"));
  507             }
  508             errcode = errno;
  509             if (! do_traditional)
  510                 update_ERRNO_int(errno);
  511             iop = iop_alloc(fd, fname, errcode);
  512             *curfile = iop_finish(iop);
  513             if (iop->public.fd == INVALID_HANDLE)
  514                 iop->errcode = errcode;
  515             else if (iop->valid)
  516                 iop->errcode = 0;
  517 
  518             if (! do_traditional && iop->errcode != 0)
  519                 update_ERRNO_int(iop->errcode);
  520 
  521             return ++i; /* run beginfile block */
  522         }
  523     }
  524 
  525     if (files == false) {
  526         files = true;
  527         /* no args. -- use stdin */
  528         /* FNR is init'ed to 0 */
  529         errno = 0;
  530         if (! do_traditional)
  531             update_ERRNO_int(errno);
  532 
  533         unref(FILENAME_node->var_value);
  534         FILENAME_node->var_value = make_string("-", 1);
  535         FILENAME_node->var_value->flags |= USER_INPUT; /* be pedantic */
  536         fname = "-";
  537         iop = iop_alloc(fileno(stdin), fname, 0);
  538         *curfile = iop_finish(iop);
  539 
  540         if (iop->public.fd == INVALID_HANDLE) {
  541             errcode = errno;
  542             errno = 0;
  543             update_ERRNO_int(errno);
  544             (void) iop_close(iop);
  545             *curfile = NULL;
  546             fatal(_("cannot open file `%s' for reading: %s"),
  547                     fname, strerror(errcode));
  548         }
  549         return ++i; /* run beginfile block */
  550     }
  551 
  552     return -1;  /* end of input, run end block or Op_atexit */
  553 }
  554 
  555 /* set_FNR --- update internal FNR from awk variable */
  556 
  557 void
  558 set_FNR()
  559 {
  560     NODE *n = FNR_node->var_value;
  561     (void) force_number(n);
  562 #ifdef HAVE_MPFR
  563     if (is_mpg_number(n))
  564         FNR = mpg_set_var(FNR_node);
  565     else
  566 #endif
  567     FNR = get_number_si(n);
  568 }
  569 
  570 /* set_NR --- update internal NR from awk variable */
  571 
  572 void
  573 set_NR()
  574 {
  575     NODE *n = NR_node->var_value;
  576     (void) force_number(n);
  577 #ifdef HAVE_MPFR
  578     if (is_mpg_number(n))
  579         NR = mpg_set_var(NR_node);
  580     else
  581 #endif
  582     NR = get_number_si(n);
  583 }
  584 
  585 /* inrec --- This reads in a record from the input file */
  586 
  587 bool
  588 inrec(IOBUF *iop, int *errcode)
  589 {
  590     char *begin;
  591     int cnt;
  592     bool retval = true;
  593     const awk_fieldwidth_info_t *field_width = NULL;
  594 
  595     if (at_eof(iop) && no_data_left(iop))
  596         cnt = EOF;
  597     else if ((iop->flag & IOP_CLOSED) != 0)
  598         cnt = EOF;
  599     else
  600         cnt = get_a_record(& begin, iop, errcode, & field_width);
  601 
  602     /* Note that get_a_record may return -2 when I/O would block */
  603     if (cnt < 0) {
  604         retval = false;
  605     } else {
  606         INCREMENT_REC(NR);
  607         INCREMENT_REC(FNR);
  608         set_record(begin, cnt, field_width);
  609         if (*errcode > 0)
  610             retval = false;
  611     }
  612 
  613     return retval;
  614 }
  615 
  616 /* remap_std_file --- reopen a standard descriptor on /dev/null */
  617 
  618 static int
  619 remap_std_file(int oldfd)
  620 {
  621     int newfd;
  622     int ret = -1;
  623 
  624     /*
  625      * Give OS-specific routines in gawkmisc.c a chance to interpret
  626      * "/dev/null" as appropriate for their platforms.
  627      */
  628     newfd = os_devopen("/dev/null", O_RDWR);
  629     if (newfd == INVALID_HANDLE)
  630         newfd = open("/dev/null", O_RDWR);
  631     if (newfd >= 0) {
  632         /* if oldfd is open, dup2() will close oldfd for us first. */
  633         ret = dup2(newfd, oldfd);
  634         if (ret == 0)
  635             close(newfd);
  636     } else
  637         ret = 0;
  638 
  639     return ret;
  640 }
  641 
  642 /* iop_close --- close an open IOP */
  643 
  644 static int
  645 iop_close(IOBUF *iop)
  646 {
  647     int ret = 0;
  648 
  649     if (iop == NULL)
  650         return 0;
  651 
  652     errno = 0;
  653 
  654     iop->flag &= ~IOP_AT_EOF;
  655     iop->flag |= IOP_CLOSED;    /* there may be dangling pointers */
  656     iop->dataend = NULL;
  657     /*
  658      * Closing standard files can cause crufty code elsewhere to lose.
  659      * So we remap the standard file to /dev/null.
  660      * Thanks to Jim Meyering for the suggestion.
  661      */
  662     if (iop->public.close_func != NULL)
  663         iop->public.close_func(&iop->public);
  664 
  665     if (iop->public.fd != INVALID_HANDLE) {
  666         if (iop->public.fd == fileno(stdin)
  667             || iop->public.fd == fileno(stdout)
  668             || iop->public.fd == fileno(stderr))
  669             ret = remap_std_file(iop->public.fd);
  670         else
  671             ret = closemaybesocket(iop->public.fd);
  672     }
  673 
  674     if (ret == -1)
  675         warning(_("close of fd %d (`%s') failed: %s"), iop->public.fd,
  676                 iop->public.name, strerror(errno));
  677     /*
  678      * Be careful -- $0 may still reference the buffer even though
  679      * an explicit close is being done; in the future, maybe we
  680      * can do this a bit better.
  681      */
  682     if (iop->buf) {
  683         if ((fields_arr[0]->stptr >= iop->buf)
  684             && (fields_arr[0]->stptr < (iop->buf + iop->size))) {
  685             NODE *t;
  686 
  687             t = make_string(fields_arr[0]->stptr,
  688                     fields_arr[0]->stlen);
  689             unref(fields_arr[0]);
  690             fields_arr[0] = t;
  691             /*
  692              * This used to be here:
  693              *
  694              * reset_record();
  695              *
  696              * Don't do that; reset_record() throws away all fields,
  697              * saves FS etc.  We just need to make sure memory isn't
  698              * corrupted and that references to $0 and fields work.
  699              */
  700         }
  701         efree(iop->buf);
  702         iop->buf = NULL;
  703     }
  704     efree(iop);
  705     return ret == -1 ? 1 : 0;
  706 }
  707 
  708 /* redflags2str --- turn redirection flags into a string, for debugging */
  709 
  710 const char *
  711 redflags2str(int flags)
  712 {
  713     static const struct flagtab redtab[] = {
  714         { RED_FILE, "RED_FILE" },
  715         { RED_PIPE, "RED_PIPE" },
  716         { RED_READ, "RED_READ" },
  717         { RED_WRITE,    "RED_WRITE" },
  718         { RED_APPEND,   "RED_APPEND" },
  719         { RED_NOBUF,    "RED_NOBUF" },
  720         { RED_EOF,  "RED_EOF" },
  721         { RED_TWOWAY,   "RED_TWOWAY" },
  722         { RED_PTY,  "RED_PTY" },
  723         { RED_SOCKET,   "RED_SOCKET" },
  724         { RED_TCP,  "RED_TCP" },
  725         { 0, NULL }
  726     };
  727 
  728     return genflags2str(flags, redtab);
  729 }
  730 
  731 /* redirect_string --- Redirection for printf and print commands, use string info */
  732 
  733 struct redirect *
  734 redirect_string(const char *str, size_t explen, bool not_string,
  735         int redirtype, int *errflg, int extfd, bool failure_fatal)
  736 {
  737     struct redirect *rp;
  738     int tflag = 0;
  739     int outflag = 0;
  740     const char *direction = "to";
  741     const char *mode;
  742     int fd;
  743     const char *what = NULL;
  744     bool new_rp = false;
  745 #ifdef HAVE_SOCKETS
  746     struct inet_socket_info isi;
  747 #endif
  748     static struct redirect *save_rp = NULL; /* hold onto rp that should
  749                                              * be freed for reuse
  750                                              */
  751 
  752     if (do_sandbox)
  753         fatal(_("redirection not allowed in sandbox mode"));
  754 
  755     switch (redirtype) {
  756     case redirect_append:
  757         tflag = RED_APPEND;
  758         /* FALL THROUGH */
  759     case redirect_output:
  760         outflag = (RED_FILE|RED_WRITE);
  761         tflag |= outflag;
  762         if (redirtype == redirect_output)
  763             what = ">";
  764         else
  765             what = ">>";
  766         break;
  767     case redirect_pipe:
  768         tflag = (RED_PIPE|RED_WRITE);
  769         what = "|";
  770         break;
  771     case redirect_pipein:
  772         tflag = (RED_PIPE|RED_READ);
  773         what = "|";
  774         break;
  775     case redirect_input:
  776         tflag = (RED_FILE|RED_READ);
  777         what = "<";
  778         break;
  779     case redirect_twoway:
  780         tflag = (RED_READ|RED_WRITE|RED_TWOWAY);
  781         what = "|&";
  782         break;
  783     default:
  784         cant_happen();
  785     }
  786     if (do_lint && not_string)
  787         lintwarn(_("expression in `%s' redirection is a number"),
  788             what);
  789 
  790     if (explen < 1 || str == NULL || *str == '\0')
  791         fatal(_("expression for `%s' redirection has null string value"),
  792             what);
  793 
  794     if (do_lint && (strncmp(str, "0", explen) == 0
  795             || strncmp(str, "1", explen) == 0))
  796         lintwarn(_("filename `%.*s' for `%s' redirection may be result of logical expression"),
  797                 (int) explen, str, what);
  798 
  799 #ifdef HAVE_SOCKETS
  800     /*
  801      * Use /inet4 to force IPv4, /inet6 to force IPv6, and plain
  802      * /inet will be whatever we get back from the system.
  803      */
  804     if (inetfile(str, explen, & isi)) {
  805         tflag |= RED_SOCKET;
  806         if (isi.protocol == SOCK_STREAM)
  807             tflag |= RED_TCP;   /* use shutdown when closing */
  808     }
  809 #endif /* HAVE_SOCKETS */
  810 
  811     for (rp = red_head; rp != NULL; rp = rp->next) {
  812 #ifndef PIPES_SIMULATED
  813         /*
  814          * This is an efficiency hack.  We want to
  815          * recover the process slot for dead children,
  816          * if at all possible.  Messing with signal() for
  817          * SIGCLD leads to lots of headaches.  However, if
  818          * we've gotten EOF from a child input pipeline, it's
  819          * a good bet that the child has died. So recover it.
  820          */
  821         if ((rp->flag & RED_EOF) != 0 && redirtype == redirect_pipein) {
  822             if (rp->pid != -1)
  823 #ifdef __MINGW32__
  824                 /* MinGW cannot wait for any process.  */
  825                 wait_any(rp->pid);
  826 #else
  827                 wait_any(0);
  828 #endif
  829         }
  830 #endif /* PIPES_SIMULATED */
  831 
  832         /* now check for a match */
  833         if (strlen(rp->value) == explen
  834             && memcmp(rp->value, str, explen) == 0
  835             && ((rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY)) == tflag
  836             || (outflag != 0
  837                 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) {
  838 
  839             int rpflag = (rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY));
  840             int newflag = (tflag & ~(RED_NOBUF|RED_EOF|RED_PTY));
  841 
  842             if (do_lint && rpflag != newflag)
  843                 lintwarn(
  844         _("unnecessary mixing of `>' and `>>' for file `%.*s'"),
  845                     (int) explen, rp->value);
  846 
  847             break;
  848         }
  849     }
  850 
  851     if (rp == NULL) {
  852         char *newstr;
  853         new_rp = true;
  854         if (save_rp != NULL) {
  855             rp = save_rp;
  856             efree(rp->value);
  857         } else
  858             emalloc(rp, struct redirect *, sizeof(struct redirect), "redirect");
  859         emalloc(newstr, char *, explen + 1, "redirect");
  860         memcpy(newstr, str, explen);
  861         newstr[explen] = '\0';
  862         str = newstr;
  863         rp->value = newstr;
  864         rp->flag = tflag;
  865         init_output_wrapper(& rp->output);
  866         rp->output.name = str;
  867         rp->iop = NULL;
  868         rp->pid = -1;
  869         rp->status = 0;
  870     } else
  871         str = rp->value;    /* get \0 terminated string */
  872     save_rp = rp;
  873 
  874     while (rp->output.fp == NULL && rp->iop == NULL) {
  875         if (! new_rp && (rp->flag & RED_EOF) != 0) {
  876             /*
  877              * Encountered EOF on file or pipe -- must be cleared
  878              * by explicit close() before reading more
  879              */
  880             save_rp = NULL;
  881             return rp;
  882         }
  883         mode = NULL;
  884         errno = 0;
  885         switch (redirtype) {
  886         case redirect_output:
  887             mode = binmode("w");
  888             if ((rp->flag & RED_USED) != 0)
  889                 mode = (rp->mode[1] == 'b') ? "ab" : "a";
  890             break;
  891         case redirect_append:
  892             mode = binmode("a");
  893             break;
  894         case redirect_pipe:
  895             if (extfd >= 0) {
  896                 warning(_("get_file cannot create pipe `%s' with fd %d"), str, extfd);
  897                 return NULL;
  898             }
  899             /* synchronize output before new pipe */
  900             (void) flush_io();
  901 
  902             os_restore_mode(fileno(stdin));
  903             set_sigpipe_to_default();
  904             /*
  905              * Don't check failure_fatal; see input pipe below.
  906              * Note that the failure happens upon failure to fork,
  907              * using a non-existant program will still succeed the
  908              * popen().
  909              */
  910             if ((rp->output.fp = popen(str, binmode("w"))) == NULL)
  911                 fatal(_("cannot open pipe `%s' for output: %s"),
  912                         str, strerror(errno));
  913             ignore_sigpipe();
  914 
  915             /* set close-on-exec */
  916             os_close_on_exec(fileno(rp->output.fp), str, "pipe", "to");
  917             rp->flag |= RED_NOBUF;
  918             break;
  919         case redirect_pipein:
  920             if (extfd >= 0) {
  921                 warning(_("get_file cannot create pipe `%s' with fd %d"), str, extfd);
  922                 return NULL;
  923             }
  924             direction = "from";
  925             if (gawk_popen(str, rp) == NULL)
  926                 fatal(_("cannot open pipe `%s' for input: %s"),
  927                     str, strerror(errno));
  928             break;
  929         case redirect_input:
  930             direction = "from";
  931             fd = (extfd >= 0) ? extfd : devopen(str, binmode("r"));
  932             if (fd == INVALID_HANDLE && errno == EISDIR) {
  933                 *errflg = EISDIR;
  934                 /* do not free rp, saving it for reuse (save_rp = rp) */
  935                 return NULL;
  936             }
  937             rp->iop = iop_alloc(fd, str, errno);
  938             find_input_parser(rp->iop);
  939             iop_finish(rp->iop);
  940             if (! rp->iop->valid) {
  941                 if (! do_traditional && rp->iop->errcode != 0)
  942                     update_ERRNO_int(rp->iop->errcode);
  943                 iop_close(rp->iop);
  944                 rp->iop = NULL;
  945             }
  946             break;
  947         case redirect_twoway:
  948 #ifndef HAVE_SOCKETS
  949             if (extfd >= 0) {
  950                 warning(_("get_file socket creation not supported on this platform for `%s' with fd %d"), str, extfd);
  951                 return NULL;
  952             }
  953 #endif
  954             direction = "to/from";
  955             if (! two_way_open(str, rp, extfd)) {
  956                 if (! failure_fatal || is_non_fatal_redirect(str, explen)) {
  957                     *errflg = errno;
  958                     /* do not free rp, saving it for reuse (save_rp = rp) */
  959                     return NULL;
  960                 } else
  961                     fatal(_("cannot open two way pipe `%s' for input/output: %s"),
  962                             str, strerror(errno));
  963             }
  964             break;
  965         default:
  966             cant_happen();
  967         }
  968 
  969         if (mode != NULL) {
  970             errno = 0;
  971             rp->output.mode = mode;
  972             fd = (extfd >= 0) ? extfd : devopen(str, mode);
  973 
  974             if (fd > INVALID_HANDLE) {
  975                 if (fd == fileno(stdin))
  976                     rp->output.fp = stdin;
  977                 else if (fd == fileno(stdout))
  978                     rp->output.fp = stdout;
  979                 else if (fd == fileno(stderr))
  980                     rp->output.fp = stderr;
  981                 else {
  982                     const char *omode = mode;
  983 #if defined(F_GETFL) && defined(O_APPEND)
  984                     int fd_flags;
  985 
  986                     fd_flags = fcntl(fd, F_GETFL);
  987                     if (fd_flags != -1 && (fd_flags & O_APPEND) == O_APPEND)
  988                         omode = binmode("a");
  989 #endif
  990                     os_close_on_exec(fd, str, "file", "");
  991                     rp->output.fp = fdopen(fd, (const char *) omode);
  992                     rp->mode = (const char *) mode;
  993                     /* don't leak file descriptors */
  994                     if (rp->output.fp == NULL)
  995                         close(fd);
  996                 }
  997                 if (rp->output.fp != NULL && os_isatty(fd))
  998                     rp->flag |= RED_NOBUF;
  999 
 1000                 /* Move rp to the head of the list. */
 1001                 if (! new_rp && red_head != rp) {
 1002                     if ((rp->prev->next = rp->next) != NULL)
 1003                         rp->next->prev = rp->prev;
 1004                     red_head->prev = rp;
 1005                     rp->prev = NULL;
 1006                     rp->next = red_head;
 1007                     red_head = rp;
 1008                 }
 1009             }
 1010             find_output_wrapper(& rp->output);
 1011         }
 1012 
 1013         if (rp->output.fp == NULL && rp->iop == NULL) {
 1014             /* too many files open -- close one and try again */
 1015             if (errno == EMFILE || errno == ENFILE)
 1016                 close_one();
 1017 #ifdef VMS
 1018             /* Alpha/VMS V7.1+ C RTL is returning these instead
 1019                of EMFILE (haven't tried other post-V6.2 systems) */
 1020             else if ((errno == EIO || errno == EVMSERR) &&
 1021                                  (vaxc$errno == SS$_EXQUOTA ||
 1022                                   vaxc$errno == SS$_EXBYTLM ||
 1023                                   vaxc$errno == RMS$_ACC ||
 1024                   vaxc$errno == RMS$_SYN)) {
 1025                 close_one();
 1026                 close_one();
 1027             }
 1028 #endif
 1029             else {
 1030                 /*
 1031                  * Some other reason for failure.
 1032                  *
 1033                  * On redirection of input from a file,
 1034                  * just return an error, so e.g. getline
 1035                  * can return -1.  For output to file,
 1036                  * complain. The shell will complain on
 1037                  * a bad command to a pipe.
 1038                  *
 1039                  * 12/2014: Take nonfatal settings in PROCINFO into account.
 1040                  */
 1041                 if (errflg != NULL)
 1042                     *errflg = errno;
 1043                 if (failure_fatal && ! is_non_fatal_redirect(str, explen) &&
 1044                     (redirtype == redirect_output
 1045                      || redirtype == redirect_append)) {
 1046                     /* multiple messages make life easier for translators */
 1047                     if (*direction == 'f')
 1048                         fatal(_("cannot redirect from `%s': %s"),
 1049                                 str, strerror(errno));
 1050                     else
 1051                         fatal(_("cannot redirect to `%s': %s"),
 1052                             str, strerror(errno));
 1053                 } else {
 1054                     /* do not free rp, saving it for reuse (save_rp = rp) */
 1055                     return NULL;
 1056                 }
 1057             }
 1058         }
 1059     }
 1060 
 1061     if (new_rp) {
 1062         /*
 1063          * It opened successfully, hook it into the list.
 1064          * Maintain the list in most-recently-used first order.
 1065          */
 1066         if (red_head != NULL)
 1067             red_head->prev = rp;
 1068         rp->prev = NULL;
 1069         rp->next = red_head;
 1070         red_head = rp;
 1071     }
 1072     save_rp = NULL;
 1073     return rp;
 1074 }
 1075 
 1076 /* redirect --- Redirection for printf and print commands */
 1077 
 1078 struct redirect *
 1079 redirect(NODE *redir_exp, int redirtype, int *errflg, bool failure_fatal)
 1080 {
 1081     bool not_string = ((fixtype(redir_exp)->flags & STRING) == 0);
 1082 
 1083     redir_exp = force_string(redir_exp);
 1084     return redirect_string(redir_exp->stptr, redir_exp->stlen, not_string,
 1085                 redirtype, errflg, -1, failure_fatal);
 1086 }
 1087 
 1088 /* getredirect --- find the struct redirect for this file or pipe */
 1089 
 1090 struct redirect *
 1091 getredirect(const char *str, int len)
 1092 {
 1093     struct redirect *rp;
 1094 
 1095     for (rp = red_head; rp != NULL; rp = rp->next)
 1096         if (strlen(rp->value) == len && memcmp(rp->value, str, len) == 0)
 1097             return rp;
 1098 
 1099     return NULL;
 1100 }
 1101 
 1102 /* is_non_fatal_std --- return true if fp is stdout/stderr and nonfatal */
 1103 
 1104 bool
 1105 is_non_fatal_std(FILE *fp)
 1106 {
 1107     if (in_PROCINFO(nonfatal, NULL, NULL))
 1108         return true;
 1109 
 1110     /* yucky logic. sigh. */
 1111     if (fp == stdout) {
 1112         return (   in_PROCINFO("-", nonfatal, NULL) != NULL
 1113                 || in_PROCINFO("/dev/stdout", nonfatal, NULL) != NULL);
 1114     } else if (fp == stderr) {
 1115         return (in_PROCINFO("/dev/stderr", nonfatal, NULL) != NULL);
 1116     }
 1117 
 1118     return false;
 1119 }
 1120 
 1121 /* is_non_fatal_redirect --- return true if redirected I/O should be nonfatal */
 1122 
 1123 bool
 1124 is_non_fatal_redirect(const char *str, size_t len)
 1125 {
 1126     bool ret;
 1127     char save;
 1128     char *s = (char *) str;
 1129 
 1130     save = s[len];
 1131     s[len] = '\0';
 1132 
 1133     ret = in_PROCINFO(nonfatal, NULL, NULL) != NULL
 1134            || in_PROCINFO(s, nonfatal, NULL) != NULL;
 1135 
 1136     s[len] = save;
 1137 
 1138     return ret;
 1139 }
 1140 
 1141 /* close_one --- temporarily close an open file to re-use the fd */
 1142 
 1143 static void
 1144 close_one()
 1145 {
 1146     struct redirect *rp;
 1147     struct redirect *rplast = NULL;
 1148 
 1149     static bool warned = false;
 1150 
 1151     if (do_lint && ! warned) {
 1152         warned = true;
 1153         lintwarn(_("reached system limit for open files: starting to multiplex file descriptors"));
 1154     }
 1155 
 1156     /* go to end of list first, to pick up least recently used entry */
 1157     for (rp = red_head; rp != NULL; rp = rp->next)
 1158         rplast = rp;
 1159     /* now work back up through the list */
 1160     for (rp = rplast; rp != NULL; rp = rp->prev) {
 1161         /* don't close standard files! */
 1162         if (rp->output.fp == NULL || rp->output.fp == stderr || rp->output.fp == stdout)
 1163             continue;
 1164 
 1165         if ((rp->flag & (RED_FILE|RED_WRITE)) == (RED_FILE|RED_WRITE)) {
 1166             rp->flag |= RED_USED;
 1167             errno = 0;
 1168             if (rp->output.gawk_fclose(rp->output.fp, rp->output.opaque) != 0)
 1169                 warning(_("close of `%s' failed: %s."),
 1170                     rp->value, strerror(errno));
 1171             rp->output.fp = NULL;
 1172             break;
 1173         }
 1174     }
 1175     if (rp == NULL)
 1176         /* surely this is the only reason ??? */
 1177         fatal(_("too many pipes or input files open"));
 1178 }
 1179 
 1180 /* do_close --- completely close an open file or pipe */
 1181 
 1182 NODE *
 1183 do_close(int nargs)
 1184 {
 1185     NODE *tmp, *tmp2;
 1186     struct redirect *rp;
 1187     two_way_close_type how = CLOSE_ALL; /* default */
 1188 
 1189     if (nargs == 2) {
 1190         /* 2nd arg if present: "to" or "from" for two-way pipe */
 1191         /* DO NOT use _() on the strings here! */
 1192         char save;
 1193 
 1194         tmp2 = POP_STRING();
 1195         save = tmp2->stptr[tmp2->stlen];
 1196         tmp2->stptr[tmp2->stlen] = '\0';
 1197         if (strcasecmp(tmp2->stptr, "to") == 0)
 1198             how = CLOSE_TO;
 1199         else if (strcasecmp(tmp2->stptr, "from") == 0)
 1200             how = CLOSE_FROM;
 1201         else {
 1202             DEREF(tmp2);
 1203             fatal(_("close: second argument must be `to' or `from'"));
 1204         }
 1205         tmp2->stptr[tmp2->stlen] = save;
 1206         DEREF(tmp2);
 1207     }
 1208 
 1209     tmp = POP_STRING();     /* 1st arg: redir to close */
 1210 
 1211     for (rp = red_head; rp != NULL; rp = rp->next) {
 1212         if (strlen(rp->value) == tmp->stlen
 1213             && memcmp(rp->value, tmp->stptr, tmp->stlen) == 0)
 1214             break;
 1215     }
 1216 
 1217     if (rp == NULL) {   /* no match, return -1 */
 1218         char *cp;
 1219 
 1220         if (do_lint)
 1221             lintwarn(_("close: `%.*s' is not an open file, pipe or co-process"),
 1222                 (int) tmp->stlen, tmp->stptr);
 1223 
 1224         if (! do_traditional) {
 1225             /* update ERRNO manually, using errno = ENOENT is a stretch. */
 1226             cp = _("close of redirection that was never opened");
 1227             update_ERRNO_string(cp);
 1228         }
 1229 
 1230         DEREF(tmp);
 1231         return make_number((AWKNUM) -1.0);
 1232     }
 1233     DEREF(tmp);
 1234     fflush(stdout); /* synchronize regular output */
 1235     tmp = make_number((AWKNUM) close_redir(rp, false, how));
 1236     rp = NULL;
 1237     /*
 1238      * POSIX says close() returns 0 on success, non-zero otherwise.
 1239      * For POSIX, at this point we just return 0.  Otherwise we
 1240      * return the exit status of the process or of pclose(), depending.
 1241      * Down in the call tree of close_redir(), we rationalize the
 1242      * value like we do for system().
 1243      */
 1244     if (do_posix) {
 1245         unref(tmp);
 1246         tmp = make_number((AWKNUM) 0);
 1247     }
 1248     return tmp;
 1249 }
 1250 
 1251 /* close_rp --- separate function to just do closing */
 1252 
 1253 int
 1254 close_rp(struct redirect *rp, two_way_close_type how)
 1255 {
 1256     int status = 0;
 1257 
 1258     errno = 0;
 1259     if ((rp->flag & RED_TWOWAY) != 0) { /* two-way pipe */
 1260         /* write end: */
 1261         if ((how == CLOSE_ALL || how == CLOSE_TO) && rp->output.fp != NULL) {
 1262 #ifdef HAVE_SOCKETS
 1263             if ((rp->flag & RED_TCP) != 0)
 1264                 (void) shutdown(fileno(rp->output.fp), SHUT_WR);
 1265 #endif /* HAVE_SOCKETS */
 1266 
 1267             if ((rp->flag & RED_PTY) != 0) {
 1268                 rp->output.gawk_fwrite("\004\n", sizeof("\004\n") - 1, 1, rp->output.fp, rp->output.opaque);
 1269                 rp->output.gawk_fflush(rp->output.fp, rp->output.opaque);
 1270             }
 1271             status = rp->output.gawk_fclose(rp->output.fp, rp->output.opaque);
 1272             rp->output.fp = NULL;
 1273         }
 1274 
 1275         /* read end: */
 1276         if (how == CLOSE_ALL || how == CLOSE_FROM) {
 1277             if ((rp->flag & RED_SOCKET) != 0 && rp->iop != NULL) {
 1278 #ifdef HAVE_SOCKETS
 1279                 if ((rp->flag & RED_TCP) != 0)
 1280                     (void) shutdown(rp->iop->public.fd, SHUT_RD);
 1281 #endif /* HAVE_SOCKETS */
 1282                 (void) iop_close(rp->iop);
 1283             } else
 1284                 /* status already sanitized */
 1285                 status = gawk_pclose(rp);
 1286 
 1287             rp->iop = NULL;
 1288         }
 1289     } else if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) {
 1290         /* write to pipe */
 1291         status = sanitize_exit_status(pclose(rp->output.fp));
 1292         if ((BINMODE & BINMODE_INPUT) != 0)
 1293             os_setbinmode(fileno(stdin), O_BINARY);
 1294 
 1295         rp->output.fp = NULL;
 1296     } else if (rp->output.fp != NULL) { /* write to file */
 1297         status = rp->output.gawk_fclose(rp->output.fp, rp->output.opaque);
 1298         rp->output.fp = NULL;
 1299     } else if (rp->iop != NULL) {   /* read from pipe/file */
 1300         if ((rp->flag & RED_PIPE) != 0)     /* read from pipe */
 1301             status = gawk_pclose(rp);
 1302             /* gawk_pclose sets rp->iop to null */
 1303         else {                  /* read from file */
 1304             status = iop_close(rp->iop);
 1305             rp->iop = NULL;
 1306         }
 1307     }
 1308 
 1309     return status;
 1310 }
 1311 
 1312 /* close_redir --- close an open file or pipe */
 1313 
 1314 static int
 1315 close_redir(struct redirect *rp, bool exitwarn, two_way_close_type how)
 1316 {
 1317     int status = 0;
 1318 
 1319     if (rp == NULL)
 1320         return 0;
 1321     if (rp->output.fp == stdout || rp->output.fp == stderr)
 1322         goto checkwarn;     /* bypass closing, remove from list */
 1323 
 1324     if (do_lint && (rp->flag & RED_TWOWAY) == 0 && how != CLOSE_ALL)
 1325         lintwarn(_("close: redirection `%s' not opened with `|&', second argument ignored"),
 1326                 rp->value);
 1327 
 1328     status = close_rp(rp, how);
 1329 
 1330     if (status != 0) {
 1331         int save_errno = errno;
 1332         char *s = strerror(save_errno);
 1333 
 1334         /*
 1335          * BWK's awk, as far back as SVR4 (1989) would check
 1336          * and warn about the status of close.  However, when
 1337          * we did this we got too many complaints, so we moved
 1338          * it to be under lint control.
 1339          */
 1340         if (do_lint) {
 1341             if ((rp->flag & RED_PIPE) != 0)
 1342                 lintwarn(_("failure status (%d) on pipe close of `%s': %s"),
 1343                      status, rp->value, s);
 1344             else
 1345                 lintwarn(_("failure status (%d) on file close of `%s': %s"),
 1346                      status, rp->value, s);
 1347         }
 1348 
 1349         if (! do_traditional) {
 1350             /* set ERRNO too so that program can get at it */
 1351             update_ERRNO_int(save_errno);
 1352         }
 1353     }
 1354 
 1355 checkwarn:
 1356     if (exitwarn) {
 1357         /*
 1358          * Don't use lintwarn() here.  If lint warnings are fatal,
 1359          * doing so prevents us from closing other open redirections.
 1360          *
 1361          * Using multiple full messages instead of string parameters
 1362          * for the types makes message translation easier.
 1363          */
 1364         if ((rp->flag & RED_SOCKET) != 0)
 1365             warning(_("no explicit close of socket `%s' provided"),
 1366                 rp->value);
 1367         else if ((rp->flag & RED_TWOWAY) != 0)
 1368             warning(_("no explicit close of co-process `%s' provided"),
 1369                 rp->value);
 1370         else if ((rp->flag & RED_PIPE) != 0)
 1371             warning(_("no explicit close of pipe `%s' provided"),
 1372                 rp->value);
 1373         else
 1374             warning(_("no explicit close of file `%s' provided"),
 1375                 rp->value);
 1376     }
 1377 
 1378     /* remove it from the list if closing both or both ends have been closed */
 1379     if (how == CLOSE_ALL || (rp->iop == NULL && rp->output.fp == NULL)) {
 1380         if (rp->next != NULL)
 1381             rp->next->prev = rp->prev;
 1382         if (rp->prev != NULL)
 1383             rp->prev->next = rp->next;
 1384         else
 1385             red_head = rp->next;
 1386         free_rp(rp);
 1387     }
 1388 
 1389     return status;
 1390 }
 1391 
 1392 /* non_fatal_flush_std_file --- flush a standard output file allowing for nonfatal setting */
 1393 
 1394 bool
 1395 non_fatal_flush_std_file(FILE *fp)
 1396 {
 1397     int status = fflush(fp);
 1398 
 1399     if (status != 0) {
 1400         bool is_fatal = ! is_non_fatal_std(fp);
 1401 
 1402         if (is_fatal) {
 1403 #ifdef __MINGW32__
 1404             if (errno == 0 || errno == EINVAL)
 1405                 w32_maybe_set_errno();
 1406 #endif
 1407             if (errno == EPIPE)
 1408                 die_via_sigpipe();
 1409             else
 1410                 fatal(fp == stdout
 1411                     ? _("fflush: cannot flush standard output: %s")
 1412                     : _("fflush: cannot flush standard error: %s"),
 1413                         strerror(errno));
 1414         } else {
 1415             update_ERRNO_int(errno);
 1416             warning(fp == stdout
 1417                 ? _("error writing standard output: %s")
 1418                 : _("error writing standard error: %s"),
 1419                     strerror(errno));
 1420         }
 1421         return false;
 1422     }
 1423 
 1424     return true;
 1425 }
 1426 
 1427 /* flush_io --- flush all open output files */
 1428 
 1429 int
 1430 flush_io()
 1431 {
 1432     struct redirect *rp;
 1433     int status = 0;
 1434 
 1435     errno = 0;
 1436     if (! non_fatal_flush_std_file(stdout)) // ERRNO updated
 1437         status++;
 1438 
 1439     errno = 0;
 1440     if (! non_fatal_flush_std_file(stderr)) // ERRNO updated
 1441         status++;
 1442 
 1443 
 1444     // now for all open redirections
 1445     for (rp = red_head; rp != NULL; rp = rp->next) {
 1446         void (*messagefunc)(const char *mesg, ...) = r_fatal;
 1447 
 1448         /* flush both files and pipes, what the heck */
 1449         if ((rp->flag & RED_WRITE) != 0 && rp->output.fp != NULL) {
 1450             if (rp->output.gawk_fflush(rp->output.fp, rp->output.opaque) != 0) {
 1451                 update_ERRNO_int(errno);
 1452 
 1453                 if (is_non_fatal_redirect(rp->value, strlen(rp->value)))
 1454                     messagefunc = r_warning;
 1455 
 1456                 if ((rp->flag & RED_PIPE) != 0)
 1457                     messagefunc(_("pipe flush of `%s' failed: %s."),
 1458                         rp->value, strerror(errno));
 1459                 else if ((rp->flag & RED_TWOWAY) != 0)
 1460                     messagefunc(_("co-process flush of pipe to `%s' failed: %s."),
 1461                         rp->value, strerror(errno));
 1462                 else
 1463                     messagefunc(_("file flush of `%s' failed: %s."),
 1464                         rp->value, strerror(errno));
 1465                 status++;
 1466             }
 1467         }
 1468     }
 1469     if (status != 0)
 1470         status = -1;    /* canonicalize it */
 1471     return status;
 1472 }
 1473 
 1474 /* close_io --- close all open files, called when exiting */
 1475 
 1476 int
 1477 close_io(bool *stdio_problem, bool *got_EPIPE)
 1478 {
 1479     struct redirect *rp;
 1480     struct redirect *next;
 1481     int status = 0;
 1482 
 1483     *stdio_problem = *got_EPIPE = false;
 1484     errno = 0;
 1485     for (rp = red_head; rp != NULL; rp = next) {
 1486         next = rp->next;
 1487         /*
 1488          * close_redir() will print a message if needed.
 1489          * if do_lint, warn about lack of explicit close
 1490          */
 1491         if (close_redir(rp, do_lint, CLOSE_ALL))
 1492             status++;
 1493         rp = NULL;
 1494     }
 1495     /*
 1496      * Some of the non-Unix os's have problems doing an fclose()
 1497      * on stdout and stderr.  Since we don't really need to close
 1498      * them, we just flush them, and do that across the board.
 1499      */
 1500     *stdio_problem = false;
 1501     /* we don't warn about stdout/stderr if EPIPE, but we do error exit */
 1502     if (fflush(stdout) != 0) {
 1503 #ifdef __MINGW32__
 1504         if (errno == 0 || errno == EINVAL)
 1505             w32_maybe_set_errno();
 1506 #endif
 1507         if (errno != EPIPE)
 1508             warning(_("error writing standard output: %s"), strerror(errno));
 1509         else
 1510             *got_EPIPE = true;
 1511 
 1512         status++;
 1513         *stdio_problem = true;
 1514     }
 1515     if (fflush(stderr) != 0) {
 1516 #ifdef __MINGW32__
 1517         if (errno == 0 || errno == EINVAL)
 1518             w32_maybe_set_errno();
 1519 #endif
 1520         if (errno != EPIPE)
 1521             warning(_("error writing standard error: %s"), strerror(errno));
 1522         else
 1523             *got_EPIPE = true;
 1524 
 1525         status++;
 1526         *stdio_problem = true;
 1527     }
 1528     return status;
 1529 }
 1530 
 1531 /* str2mode --- convert a string mode to an integer mode */
 1532 
 1533 static int
 1534 str2mode(const char *mode)
 1535 {
 1536     int ret;
 1537     const char *second = & mode[1];
 1538 
 1539     if (*second == 'b')
 1540         second++;
 1541 
 1542     switch(mode[0]) {
 1543     case 'r':
 1544         ret = O_RDONLY;
 1545         if (*second == '+' || *second == 'w')
 1546             ret = O_RDWR;
 1547         break;
 1548 
 1549     case 'w':
 1550         ret = O_WRONLY|O_CREAT|O_TRUNC;
 1551         if (*second == '+' || *second == 'r')
 1552             ret = O_RDWR|O_CREAT|O_TRUNC;
 1553         break;
 1554 
 1555     case 'a':
 1556         ret = O_WRONLY|O_APPEND|O_CREAT;
 1557         if (*second == '+')
 1558             ret = O_RDWR|O_APPEND|O_CREAT;
 1559         break;
 1560 
 1561     default:
 1562         ret = 0;        /* lint */
 1563         cant_happen();
 1564     }
 1565     if (strchr(mode, 'b') != NULL)
 1566         ret |= O_BINARY;
 1567     return ret;
 1568 }
 1569 
 1570 #ifdef HAVE_SOCKETS
 1571 
 1572 /* socketopen --- open a socket and set it into connected state */
 1573 
 1574 static int
 1575 socketopen(int family, int type, const char *localpname,
 1576     const char *remotepname, const char *remotehostname, bool *hard_error)
 1577 {
 1578     struct addrinfo *lres, *lres0;
 1579     struct addrinfo lhints;
 1580     struct addrinfo *rres, *rres0;
 1581     struct addrinfo rhints;
 1582 
 1583     int lerror, rerror;
 1584 
 1585     int socket_fd = INVALID_HANDLE;
 1586     int any_remote_host = (strcmp(remotehostname, "0") == 0);
 1587 
 1588     memset(& lhints, '\0', sizeof (lhints));
 1589 
 1590     lhints.ai_socktype = type;
 1591     lhints.ai_family = family;
 1592 
 1593     /*
 1594          * If only the loopback interface is up and hints.ai_flags has
 1595      * AI_ADDRCONFIG, getaddrinfo() will succeed and return all wildcard
 1596      * addresses, but only if hints.ai_family == AF_UNSPEC
 1597      *
 1598      * Do return the wildcard address in case the loopback interface
 1599      * is the only one that is up (and
 1600      * hints.ai_family == either AF_INET4 or AF_INET6)
 1601          */
 1602     lhints.ai_flags = AI_PASSIVE;
 1603     if (lhints.ai_family == AF_UNSPEC)
 1604         lhints.ai_flags |= AI_ADDRCONFIG;
 1605 
 1606     lerror = getaddrinfo(NULL, localpname, & lhints, & lres);
 1607     if (lerror) {
 1608         if (strcmp(localpname, "0") != 0) {
 1609 #ifdef HAVE_GAI_STRERROR
 1610             warning(_("local port %s invalid in `/inet': %s"), localpname,
 1611                     gai_strerror(lerror));
 1612 #else
 1613             warning(_("local port %s invalid in `/inet'"), localpname);
 1614 #endif
 1615             *hard_error = true;
 1616             return INVALID_HANDLE;
 1617         }
 1618         lres0 = NULL;
 1619         lres = & lhints;
 1620     } else
 1621         lres0 = lres;
 1622 
 1623     while (lres != NULL) {
 1624         memset (& rhints, '\0', sizeof (rhints));
 1625         rhints.ai_flags = lhints.ai_flags;
 1626         rhints.ai_socktype = lhints.ai_socktype;
 1627         rhints.ai_family = lhints.ai_family;
 1628         rhints.ai_protocol = lhints.ai_protocol;
 1629 
 1630         rerror = getaddrinfo(any_remote_host ? NULL : remotehostname,
 1631                 remotepname, & rhints, & rres);
 1632         if (rerror) {
 1633             if (lres0 != NULL)
 1634                 freeaddrinfo(lres0);
 1635 #ifdef HAVE_GAI_STRERROR
 1636             warning(_("remote host and port information (%s, %s) invalid: %s"), remotehostname, remotepname,
 1637                     gai_strerror(rerror));
 1638 #else
 1639             warning(_("remote host and port information (%s, %s) invalid"), remotehostname, remotepname);
 1640 #endif
 1641             *hard_error = true;
 1642             return INVALID_HANDLE;
 1643         }
 1644         rres0 = rres;
 1645         socket_fd = INVALID_HANDLE;
 1646         while (rres != NULL) {
 1647             socket_fd = socket(rres->ai_family,
 1648                 rres->ai_socktype, rres->ai_protocol);
 1649             if (socket_fd < 0 || socket_fd == INVALID_HANDLE)
 1650                 goto nextrres;
 1651 
 1652             if (type == SOCK_STREAM) {
 1653                 int on = 1;
 1654 #ifdef SO_LINGER
 1655                 struct linger linger;
 1656                 memset(& linger, '\0', sizeof(linger));
 1657 #endif
 1658                 setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR,
 1659                     (char *) & on, sizeof(on));
 1660 #ifdef SO_LINGER
 1661                 linger.l_onoff = 1;
 1662                 /* linger for 30/100 second */
 1663                 linger.l_linger = 30;
 1664                 setsockopt(socket_fd, SOL_SOCKET, SO_LINGER,
 1665                     (char *) & linger, sizeof(linger));
 1666 #endif
 1667             }
 1668             if (bind(socket_fd, lres->ai_addr, lres->ai_addrlen) != 0)
 1669                 goto nextrres;
 1670 
 1671             if (! any_remote_host) { /* not ANY => create a client */
 1672                 if (connect(socket_fd, rres->ai_addr, rres->ai_addrlen) == 0)
 1673                     break;
 1674             } else { /* remote host is ANY => create a server */
 1675                 if (type == SOCK_STREAM) {
 1676                     int clientsocket_fd = INVALID_HANDLE;
 1677 
 1678                     struct sockaddr_storage remote_addr;
 1679                     socklen_t namelen = sizeof(remote_addr);
 1680 
 1681                     if (listen(socket_fd, 1) >= 0
 1682                         && (clientsocket_fd = accept(socket_fd,
 1683                         (struct sockaddr *) & remote_addr,
 1684                         & namelen)) >= 0) {
 1685                         closemaybesocket(socket_fd);
 1686                         socket_fd = clientsocket_fd;
 1687                         break;
 1688                     }
 1689                 } else if (type == SOCK_DGRAM) {
 1690 #ifdef MSG_PEEK
 1691                     char buf[10];
 1692                     struct sockaddr_storage remote_addr;
 1693                     socklen_t read_len = sizeof(remote_addr);
 1694 
 1695                     if (recvfrom(socket_fd, buf, 1, MSG_PEEK,
 1696                         (struct sockaddr *) & remote_addr,
 1697                             & read_len) >= 0
 1698                             && read_len
 1699                             && connect(socket_fd,
 1700                         (struct sockaddr *) & remote_addr,
 1701                                 read_len) == 0)
 1702                             break;
 1703 #endif
 1704                 }
 1705             }
 1706 
 1707 nextrres:
 1708             if (socket_fd != INVALID_HANDLE)
 1709                 closemaybesocket(socket_fd);
 1710             socket_fd = INVALID_HANDLE;
 1711             rres = rres->ai_next;
 1712         }
 1713         freeaddrinfo(rres0);
 1714         if (socket_fd != INVALID_HANDLE)
 1715             break;
 1716         lres = lres->ai_next;
 1717     }
 1718     if (lres0)
 1719         freeaddrinfo(lres0);
 1720 
 1721     return socket_fd;
 1722 }
 1723 #endif /* HAVE_SOCKETS */
 1724 
 1725 
 1726 /* devopen_simple --- handle "-", /dev/std{in,out,err}, /dev/fd/N */
 1727 
 1728 /*
 1729  * 9/2014: Flow here is a little messy.
 1730  *
 1731  * For do_posix, we don't allow any of the special filenames.
 1732  *
 1733  * For do_traditional, we allow /dev/{stdin,stdout,stderr} since BWK awk
 1734  * (and mawk) support them.  But we don't allow /dev/fd/N or /inet.
 1735  *
 1736  * Note that for POSIX systems os_devopen() is a no-op.
 1737  */
 1738 
 1739 int
 1740 devopen_simple(const char *name, const char *mode, bool try_real_open)
 1741 {
 1742     int openfd;
 1743     char *cp;
 1744     char *ptr;
 1745     int flag = 0;
 1746 
 1747     if (strcmp(name, "-") == 0) {
 1748         if (mode[0] == 'r')
 1749             return fileno(stdin);
 1750         else
 1751             return fileno(stdout);
 1752     }
 1753 
 1754     flag = str2mode(mode);
 1755     openfd = INVALID_HANDLE;
 1756 
 1757     if (do_posix)
 1758         goto done;
 1759 
 1760     if ((openfd = os_devopen(name, flag)) != INVALID_HANDLE) {
 1761         os_close_on_exec(openfd, name, "file", "");
 1762         return openfd;
 1763     }
 1764 
 1765     if (strncmp(name, "/dev/", 5) == 0) {
 1766         cp = (char *) name + 5;
 1767 
 1768         if (strcmp(cp, "stdin") == 0 && (flag & O_ACCMODE) == O_RDONLY)
 1769             openfd = fileno(stdin);
 1770         else if (strcmp(cp, "stdout") == 0 && (flag & O_ACCMODE) == O_WRONLY)
 1771             openfd = fileno(stdout);
 1772         else if (strcmp(cp, "stderr") == 0 && (flag & O_ACCMODE) == O_WRONLY)
 1773             openfd = fileno(stderr);
 1774         else if (do_traditional)
 1775             goto done;
 1776         else if (strncmp(cp, "fd/", 3) == 0) {
 1777             struct stat sbuf;
 1778 
 1779             cp += 3;
 1780             openfd = (int) strtoul(cp, & ptr, 10);
 1781             if (openfd <= INVALID_HANDLE || ptr == cp
 1782                 || fstat(openfd, & sbuf) < 0)
 1783                 openfd = INVALID_HANDLE;
 1784         }
 1785         /* do not set close-on-exec for inherited fd's */
 1786     }
 1787 done:
 1788     if (try_real_open)
 1789         openfd = open(name, flag, 0666);
 1790 
 1791     return openfd;
 1792 }
 1793 
 1794 /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, /inet, regular files */
 1795 
 1796 /*
 1797  * Strictly speaking, "name" is not a "const char *" because we temporarily
 1798  * change the string.
 1799  */
 1800 
 1801 int
 1802 devopen(const char *name, const char *mode)
 1803 {
 1804     int openfd;
 1805     int flag;
 1806     struct inet_socket_info isi;
 1807     int save_errno = 0;
 1808 
 1809     openfd = devopen_simple(name, mode, false);
 1810     if (openfd != INVALID_HANDLE)
 1811         return openfd;
 1812 
 1813     flag = str2mode(mode);
 1814 
 1815     if (do_traditional) {
 1816         goto strictopen;
 1817     } else if (inetfile(name, strlen(name), & isi)) {
 1818 #ifdef HAVE_SOCKETS
 1819 #define DEFAULT_RETRIES 20
 1820         static unsigned long def_retries = DEFAULT_RETRIES;
 1821         static bool first_time = true;
 1822         unsigned long retries = 0;
 1823         static long msleep = 1000;
 1824         bool hard_error = false;
 1825         bool non_fatal = is_non_fatal_redirect(name, strlen(name));
 1826         char save;
 1827         char *cp = (char *) name;
 1828 
 1829         /* socketopen requires NUL-terminated strings */
 1830         cp[isi.localport.offset+isi.localport.len] = '\0';
 1831         cp[isi.remotehost.offset+isi.remotehost.len] = '\0';
 1832         save = cp[isi.remoteport.offset+isi.remoteport.len];
 1833         cp[isi.remoteport.offset+isi.remoteport.len] = '\0';
 1834 
 1835         if (first_time) {
 1836             char *cp, *end;
 1837             unsigned long count = 0;
 1838             char *ms2;
 1839 
 1840             first_time = false;
 1841             if ((cp = getenv("GAWK_SOCK_RETRIES")) != NULL) {
 1842                 count = strtoul(cp, & end, 10);
 1843                 if (end != cp && count > 0)
 1844                     def_retries = count;
 1845             }
 1846 
 1847             /*
 1848              * Env var is in milliseconds, paramter to usleep()
 1849              * is microseconds, make the conversion. Default is
 1850              * 1 millisecond.
 1851              */
 1852             if ((ms2 = getenv("GAWK_MSEC_SLEEP")) != NULL) {
 1853                 msleep = strtol(ms2, & end, 10);
 1854                 if (end == ms2 || msleep < 0)
 1855                     msleep = 1000;
 1856                 else
 1857                     msleep *= 1000;
 1858             }
 1859         }
 1860         /*
 1861          * PROCINFO["NONFATAL"] or PROCINFO[name, "NONFATAL"] overrrides
 1862          * GAWK_SOCK_RETRIES.  The explicit code in the program carries
 1863          * a bigger stick than the environment variable does.
 1864          */
 1865         retries = non_fatal ? 1 : def_retries;
 1866 
 1867         errno = 0;
 1868         do {
 1869             openfd = socketopen(isi.family, isi.protocol, name+isi.localport.offset,
 1870                     name+isi.remoteport.offset, name+isi.remotehost.offset,
 1871                     & hard_error);
 1872             retries--;
 1873         } while (openfd == INVALID_HANDLE && ! hard_error && retries > 0 && usleep(msleep) == 0);
 1874         save_errno = errno;
 1875 
 1876         /* restore original name string */
 1877         cp[isi.localport.offset+isi.localport.len] = '/';
 1878         cp[isi.remotehost.offset+isi.remotehost.len] = '/';
 1879         cp[isi.remoteport.offset+isi.remoteport.len] = save;
 1880 #else /* ! HAVE_SOCKETS */
 1881         fatal(_("TCP/IP communications are not supported"));
 1882 #endif /* HAVE_SOCKETS */
 1883     }
 1884 
 1885 strictopen:
 1886     if (openfd == INVALID_HANDLE) {
 1887         openfd = open(name, flag, 0666);
 1888         /*
 1889          * ENOENT means there is no such name in the filesystem.
 1890          * Therefore it's ok to propagate up the error from
 1891          * getaddrinfo() that's in save_errno.
 1892          */
 1893         if (openfd == INVALID_HANDLE && errno == ENOENT && save_errno)
 1894             errno = save_errno;
 1895     }
 1896 #if defined(__EMX__) || defined(__MINGW32__)
 1897     if (openfd == INVALID_HANDLE && errno == EACCES) {
 1898         /* On OS/2 and Windows directory access via open() is
 1899            not permitted.  */
 1900         struct stat buf;
 1901 
 1902         if (! inetfile(name, strlen(name), NULL)
 1903             && stat(name, & buf) == 0 && S_ISDIR(buf.st_mode))
 1904             errno = EISDIR;
 1905     }
 1906 #endif
 1907     if (openfd != INVALID_HANDLE) {
 1908         if (openfd > fileno(stderr))
 1909             os_close_on_exec(openfd, name, "file", "");
 1910     }
 1911 
 1912     return openfd;
 1913 }
 1914 
 1915 #if defined(HAVE_TERMIOS_H)
 1916 /* push_pty_line_disciplines --- push line disciplines if we work that way */
 1917 
 1918 // Factors out common code for the two versions of fork_and_open_slave_pty().
 1919 
 1920 static void
 1921 push_pty_line_disciplines(int slave)
 1922 {
 1923 #ifdef I_PUSH
 1924     /*
 1925      * Push the necessary modules onto the slave to
 1926      * get terminal semantics.  Check that they aren't
 1927      * already there to avoid hangs on said "limited" systems.
 1928      */
 1929 #ifdef I_FIND
 1930     if (ioctl(slave, I_FIND, "ptem") == 0)
 1931 #endif
 1932         ioctl(slave, I_PUSH, "ptem");
 1933 #ifdef I_FIND
 1934     if (ioctl(slave, I_FIND, "ldterm") == 0)
 1935 #endif
 1936         ioctl(slave, I_PUSH, "ldterm");
 1937 #endif
 1938 }
 1939 
 1940 /* set_slave_pty_attributes --- set terminal attributes for slave pty */
 1941 
 1942 // Factors out common code for the two versions of fork_and_open_slave_pty().
 1943 
 1944 static void
 1945 set_slave_pty_attributes(int slave)
 1946 {
 1947     struct termios st;
 1948 
 1949     tcgetattr(slave, & st);
 1950     st.c_iflag &= ~(ISTRIP | IGNCR | INLCR | IXOFF);
 1951     st.c_iflag |= (ICRNL | IGNPAR | BRKINT | IXON);
 1952     st.c_oflag &= ~OPOST;
 1953     st.c_cflag &= ~CSIZE;
 1954     st.c_cflag |= CREAD | CS8 | CLOCAL;
 1955     st.c_lflag &= ~(ECHO | ECHOE | ECHOK | NOFLSH | TOSTOP);
 1956     st.c_lflag |= ISIG;
 1957 
 1958     /* Set some control codes to default values */
 1959 #ifdef VINTR
 1960     st.c_cc[VINTR] = '\003';        /* ^c */
 1961 #endif
 1962 #ifdef VQUIT
 1963     st.c_cc[VQUIT] = '\034';        /* ^| */
 1964 #endif
 1965 #ifdef VERASE
 1966     st.c_cc[VERASE] = '\177';       /* ^? */
 1967 #endif
 1968 #ifdef VKILL
 1969     st.c_cc[VKILL] = '\025';        /* ^u */
 1970 #endif
 1971 #ifdef VEOF
 1972     st.c_cc[VEOF] = '\004'; /* ^d */
 1973 #endif
 1974     tcsetattr(slave, TCSANOW, & st);
 1975 }
 1976 
 1977 
 1978 /* fork_and_open_slave_pty --- handle forking the child and slave pty setup */
 1979 
 1980 /*
 1981  * January, 2018:
 1982  * This is messy. AIX and HP-UX require that the slave pty be opened and
 1983  * set up in the child.  Everything else wants it to be done in the parent,
 1984  * before the fork.  Thus we have two different versions of the routine that
 1985  * do the same thing, but in different orders.  This is not pretty, but it
 1986  * seems to be the simplest thing to do.
 1987  */
 1988 
 1989 static bool
 1990 fork_and_open_slave_pty(const char *slavenam, int master, const char *command, pid_t *pid)
 1991 {
 1992     int slave;
 1993     int save_errno;
 1994 
 1995 #if defined _AIX || defined __hpux
 1996     /*
 1997      * We specifically open the slave only in the child. This allows
 1998      * AIX and HP0UX to work.  The open is specifically without O_NOCTTY
 1999      * in order to make the slave become the controlling terminal.
 2000      */
 2001 
 2002     switch (*pid = fork()) {
 2003     case 0:
 2004         /* Child process */
 2005         setsid();
 2006 
 2007         if ((slave = open(slavenam, O_RDWR)) < 0) {
 2008             close(master);
 2009             fatal(_("could not open `%s', mode `%s'"),
 2010                 slavenam, "r+");
 2011         }
 2012 
 2013         push_pty_line_disciplines(slave);
 2014         set_slave_pty_attributes(slave);
 2015 
 2016         if (close(master) == -1)
 2017             fatal(_("close of master pty failed: %s"), strerror(errno));
 2018         if (close(1) == -1)
 2019             fatal(_("close of stdout in child failed: %s"),
 2020                 strerror(errno));
 2021         if (dup(slave) != 1)
 2022             fatal(_("moving slave pty to stdout in child failed (dup: %s)"), strerror(errno));
 2023         if (close(0) == -1)
 2024             fatal(_("close of stdin in child failed: %s"),
 2025                 strerror(errno));
 2026         if (dup(slave) != 0)
 2027             fatal(_("moving slave pty to stdin in child failed (dup: %s)"), strerror(errno));
 2028         if (close(slave))
 2029             fatal(_("close of slave pty failed: %s"), strerror(errno));
 2030 
 2031         /* stderr does NOT get dup'ed onto child's stdout */
 2032 
 2033         set_sigpipe_to_default();
 2034 
 2035         execl("/bin/sh", "sh", "-c", command, NULL);
 2036         _exit(errno == ENOENT ? 127 : 126);
 2037 
 2038     case -1:
 2039         save_errno = errno;
 2040         close(master);
 2041         errno = save_errno;
 2042         return false;
 2043 
 2044     default:
 2045         return true;
 2046     }
 2047 
 2048 #else
 2049 
 2050     if ((slave = open(slavenam, O_RDWR)) < 0) {
 2051         close(master);
 2052         fatal(_("could not open `%s', mode `%s'"),
 2053             slavenam, "r+");
 2054     }
 2055 
 2056     push_pty_line_disciplines(slave);
 2057     set_slave_pty_attributes(slave);
 2058 
 2059     switch (*pid = fork()) {
 2060     case 0:
 2061         /* Child process */
 2062         setsid();
 2063 
 2064 #ifdef TIOCSCTTY
 2065         ioctl(slave, TIOCSCTTY, 0);
 2066 #endif
 2067 
 2068         if (close(master) == -1)
 2069             fatal(_("close of master pty failed: %s"), strerror(errno));
 2070         if (close(1) == -1)
 2071             fatal(_("close of stdout in child failed: %s"),
 2072                 strerror(errno));
 2073         if (dup(slave) != 1)
 2074             fatal(_("moving slave pty to stdout in child failed (dup: %s)"), strerror(errno));
 2075         if (close(0) == -1)
 2076             fatal(_("close of stdin in child failed: %s"),
 2077                 strerror(errno));
 2078         if (dup(slave) != 0)
 2079             fatal(_("moving slave pty to stdin in child failed (dup: %s)"), strerror(errno));
 2080         if (close(slave))
 2081             fatal(_("close of slave pty failed: %s"), strerror(errno));
 2082 
 2083         /* stderr does NOT get dup'ed onto child's stdout */
 2084 
 2085         signal(SIGPIPE, SIG_DFL);
 2086 
 2087         execl("/bin/sh", "sh", "-c", command, NULL);
 2088         _exit(errno == ENOENT ? 127 : 126);
 2089 
 2090     case -1:
 2091         save_errno = errno;
 2092         close(master);
 2093         close(slave);
 2094         errno = save_errno;
 2095         return false;
 2096 
 2097     }
 2098 
 2099     /* parent */
 2100     if (close(slave) != 0) {
 2101         close(master);
 2102         (void) kill(*pid, SIGKILL);
 2103         fatal(_("close of slave pty failed: %s"), strerror(errno));
 2104     }
 2105 
 2106     return true;
 2107 #endif
 2108 }
 2109 
 2110 #endif /* defined(HAVE_TERMIOS_H) */
 2111 
 2112 /* two_way_open --- open a two way communications channel */
 2113 
 2114 static int
 2115 two_way_open(const char *str, struct redirect *rp, int extfd)
 2116 {
 2117     static bool no_ptys = false;
 2118 
 2119 #ifdef HAVE_SOCKETS
 2120     /* case 1: socket */
 2121     if (extfd >= 0 || inetfile(str, strlen(str), NULL)) {
 2122         int fd, newfd;
 2123 
 2124         fd = (extfd >= 0) ? extfd : devopen(str, "rw");
 2125         if (fd == INVALID_HANDLE)
 2126             return false;
 2127         if ((BINMODE & BINMODE_OUTPUT) != 0)
 2128             os_setbinmode(fd, O_BINARY);
 2129         rp->output.fp = fdopen(fd, binmode("wb"));
 2130         if (rp->output.fp == NULL) {
 2131             close(fd);
 2132             return false;
 2133         }
 2134         newfd = dup(fd);
 2135         if (newfd < 0) {
 2136             rp->output.gawk_fclose(rp->output.fp, rp->output.opaque);
 2137             return false;
 2138         }
 2139         if ((BINMODE & BINMODE_INPUT) != 0)
 2140             os_setbinmode(newfd, O_BINARY);
 2141         os_close_on_exec(fd, str, "socket", "to/from");
 2142         os_close_on_exec(newfd, str, "socket", "to/from");
 2143         rp->iop = iop_alloc(newfd, str, 0);
 2144         rp->output.name = str;
 2145         find_input_parser(rp->iop);
 2146         iop_finish(rp->iop);
 2147         if (! rp->iop->valid) {
 2148             if (! do_traditional && rp->iop->errcode != 0)
 2149                 update_ERRNO_int(rp->iop->errcode);
 2150             iop_close(rp->iop);
 2151             rp->iop = NULL;
 2152             rp->output.gawk_fclose(rp->output.fp, rp->output.opaque);
 2153             return false;
 2154         }
 2155         rp->flag |= RED_SOCKET;
 2156         return true;
 2157     }
 2158 #endif /* HAVE_SOCKETS */
 2159 
 2160     /* case 2: see if an extension wants it */
 2161     if (find_two_way_processor(str, rp))
 2162         return true;
 2163 
 2164 #if defined(HAVE_TERMIOS_H)
 2165     /* case 3: use ptys for two-way communications to child */
 2166     if (! no_ptys && pty_vs_pipe(str)) {
 2167         static bool initialized = false;
 2168         static char first_pty_letter;
 2169 #if defined(HAVE_GRANTPT) && ! defined(HAVE_POSIX_OPENPT)
 2170         static int have_dev_ptmx;
 2171 #endif
 2172         char slavenam[32];
 2173         char c;
 2174         int master, dup_master;
 2175         pid_t pid;
 2176         struct stat statb;
 2177         /* Use array of chars to avoid ASCII / EBCDIC issues */
 2178         static char pty_chars[] = "pqrstuvwxyzabcdefghijklmno";
 2179         int i;
 2180 
 2181         if (! initialized) {
 2182             initialized = true;
 2183 #if defined(HAVE_GRANTPT) && ! defined(HAVE_POSIX_OPENPT)
 2184             have_dev_ptmx = (stat("/dev/ptmx", & statb) >= 0);
 2185 #endif
 2186             i = 0;
 2187             do {
 2188                 c = pty_chars[i++];
 2189                 sprintf(slavenam, "/dev/pty%c0", c);
 2190                 if (stat(slavenam, & statb) >= 0) {
 2191                     first_pty_letter = c;
 2192                     break;
 2193                 }
 2194             } while (pty_chars[i] != '\0');
 2195         }
 2196 
 2197 #ifdef HAVE_GRANTPT
 2198 #ifdef HAVE_POSIX_OPENPT
 2199         {
 2200             master = posix_openpt(O_RDWR|O_NOCTTY);
 2201 #else
 2202         if (have_dev_ptmx) {
 2203             master = open("/dev/ptmx", O_RDWR);
 2204 #endif
 2205             if (master >= 0) {
 2206                 char *tem;
 2207 
 2208                 grantpt(master);
 2209                 unlockpt(master);
 2210                 tem = ptsname(master);
 2211                 if (tem != NULL) {
 2212                     strcpy(slavenam, tem);
 2213                     goto got_the_pty;
 2214                 }
 2215                 (void) close(master);
 2216             }
 2217         }
 2218 #endif
 2219 
 2220         if (first_pty_letter) {
 2221             /*
 2222              * Assume /dev/ptyXNN and /dev/ttyXN naming system.
 2223              * The FIRST_PTY_LETTER gives the first X to try.
 2224              * We try in the sequence FIRST_PTY_LETTER, ..,
 2225              * 'z', 'a', .., FIRST_PTY_LETTER.
 2226              * Is this worthwhile, or just over-zealous?
 2227              */
 2228             c = first_pty_letter;
 2229             do {
 2230                 int i;
 2231                 char *cp;
 2232 
 2233                 for (i = 0; i < 16; i++) {
 2234                     sprintf(slavenam, "/dev/pty%c%x", c, i);
 2235                     if (stat(slavenam, & statb) < 0) {
 2236                         no_ptys = true; /* bypass all this next time */
 2237                         goto use_pipes;
 2238                     }
 2239 
 2240                     if ((master = open(slavenam, O_RDWR)) >= 0) {
 2241                         slavenam[sizeof("/dev/") - 1] = 't';
 2242                         if (access(slavenam, R_OK | W_OK) == 0)
 2243                             goto got_the_pty;
 2244                         close(master);
 2245                     }
 2246                 }
 2247                 /* move to next character */
 2248                 cp = strchr(pty_chars, c);
 2249                 if (cp[1] != '\0')
 2250                     cp++;
 2251                 else
 2252                     cp = pty_chars;
 2253                 c = *cp;
 2254             } while (c != first_pty_letter);
 2255         } else
 2256             no_ptys = true;
 2257 
 2258         /* Couldn't find a pty. Fall back to using pipes. */
 2259         goto use_pipes;
 2260 
 2261     got_the_pty:
 2262 
 2263         /* this is the parent */
 2264         if (! fork_and_open_slave_pty(slavenam, master, str, & pid))
 2265             fatal(_("could not create child process or open pty"));
 2266 
 2267         rp->pid = pid;
 2268         rp->iop = iop_alloc(master, str, 0);
 2269         find_input_parser(rp->iop);
 2270         iop_finish(rp->iop);
 2271         if (! rp->iop->valid) {
 2272             if (! do_traditional && rp->iop->errcode != 0)
 2273                 update_ERRNO_int(rp->iop->errcode);
 2274             iop_close(rp->iop);
 2275             rp->iop = NULL;
 2276             (void) kill(pid, SIGKILL);
 2277             return false;
 2278         }
 2279 
 2280         rp->output.name = str;
 2281         /*
 2282          * Force read and write ends of two-way connection to
 2283          * be different fd's so they can be closed independently.
 2284          */
 2285         rp->output.mode = "w";
 2286         if ((dup_master = dup(master)) < 0
 2287             || (rp->output.fp = fdopen(dup_master, "w")) == NULL) {
 2288             iop_close(rp->iop);
 2289             rp->iop = NULL;
 2290             (void) close(master);
 2291             (void) kill(pid, SIGKILL);
 2292             if (dup_master > 0)
 2293                 (void) close(dup_master);
 2294             return false;
 2295         } else
 2296             find_output_wrapper(& rp->output);
 2297         rp->flag |= RED_PTY;
 2298         os_close_on_exec(master, str, "pipe", "from");
 2299         os_close_on_exec(dup_master, str, "pipe", "to");
 2300         first_pty_letter = '\0';    /* reset for next command */
 2301         return true;
 2302     }
 2303 #endif /* defined(HAVE_TERMIOS_H) */
 2304 
 2305 use_pipes:
 2306 #ifndef PIPES_SIMULATED     /* real pipes */
 2307     /* case 4: two way pipe to a child process */
 2308     {
 2309     int ptoc[2], ctop[2];
 2310     int pid;
 2311     int save_errno;
 2312 #if defined(__EMX__) || defined(__MINGW32__)
 2313     int save_stdout, save_stdin;
 2314 #ifdef __MINGW32__
 2315     char *qcmd = NULL;
 2316 #endif
 2317 #endif
 2318 
 2319     if (pipe(ptoc) < 0)
 2320         return false;   /* errno set, diagnostic from caller */
 2321 
 2322     if (pipe(ctop) < 0) {
 2323         save_errno = errno;
 2324         close(ptoc[0]);
 2325         close(ptoc[1]);
 2326         errno = save_errno;
 2327         return false;
 2328     }
 2329 
 2330 #if defined(__EMX__) || defined(__MINGW32__)
 2331     save_stdin = dup(0);    /* duplicate stdin */
 2332     save_stdout = dup(1);   /* duplicate stdout */
 2333 
 2334     if (save_stdout == -1 || save_stdin == -1) {
 2335         /* if an error occurs close all open file handles */
 2336         save_errno = errno;
 2337         if (save_stdin != -1)
 2338             close(save_stdin);
 2339         if (save_stdout != -1)
 2340             close(save_stdout);
 2341         close(ptoc[0]); close(ptoc[1]);
 2342         close(ctop[0]); close(ctop[1]);
 2343         errno = save_errno;
 2344         return false;
 2345     }
 2346 
 2347     /* connect pipes to stdin and stdout */
 2348     close(1);   /* close stdout */
 2349     if (dup(ctop[1]) != 1) {    /* connect pipe input to stdout */
 2350         close(save_stdin); close(save_stdout);
 2351         close(ptoc[0]); close(ptoc[1]);
 2352         close(ctop[0]); close(ctop[1]);
 2353         fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
 2354     }
 2355     close(0);   /* close stdin */
 2356     if (dup(ptoc[0]) != 0) {    /* connect pipe output to stdin */
 2357         close(save_stdin); close(save_stdout);
 2358         close(ptoc[0]); close(ptoc[1]);
 2359         close(ctop[0]); close(ctop[1]);
 2360         fatal(_("moving pipe to stdin in child failed (dup: %s)"), strerror(errno));
 2361     }
 2362 
 2363     /* none of these handles must be inherited by the child process */
 2364     (void) close(ptoc[0]);  /* close pipe output, child will use stdin instead */
 2365     (void) close(ctop[1]);  /* close pipe input, child will use stdout instead */
 2366 
 2367     os_close_on_exec(ptoc[1], str, "pipe", "from"); /* pipe input: output of the parent process */
 2368     os_close_on_exec(ctop[0], str, "pipe", "from"); /* pipe output: input of the parent process */
 2369     os_close_on_exec(save_stdin, str, "pipe", "from"); /* saved stdin of the parent process */
 2370     os_close_on_exec(save_stdout, str, "pipe", "from"); /* saved stdout of the parent process */
 2371 
 2372     /* stderr does NOT get dup'ed onto child's stdout */
 2373 #ifdef __EMX__
 2374     pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", str, NULL);
 2375 #else  /* __MINGW32__ */
 2376     pid = spawnl(P_NOWAIT, getenv("ComSpec"), "cmd.exe", "/c",
 2377              qcmd = quote_cmd(str), NULL);
 2378     efree(qcmd);
 2379 #endif
 2380 
 2381     /* restore stdin and stdout */
 2382     close(1);
 2383     if (dup(save_stdout) != 1) {
 2384         close(save_stdin); close(save_stdout);
 2385         close(ptoc[1]); close(ctop[0]);
 2386         fatal(_("restoring stdout in parent process failed"));
 2387     }
 2388     close(save_stdout);
 2389 
 2390     close(0);
 2391     if (dup(save_stdin) != 0) {
 2392         close(save_stdin);
 2393         close(ptoc[1]); close(ctop[0]);
 2394         fatal(_("restoring stdin in parent process failed"));
 2395     }
 2396     close(save_stdin);
 2397 
 2398     if (pid < 0) { /* spawnl() failed */
 2399         save_errno = errno;
 2400         close(ptoc[1]);
 2401         close(ctop[0]);
 2402 
 2403         errno = save_errno;
 2404         return false;
 2405     }
 2406 
 2407 #else /* NOT __EMX__, NOT __MINGW32__ */
 2408     if ((pid = fork()) < 0) {
 2409         save_errno = errno;
 2410         close(ptoc[0]); close(ptoc[1]);
 2411         close(ctop[0]); close(ctop[1]);
 2412         errno = save_errno;
 2413         return false;
 2414     }
 2415 
 2416     if (pid == 0) { /* child */
 2417         if (close(1) == -1)
 2418             fatal(_("close of stdout in child failed: %s"),
 2419                 strerror(errno));
 2420         if (dup(ctop[1]) != 1)
 2421             fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
 2422         if (close(0) == -1)
 2423             fatal(_("close of stdin in child failed: %s"),
 2424                 strerror(errno));
 2425         if (dup(ptoc[0]) != 0)
 2426             fatal(_("moving pipe to stdin in child failed (dup: %s)"), strerror(errno));
 2427         if (   close(ptoc[0]) == -1 || close(ptoc[1]) == -1
 2428             || close(ctop[0]) == -1 || close(ctop[1]) == -1)
 2429             fatal(_("close of pipe failed: %s"), strerror(errno));
 2430         /* stderr does NOT get dup'ed onto child's stdout */
 2431         set_sigpipe_to_default();
 2432         execl("/bin/sh", "sh", "-c", str, NULL);
 2433         _exit(errno == ENOENT ? 127 : 126);
 2434     }
 2435 #endif /* NOT __EMX__, NOT __MINGW32__ */
 2436 
 2437     /* parent */
 2438     if ((BINMODE & BINMODE_INPUT) != 0)
 2439         os_setbinmode(ctop[0], O_BINARY);
 2440     if ((BINMODE & BINMODE_OUTPUT) != 0)
 2441         os_setbinmode(ptoc[1], O_BINARY);
 2442     rp->pid = pid;
 2443     rp->iop = iop_alloc(ctop[0], str, 0);
 2444     find_input_parser(rp->iop);
 2445     iop_finish(rp->iop);
 2446     if (! rp->iop->valid) {
 2447         if (! do_traditional && rp->iop->errcode != 0)
 2448             update_ERRNO_int(rp->iop->errcode);
 2449         iop_close(rp->iop);
 2450         rp->iop = NULL;
 2451         (void) close(ctop[1]);
 2452         (void) close(ptoc[0]);
 2453         (void) close(ptoc[1]);
 2454         (void) kill(pid, SIGKILL);
 2455 
 2456         return false;
 2457     }
 2458     rp->output.fp = fdopen(ptoc[1], binmode("w"));
 2459     rp->output.mode = "w";
 2460     rp->output.name = str;
 2461     if (rp->output.fp == NULL) {
 2462         iop_close(rp->iop);
 2463         rp->iop = NULL;
 2464         (void) close(ctop[0]);
 2465         (void) close(ctop[1]);
 2466         (void) close(ptoc[0]);
 2467         (void) close(ptoc[1]);
 2468         (void) kill(pid, SIGKILL);
 2469 
 2470         return false;
 2471     }
 2472     else
 2473         find_output_wrapper(& rp->output);
 2474 
 2475 #if !defined(__EMX__) && !defined(__MINGW32__)
 2476     os_close_on_exec(ctop[0], str, "pipe", "from");
 2477     os_close_on_exec(ptoc[1], str, "pipe", "from");
 2478 
 2479     (void) close(ptoc[0]);
 2480     (void) close(ctop[1]);
 2481 #endif
 2482 
 2483     return true;
 2484     }
 2485 
 2486 #else   /*PIPES_SIMULATED*/
 2487 
 2488     fatal(_("`|&' not supported"));
 2489     /*NOTREACHED*/
 2490     return false;
 2491 
 2492 #endif
 2493 }
 2494 
 2495 #ifndef PIPES_SIMULATED     /* real pipes */
 2496 
 2497 /*
 2498  * wait_any --- if the argument pid is 0, wait for all child processes that
 2499  * have exited.  We loop to make sure to reap all children that have exited to
 2500  * minimize the risk of running out of process slots.  Since we don't process
 2501  * SIGCHLD, we do not immediately reap exited children.  So when we get here,
 2502  * we want to reap any that have piled up.
 2503  *
 2504  * Note: on platforms that do not support waitpid with WNOHANG, when called with
 2505  * a zero argument, this function will hang until all children have exited.
 2506  *
 2507  * AJS, 2013-07-07: I do not see why we need to ignore signals during this
 2508  * function.  This function just waits and updates the pid and status fields.
 2509  * I don't see why that should interfere with any signal handlers.  But I am
 2510  * reluctant to remove this protection.  So I changed to use sigprocmask to
 2511  * block signals instead to avoid interfering with installed signal handlers.
 2512  */
 2513 
 2514 static int
 2515 wait_any(int interesting)   /* pid of interest, if any */
 2516 {
 2517     int pid;
 2518     int status = 0;
 2519     struct redirect *redp;
 2520 #ifdef HAVE_SIGPROCMASK
 2521     sigset_t set, oldset;
 2522 
 2523     /* I have no idea why we are blocking signals during this function... */
 2524     sigemptyset(& set);
 2525     sigaddset(& set, SIGINT);
 2526     sigaddset(& set, SIGHUP);
 2527     sigaddset(& set, SIGQUIT);
 2528     sigprocmask(SIG_BLOCK, & set, & oldset);
 2529 #else
 2530     void (*hstat)(int), (*istat)(int), (*qstat)(int);
 2531 
 2532     istat = signal(SIGINT, SIG_IGN);
 2533 #endif
 2534 #ifdef __MINGW32__
 2535     if (interesting < 0) {
 2536         status = -1;
 2537         pid = -1;
 2538     }
 2539     else
 2540         pid = _cwait(& status, interesting, 0);
 2541     if (pid == interesting && pid > 0) {
 2542         for (redp = red_head; redp != NULL; redp = redp->next)
 2543             if (interesting == redp->pid) {
 2544                 redp->pid = -1;
 2545                 redp->status = status;
 2546                 break;
 2547             }
 2548     }
 2549 #else /* ! __MINGW32__ */
 2550 #ifndef HAVE_SIGPROCMASK
 2551     hstat = signal(SIGHUP, SIG_IGN);
 2552     qstat = signal(SIGQUIT, SIG_IGN);
 2553 #endif
 2554     for (;;) {
 2555 # if defined(HAVE_WAITPID) && defined(WNOHANG)
 2556         /*
 2557          * N.B. If the caller wants status for a specific child process
 2558          * (i.e. interesting is non-zero), then we must hang until we
 2559          * get exit status for that child.
 2560          */
 2561         if ((pid = waitpid(-1, & status, (interesting ? 0 : WNOHANG))) == 0)
 2562             /* No children have exited */
 2563             break;
 2564 # elif defined(HAVE_SYS_WAIT_H) /* POSIX compatible sys/wait.h */
 2565         pid = wait(& status);
 2566 # else
 2567         pid = wait((union wait *) & status);
 2568 # endif
 2569         if (interesting && pid == interesting) {
 2570             break;
 2571         } else if (pid != -1) {
 2572             for (redp = red_head; redp != NULL; redp = redp->next)
 2573                 if (pid == redp->pid) {
 2574                     redp->pid = -1;
 2575                     redp->status = status;
 2576                     break;
 2577                 }
 2578         }
 2579         if (pid == -1 && errno == ECHILD)
 2580             break;
 2581     }
 2582 #ifndef HAVE_SIGPROCMASK
 2583     signal(SIGHUP, hstat);
 2584     signal(SIGQUIT, qstat);
 2585 #endif
 2586 #endif /* ! __MINGW32__ */
 2587 #ifndef HAVE_SIGPROCMASK
 2588     signal(SIGINT, istat);
 2589 #else
 2590     sigprocmask(SIG_SETMASK, & oldset, NULL);
 2591 #endif
 2592     return status;
 2593 }
 2594 
 2595 /* gawk_popen --- open an IOBUF on a child process */
 2596 
 2597 static IOBUF *
 2598 gawk_popen(const char *cmd, struct redirect *rp)
 2599 {
 2600     int p[2];
 2601     int pid;
 2602 #if defined(__EMX__) || defined(__MINGW32__)
 2603     int save_stdout;
 2604 #ifdef __MINGW32__
 2605     char *qcmd = NULL;
 2606 #endif
 2607 #endif
 2608 
 2609     /*
 2610      * We used to wait for any children to synchronize input and output,
 2611      * but this could cause gawk to hang when it is started in a pipeline
 2612      * and thus has a child process feeding it input (shell dependent).
 2613      *
 2614      * (void) wait_any(0);  // wait for outstanding processes
 2615      */
 2616 
 2617     if (pipe(p) < 0)
 2618         fatal(_("cannot open pipe `%s': %s"), cmd, strerror(errno));
 2619 
 2620 #if defined(__EMX__) || defined(__MINGW32__)
 2621     rp->iop = NULL;
 2622     save_stdout = dup(1); /* save stdout */
 2623     if (save_stdout == -1) {
 2624         close(p[0]);
 2625         close(p[1]);
 2626         return NULL;    /* failed */
 2627     }
 2628 
 2629     close(1); /* close stdout */
 2630     if (dup(p[1]) != 1) {
 2631         close(p[0]);
 2632         close(p[1]);
 2633         fatal(_("moving pipe to stdout in child failed (dup: %s)"),
 2634                 strerror(errno));
 2635     }
 2636 
 2637     /* none of these handles must be inherited by the child process */
 2638     close(p[1]); /* close pipe input */
 2639 
 2640     os_close_on_exec(p[0], cmd, "pipe", "from"); /* pipe output: input of the parent process */
 2641     os_close_on_exec(save_stdout, cmd, "pipe", "from"); /* saved stdout of the parent process */
 2642 
 2643 #ifdef __EMX__
 2644     pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", cmd, NULL);
 2645 #else  /* __MINGW32__ */
 2646     pid = spawnl(P_NOWAIT, getenv("ComSpec"), "cmd.exe", "/c",
 2647              qcmd = quote_cmd(cmd), NULL);
 2648     efree(qcmd);
 2649 #endif
 2650 
 2651     /* restore stdout */
 2652     close(1);
 2653     if (dup(save_stdout) != 1) {
 2654         close(p[0]);
 2655         fatal(_("restoring stdout in parent process failed"));
 2656     }
 2657     close(save_stdout);
 2658 
 2659 #else /* NOT __EMX__, NOT __MINGW32__ */
 2660     if ((pid = fork()) == 0) {
 2661         if (close(1) == -1)
 2662             fatal(_("close of stdout in child failed: %s"),
 2663                 strerror(errno));
 2664         if (dup(p[1]) != 1)
 2665             fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
 2666         if (close(p[0]) == -1 || close(p[1]) == -1)
 2667             fatal(_("close of pipe failed: %s"), strerror(errno));
 2668         set_sigpipe_to_default();
 2669         execl("/bin/sh", "sh", "-c", cmd, NULL);
 2670         _exit(errno == ENOENT ? 127 : 126);
 2671     }
 2672 #endif /* NOT __EMX__, NOT __MINGW32__ */
 2673 
 2674     if (pid == -1) {
 2675         close(p[0]); close(p[1]);
 2676         fatal(_("cannot create child process for `%s' (fork: %s)"), cmd, strerror(errno));
 2677     }
 2678     rp->pid = pid;
 2679 #if !defined(__EMX__) && !defined(__MINGW32__)
 2680     if (close(p[1]) == -1) {
 2681         close(p[0]);
 2682         fatal(_("close of pipe failed: %s"), strerror(errno));
 2683     }
 2684 #endif
 2685     os_close_on_exec(p[0], cmd, "pipe", "from");
 2686     if ((BINMODE & BINMODE_INPUT) != 0)
 2687         os_setbinmode(p[0], O_BINARY);
 2688     rp->iop = iop_alloc(p[0], cmd, 0);
 2689     find_input_parser(rp->iop);
 2690     iop_finish(rp->iop);
 2691     if (! rp->iop->valid) {
 2692         if (! do_traditional && rp->iop->errcode != 0)
 2693             update_ERRNO_int(rp->iop->errcode);
 2694         iop_close(rp->iop);
 2695         rp->iop = NULL;
 2696     }
 2697 
 2698     return rp->iop;
 2699 }
 2700 
 2701 /* gawk_pclose --- close an open child pipe */
 2702 
 2703 static int
 2704 gawk_pclose(struct redirect *rp)
 2705 {
 2706     if (rp->iop != NULL)
 2707         (void) iop_close(rp->iop);
 2708     rp->iop = NULL;
 2709 
 2710     /* process previously found, return stored status */
 2711     if (rp->pid == -1)
 2712         return rp->status;
 2713     rp->status = sanitize_exit_status(wait_any(rp->pid));
 2714     rp->pid = -1;
 2715     return rp->status;
 2716 }
 2717 
 2718 #else   /* PIPES_SIMULATED */
 2719 
 2720 /*
 2721  * use temporary file rather than pipe
 2722  * except if popen() provides real pipes too
 2723  */
 2724 
 2725 /* gawk_popen --- open an IOBUF on a child process */
 2726 
 2727 static IOBUF *
 2728 gawk_popen(const char *cmd, struct redirect *rp)
 2729 {
 2730     FILE *current;
 2731 
 2732     os_restore_mode(fileno(stdin));
 2733     set_sigpipe_to_default();
 2734 
 2735     current = popen(cmd, binmode("r"));
 2736 
 2737     if ((BINMODE & BINMODE_INPUT) != 0)
 2738         os_setbinmode(fileno(stdin), O_BINARY);
 2739     ignore_sigpipe();
 2740 
 2741     if (current == NULL)
 2742         return NULL;
 2743     os_close_on_exec(fileno(current), cmd, "pipe", "from");
 2744     rp->iop = iop_alloc(fileno(current), cmd, 0);
 2745     find_input_parser(rp->iop);
 2746     iop_finish(rp->iop);
 2747     if (! rp->iop->valid) {
 2748         if (! do_traditional && rp->iop->errcode != 0)
 2749             update_ERRNO_int(rp->iop->errcode);
 2750         (void) pclose(current);
 2751         rp->iop->public.fd = INVALID_HANDLE;
 2752         iop_close(rp->iop);
 2753         rp->iop = NULL;
 2754         current = NULL;
 2755     }
 2756     rp->ifp = current;
 2757     return rp->iop;
 2758 }
 2759 
 2760 /* gawk_pclose --- close an open child pipe */
 2761 
 2762 static int
 2763 gawk_pclose(struct redirect *rp)
 2764 {
 2765     int rval, aval, fd = rp->iop->public.fd;
 2766 
 2767     if (rp->iop != NULL) {
 2768         rp->iop->public.fd = dup(fd);     /* kludge to allow close() + pclose() */
 2769         rval = iop_close(rp->iop);
 2770     }
 2771     rp->iop = NULL;
 2772     aval = pclose(rp->ifp);
 2773     rp->ifp = NULL;
 2774     return (rval < 0 ? rval : aval);
 2775 }
 2776 
 2777 #endif  /* PIPES_SIMULATED */
 2778 
 2779 /* do_getline_redir --- read in a line, into var and with redirection */
 2780 
 2781 NODE *
 2782 do_getline_redir(int into_variable, enum redirval redirtype)
 2783 {
 2784     struct redirect *rp = NULL;
 2785     IOBUF *iop;
 2786     int cnt = EOF;
 2787     char *s = NULL;
 2788     int errcode;
 2789     NODE *redir_exp = NULL;
 2790     NODE **lhs = NULL;
 2791     int redir_error = 0;
 2792     const awk_fieldwidth_info_t *field_width = NULL;
 2793 
 2794     if (into_variable)
 2795         lhs = POP_ADDRESS();
 2796 
 2797     assert(redirtype != redirect_none);
 2798     redir_exp = TOP();
 2799     rp = redirect(redir_exp, redirtype, & redir_error, false);
 2800     DEREF(redir_exp);
 2801     decr_sp();
 2802     if (rp == NULL) {
 2803         if (redir_error) { /* failed redirect */
 2804             if (! do_traditional)
 2805                 update_ERRNO_int(redir_error);
 2806         }
 2807         return make_number((AWKNUM) -1.0);
 2808     } else if ((rp->flag & RED_TWOWAY) != 0 && rp->iop == NULL) {
 2809         if (is_non_fatal_redirect(redir_exp->stptr, redir_exp->stlen)) {
 2810             update_ERRNO_int(EBADF);
 2811             return make_number((AWKNUM) -1.0);
 2812         }
 2813         (void) close_rp(rp, CLOSE_ALL);
 2814         fatal(_("getline: attempt to read from closed read end of two-way pipe"));
 2815     }
 2816     iop = rp->iop;
 2817     if (iop == NULL)        /* end of input */
 2818         return make_number((AWKNUM) 0.0);
 2819 
 2820     errcode = 0;
 2821     cnt = get_a_record(& s, iop, & errcode, (lhs ? NULL : & field_width));
 2822     if (errcode != 0) {
 2823         if (! do_traditional && (errcode != -1))
 2824             update_ERRNO_int(errcode);
 2825         return make_number((AWKNUM) cnt);
 2826     }
 2827 
 2828     if (cnt == EOF) {
 2829         /*
 2830          * Don't do iop_close() here if we are
 2831          * reading from a pipe; otherwise
 2832          * gawk_pclose will not be called.
 2833          */
 2834         if ((rp->flag & (RED_PIPE|RED_TWOWAY)) == 0) {
 2835             (void) iop_close(iop);
 2836             rp->iop = NULL;
 2837         }
 2838         rp->flag |= RED_EOF;    /* sticky EOF */
 2839         return make_number((AWKNUM) 0.0);
 2840     }
 2841 
 2842     if (lhs == NULL)    /* no optional var. */
 2843         set_record(s, cnt, field_width);
 2844     else {          /* assignment to variable */
 2845         unref(*lhs);
 2846         *lhs = make_string(s, cnt);
 2847         (*lhs)->flags |= USER_INPUT;
 2848     }
 2849 
 2850     return make_number((AWKNUM) 1.0);
 2851 }
 2852 
 2853 /* do_getline --- read in a line, into var and without redirection */
 2854 
 2855 NODE *
 2856 do_getline(int into_variable, IOBUF *iop)
 2857 {
 2858     int cnt = EOF;
 2859     char *s = NULL;
 2860     int errcode;
 2861     const awk_fieldwidth_info_t *field_width = NULL;
 2862 
 2863     if (iop == NULL) {  /* end of input */
 2864         if (into_variable)
 2865             (void) POP_ADDRESS();
 2866         return make_number((AWKNUM) 0.0);
 2867     }
 2868 
 2869     errcode = 0;
 2870     cnt = get_a_record(& s, iop, & errcode, (into_variable ? NULL : & field_width));
 2871     if (errcode != 0) {
 2872         if (! do_traditional && (errcode != -1))
 2873             update_ERRNO_int(errcode);
 2874         if (into_variable)
 2875             (void) POP_ADDRESS();
 2876         return make_number((AWKNUM) cnt);
 2877     }
 2878 
 2879     if (cnt == EOF)
 2880         return NULL;    /* try next file */
 2881     INCREMENT_REC(NR);
 2882     INCREMENT_REC(FNR);
 2883 
 2884     if (! into_variable)    /* no optional var. */
 2885         set_record(s, cnt, field_width);
 2886     else {          /* assignment to variable */
 2887         NODE **lhs;
 2888         lhs = POP_ADDRESS();
 2889         unref(*lhs);
 2890         *lhs = make_string(s, cnt);
 2891         (*lhs)->flags |= USER_INPUT;
 2892     }
 2893     return make_number((AWKNUM) 1.0);
 2894 }
 2895 
 2896 typedef struct {
 2897     const char *envname;
 2898     char **dfltp;       /* pointer to address of default path */
 2899     char **awkpath;     /* array containing library search paths */
 2900     int max_pathlen;    /* length of the longest item in awkpath */
 2901 } path_info;
 2902 
 2903 static path_info pi_awkpath = {
 2904     /* envname */   "AWKPATH",
 2905     /* dfltp */ & defpath,
 2906 };
 2907 
 2908 static path_info pi_awklibpath = {
 2909     /* envname */   "AWKLIBPATH",
 2910     /* dfltp */ & deflibpath,
 2911 };
 2912 
 2913 /* init_awkpath --- split path(=$AWKPATH) into components */
 2914 
 2915 static void
 2916 init_awkpath(path_info *pi)
 2917 {
 2918     char *path;
 2919     char *start, *end, *p;
 2920     int len, i;
 2921     int max_path;       /* (# of allocated paths)-1 */
 2922 
 2923     pi->max_pathlen = 0;
 2924     if ((path = getenv(pi->envname)) == NULL || *path == '\0')
 2925         path = pi->dfltp[0];
 2926 
 2927     /* count number of separators */
 2928     for (max_path = 0, p = path; *p; p++)
 2929         if (*p == envsep)
 2930             max_path++;
 2931 
 2932     // +3 --> 2 for null entries at front and end of path, 1 for NULL end of list
 2933     ezalloc(pi->awkpath, char **, (max_path + 3) * sizeof(char *), "init_awkpath");
 2934 
 2935     start = path;
 2936     i = 0;
 2937 
 2938     if (*path == envsep) {  /* null entry at front of path */
 2939         pi->awkpath[i++] = ".";
 2940         pi->max_pathlen = 1;
 2941     }
 2942 
 2943     while (*start) {
 2944         if (*start == envsep) {
 2945             if (start[1] == envsep) {
 2946                 pi->awkpath[i++] = ".";
 2947                 if (pi->max_pathlen == 0)
 2948                     pi->max_pathlen = 1;
 2949                 start++;
 2950             } else if (start[1] == '\0') {
 2951                 pi->awkpath[i++] = ".";
 2952                 if (pi->max_pathlen == 0)
 2953                     pi->max_pathlen = 1;
 2954                 break;
 2955             } else
 2956                 start++;
 2957         } else {
 2958             for (end = start; *end && *end != envsep; end++)
 2959                 continue;
 2960 
 2961             len = end - start;
 2962             if (len > 0) {
 2963                 emalloc(p, char *, len + 2, "init_awkpath");
 2964                 memcpy(p, start, len);
 2965 
 2966                 /* add directory punctuation if necessary */
 2967                 if (! isdirpunct(end[-1]))
 2968                     p[len++] = '/';
 2969                 p[len] = '\0';
 2970                 pi->awkpath[i++] = p;
 2971                 if (len > pi->max_pathlen)
 2972                     pi->max_pathlen = len;
 2973 
 2974                 start = end;
 2975             } else
 2976                 start++;
 2977         }
 2978     }
 2979 
 2980     pi->awkpath[i] = NULL;
 2981 }
 2982 
 2983 /* do_find_source --- search $AWKPATH for file, return NULL if not found */
 2984 
 2985 static char *
 2986 do_find_source(const char *src, struct stat *stb, int *errcode, path_info *pi)
 2987 {
 2988     char *path;
 2989     int i;
 2990 
 2991     assert(errcode != NULL);
 2992 
 2993     /* some kind of path name, no search */
 2994     if (ispath(src)) {
 2995         emalloc(path, char *, strlen(src) + 1, "do_find_source");
 2996         strcpy(path, src);
 2997         if (stat(path, stb) == 0)
 2998             return path;
 2999         *errcode = errno;
 3000         efree(path);
 3001         return NULL;
 3002     }
 3003 
 3004     if (pi->awkpath == NULL)
 3005         init_awkpath(pi);
 3006 
 3007     emalloc(path, char *, pi->max_pathlen + strlen(src) + 1, "do_find_source");
 3008     for (i = 0; pi->awkpath[i] != NULL; i++) {
 3009         if (strcmp(pi->awkpath[i], "./") == 0 || strcmp(pi->awkpath[i], ".") == 0)
 3010             *path = '\0';
 3011         else
 3012             strcpy(path, pi->awkpath[i]);
 3013         strcat(path, src);
 3014         if (stat(path, stb) == 0)
 3015             return path;
 3016     }
 3017 
 3018     /* not found, give up */
 3019     *errcode = errno;
 3020     efree(path);
 3021     return NULL;
 3022 }
 3023 
 3024 /* find_source --- find source file with default file extension handling */
 3025 
 3026 char *
 3027 find_source(const char *src, struct stat *stb, int *errcode, int is_extlib)
 3028 {
 3029     char *path;
 3030     path_info *pi = (is_extlib ? & pi_awklibpath : & pi_awkpath);
 3031 
 3032     *errcode = 0;
 3033     if (src == NULL || *src == '\0')
 3034         return NULL;
 3035 #ifdef __EMX__
 3036     char os2_src[strlen(src) + 1];
 3037 
 3038     if (is_extlib)
 3039         src = os2_fixdllname(os2_src, src, sizeof(os2_src));
 3040 #endif /* __EMX__ */
 3041     path = do_find_source(src, stb, errcode, pi);
 3042 
 3043     if (path == NULL && is_extlib) {
 3044         char *file_ext;
 3045         int save_errno;
 3046         size_t src_len;
 3047         size_t suffix_len;
 3048 
 3049 #define EXTLIB_SUFFIX   "." SHLIBEXT
 3050         src_len = strlen(src);
 3051         suffix_len = strlen(EXTLIB_SUFFIX);
 3052 
 3053         /* check if already has the SUFFIX */
 3054         if (src_len >= suffix_len && strcmp(& src[src_len - suffix_len], EXTLIB_SUFFIX) == 0)
 3055             return NULL;
 3056 
 3057         /* append EXTLIB_SUFFIX and try again */
 3058         save_errno = errno;
 3059         emalloc(file_ext, char *, src_len + suffix_len + 1, "find_source");
 3060         sprintf(file_ext, "%s%s", src, EXTLIB_SUFFIX);
 3061         path = do_find_source(file_ext, stb, errcode, pi);
 3062         efree(file_ext);
 3063         if (path == NULL)
 3064             errno = save_errno;
 3065         return path;
 3066 #undef EXTLIB_SUFFIX
 3067     }
 3068 
 3069 /*
 3070  * Try searching with .awk appended if the platform headers have not specified
 3071  * another suffix.
 3072  */
 3073 #ifndef DEFAULT_FILETYPE
 3074 #define DEFAULT_FILETYPE ".awk"
 3075 #endif
 3076 
 3077 #ifdef DEFAULT_FILETYPE
 3078     if (! do_traditional && path == NULL) {
 3079         char *file_awk;
 3080         int save_errno = errno;
 3081 #ifdef VMS
 3082         int vms_save = vaxc$errno;
 3083 #endif
 3084 
 3085         /* append ".awk" and try again */
 3086         emalloc(file_awk, char *, strlen(src) +
 3087             sizeof(DEFAULT_FILETYPE) + 1, "find_source");
 3088         sprintf(file_awk, "%s%s", src, DEFAULT_FILETYPE);
 3089         path = do_find_source(file_awk, stb, errcode, pi);
 3090         efree(file_awk);
 3091         if (path == NULL) {
 3092             errno = save_errno;
 3093 #ifdef VMS
 3094             vaxc$errno = vms_save;
 3095 #endif
 3096         }
 3097     }
 3098 #endif  /*DEFAULT_FILETYPE*/
 3099 
 3100     return path;
 3101 }
 3102 
 3103 
 3104 /* srcopen --- open source file */
 3105 
 3106 int
 3107 srcopen(SRCFILE *s)
 3108 {
 3109     int fd = INVALID_HANDLE;
 3110 
 3111     if (s->stype == SRC_STDIN)
 3112         fd = fileno(stdin);
 3113     else if (s->stype == SRC_FILE || s->stype == SRC_INC)
 3114         fd = devopen(s->fullpath, "r");
 3115 
 3116     /* set binary mode so that debugger byte offset calculations will be right */
 3117     if (fd != INVALID_HANDLE)
 3118         os_setbinmode(fd, O_BINARY);
 3119 
 3120     return fd;
 3121 }
 3122 
 3123 /* input parsers, mainly for use by extension functions */
 3124 
 3125 static awk_input_parser_t *ip_head, *ip_tail;
 3126 
 3127 /*
 3128  * register_input_parser --- add an input parser to the list, FIFO.
 3129  *  The main reason to use FIFO is to provide the diagnostic
 3130  *  with the correct information: input parser 2 conflicts
 3131  *  with input parser 1.  Otherwise LIFO would have been easier.
 3132  */
 3133 
 3134 void
 3135 register_input_parser(awk_input_parser_t *input_parser)
 3136 {
 3137     if (input_parser == NULL)
 3138         fatal(_("register_input_parser: received NULL pointer"));
 3139 
 3140     input_parser->next = NULL;  /* force it */
 3141     if (ip_head == NULL) {
 3142         ip_head = ip_tail = input_parser;
 3143     } else {
 3144         ip_tail->next = input_parser;
 3145         ip_tail = ip_tail->next;
 3146     }
 3147 }
 3148 
 3149 /* find_input_parser --- search the list of input parsers */
 3150 
 3151 static void
 3152 find_input_parser(IOBUF *iop)
 3153 {
 3154     awk_input_parser_t *ip, *ip2;
 3155 
 3156     /* if already associated with an input parser, bail out early */
 3157     if (iop->public.get_record != NULL)
 3158         return;
 3159 
 3160     ip = ip2 = NULL;
 3161     for (ip2 = ip_head; ip2 != NULL; ip2 = ip2->next) {
 3162         if (ip2->can_take_file(& iop->public)) {
 3163             if (ip == NULL)
 3164                 ip = ip2;   /* found first one */
 3165             else
 3166                 fatal(_("input parser `%s' conflicts with previously installed input parser `%s'"),
 3167                         ip2->name, ip->name);
 3168         }
 3169     }
 3170 
 3171     if (ip != NULL) {
 3172         if (! ip->take_control_of(& iop->public))
 3173             warning(_("input parser `%s' failed to open `%s'"),
 3174                     ip->name, iop->public.name);
 3175         else
 3176             iop->valid = true;
 3177     }
 3178 }
 3179 
 3180 /* output wrappers --- for use by extensions */
 3181 
 3182 static awk_output_wrapper_t *op_head, *op_tail;
 3183 
 3184 /*
 3185  * register_output_wrapper --- add an output wrapper to the list.
 3186  *  Same stuff here as for input parsers.
 3187  */
 3188 
 3189 void
 3190 register_output_wrapper(awk_output_wrapper_t *wrapper)
 3191 {
 3192     if (wrapper == NULL)
 3193         fatal(_("register_output_wrapper: received NULL pointer"));
 3194 
 3195     wrapper->next = NULL;   /* force it */
 3196     if (op_head == NULL) {
 3197         op_head = op_tail = wrapper;
 3198     } else {
 3199         op_tail->next = wrapper;
 3200         op_tail = op_tail->next;
 3201     }
 3202 }
 3203 
 3204 /* find_output_wrapper --- search the list of output wrappers */
 3205 
 3206 static bool
 3207 find_output_wrapper(awk_output_buf_t *outbuf)
 3208 {
 3209     awk_output_wrapper_t *op, *op2;
 3210 
 3211     /* if already associated with an output wrapper, bail out early */
 3212     if (outbuf->redirected)
 3213         return false;
 3214 
 3215     op = op2 = NULL;
 3216     for (op2 = op_head; op2 != NULL; op2 = op2->next) {
 3217         if (op2->can_take_file(outbuf)) {
 3218             if (op == NULL)
 3219                 op = op2;   /* found first one */
 3220             else
 3221                 fatal(_("output wrapper `%s' conflicts with previously installed output wrapper `%s'"),
 3222                         op2->name, op->name);
 3223         }
 3224     }
 3225 
 3226     if (op != NULL) {
 3227         if (! op->take_control_of(outbuf)) {
 3228             warning(_("output wrapper `%s' failed to open `%s'"),
 3229                     op->name, outbuf->name);
 3230             return false;
 3231         }
 3232         return true;
 3233     }
 3234 
 3235     return false;
 3236 }
 3237 
 3238 
 3239 /* two way processors --- for use by extensions */
 3240 
 3241 static awk_two_way_processor_t *tw_head, *tw_tail;
 3242 
 3243 /* register_two_way_processor --- register a two-way I/O processor, for extensions */
 3244 
 3245 void
 3246 register_two_way_processor(awk_two_way_processor_t *processor)
 3247 {
 3248     if (processor == NULL)
 3249         fatal(_("register_output_processor: received NULL pointer"));
 3250 
 3251     processor->next = NULL; /* force it */
 3252     if (tw_head == NULL) {
 3253         tw_head = tw_tail = processor;
 3254     } else {
 3255         tw_tail->next = processor;
 3256         tw_tail = tw_tail->next;
 3257     }
 3258 }
 3259 
 3260 /* find_two_way_processor --- search the list of two way processors */
 3261 
 3262 static bool
 3263 find_two_way_processor(const char *name, struct redirect *rp)
 3264 {
 3265     awk_two_way_processor_t *tw, *tw2;
 3266 
 3267     /* if already associated with i/o, bail out early */
 3268     if (   (rp->iop != NULL && rp->iop->public.fd != INVALID_HANDLE)
 3269         || rp->output.fp != NULL)
 3270         return false;
 3271 
 3272     tw = tw2 = NULL;
 3273     for (tw2 = tw_head; tw2 != NULL; tw2 = tw2->next) {
 3274         if (tw2->can_take_two_way(name)) {
 3275             if (tw == NULL)
 3276                 tw = tw2;   /* found first one */
 3277             else
 3278                 fatal(_("two-way processor `%s' conflicts with previously installed two-way processor `%s'"),
 3279                         tw2->name, tw->name);
 3280         }
 3281     }
 3282 
 3283     if (tw != NULL) {
 3284         if (rp->iop == NULL)
 3285             rp->iop = iop_alloc(INVALID_HANDLE, name, 0);
 3286         if (! tw->take_control_of(name, & rp->iop->public, & rp->output)) {
 3287             warning(_("two way processor `%s' failed to open `%s'"),
 3288                     tw->name, name);
 3289             return false;
 3290         }
 3291         iop_finish(rp->iop);
 3292         return true;
 3293     }
 3294 
 3295     return false;
 3296 }
 3297 
 3298 /*
 3299  * IOBUF management is somewhat complicated.  In particular,
 3300  * it is possible and OK for an IOBUF to be allocated with
 3301  * a file descriptor that is either valid or not usable with
 3302  * read(2), in case an input parser will come along later and
 3303  * make it readable.  Alternatively, an input parser can simply
 3304  * come along and take over reading on a valid readable descriptor.
 3305  *
 3306  * The first stage is simply to allocate the IOBUF.  This is done
 3307  * during nextfile() for command line files and by redirect()
 3308  * and other routines for getline, input pipes, and the input
 3309  * side of a two-way pipe.
 3310  *
 3311  * The second stage is to check for input parsers.  This is done
 3312  * for command line files in after_beginfile() and for the others
 3313  * as part of the full flow.  At this point, either:
 3314  *  - The fd is valid on a readable file
 3315  *  - The input parser has taken over a valid fd and made
 3316  *    it usable (e.g., directories)
 3317  *  - Or the input parser has simply hijacked the reading
 3318  *    (such as the gawkextlib XML extension)
 3319  * If none of those are true, the fd should be closed, reset
 3320  * to INVALID_HANDLE, and iop->errcode set to indicate the error
 3321  * (EISDIR for directories, EIO for anything else).
 3322  * iop->valid should be set to false in this case.
 3323  *
 3324  * Otherwise, after the second stage, iop->errcode should be
 3325  * zero, iop->valid should be true, and iop->public.fd should
 3326  * not be INVALID_HANDLE.
 3327  *
 3328  * The third stage is to set up the rest of the IOBUF for
 3329  * use by get_a_record(). In this case, iop->valid must
 3330  * be true already, and iop->public.fd cannot be INVALID_HANDLE.
 3331  *
 3332  * Checking for input parsers for command line files is delayed
 3333  * to after_beginfile() so that the BEGINFILE rule has an
 3334  * opportunity to look at FILENAME and ERRNO and attempt to
 3335  * recover with a custom input parser. The XML extension, in
 3336  * particular, relies strongly upon this ability.
 3337  */
 3338 
 3339 /* iop_alloc --- allocate an IOBUF structure for an open fd */
 3340 
 3341 static IOBUF *
 3342 iop_alloc(int fd, const char *name, int errno_val)
 3343 {
 3344     IOBUF *iop;
 3345 
 3346     ezalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
 3347 
 3348     iop->public.fd = fd;
 3349     iop->public.name = name;
 3350     iop->public.read_func = ( ssize_t(*)() ) read;
 3351     iop->valid = false;
 3352     iop->errcode = errno_val;
 3353 
 3354     if (fd != INVALID_HANDLE)
 3355         fstat(fd, & iop->public.sbuf);
 3356 #if defined(__EMX__) || defined(__MINGW32__)
 3357     else if (errno_val == EISDIR) {
 3358         iop->public.sbuf.st_mode = (_S_IFDIR | _S_IRWXU);
 3359         iop->public.fd = FAKE_FD_VALUE;
 3360     }
 3361 #endif
 3362 
 3363     return iop;
 3364 }
 3365 
 3366 /* iop_finish --- finish setting up an IOBUF */
 3367 
 3368 static IOBUF *
 3369 iop_finish(IOBUF *iop)
 3370 {
 3371     bool isdir = false;
 3372 
 3373     if (iop->public.fd != INVALID_HANDLE) {
 3374         if (os_isreadable(& iop->public, & isdir))
 3375             iop->valid = true;
 3376         else {
 3377             if (isdir)
 3378                 iop->errcode = EISDIR;
 3379             else {
 3380                 iop->errcode = EIO;
 3381                 /*
 3382                  * Extensions can supply values that are not
 3383                  * INVALID_HANDLE but that are also not real
 3384                  * file descriptors. So check the fd before
 3385                  * trying to close it, which avoids errors
 3386                  * on some operating systems.
 3387                  *
 3388                  * The fcntl call works for Windows, too.
 3389                  */
 3390 #if defined(F_GETFL)
 3391                 if (fcntl(iop->public.fd, F_GETFL) >= 0)
 3392 #endif
 3393                     (void) close(iop->public.fd);
 3394                 iop->public.fd = INVALID_HANDLE;
 3395             }
 3396             /*
 3397              * Don't close directories: after_beginfile(),
 3398              * special cases them.
 3399              */
 3400         }
 3401     }
 3402 
 3403     if (! iop->valid || iop->public.fd == INVALID_HANDLE)
 3404         return iop;
 3405 
 3406     if (os_isatty(iop->public.fd))
 3407         iop->flag |= IOP_IS_TTY;
 3408 
 3409     iop->readsize = iop->size = optimal_bufsize(iop->public.fd, & iop->public.sbuf);
 3410     if (do_lint && S_ISREG(iop->public.sbuf.st_mode) && iop->public.sbuf.st_size == 0)
 3411         lintwarn(_("data file `%s' is empty"), iop->public.name);
 3412     iop->errcode = errno = 0;
 3413     iop->count = iop->scanoff = 0;
 3414     emalloc(iop->buf, char *, iop->size += 1, "iop_finish");
 3415     iop->off = iop->buf;
 3416     iop->dataend = NULL;
 3417     iop->end = iop->buf + iop->size;
 3418     iop->flag |= IOP_AT_START;
 3419 
 3420     return iop;
 3421 }
 3422 
 3423 #define set_RT_to_null() \
 3424     (void)(! do_traditional && (unref(RT_node->var_value), \
 3425                RT_node->var_value = dupnode(Nnull_string)))
 3426 
 3427 #define set_RT(str, len) \
 3428     (void)(! do_traditional && (unref(RT_node->var_value), \
 3429                RT_node->var_value = make_string(str, len)))
 3430 
 3431 /*
 3432  * grow_iop_buffer:
 3433  *
 3434  * grow must increase size of buffer, set end, make sure off and dataend
 3435  * point at the right spot.
 3436  */
 3437 
 3438 static void
 3439 grow_iop_buffer(IOBUF *iop)
 3440 {
 3441     size_t valid = iop->dataend - iop->off;
 3442     size_t off = iop->off - iop->buf;
 3443     size_t newsize;
 3444 
 3445     /*
 3446      * Lop off original extra byte, double the size,
 3447      * add it back.
 3448      */
 3449     newsize = ((iop->size - 1) * 2) + 1;
 3450 
 3451     /* Check for overflow */
 3452     if (newsize <= iop->size)
 3453         fatal(_("could not allocate more input memory"));
 3454 
 3455     /* Make sure there's room for a disk block */
 3456     if (newsize - valid < iop->readsize)
 3457         newsize += iop->readsize + 1;
 3458 
 3459     /* Check for overflow, again */
 3460     if (newsize <= iop->size)
 3461         fatal(_("could not allocate more input memory"));
 3462 
 3463     iop->size = newsize;
 3464     erealloc(iop->buf, char *, iop->size, "grow_iop_buffer");
 3465     iop->off = iop->buf + off;
 3466     iop->dataend = iop->off + valid;
 3467     iop->end = iop->buf + iop->size;
 3468 }
 3469 
 3470 /* rs1scan --- scan for a single character record terminator */
 3471 
 3472 static RECVALUE
 3473 rs1scan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state)
 3474 {
 3475     char *bp;
 3476     char rs;
 3477     size_t mbclen = 0;
 3478     mbstate_t mbs;
 3479 
 3480     memset(recm, '\0', sizeof(struct recmatch));
 3481     rs = RS->stptr[0];
 3482     *(iop->dataend) = rs;   /* set sentinel */
 3483     recm->start = iop->off; /* beginning of record */
 3484 
 3485     bp = iop->off;
 3486     if (*state == INDATA)   /* skip over data we've already seen */
 3487         bp += iop->scanoff;
 3488 
 3489     /*
 3490      * From: Bruno Haible <bruno@clisp.org>
 3491      * To: Aharon Robbins <arnold@skeeve.com>, gnits@gnits.org
 3492      * Subject: Re: multibyte locales: any way to find if a character isn't multibyte?
 3493      * Date: Mon, 23 Jun 2003 12:20:16 +0200
 3494      * Cc: isamu@yamato.ibm.com
 3495      *
 3496      * Hi,
 3497      *
 3498      * > Is there any way to make the following query to the current locale?
 3499      * >
 3500      * >    Given an 8-bit value, can this value ever appear as part of
 3501      * >    a multibyte character?
 3502      *
 3503      * There is no simple answer here. The easiest solution I see is to
 3504      * get the current locale's codeset (via locale_charset() which is a
 3505      * wrapper around nl_langinfo(CODESET)), and then perform a case-by-case
 3506      * treatment of the known multibyte encodings, from GB2312 to EUC-JISX0213;
 3507      * for the unibyte encodings, a single btowc() call will tell you.
 3508      *
 3509      * > This is particularly critical for me for ASCII newline ('\n').  If I
 3510      * > can be guaranteed that it never shows up as part of a multibyte character,
 3511      * > I can speed up gawk considerably in mulitbyte locales.
 3512      *
 3513      * This is much simpler to answer!
 3514      * In all ASCII based multibyte encodings used for locales today (this
 3515      * excludes EBCDIC based doublebyte encodings from IBM, and also excludes
 3516      * ISO-2022-JP which is used for email exchange but not as a locale encoding)
 3517      * ALL bytes in the range 0x00..0x2F occur only as a single character, not
 3518      * as part of a multibyte character.
 3519      *
 3520      * So it's safe to assume, but deserves a comment in the source.
 3521      *
 3522      * Bruno
 3523      ***************************************************************
 3524      * From: Bruno Haible <bruno@clisp.org>
 3525      * To: Aharon Robbins <arnold@skeeve.com>
 3526      * Subject: Re: multibyte locales: any way to find if a character isn't multibyte?
 3527      * Date: Mon, 23 Jun 2003 14:27:49 +0200
 3528      *
 3529      * On Monday 23 June 2003 14:11, you wrote:
 3530      *
 3531      * >       if (rs != '\n' && MB_CUR_MAX > 1) {
 3532      *
 3533      * If you assume ASCII, you can even write
 3534      *
 3535      *         if (rs >= 0x30 && MB_CUR_MAX > 1) {
 3536      *
 3537      * (this catches also the space character) but if portability to EBCDIC
 3538      * systems is desired, your code is fine as is.
 3539      *
 3540      * Bruno
 3541      */
 3542     /* Thus, the check for \n here; big speedup ! */
 3543     if (rs != '\n' && gawk_mb_cur_max > 1) {
 3544         int len = iop->dataend - bp;
 3545         bool found = false;
 3546 
 3547         memset(& mbs, 0, sizeof(mbstate_t));
 3548         do {
 3549             if (*bp == rs)
 3550                 found = true;
 3551             if (is_valid_character(*bp))
 3552                 mbclen = 1;
 3553             else
 3554                 mbclen = mbrlen(bp, len, & mbs);
 3555             if (   mbclen == 1
 3556                 || mbclen == (size_t) -1
 3557                 || mbclen == (size_t) -2
 3558                 || mbclen == 0) {
 3559                 /* We treat it as a single-byte character.  */
 3560                 mbclen = 1;
 3561             }
 3562             len -= mbclen;
 3563             bp += mbclen;
 3564         } while (len > 0 && ! found);
 3565 
 3566         /* Check that newline found isn't the sentinel. */
 3567         if (found && (bp - mbclen) < iop->dataend) {
 3568             /*
 3569              * Set len to what we have so far, in case this is
 3570              * all there is.
 3571              */
 3572             recm->len = bp - recm->start - mbclen;
 3573             recm->rt_start = bp - mbclen;
 3574             recm->rt_len = mbclen;
 3575             *state = NOSTATE;
 3576             return REC_OK;
 3577         } else {
 3578             /* also set len */
 3579             recm->len = bp - recm->start;
 3580             *state = INDATA;
 3581             iop->scanoff = bp - iop->off;
 3582             return NOTERM;
 3583         }
 3584     }
 3585 
 3586     while (*bp != rs)
 3587         bp++;
 3588 
 3589     /* set len to what we have so far, in case this is all there is */
 3590     recm->len = bp - recm->start;
 3591 
 3592     if (bp < iop->dataend) {        /* found it in the buffer */
 3593         recm->rt_start = bp;
 3594         recm->rt_len = 1;
 3595         *state = NOSTATE;
 3596         return REC_OK;
 3597     } else {
 3598         *state = INDATA;
 3599         iop->scanoff = bp - iop->off;
 3600         return NOTERM;
 3601     }
 3602 }
 3603 
 3604 /* rsrescan --- search for a regex match in the buffer */
 3605 
 3606 static RECVALUE
 3607 rsrescan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state)
 3608 {
 3609     char *bp;
 3610     size_t restart = 0, reend = 0;
 3611     Regexp *RSre = RS_regexp;
 3612     int regex_flags = RE_NEED_START;
 3613 
 3614     memset(recm, '\0', sizeof(struct recmatch));
 3615     recm->start = iop->off;
 3616 
 3617     bp = iop->off;
 3618     if (*state == INDATA)
 3619         bp += iop->scanoff;
 3620 
 3621     if ((iop->flag & IOP_AT_START) == 0)
 3622         regex_flags |= RE_NO_BOL;
 3623 again:
 3624     /* case 1, no match */
 3625     if (research(RSre, bp, 0, iop->dataend - bp, regex_flags) == -1) {
 3626         /* set len, in case this all there is. */
 3627         recm->len = iop->dataend - iop->off;
 3628         return NOTERM;
 3629     }
 3630 
 3631     /* ok, we matched within the buffer, set start and end */
 3632     restart = RESTART(RSre, iop->off);
 3633     reend = REEND(RSre, iop->off);
 3634 
 3635     /* case 2, null regex match, grow buffer, try again */
 3636     if (restart == reend) {
 3637         *state = INDATA;
 3638         iop->scanoff = reend + 1;
 3639         /*
 3640          * If still room in buffer, skip over null match
 3641          * and restart search. Otherwise, return.
 3642          */
 3643         if (bp + iop->scanoff < iop->dataend) {
 3644             bp += iop->scanoff;
 3645             goto again;
 3646         }
 3647         recm->len = (bp - iop->off) + restart;
 3648         return NOTERM;
 3649     }
 3650 
 3651     /*
 3652      * At this point, we have a non-empty match.
 3653      *
 3654      * First, fill in rest of data. The rest of the cases return
 3655      * a record and terminator.
 3656      */
 3657     recm->len = restart;
 3658     recm->rt_start = bp + restart;
 3659     recm->rt_len = reend - restart;
 3660     *state = NOSTATE;
 3661 
 3662     /*
 3663      * 3. Match exactly at end:
 3664      *      if re is a simple string match
 3665      *              found a simple string match at end, return REC_OK
 3666      *      else
 3667      *              grow buffer, add more data, try again
 3668      *      fi
 3669      */
 3670     if (iop->off + reend >= iop->dataend) {
 3671         if (reisstring(RS->stptr, RS->stlen, RSre, iop->off))
 3672             return REC_OK;
 3673         else
 3674             return TERMATEND;
 3675     }
 3676 
 3677     /*
 3678      * 4. Match within xxx bytes of end & maybe islong re:
 3679      *      return TERMNEAREND
 3680      */
 3681 
 3682         /*
 3683          * case 4, match succeeded, but there may be more in
 3684          * the next input buffer.
 3685          *
 3686          * Consider an RS of   xyz(abc)?   where the
 3687          * exact end of the buffer is   xyza  and the
 3688          * next two, unread, characters are bc.
 3689          *
 3690          * This matches the "xyz" and ends up putting the
 3691          * "abc" into the front of the next record. Ooops.
 3692          *
 3693          * The re->maybe_long member is true if the
 3694          * regex contains one of: + * ? |.  This is a very
 3695          * simple heuristic, but in combination with the
 3696          * "end of match within a few bytes of end of buffer"
 3697          * check, should keep things reasonable.
 3698          */
 3699 
 3700     /* succession of tests is easier to trace in GDB. */
 3701     if (RSre->maybe_long) {
 3702         char *matchend = iop->off + reend;
 3703 
 3704         if (iop->dataend - matchend < RS->stlen)
 3705             return TERMNEAREND;
 3706     }
 3707 
 3708     return REC_OK;
 3709 }
 3710 
 3711 /* rsnullscan --- handle RS = "" */
 3712 
 3713 static RECVALUE
 3714 rsnullscan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state)
 3715 {
 3716     char *bp;
 3717 
 3718     if (*state == NOSTATE || *state == INLEADER)
 3719         memset(recm, '\0', sizeof(struct recmatch));
 3720 
 3721     recm->start = iop->off;
 3722 
 3723     bp = iop->off;
 3724     if (*state != NOSTATE)
 3725         bp += iop->scanoff;
 3726 
 3727     /* set sentinel */
 3728     *(iop->dataend) = '\n';
 3729 
 3730     if (*state == INTERM)
 3731         goto find_longest_terminator;
 3732     else if (*state == INDATA)
 3733         goto scan_data;
 3734     /* else
 3735         fall into things from beginning,
 3736         either NOSTATE or INLEADER */
 3737 
 3738 /* skip_leading: */
 3739     /* leading newlines are ignored */
 3740     while (*bp == '\n' && bp < iop->dataend)
 3741         bp++;
 3742 
 3743     if (bp >= iop->dataend) {       /* LOTS of leading newlines, sheesh. */
 3744         *state = INLEADER;
 3745         iop->scanoff = bp - iop->off;
 3746         return NOTERM;
 3747     }
 3748 
 3749     iop->off = recm->start = bp;    /* real start of record */
 3750 scan_data:
 3751     while (*bp++ != '\n')
 3752         continue;
 3753 
 3754     if (bp >= iop->dataend) {       /* no full terminator */
 3755         iop->scanoff = recm->len = bp - iop->off - 1;
 3756         if (bp == iop->dataend) {   /* half a terminator */
 3757             recm->rt_start = bp - 1;
 3758             recm->rt_len = 1;
 3759         }
 3760         *state = INDATA;
 3761         return NOTERM;
 3762     }
 3763 
 3764     /* found one newline before end of buffer, check next char */
 3765     if (*bp != '\n')
 3766         goto scan_data;
 3767 
 3768     /* we've now seen at least two newlines */
 3769     *state = INTERM;
 3770     recm->len = bp - iop->off - 1;
 3771     recm->rt_start = bp - 1;
 3772 
 3773 find_longest_terminator:
 3774     /* find as many newlines as we can, to set RT */
 3775     while (*bp == '\n' && bp < iop->dataend)
 3776         bp++;
 3777 
 3778     recm->rt_len = bp - recm->rt_start;
 3779     iop->scanoff = bp - iop->off;
 3780 
 3781     if (bp >= iop->dataend)
 3782         return TERMATEND;
 3783 
 3784     return REC_OK;
 3785 }
 3786 
 3787 /* retryable --- return true if PROCINFO[<filename>, "RETRY"] exists */
 3788 
 3789 static inline int
 3790 retryable(IOBUF *iop)
 3791 {
 3792     return PROCINFO_node && in_PROCINFO(iop->public.name, "RETRY", NULL);
 3793 }
 3794 
 3795 /* errno_io_retry --- Does the I/O error indicate that the operation should be retried later? */
 3796 
 3797 static inline int
 3798 errno_io_retry(void)
 3799 {
 3800     switch (errno) {
 3801 #ifdef EAGAIN
 3802     case EAGAIN:
 3803 #endif
 3804 #ifdef EWOULDBLOCK
 3805 #if !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)
 3806     case EWOULDBLOCK:
 3807 #endif
 3808 #endif
 3809 #ifdef EINTR
 3810     case EINTR:
 3811 #endif
 3812 #ifdef ETIMEDOUT
 3813     case ETIMEDOUT:
 3814 #endif
 3815         return 1;
 3816     default:
 3817         return 0;
 3818     }
 3819 }
 3820 
 3821 /*
 3822  * get_a_record --- read a record from IOP into out,
 3823  * return length of EOF, set RT.
 3824  * Note that errcode is never NULL, and the caller initializes *errcode to 0.
 3825  * If I/O would block, return -2.
 3826  */
 3827 
 3828 static int
 3829 get_a_record(char **out,        /* pointer to pointer to data */
 3830         IOBUF *iop,             /* input IOP */
 3831         int *errcode,           /* pointer to error variable */
 3832         const awk_fieldwidth_info_t **field_width)
 3833                 /* pointer to pointer to field_width info */
 3834 {
 3835     struct recmatch recm;
 3836     SCANSTATE state;
 3837     RECVALUE ret;
 3838     int retval;
 3839     NODE *rtval = NULL;
 3840     static RECVALUE (*lastmatchrec)(IOBUF *iop, struct recmatch *recm, SCANSTATE *state) = NULL;
 3841 
 3842     if (at_eof(iop) && no_data_left(iop))
 3843         return EOF;
 3844 
 3845     if (read_can_timeout)
 3846         read_timeout = get_read_timeout(iop);
 3847 
 3848     if (iop->public.get_record != NULL) {
 3849         char *rt_start;
 3850         size_t rt_len;
 3851         int rc = iop->public.get_record(out, &iop->public, errcode,
 3852                         &rt_start, &rt_len,
 3853                         field_width);
 3854         if (rc == EOF)
 3855             iop->flag |= IOP_AT_EOF;
 3856         else {
 3857             if (rt_len != 0)
 3858                 set_RT(rt_start, rt_len);
 3859             else
 3860                 set_RT_to_null();
 3861         }
 3862         return rc;
 3863     }
 3864 
 3865         /* fill initial buffer */
 3866     if (has_no_data(iop) || no_data_left(iop)) {
 3867         iop->count = iop->public.read_func(iop->public.fd, iop->buf, iop->readsize);
 3868         if (iop->count == 0) {
 3869             iop->flag |= IOP_AT_EOF;
 3870             return EOF;
 3871         } else if (iop->count == -1) {
 3872             *errcode = errno;
 3873             if (errno_io_retry() && retryable(iop))
 3874                 return -2;
 3875             iop->flag |= IOP_AT_EOF;
 3876             return EOF;
 3877         } else {
 3878             iop->dataend = iop->buf + iop->count;
 3879             iop->off = iop->buf;
 3880         }
 3881     }
 3882 
 3883     /* loop through file to find a record */
 3884     state = NOSTATE;
 3885     for (;;) {
 3886         size_t dataend_off;
 3887         size_t room_left;
 3888         size_t amt_to_read;
 3889 
 3890         ret = (*matchrec)(iop, & recm, & state);
 3891         iop->flag &= ~IOP_AT_START;
 3892         /* found the record, we're done, break the loop */
 3893         if (ret == REC_OK)
 3894             break;
 3895 
 3896         /*
 3897          * Likely found the record; if there's no more data
 3898          * to be had (like from a tiny regular file), break the
 3899          * loop. Otherwise, see if we can read more.
 3900          */
 3901         if (ret == TERMNEAREND && buffer_has_all_data(iop))
 3902             break;
 3903 
 3904         /* need to add more data to buffer */
 3905         /* shift data down in buffer */
 3906         dataend_off = iop->dataend - iop->off;
 3907         memmove(iop->buf, iop->off, dataend_off);
 3908         iop->off = iop->buf;
 3909         iop->dataend = iop->buf + dataend_off;
 3910 
 3911         /* adjust recm contents */
 3912         recm.start = iop->off;
 3913         if (recm.rt_start != NULL)
 3914             recm.rt_start = iop->off + recm.len;
 3915 
 3916         /* read more data, break if EOF */
 3917 #ifndef MIN
 3918 #define MIN(x, y) (x < y ? x : y)
 3919 #endif
 3920         /* subtract one in read count to leave room for sentinel */
 3921         room_left = iop->end - iop->dataend - 1;
 3922         amt_to_read = MIN(iop->readsize, room_left);
 3923 
 3924         if (amt_to_read < iop->readsize) {
 3925             grow_iop_buffer(iop);
 3926             /* adjust recm contents */
 3927             recm.start = iop->off;
 3928             if (recm.rt_start != NULL)
 3929                 recm.rt_start = iop->off + recm.len;
 3930 
 3931             /* recalculate amt_to_read */
 3932             room_left = iop->end - iop->dataend - 1;
 3933             amt_to_read = MIN(iop->readsize, room_left);
 3934         }
 3935         while (amt_to_read + iop->readsize < room_left)
 3936             amt_to_read += iop->readsize;
 3937 
 3938 #ifdef SSIZE_MAX
 3939         /*
 3940          * POSIX limits read to SSIZE_MAX. There are (bizarre)
 3941          * systems where this amount is small.
 3942          */
 3943         amt_to_read = MIN(amt_to_read, SSIZE_MAX);
 3944 #endif
 3945 
 3946         iop->count = iop->public.read_func(iop->public.fd, iop->dataend, amt_to_read);
 3947         if (iop->count == -1) {
 3948             *errcode = errno;
 3949             if (errno_io_retry() && retryable(iop))
 3950                 return -2;
 3951             iop->flag |= IOP_AT_EOF;
 3952             break;
 3953         } else if (iop->count == 0) {
 3954             /*
 3955              * Hit EOF before being certain that we've matched
 3956              * the end of the record. If ret is TERMNEAREND,
 3957              * we need to pull out what we've got in the buffer.
 3958              * Eventually we'll come back here and see the EOF,
 3959              * end the record and set RT to "".
 3960              */
 3961             if (ret != TERMNEAREND)
 3962                 iop->flag |= IOP_AT_EOF;
 3963             break;
 3964         } else
 3965             iop->dataend += iop->count;
 3966     }
 3967 
 3968     /* set record, RT, return right value */
 3969 
 3970     /*
 3971      * rtval is not a static pointer to avoid dangling pointer problems
 3972      * in case awk code assigns to RT.  A remote possibility, to be sure,
 3973      * but Bitter Experience teaches us not to make ``that'll never
 3974      * happen'' kinds of assumptions.
 3975      */
 3976     rtval = RT_node->var_value;
 3977 
 3978     if (recm.rt_len == 0) {
 3979         set_RT_to_null();
 3980         lastmatchrec = NULL;
 3981     } else {
 3982         assert(recm.rt_start != NULL);
 3983         /*
 3984          * Optimization. For rs1 case, don't set RT if
 3985          * character is same as last time.  This knocks a
 3986          * chunk of time off something simple like
 3987          *
 3988          *      gawk '{ print }' /some/big/file
 3989          *
 3990          * Similarly, for rsnull case, if length of new RT is
 3991          * shorter than current RT, just bump length down in RT.
 3992          *
 3993          * Make sure that matchrec didn't change since the last
 3994          * check.  (Ugh, details, details, details.)
 3995          */
 3996         if (lastmatchrec == NULL || lastmatchrec != matchrec) {
 3997             lastmatchrec = matchrec;
 3998             set_RT(recm.rt_start, recm.rt_len);
 3999         } else if (matchrec == rs1scan) {
 4000             if (rtval->stlen != 1 || rtval->stptr[0] != recm.rt_start[0])
 4001                 set_RT(recm.rt_start, recm.rt_len);
 4002             /* else
 4003                 leave it alone */
 4004         } else if (matchrec == rsnullscan) {
 4005             if (rtval->stlen >= recm.rt_len) {
 4006                 rtval->stlen = recm.rt_len;
 4007                 free_wstr(rtval);
 4008             } else
 4009                 set_RT(recm.rt_start, recm.rt_len);
 4010         } else
 4011             set_RT(recm.rt_start, recm.rt_len);
 4012     }
 4013 
 4014     if (recm.len == 0) {
 4015         *out = NULL;
 4016         retval = 0;
 4017     } else {
 4018         assert(recm.start != NULL);
 4019         *out = recm.start;
 4020         retval = recm.len;
 4021     }
 4022 
 4023     iop->off += recm.len + recm.rt_len;
 4024 
 4025     if (recm.len == 0 && recm.rt_len == 0 && at_eof(iop))
 4026         return EOF;
 4027     else
 4028         return retval;
 4029 }
 4030 
 4031 /* set_RS --- update things as appropriate when RS is set */
 4032 
 4033 void
 4034 set_RS()
 4035 {
 4036     static NODE *save_rs = NULL;
 4037 
 4038     /*
 4039      * Don't use cmp_nodes(), which pays attention to IGNORECASE.
 4040      */
 4041     if (save_rs
 4042         && RS_node->var_value->stlen == save_rs->stlen
 4043         && memcmp(RS_node->var_value->stptr, save_rs->stptr, save_rs->stlen) == 0) {
 4044         /*
 4045          * It could be that just IGNORECASE changed.  If so,
 4046          * update the regex and then do the same for FS.
 4047          * set_IGNORECASE() relies on this routine to call
 4048          * set_FS().
 4049          */
 4050         RS_regexp = RS_re[IGNORECASE];
 4051         goto set_FS;
 4052     }
 4053     unref(save_rs);
 4054     save_rs = dupnode(RS_node->var_value);
 4055     RS_is_null = false;
 4056     RS = force_string(RS_node->var_value);
 4057     /*
 4058      * used to be if (RS_regexp != NULL) { refree(..); refree(..); ...; }.
 4059      * Please do not remerge the if condition; hinders memory deallocation
 4060      * in case of fatal error in make_regexp.
 4061      */
 4062     refree(RS_re[0]);   /* NULL argument is ok */
 4063     refree(RS_re[1]);
 4064     RS_re[0] = RS_re[1] = RS_regexp = NULL;
 4065 
 4066     if (RS->stlen == 0) {
 4067         RS_is_null = true;
 4068         matchrec = rsnullscan;
 4069     } else if ((RS->stlen > 1 || (RS->flags & REGEX) != 0) && ! do_traditional) {
 4070         static bool warned = false;
 4071 
 4072         RS_re[0] = make_regexp(RS->stptr, RS->stlen, false, true, true);
 4073         RS_re[1] = make_regexp(RS->stptr, RS->stlen, true, true, true);
 4074         RS_regexp = RS_re[IGNORECASE];
 4075 
 4076         matchrec = rsrescan;
 4077 
 4078         if (do_lint_extensions && ! warned) {
 4079             lintwarn(_("multicharacter value of `RS' is a gawk extension"));
 4080             warned = true;
 4081         }
 4082     } else
 4083         matchrec = rs1scan;
 4084 set_FS:
 4085     if (current_field_sep() == Using_FS)
 4086         set_FS();
 4087 }
 4088 
 4089 
 4090 /* pty_vs_pipe --- return true if should use pty instead of pipes for `|&' */
 4091 
 4092 /*
 4093  * This works by checking if PROCINFO["command", "pty"] exists and is true.
 4094  */
 4095 
 4096 static bool
 4097 pty_vs_pipe(const char *command)
 4098 {
 4099 #ifdef HAVE_TERMIOS_H
 4100     NODE *val;
 4101 
 4102     /*
 4103      * N.B. No need to check for NULL PROCINFO_node, since the
 4104      * in_PROCINFO function now checks that for us.
 4105      */
 4106     val = in_PROCINFO(command, "pty", NULL);
 4107     if (val)
 4108         return boolval(val);
 4109 #endif /* HAVE_TERMIOS_H */
 4110     return false;
 4111 }
 4112 
 4113 /* iopflags2str --- make IOP flags printable */
 4114 
 4115 const char *
 4116 iopflags2str(int flag)
 4117 {
 4118     static const struct flagtab values[] = {
 4119         { IOP_IS_TTY, "IOP_IS_TTY" },
 4120         { IOP_AT_EOF,  "IOP_AT_EOF" },
 4121         { IOP_CLOSED, "IOP_CLOSED" },
 4122         { IOP_AT_START,  "IOP_AT_START" },
 4123         { 0, NULL }
 4124     };
 4125 
 4126     return genflags2str(flag, values);
 4127 }
 4128 
 4129 /* free_rp --- release the memory used by rp */
 4130 
 4131 static void
 4132 free_rp(struct redirect *rp)
 4133 {
 4134     efree(rp->value);
 4135     efree(rp);
 4136 }
 4137 
 4138 /* inetfile --- return true for a /inet special file, set other values */
 4139 
 4140 static bool
 4141 inetfile(const char *str, size_t len, struct inet_socket_info *isi)
 4142 {
 4143 #ifndef HAVE_SOCKETS
 4144     return false;
 4145 #else
 4146     const char *cp = str;
 4147     const char *cpend = str + len;
 4148     struct inet_socket_info buf;
 4149 
 4150     /* syntax: /inet/protocol/localport/hostname/remoteport */
 4151     if (len < 5 || memcmp(cp, "/inet", 5) != 0)
 4152         /* quick exit */
 4153         return false;
 4154     if (! isi)
 4155         isi = & buf;
 4156     cp += 5;
 4157     if (cpend - cp < 2)
 4158         return false;
 4159     switch (*cp) {
 4160     case '/':
 4161         isi->family = AF_UNSPEC;
 4162         break;
 4163     case '4':
 4164         if (*++cp != '/')
 4165             return false;
 4166         isi->family = AF_INET;
 4167         break;
 4168     case '6':
 4169         if (*++cp != '/')
 4170             return false;
 4171         isi->family = AF_INET6;
 4172         break;
 4173     default:
 4174         return false;
 4175     }
 4176     cp++;   /* skip past '/' */
 4177 
 4178     /* which protocol? */
 4179     if (cpend - cp < 5)
 4180         return false;
 4181     if (memcmp(cp, "tcp/", 4) == 0)
 4182         isi->protocol = SOCK_STREAM;
 4183     else if (memcmp(cp, "udp/", 4) == 0)
 4184         isi->protocol = SOCK_DGRAM;
 4185     else
 4186         return false;
 4187     cp += 4;
 4188 
 4189     /* which localport? */
 4190     isi->localport.offset = cp-str;
 4191     while (*cp != '/') {
 4192         if (++cp >= cpend)
 4193             return false;
 4194     }
 4195     /*
 4196      * Require a port, let them explicitly put 0 if
 4197      * they don't care.
 4198      */
 4199     if ((isi->localport.len = (cp-str)-isi->localport.offset) == 0)
 4200         return false;
 4201 
 4202     /* which hostname? */
 4203     if (cpend - cp < 2)
 4204         return false;
 4205     cp++;
 4206     isi->remotehost.offset = cp-str;
 4207     while (*cp != '/') {
 4208         if (++cp >= cpend)
 4209             return false;
 4210     }
 4211     if ((isi->remotehost.len = (cp-str)-isi->remotehost.offset) == 0)
 4212         return false;
 4213 
 4214     /* which remoteport? */
 4215     if (cpend - cp < 2)
 4216         return false;
 4217     cp++;
 4218     /*
 4219      * The remote port ends the special file name.
 4220      *
 4221      * Here too, require a port, let them explicitly put 0 if
 4222      * they don't care.
 4223      */
 4224     isi->remoteport.offset = cp-str;
 4225     while (*cp != '/' && cp < cpend)
 4226         cp++;
 4227     if (cp != cpend || ((isi->remoteport.len = (cp-str)-isi->remoteport.offset) == 0))
 4228         return false;
 4229 
 4230 #ifndef HAVE_GETADDRINFO
 4231     /* final check for IPv6: */
 4232     if (isi->family == AF_INET6)
 4233         fatal(_("IPv6 communication is not supported"));
 4234 #endif
 4235     return true;
 4236 #endif /* HAVE_SOCKETS */
 4237 }
 4238 
 4239 /*
 4240  * in_PROCINFO --- return value for a PROCINFO element with
 4241  *  SUBSEP seperated indices.
 4242  */
 4243 
 4244 static NODE *
 4245 in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx)
 4246 {
 4247     char *str;
 4248     size_t str_len;
 4249     NODE *r, *sub = NULL;
 4250     NODE *subsep = SUBSEP_node->var_value;
 4251 
 4252     if (PROCINFO_node == NULL || (pidx1 == NULL && pidx2 == NULL))
 4253         return NULL;
 4254 
 4255     /* full_idx is in+out parameter */
 4256 
 4257     if (full_idx)
 4258         sub = *full_idx;
 4259 
 4260     if (pidx1 != NULL && pidx2 == NULL)
 4261         str_len = strlen(pidx1);
 4262     else if (pidx1 == NULL && pidx2 != NULL)
 4263         str_len = strlen(pidx2);
 4264     else
 4265         str_len = strlen(pidx1) + subsep->stlen + strlen(pidx2);
 4266 
 4267     if (sub == NULL) {
 4268         emalloc(str, char *, str_len + 1, "in_PROCINFO");
 4269         sub = make_str_node(str, str_len, ALREADY_MALLOCED);
 4270         if (full_idx)
 4271             *full_idx = sub;
 4272     } else if (str_len != sub->stlen) {
 4273         /* *full_idx != NULL */
 4274 
 4275         assert(sub->valref == 1);
 4276         erealloc(sub->stptr, char *, str_len + 1, "in_PROCINFO");
 4277         sub->stlen = str_len;
 4278     }
 4279 
 4280     if (pidx1 != NULL && pidx2 == NULL)
 4281         strcpy(sub->stptr, pidx1);
 4282     else if (pidx1 == NULL && pidx2 != NULL)
 4283         strcpy(sub->stptr, pidx2);
 4284     else
 4285         sprintf(sub->stptr, "%s%.*s%s", pidx1, (int)subsep->stlen,
 4286                 subsep->stptr, pidx2);
 4287 
 4288     r = in_array(PROCINFO_node, sub);
 4289     if (! full_idx)
 4290         unref(sub);
 4291     return r;
 4292 }
 4293 
 4294 
 4295 /* get_read_timeout --- get timeout in milliseconds for reading */
 4296 
 4297 static long
 4298 get_read_timeout(IOBUF *iop)
 4299 {
 4300     long tmout = 0;
 4301 
 4302     if (PROCINFO_node != NULL) {
 4303         const char *name = iop->public.name;
 4304         NODE *val = NULL;
 4305         static NODE *full_idx = NULL;
 4306         static const char *last_name = NULL;
 4307 
 4308         /*
 4309          * Do not re-construct the full index when last redirection
 4310          * string is the same as the current; "efficiency_hack++".
 4311          */
 4312         if (full_idx == NULL || strcmp(name, last_name) != 0) {
 4313             val = in_PROCINFO(name, "READ_TIMEOUT", & full_idx);
 4314             if (last_name != NULL)
 4315                 efree((void *) last_name);
 4316             last_name = estrdup(name, strlen(name));
 4317         } else  /* use cached full index */
 4318             val = in_array(PROCINFO_node, full_idx);
 4319 
 4320         if (val != NULL) {
 4321             (void) force_number(val);
 4322             tmout = get_number_si(val);
 4323         }
 4324     } else
 4325         tmout = read_default_timeout;   /* initialized from env. variable in init_io() */
 4326 
 4327     /* overwrite read routine only if an extension has not done so */
 4328     if ((iop->public.read_func == ( ssize_t(*)() ) read) && tmout > 0)
 4329         iop->public.read_func = read_with_timeout;
 4330 
 4331     return tmout;
 4332 }
 4333 
 4334 /*
 4335  * read_with_timeout --- read with a timeout, return failure
 4336  *  if no data is available within the timeout period.
 4337  */
 4338 
 4339 static ssize_t
 4340 read_with_timeout(int fd, char *buf, size_t size)
 4341 {
 4342 #if ! defined(VMS)
 4343     fd_set readfds;
 4344     struct timeval tv;
 4345 #ifdef __MINGW32__
 4346     /*
 4347      * Only sockets can be read with a timeout.  Also, the FD_*
 4348      * macros work on SOCKET type, not on int file descriptors.
 4349      */
 4350     SOCKET s = valid_socket(fd);
 4351 
 4352     if (!s)
 4353         return read(fd, buf, size);
 4354 #else
 4355     int s = fd;
 4356 #endif
 4357 
 4358     tv.tv_sec = read_timeout / 1000;
 4359     tv.tv_usec = 1000 * (read_timeout - 1000 * tv.tv_sec);
 4360 
 4361     FD_ZERO(& readfds);
 4362     FD_SET(s, & readfds);
 4363 
 4364     errno = 0;
 4365     /*
 4366      * Note: the 1st arg of 'select' is ignored on MS-Windows, so
 4367      * it's not a mistake to pass fd+1 there, although we use
 4368      * sockets, not file descriptors.
 4369      */
 4370     if (select(fd + 1, & readfds, NULL, NULL, & tv) < 0)
 4371         return -1;
 4372 
 4373     if (FD_ISSET(s, & readfds))
 4374         return read(fd, buf, size);
 4375     /* else
 4376         timed out */
 4377 
 4378     /* Set a meaningful errno */
 4379 #ifdef ETIMEDOUT
 4380     errno = ETIMEDOUT;
 4381 #else
 4382     errno = EAGAIN;
 4383 #endif
 4384     return -1;
 4385 #else  /* VMS */
 4386     return read(fd, buf, size);
 4387 #endif  /* VMS */
 4388 }
 4389 
 4390 /*
 4391  * Dummy pass through functions for default output.
 4392  */
 4393 
 4394 /* gawk_fwrite --- like fwrite */
 4395 
 4396 static size_t
 4397 gawk_fwrite(const void *buf, size_t size, size_t count, FILE *fp, void *opaque)
 4398 {
 4399     (void) opaque;
 4400 
 4401     return fwrite(buf, size, count, fp);
 4402 }
 4403 
 4404 /* gawk_fflush --- like fflush */
 4405 
 4406 static int
 4407 gawk_fflush(FILE *fp, void *opaque)
 4408 {
 4409     (void) opaque;
 4410 
 4411     return fflush(fp);
 4412 }
 4413 
 4414 /* gawk_ferror --- like ferror */
 4415 
 4416 static int
 4417 gawk_ferror(FILE *fp, void *opaque)
 4418 {
 4419     (void) opaque;
 4420 
 4421     return ferror(fp);
 4422 }
 4423 
 4424 /* gawk_fclose --- like fclose */
 4425 
 4426 static int
 4427 gawk_fclose(FILE *fp, void *opaque)
 4428 {
 4429     int result;
 4430 #ifdef __MINGW32__
 4431     SOCKET s = valid_socket (fileno(fp));
 4432 #endif
 4433     (void) opaque;
 4434 
 4435     result =  fclose(fp);
 4436 #ifdef __MINGW32__
 4437     if (s && closesocket(s) == SOCKET_ERROR)
 4438         result = -1;
 4439 #endif
 4440     return result;
 4441 }
 4442 
 4443 /* init_output_wrapper --- initialize the output wrapper */
 4444 
 4445 static void
 4446 init_output_wrapper(awk_output_buf_t *outbuf)
 4447 {
 4448     outbuf->name = NULL;
 4449     outbuf->mode = NULL;
 4450     outbuf->fp = NULL;
 4451     outbuf->opaque = NULL;
 4452     outbuf->redirected = awk_false;
 4453     outbuf->gawk_fwrite = gawk_fwrite;
 4454     outbuf->gawk_fflush = gawk_fflush;
 4455     outbuf->gawk_ferror = gawk_ferror;
 4456     outbuf->gawk_fclose = gawk_fclose;
 4457 }