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