home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gawk-2.15.6-base.tgz / gawk-2.15.6-base.tar / fsf / gawk / io.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  29KB  |  1,291 lines

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