home *** CD-ROM | disk | FTP | other *** search
/ ftp.uni-stuttgart.de/pub/systems/acorn/ / Acorn.tar / Acorn / acornet / dev / gawk.spk / gawk-2154 / c / io < prev    next >
Text File  |  1994-01-14  |  29KB  |  1,271 lines

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