home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gawk-2.15.6-src.tgz / tar.out / fsf / gawk / io.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  29KB  |  1,295 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. #ifndef __amigaos__  /* HACK (fnf) */
  567.         warning("error writing standard error (%s).", strerror(errno));
  568.         status++;
  569. #endif
  570.     }
  571.     for (rp = red_head; rp != NULL; rp = rp->next)
  572.         /* flush both files and pipes, what the heck */
  573.         if ((rp->flag & RED_WRITE) && rp->fp != NULL) {
  574.             if (fflush(rp->fp)) {
  575.                 warning("%s flush of \"%s\" failed (%s).",
  576.                     (rp->flag  & RED_PIPE) ? "pipe" :
  577.                     "file", rp->value, strerror(errno));
  578.                 status++;
  579.             }
  580.         }
  581.     return status;
  582. }
  583.  
  584. int
  585. close_io ()
  586. {
  587.     register struct redirect *rp;
  588.     register struct redirect *next;
  589.     int status = 0;
  590.  
  591.     errno = 0;
  592.     for (rp = red_head; rp != NULL; rp = next) {
  593.         next = rp->next;
  594.         /* close_redir() will print a message if needed */
  595.         /* if do_lint, warn about lack of explicit close */
  596.         if (close_redir(rp, do_lint))
  597.             status++;
  598.         rp = NULL;
  599.     }
  600.     /*
  601.      * Some of the non-Unix os's have problems doing an fclose
  602.      * on stdout and stderr.  Since we don't really need to close
  603.      * them, we just flush them, and do that across the board.
  604.      */
  605.     if (fflush(stdout)) {
  606.         warning("error writing standard output (%s).", strerror(errno));
  607.         status++;
  608.     }
  609.     if (fflush(stderr)) {
  610. #ifndef __amigaos__  /* HACK (fnf) */
  611.         warning("error writing standard error (%s).", strerror(errno));
  612.         status++;
  613. #endif
  614.     }
  615.     return status;
  616. }
  617.  
  618. /* str2mode --- convert a string mode to an integer mode */
  619.  
  620. static int
  621. str2mode(mode)
  622. const char *mode;
  623. {
  624.     int ret;
  625.  
  626.     switch(mode[0]) {
  627.     case 'r':
  628.         ret = O_RDONLY;
  629.         break;
  630.  
  631.     case 'w':
  632.         ret = O_WRONLY|O_CREAT|O_TRUNC;
  633.         break;
  634.  
  635.     case 'a':
  636.         ret = O_WRONLY|O_APPEND|O_CREAT;
  637.         break;
  638.  
  639.     default:
  640.         ret = 0;        /* lint */
  641.         cant_happen();
  642.     }
  643.     return ret;
  644. }
  645.  
  646. /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
  647.  
  648. /*
  649.  * This separate version is still needed for output, since file and pipe
  650.  * output is done with stdio. iop_open() handles input with IOBUFs of
  651.  * more "special" files.  Those files are not handled here since it makes
  652.  * no sense to use them for output.
  653.  */
  654.  
  655. int
  656. devopen(name, mode)
  657. const char *name, *mode;
  658. {
  659.     int openfd = INVALID_HANDLE;
  660.     const char *cp;
  661.     char *ptr;
  662.     int flag = 0;
  663.     struct stat buf;
  664.     extern double strtod();
  665.  
  666.     flag = str2mode(mode);
  667.  
  668.     if (do_unix)
  669.         goto strictopen;
  670.  
  671. #ifdef VMS
  672.     if ((openfd = vms_devopen(name, flag)) >= 0)
  673.         return openfd;
  674. #endif /* VMS */
  675.  
  676.     if (STREQ(name, "-"))
  677.         openfd = fileno(stdin);
  678.     else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
  679.         cp = name + 5;
  680.         
  681.         if (STREQ(cp, "stdin") && (flag & O_RDONLY) == O_RDONLY)
  682.             openfd = fileno(stdin);
  683.         else if (STREQ(cp, "stdout") && (flag & O_WRONLY) == O_WRONLY)
  684.             openfd = fileno(stdout);
  685.         else if (STREQ(cp, "stderr") && (flag & O_WRONLY) == O_WRONLY)
  686.             openfd = fileno(stderr);
  687.         else if (STREQN(cp, "fd/", 3)) {
  688.             cp += 3;
  689.             openfd = (int)strtod(cp, &ptr);
  690.             if (openfd <= INVALID_HANDLE || ptr == cp)
  691.                 openfd = INVALID_HANDLE;
  692.         }
  693.     }
  694.  
  695. strictopen:
  696.     if (openfd == INVALID_HANDLE)
  697.         openfd = open(name, flag, 0666);
  698.     if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) 
  699.         if (S_ISDIR(buf.st_mode))
  700.             fatal("file `%s' is a directory", name);
  701.     return openfd;
  702. }
  703.  
  704.  
  705. /* spec_setup --- setup an IOBUF for a special internal file */
  706.  
  707. static void
  708. spec_setup(iop, len, allocate)
  709. IOBUF *iop;
  710. int len;
  711. int allocate;
  712. {
  713.     char *cp;
  714.  
  715.     if (allocate) {
  716.         emalloc(cp, char *, len+2, "spec_setup");
  717.         iop->buf = cp;
  718.     } else {
  719.         len = strlen(iop->buf);
  720.         iop->buf[len++] = '\n';    /* get_a_record clobbered it */
  721.         iop->buf[len] = '\0';    /* just in case */
  722.     }
  723.     iop->off = iop->buf;
  724.     iop->cnt = 0;
  725.     iop->secsiz = 0;
  726.     iop->size = len;
  727.     iop->end = iop->buf + len;
  728.     iop->fd = -1;
  729.     iop->flag = IOP_IS_INTERNAL;
  730. }
  731.  
  732. /* specfdopen --- open a fd special file */
  733.  
  734. static int
  735. specfdopen(iop, name, mode)
  736. IOBUF *iop;
  737. const char *name, *mode;
  738. {
  739.     int fd;
  740.     IOBUF *tp;
  741.  
  742.     fd = devopen(name, mode);
  743.     if (fd == INVALID_HANDLE)
  744.         return INVALID_HANDLE;
  745.     tp = iop_alloc(fd);
  746.     if (tp == NULL)
  747.         return INVALID_HANDLE;
  748.     *iop = *tp;
  749.     iop->flag |= IOP_NO_FREE;
  750.     free(tp);
  751.     return 0;
  752. }
  753.  
  754. /*
  755.  * Following mess will improve in 2.16; this is written to avoid
  756.  * long lines, avoid splitting #if with backslash, and avoid #elif
  757.  * to maximize portability.
  758.  */
  759. #ifndef GETPGRP_NOARG
  760. #if defined(__svr4__) || defined(BSD4_4) || defined(_POSIX_SOURCE)
  761. #define GETPGRP_NOARG
  762. #else
  763. #if defined(i860) || defined(_AIX) || defined(hpux) || defined(VMS)
  764. #define GETPGRP_NOARG
  765. #else
  766. #if defined(OS2) || defined(MSDOS) || defined(AMIGA) || defined(atarist)
  767. #define GETPGRP_NOARG
  768. #endif
  769. #endif
  770. #endif
  771. #endif
  772.  
  773. #ifdef GETPGRP_NOARG
  774. #define getpgrp_ARG /* nothing */
  775. #else
  776. #define getpgrp_ARG getpid()
  777. #endif
  778.  
  779. /* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */
  780.  
  781. static int
  782. pidopen(iop, name, mode)
  783. IOBUF *iop;
  784. const char *name, *mode;
  785. {
  786.     char tbuf[BUFSIZ];
  787.     int i;
  788.  
  789.     if (name[6] == 'g')
  790.         sprintf(tbuf, "%d\n", getpgrp( getpgrp_ARG ));
  791.     else if (name[6] == 'i')
  792.         sprintf(tbuf, "%d\n", getpid());
  793.     else
  794.         sprintf(tbuf, "%d\n", getppid());
  795.     i = strlen(tbuf);
  796.     spec_setup(iop, i, 1);
  797.     strcpy(iop->buf, tbuf);
  798.     return 0;
  799. }
  800.  
  801. /* useropen --- "open" /dev/user */
  802.  
  803. /*
  804.  * /dev/user creates a record as follows:
  805.  *    $1 = getuid()
  806.  *    $2 = geteuid()
  807.  *    $3 = getgid()
  808.  *    $4 = getegid()
  809.  * If multiple groups are supported, the $5 through $NF are the
  810.  * supplementary group set.
  811.  */
  812.  
  813. static int
  814. useropen(iop, name, mode)
  815. IOBUF *iop;
  816. const char *name, *mode;
  817. {
  818.     char tbuf[BUFSIZ], *cp;
  819.     int i;
  820. #if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
  821. #if defined(atarist) || defined(__svr4__) || defined(__osf__) || defined(__bsdi__)
  822.     gid_t groupset[NGROUPS_MAX];
  823. #else
  824.     int groupset[NGROUPS_MAX];
  825. #endif
  826.     int ngroups;
  827. #endif
  828.  
  829.     sprintf(tbuf, "%d %d %d %d", getuid(), geteuid(), getgid(), getegid());
  830.  
  831.     cp = tbuf + strlen(tbuf);
  832. #if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
  833.     ngroups = getgroups(NGROUPS_MAX, groupset);
  834.     if (ngroups == -1)
  835.         fatal("could not find groups: %s", strerror(errno));
  836.  
  837.     for (i = 0; i < ngroups; i++) {
  838.         *cp++ = ' ';
  839.         sprintf(cp, "%d", (int)groupset[i]);
  840.         cp += strlen(cp);
  841.     }
  842. #endif
  843.     *cp++ = '\n';
  844.     *cp++ = '\0';
  845.  
  846.  
  847.     i = strlen(tbuf);
  848.     spec_setup(iop, i, 1);
  849.     strcpy(iop->buf, tbuf);
  850.     return 0;
  851. }
  852.  
  853. /* iop_open --- handle special and regular files for input */
  854.  
  855. static IOBUF *
  856. iop_open(name, mode)
  857. const char *name, *mode;
  858. {
  859.     int openfd = INVALID_HANDLE;
  860.     int flag = 0;
  861.     struct stat buf;
  862.     IOBUF *iop;
  863.     static struct internal {
  864.         const char *name;
  865.         int compare;
  866.         int (*fp) P((IOBUF*,const char *,const char *));
  867.         IOBUF iob;
  868.     } table[] = {
  869.         { "/dev/fd/",        8,    specfdopen },
  870.         { "/dev/stdin",        10,    specfdopen },
  871.         { "/dev/stdout",    11,    specfdopen },
  872.         { "/dev/stderr",    11,    specfdopen },
  873.         { "/dev/pid",        8,    pidopen },
  874.         { "/dev/ppid",        9,    pidopen },
  875.         { "/dev/pgrpid",    11,    pidopen },
  876.         { "/dev/user",        9,    useropen },
  877.     };
  878.     int devcount = sizeof(table) / sizeof(table[0]);
  879.  
  880.     flag = str2mode(mode);
  881.  
  882.     if (do_unix)
  883.         goto strictopen;
  884.  
  885.     if (STREQ(name, "-"))
  886.         openfd = fileno(stdin);
  887.     else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
  888.         int i;
  889.  
  890.         for (i = 0; i < devcount; i++) {
  891.             if (STREQN(name, table[i].name, table[i].compare)) {
  892.                 iop = & table[i].iob;
  893.  
  894.                 if (iop->buf != NULL) {
  895.                     spec_setup(iop, 0, 0);
  896.                     return iop;
  897.                 } else if ((*table[i].fp)(iop, name, mode) == 0)
  898.                     return iop;
  899.                 else {
  900.                     warning("could not open %s, mode `%s'",
  901.                         name, mode);
  902.                     return NULL;
  903.                 }
  904.             }
  905.         }
  906.     }
  907.  
  908. strictopen:
  909.     if (openfd == INVALID_HANDLE)
  910.         openfd = open(name, flag, 0666);
  911.     if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) 
  912.         if ((buf.st_mode & S_IFMT) == S_IFDIR)
  913.             fatal("file `%s' is a directory", name);
  914.     iop = iop_alloc(openfd);
  915.     return iop;
  916. }
  917.  
  918. #ifndef PIPES_SIMULATED
  919.     /* real pipes */
  920. static int
  921. wait_any(interesting)
  922. int interesting;    /* pid of interest, if any */
  923. {
  924.     RETSIGTYPE (*hstat)(), (*istat)(), (*qstat)();
  925.     int pid;
  926.     int status = 0;
  927.     struct redirect *redp;
  928.     extern int errno;
  929.  
  930.     hstat = signal(SIGHUP, SIG_IGN);
  931.     istat = signal(SIGINT, SIG_IGN);
  932.     qstat = signal(SIGQUIT, SIG_IGN);
  933.     for (;;) {
  934. #ifdef NeXT
  935.         pid = wait((union wait *)&status);
  936. #else
  937.         pid = wait(&status);
  938. #endif /* NeXT */
  939.         if (interesting && pid == interesting) {
  940.             break;
  941.         } else if (pid != -1) {
  942.             for (redp = red_head; redp != NULL; redp = redp->next)
  943.                 if (pid == redp->pid) {
  944.                     redp->pid = -1;
  945.                     redp->status = status;
  946.                     if (redp->fp) {
  947.                         pclose(redp->fp);
  948.                         redp->fp = 0;
  949.                     }
  950.                     if (redp->iop) {
  951.                         (void) iop_close(redp->iop);
  952.                         redp->iop = 0;
  953.                     }
  954.                     break;
  955.                 }
  956.         }
  957.         if (pid == -1 && errno == ECHILD)
  958.             break;
  959.     }
  960.     signal(SIGHUP, hstat);
  961.     signal(SIGINT, istat);
  962.     signal(SIGQUIT, qstat);
  963.     return(status);
  964. }
  965.  
  966. static IOBUF *
  967. gawk_popen(cmd, rp)
  968. char *cmd;
  969. struct redirect *rp;
  970. {
  971.     int p[2];
  972.     register int pid;
  973.  
  974.     /* used to wait for any children to synchronize input and output,
  975.      * but this could cause gawk to hang when it is started in a pipeline
  976.      * and thus has a child process feeding it input (shell dependant)
  977.      */
  978.     /*(void) wait_any(0);*/    /* wait for outstanding processes */
  979.  
  980.     if (pipe(p) < 0)
  981.         fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno));
  982.     if ((pid = fork()) == 0) {
  983.         if (close(1) == -1)
  984.             fatal("close of stdout in child failed (%s)",
  985.                 strerror(errno));
  986.         if (dup(p[1]) != 1)
  987.             fatal("dup of pipe failed (%s)", strerror(errno));
  988.         if (close(p[0]) == -1 || close(p[1]) == -1)
  989.             fatal("close of pipe failed (%s)", strerror(errno));
  990.         if (close(0) == -1)
  991.             fatal("close of stdin in child failed (%s)",
  992.                 strerror(errno));
  993.         execl("/bin/sh", "sh", "-c", cmd, 0);
  994.         _exit(127);
  995.     }
  996.     if (pid == -1)
  997.         fatal("cannot fork for \"%s\" (%s)", cmd, strerror(errno));
  998.     rp->pid = pid;
  999.     if (close(p[1]) == -1)
  1000.         fatal("close of pipe failed (%s)", strerror(errno));
  1001.     return (rp->iop = iop_alloc(p[0]));
  1002. }
  1003.  
  1004. static int
  1005. gawk_pclose(rp)
  1006. struct redirect *rp;
  1007. {
  1008.     (void) iop_close(rp->iop);
  1009.     rp->iop = NULL;
  1010.  
  1011.     /* process previously found, return stored status */
  1012.     if (rp->pid == -1)
  1013.         return (rp->status >> 8) & 0xFF;
  1014.     rp->status = wait_any(rp->pid);
  1015.     rp->pid = -1;
  1016.     return (rp->status >> 8) & 0xFF;
  1017. }
  1018.  
  1019. #else    /* PIPES_SIMULATED */
  1020.     /* use temporary file rather than pipe */
  1021.     /* except if popen() provides real pipes too */
  1022.  
  1023. #if defined(VMS) || defined(OS2) || defined (MSDOS)
  1024. static IOBUF *
  1025. gawk_popen(cmd, rp)
  1026. char *cmd;
  1027. struct redirect *rp;
  1028. {
  1029.     FILE *current;
  1030.  
  1031.     if ((current = popen(cmd, "r")) == NULL)
  1032.         return NULL;
  1033.     return (rp->iop = iop_alloc(fileno(current)));
  1034. }
  1035.  
  1036. static int
  1037. gawk_pclose(rp)
  1038. struct redirect *rp;
  1039. {
  1040.     int rval, aval, fd = rp->iop->fd;
  1041.     FILE *kludge = fdopen(fd, (char *) "r"); /* pclose needs FILE* w/ right fileno */
  1042.  
  1043.     rp->iop->fd = dup(fd);      /* kludge to allow close() + pclose() */
  1044.     rval = iop_close(rp->iop);
  1045.     rp->iop = NULL;
  1046.     aval = pclose(kludge);
  1047.     return (rval < 0 ? rval : aval);
  1048. }
  1049. #else    /* VMS || OS2 || MSDOS */
  1050.  
  1051. static
  1052. struct {
  1053.     char *command;
  1054.     char *name;
  1055. } pipes[_NFILE];
  1056.  
  1057. static IOBUF *
  1058. gawk_popen(cmd, rp)
  1059. char *cmd;
  1060. struct redirect *rp;
  1061. {
  1062.     extern char *strdup(const char *);
  1063.     int current;
  1064.     char *name;
  1065.     static char cmdbuf[256];
  1066.  
  1067.     /* get a name to use.  */
  1068.     if ((name = tempnam(".", "pip")) == NULL)
  1069.         return NULL;
  1070.     sprintf(cmdbuf,"%s > %s", cmd, name);
  1071.     system(cmdbuf);
  1072.     if ((current = open(name,O_RDONLY)) == INVALID_HANDLE)
  1073.         return NULL;
  1074.     pipes[current].name = name;
  1075.     pipes[current].command = strdup(cmd);
  1076.     rp->iop = iop_alloc(current);
  1077.     return (rp->iop = iop_alloc(current));
  1078. }
  1079.  
  1080. static int
  1081. gawk_pclose(rp)
  1082. struct redirect *rp;
  1083. {
  1084.     int cur = rp->iop->fd;
  1085.     int rval;
  1086.  
  1087.     rval = iop_close(rp->iop);
  1088.     rp->iop = NULL;
  1089.  
  1090.     /* check for an open file  */
  1091.     if (pipes[cur].name == NULL)
  1092.         return -1;
  1093.     unlink(pipes[cur].name);
  1094.     free(pipes[cur].name);
  1095.     pipes[cur].name = NULL;
  1096.     free(pipes[cur].command);
  1097.     return rval;
  1098. }
  1099. #endif    /* VMS || OS2 || MSDOS */
  1100.  
  1101. #endif    /* PIPES_SIMULATED */
  1102.  
  1103. NODE *
  1104. do_getline(tree)
  1105. NODE *tree;
  1106. {
  1107.     struct redirect *rp = NULL;
  1108.     IOBUF *iop;
  1109.     int cnt = EOF;
  1110.     char *s = NULL;
  1111.     int errcode;
  1112.  
  1113.     while (cnt == EOF) {
  1114.         if (tree->rnode == NULL) {     /* no redirection */
  1115.             iop = nextfile(0);
  1116.             if (iop == NULL)        /* end of input */
  1117.                 return tmp_number((AWKNUM) 0.0);
  1118.         } else {
  1119.             int redir_error = 0;
  1120.  
  1121.             rp = redirect(tree->rnode, &redir_error);
  1122.             if (rp == NULL && redir_error) { /* failed redirect */
  1123.                 if (! do_unix) {
  1124.                     s = strerror(redir_error);
  1125.  
  1126.                     unref(ERRNO_node->var_value);
  1127.                     ERRNO_node->var_value =
  1128.                         make_string(s, strlen(s));
  1129.                 }
  1130.                 return tmp_number((AWKNUM) -1.0);
  1131.             }
  1132.             iop = rp->iop;
  1133.             if (iop == NULL)        /* end of input */
  1134.                 return tmp_number((AWKNUM) 0.0);
  1135.         }
  1136.         errcode = 0;
  1137.         cnt = get_a_record(&s, iop, *RS, & errcode);
  1138.         if (! do_unix && errcode != 0) {
  1139.             s = strerror(errcode);
  1140.  
  1141.             unref(ERRNO_node->var_value);
  1142.             ERRNO_node->var_value = make_string(s, strlen(s));
  1143.             return tmp_number((AWKNUM) -1.0);
  1144.         }
  1145.         if (cnt == EOF) {
  1146.             if (rp) {
  1147.                 /*
  1148.                  * Don't do iop_close() here if we are
  1149.                  * reading from a pipe; otherwise
  1150.                  * gawk_pclose will not be called.
  1151.                  */
  1152.                 if (!(rp->flag & RED_PIPE)) {
  1153.                     (void) iop_close(iop);
  1154.                     rp->iop = NULL;
  1155.                 }
  1156.                 rp->flag |= RED_EOF;    /* sticky EOF */
  1157.                 return tmp_number((AWKNUM) 0.0);
  1158.             } else
  1159.                 continue;    /* try another file */
  1160.         }
  1161.         if (!rp) {
  1162.             NR += 1;
  1163.             FNR += 1;
  1164.         }
  1165.         if (tree->lnode == NULL)    /* no optional var. */
  1166.             set_record(s, cnt, 1);
  1167.         else {            /* assignment to variable */
  1168.             Func_ptr after_assign = NULL;
  1169.             NODE **lhs;
  1170.  
  1171.             lhs = get_lhs(tree->lnode, &after_assign);
  1172.             unref(*lhs);
  1173.             *lhs = make_string(s, strlen(s));
  1174.             (*lhs)->flags |= MAYBE_NUM;
  1175.             /* we may have to regenerate $0 here! */
  1176.             if (after_assign)
  1177.                 (*after_assign)();
  1178.         }
  1179.     }
  1180.     return tmp_number((AWKNUM) 1.0);
  1181. }
  1182.  
  1183. int
  1184. pathopen (file)
  1185. const char *file;
  1186. {
  1187.     int fd = do_pathopen(file);
  1188.  
  1189. #ifdef DEFAULT_FILETYPE
  1190.     if (! do_unix && fd <= INVALID_HANDLE) {
  1191.         char *file_awk;
  1192.         int save = errno;
  1193. #ifdef VMS
  1194.         int vms_save = vaxc$errno;
  1195. #endif
  1196.  
  1197.         /* append ".awk" and try again */
  1198.         emalloc(file_awk, char *, strlen(file) +
  1199.             sizeof(DEFAULT_FILETYPE) + 1, "pathopen");
  1200.         sprintf(file_awk, "%s%s", file, DEFAULT_FILETYPE);
  1201.         fd = do_pathopen(file_awk);
  1202.         free(file_awk);
  1203.         if (fd <= INVALID_HANDLE) {
  1204.             errno = save;
  1205. #ifdef VMS
  1206.             vaxc$errno = vms_save;
  1207. #endif
  1208.         }
  1209.     }
  1210. #endif    /*DEFAULT_FILETYPE*/
  1211.  
  1212.     return fd;
  1213. }
  1214.  
  1215. static int
  1216. do_pathopen (file)
  1217. const char *file;
  1218. {
  1219.     static const char *savepath = DEFPATH;    /* defined in config.h */
  1220.     static int first = 1;
  1221.     const char *awkpath;
  1222.     char *cp, trypath[BUFSIZ];
  1223.     int fd;
  1224.  
  1225.     if (STREQ(file, "-"))
  1226.         return (0);
  1227.  
  1228.     if (do_unix)
  1229.         return (devopen(file, "r"));
  1230.  
  1231.     if (first) {
  1232.         first = 0;
  1233.         if ((awkpath = getenv ("AWKPATH")) != NULL && *awkpath)
  1234.             savepath = awkpath;    /* used for restarting */
  1235.     }
  1236.     awkpath = savepath;
  1237.  
  1238.     /* some kind of path name, no search */
  1239. #ifdef VMS    /* (strchr not equal implies either or both not NULL) */
  1240.     if (strchr(file, ':') != strchr(file, ']')
  1241.      || strchr(file, '>') != strchr(file, '/'))
  1242. #else /*!VMS*/
  1243. #if defined(MSDOS) || defined(OS2)
  1244.     if (strchr(file, '/') != strchr(file, '\\')
  1245.      || strchr(file, ':') != NULL)
  1246. #else
  1247.     if (strchr(file, '/') != NULL)
  1248. #endif    /*MSDOS*/
  1249. #endif    /*VMS*/
  1250.         return (devopen(file, "r"));
  1251.  
  1252. #if defined(MSDOS) || defined(OS2)
  1253.     _searchenv(file, "AWKPATH", trypath);
  1254.     if (trypath[0] == '\0')
  1255.         _searchenv(file, "PATH", trypath);
  1256.     return (trypath[0] == '\0') ? 0 : devopen(trypath, "r");
  1257. #else
  1258.     do {
  1259.         trypath[0] = '\0';
  1260.         /* this should take into account limits on size of trypath */
  1261.         for (cp = trypath; *awkpath && *awkpath != ENVSEP; )
  1262.             *cp++ = *awkpath++;
  1263.  
  1264.         if (cp != trypath) {    /* nun-null element in path */
  1265.             /* add directory punctuation only if needed */
  1266. #ifdef VMS
  1267.             if (strchr(":]>/", *(cp-1)) == NULL)
  1268. #else
  1269. #if defined(MSDOS) || defined(OS2)
  1270.             if (strchr(":\\/", *(cp-1)) == NULL)
  1271. #else
  1272.             if (*(cp-1) != '/')
  1273. #endif
  1274. #endif
  1275.                 *cp++ = '/';
  1276.             /* append filename */
  1277.             strcpy (cp, file);
  1278.         } else
  1279.             strcpy (trypath, file);
  1280.         if ((fd = devopen(trypath, "r")) >= 0)
  1281.             return (fd);
  1282.  
  1283.         /* no luck, keep going */
  1284.         if(*awkpath == ENVSEP && awkpath[1] != '\0')
  1285.             awkpath++;    /* skip colon */
  1286.     } while (*awkpath);
  1287.     /*
  1288.      * You might have one of the awk
  1289.      * paths defined, WITHOUT the current working directory in it.
  1290.      * Therefore try to open the file in the current directory.
  1291.      */
  1292.     return (devopen(file, "r"));
  1293. #endif
  1294. }
  1295.