home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gnuawk.zip / io.c < prev    next >
C/C++ Source or Header  |  1997-05-14  |  46KB  |  1,942 lines

  1. /*
  2.  * io.c --- routines for dealing with input and output and records
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991-1997 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Programming 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 this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  24.  */
  25.  
  26. #include "awk.h"
  27. #undef HAVE_MMAP    /* for now, probably forever */
  28.  
  29. #ifdef HAVE_SYS_PARAM_H
  30. #undef RE_DUP_MAX    /* avoid spurious conflict w/regex.h */
  31. #include <sys/param.h>
  32. #endif /* HAVE_SYS_PARAM_H */
  33.  
  34. #ifdef HAVE_SYS_WAIT_H
  35. #include <sys/wait.h>
  36. #endif /* HAVE_SYS_WAIT_H */
  37.  
  38. #ifdef HAVE_MMAP
  39. #include <sys/mman.h>
  40. #ifndef MAP_FAILED
  41. #define MAP_FAILED    ((caddr_t) -1)
  42. #endif /* ! defined (MAP_FAILED) */
  43. #endif /* HAVE_MMAP */
  44.  
  45. #ifndef O_RDONLY
  46. #include <fcntl.h>
  47. #endif
  48. #ifndef O_ACCMODE
  49. #define O_ACCMODE    (O_RDONLY|O_WRONLY|O_RDWR)
  50. #endif
  51.  
  52. #include <assert.h>
  53.  
  54. #if ! defined(S_ISREG) && defined(S_IFREG)
  55. #define    S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  56. #endif
  57.  
  58. #if ! defined(S_ISDIR) && defined(S_IFDIR)
  59. #define    S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  60. #endif
  61.  
  62. #ifndef ENFILE
  63. #define ENFILE EMFILE
  64. #endif
  65.  
  66. #ifdef atarist
  67. #include <stddef.h>
  68. #endif
  69.  
  70. #if defined(MSDOS) || defined(OS2) || defined(WIN32)
  71. #define PIPES_SIMULATED
  72. #endif
  73.  
  74. static IOBUF *nextfile P((int skipping));
  75. static int inrec P((IOBUF *iop));
  76. static int iop_close P((IOBUF *iop));
  77. struct redirect *redirect P((NODE *tree, int *errflg));
  78. static void close_one P((void));
  79. static int close_redir P((struct redirect *rp, int exitwarn));
  80. #ifndef PIPES_SIMULATED
  81. static int wait_any P((int interesting));
  82. #endif
  83. static IOBUF *gawk_popen P((char *cmd, struct redirect *rp));
  84. static IOBUF *iop_open P((const char *file, const char *how, IOBUF *buf));
  85. static IOBUF *iop_alloc P((int fd, const char *name, IOBUF *buf));
  86. static int gawk_pclose P((struct redirect *rp));
  87. static int do_pathopen P((const char *file));
  88. static int get_a_record P((char **out, IOBUF *iop, int rs, Regexp *RSre, int *errcode));
  89. #ifdef HAVE_MMAP
  90. static int mmap_get_record P((char **out, IOBUF *iop, int rs, Regexp *RSre, int *errcode));
  91. #endif /* HAVE_MMAP */
  92. static int str2mode P((const char *mode));
  93. static void spec_setup P((IOBUF *iop, int len, int allocate));
  94. static int specfdopen P((IOBUF *iop, const char *name, const char *mode));
  95. static int pidopen P((IOBUF *iop, const char *name, const char *mode));
  96. static int useropen P((IOBUF *iop, const char *name, const char *mode));
  97.  
  98. #if defined (MSDOS) && !defined (__GO32__)
  99. #include "popen.h"
  100. #define popen(c, m)    os_popen(c, m)
  101. #define pclose(f)    os_pclose(f)
  102. #else
  103. #if defined (OS2)    /* OS/2, but not family mode */
  104. #if defined (_MSC_VER)
  105. #define popen(c, m)    _popen(c, m)
  106. #define pclose(f)    _pclose(f)
  107. #endif
  108. #else
  109. extern FILE    *popen();
  110. #endif
  111. #endif
  112.  
  113. static struct redirect *red_head = NULL;
  114. static NODE *RS;
  115. static Regexp *RS_regexp;
  116.  
  117. int RS_is_null;
  118.  
  119. extern int output_is_tty;
  120. extern NODE *ARGC_node;
  121. extern NODE *ARGV_node;
  122. extern NODE *ARGIND_node;
  123. extern NODE *ERRNO_node;
  124. extern NODE **fields_arr;
  125.  
  126. static jmp_buf filebuf;        /* for do_nextfile() */
  127.  
  128. /* do_nextfile --- implement gawk "nextfile" extension */
  129.  
  130. void
  131. do_nextfile()
  132. {
  133.     (void) nextfile(TRUE);
  134.     longjmp(filebuf, 1);
  135. }
  136.  
  137. /* nextfile --- move to the next input data file */
  138.  
  139. static IOBUF *
  140. nextfile(skipping)
  141. int skipping;
  142. {
  143.     static long i = 1;
  144.     static int files = 0;
  145.     NODE *arg;
  146.     static IOBUF *curfile = NULL;
  147.     static IOBUF mybuf;
  148.     const char *fname;
  149.  
  150.     if (skipping) {
  151.         if (curfile != NULL)
  152.             iop_close(curfile);
  153.         curfile = NULL;
  154.         return NULL;
  155.     }
  156.     if (curfile != NULL) {
  157.         if (curfile->cnt == EOF) {
  158.             (void) iop_close(curfile);
  159.             curfile = NULL;
  160.         } else
  161.             return curfile;
  162.     }
  163.     for (; i < (long) (ARGC_node->lnode->numbr); i++) {
  164.         arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i));
  165.         if (arg->stlen == 0)
  166.             continue;
  167.         arg->stptr[arg->stlen] = '\0';
  168.         if (! do_traditional) {
  169.             unref(ARGIND_node->var_value);
  170.             ARGIND_node->var_value = make_number((AWKNUM) i);
  171.         }
  172.         if (! arg_assign(arg->stptr)) {
  173.             files++;
  174.             fname = arg->stptr;
  175.             curfile = iop_open(fname, "r", &mybuf);
  176.             if (curfile == NULL)
  177.                 goto give_up;
  178.             curfile->flag |= IOP_NOFREE_OBJ;
  179.             /* This is a kludge.  */
  180.             unref(FILENAME_node->var_value);
  181.             FILENAME_node->var_value = dupnode(arg);
  182.             FNR = 0;
  183.             i++;
  184.             break;
  185.         }
  186.     }
  187.     if (files == 0) {
  188.         files++;
  189.         /* no args. -- use stdin */
  190.         /* FNR is init'ed to 0 */
  191.         FILENAME_node->var_value = make_string("-", 1);
  192.         fname = "-";
  193.         curfile = iop_open(fname, "r", &mybuf);
  194.         if (curfile == NULL)
  195.             goto give_up;
  196.         curfile->flag |= IOP_NOFREE_OBJ;
  197.     }
  198.     return curfile;
  199.  
  200.  give_up:
  201.     fatal("cannot open file `%s' for reading (%s)",
  202.         fname, strerror(errno));
  203.     /* NOTREACHED */
  204.     return 0;
  205. }
  206.  
  207. /* set_FNR --- update internal FNR from awk variable */
  208.  
  209. void
  210. set_FNR()
  211. {
  212.     FNR = (long) FNR_node->var_value->numbr;
  213. }
  214.  
  215. /* set_NR --- update internal NR from awk variable */
  216.  
  217. void
  218. set_NR()
  219. {
  220.     NR = (long) NR_node->var_value->numbr;
  221. }
  222.  
  223. /* inrec --- This reads in a record from the input file */
  224.  
  225. static int
  226. inrec(iop)
  227. IOBUF *iop;
  228. {
  229.     char *begin;
  230.     register int cnt;
  231.     int retval = 0;
  232.  
  233.     if ((cnt = iop->cnt) != EOF)
  234.         cnt = (*(iop->getrec))
  235.                 (&begin, iop, RS->stptr[0], RS_regexp, NULL);
  236.     if (cnt == EOF) {
  237.         cnt = 0;
  238.         retval = 1;
  239.     } else {
  240.         NR += 1;
  241.         FNR += 1;
  242.         set_record(begin, cnt, TRUE);
  243.     }
  244.  
  245.     return retval;
  246. }
  247.  
  248. /* iop_close --- close an open IOP */
  249.  
  250. static int
  251. iop_close(iop)
  252. IOBUF *iop;
  253. {
  254.     int ret;
  255.  
  256.     if (iop == NULL)
  257.         return 0;
  258.     errno = 0;
  259.  
  260. #ifdef _CRAY
  261.     /* Work around bug in UNICOS popen */
  262.     if (iop->fd < 3)
  263.         ret = 0;
  264.     else
  265. #endif
  266.     /* save these for re-use; don't free the storage */
  267.     if ((iop->flag & IOP_IS_INTERNAL) != 0) {
  268.         iop->off = iop->buf;
  269.         iop->end = iop->buf + strlen(iop->buf);
  270.         iop->cnt = 0;
  271.         iop->secsiz = 0;
  272.         return 0;
  273.     }
  274.  
  275.     /* Don't close standard files or else crufty code elsewhere will lose */
  276.     if (iop->fd == fileno(stdin)
  277.         || iop->fd == fileno(stdout)
  278.         || iop->fd == fileno(stderr)
  279.         || (iop->flag & IOP_MMAPPED) != 0)
  280.         ret = 0;
  281.     else
  282.         ret = close(iop->fd);
  283.  
  284.     if (ret == -1)
  285.         warning("close of fd %d (`%s') failed (%s)", iop->fd,
  286.                 iop->name, strerror(errno));
  287.     if ((iop->flag & IOP_NO_FREE) == 0) {
  288.         /*
  289.          * Be careful -- $0 may still reference the buffer even though
  290.          * an explicit close is being done; in the future, maybe we
  291.          * can do this a bit better.
  292.          */
  293.         if (iop->buf) {
  294.             if ((fields_arr[0]->stptr >= iop->buf)
  295.                 && (fields_arr[0]->stptr < (iop->buf + iop->secsiz + iop->size))) {
  296.                 NODE *t;
  297.     
  298.                 t = make_string(fields_arr[0]->stptr,
  299.                         fields_arr[0]->stlen);
  300.                 unref(fields_arr[0]);
  301.                 fields_arr[0] = t;
  302.                 reset_record();
  303.             }
  304.             if ((iop->flag & IOP_MMAPPED) == 0)
  305.                   free(iop->buf);
  306. #ifdef HAVE_MMAP
  307.             else
  308.                 (void) munmap(iop->buf, iop->size);
  309. #endif
  310.         }
  311.         if ((iop->flag & IOP_NOFREE_OBJ) == 0)
  312.             free((char *) iop);
  313.     }
  314.     return ret == -1 ? 1 : 0;
  315. }
  316.  
  317. /* do_input --- the main input processing loop */
  318.  
  319. void
  320. do_input()
  321. {
  322.     IOBUF *iop;
  323.     extern int exiting;
  324.  
  325.     (void) setjmp(filebuf);    /* for `nextfile' */
  326.  
  327.     while ((iop = nextfile(FALSE)) != NULL) {
  328.         if (inrec(iop) == 0)
  329.             while (interpret(expression_value) && inrec(iop) == 0)
  330.                 continue;
  331. #ifdef C_ALLOCA
  332.         /* recover any space from C based alloca */
  333.         (void) alloca(0);
  334. #endif
  335.         if (exiting)
  336.             break;
  337.     }
  338. }
  339.  
  340. /* redirect --- Redirection for printf and print commands */
  341.  
  342. struct redirect *
  343. redirect(tree, errflg)
  344. NODE *tree;
  345. int *errflg;
  346. {
  347.     register NODE *tmp;
  348.     register struct redirect *rp;
  349.     register char *str;
  350.     int tflag = 0;
  351.     int outflag = 0;
  352.     const char *direction = "to";
  353.     const char *mode;
  354.     int fd;
  355.     const char *what = NULL;
  356.  
  357.     switch (tree->type) {
  358.     case Node_redirect_append:
  359.         tflag = RED_APPEND;
  360.         /* FALL THROUGH */
  361.     case Node_redirect_output:
  362.         outflag = (RED_FILE|RED_WRITE);
  363.         tflag |= outflag;
  364.         if (tree->type == Node_redirect_output)
  365.             what = ">";
  366.         else
  367.             what = ">>";
  368.         break;
  369.     case Node_redirect_pipe:
  370.         tflag = (RED_PIPE|RED_WRITE);
  371.         what = "|";
  372.         break;
  373.     case Node_redirect_pipein:
  374.         tflag = (RED_PIPE|RED_READ);
  375.         what = "|";
  376.         break;
  377.     case Node_redirect_input:
  378.         tflag = (RED_FILE|RED_READ);
  379.         what = "<";
  380.         break;
  381.     default:
  382.         fatal("invalid tree type %d in redirect()", tree->type);
  383.         break;
  384.     }
  385.     tmp = tree_eval(tree->subnode);
  386.     if (do_lint && (tmp->flags & STR) == 0)
  387.         warning("expression in `%s' redirection only has numeric value",
  388.             what);
  389.     tmp = force_string(tmp);
  390.     str = tmp->stptr;
  391.  
  392.     if (str == NULL || *str == '\0')
  393.         fatal("expression for `%s' redirection has null string value",
  394.             what);
  395.  
  396.     if (do_lint
  397.         && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen)))
  398.         warning("filename `%s' for `%s' redirection may be result of logical expression", str, what);
  399.     for (rp = red_head; rp != NULL; rp = rp->next)
  400.         if (strlen(rp->value) == tmp->stlen
  401.             && STREQN(rp->value, str, tmp->stlen)
  402.             && ((rp->flag & ~(RED_NOBUF|RED_EOF)) == tflag
  403.             || (outflag != 0
  404.                 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag)))
  405.             break;
  406.     if (rp == NULL) {
  407.         emalloc(rp, struct redirect *, sizeof(struct redirect),
  408.             "redirect");
  409.         emalloc(str, char *, tmp->stlen+1, "redirect");
  410.         memcpy(str, tmp->stptr, tmp->stlen);
  411.         str[tmp->stlen] = '\0';
  412.         rp->value = str;
  413.         rp->flag = tflag;
  414.         rp->fp = NULL;
  415.         rp->iop = NULL;
  416.         rp->pid = 0;    /* unlikely that we're worried about init */
  417.         rp->status = 0;
  418.         /* maintain list in most-recently-used first order */
  419.         if (red_head != NULL)
  420.             red_head->prev = rp;
  421.         rp->prev = NULL;
  422.         rp->next = red_head;
  423.         red_head = rp;
  424.     } else
  425.         str = rp->value;    /* get \0 terminated string */
  426.     while (rp->fp == NULL && rp->iop == NULL) {
  427.         if (rp->flag & RED_EOF)
  428.             /*
  429.              * encountered EOF on file or pipe -- must be cleared
  430.              * by explicit close() before reading more
  431.              */
  432.             return rp;
  433.         mode = NULL;
  434.         errno = 0;
  435.         switch (tree->type) {
  436.         case Node_redirect_output:
  437.             mode = "w";
  438.             if ((rp->flag & RED_USED) != 0)
  439.                 mode = "a";
  440.             break;
  441.         case Node_redirect_append:
  442.             mode = "a";
  443.             break;
  444.         case Node_redirect_pipe:
  445.             /* synchronize output before new pipe */
  446.             (void) flush_io();
  447.  
  448.             if ((rp->fp = popen(str, "w")) == NULL)
  449.                 fatal("can't open pipe (\"%s\") for output (%s)",
  450.                     str, strerror(errno));
  451.             rp->flag |= RED_NOBUF;
  452.             break;
  453.         case Node_redirect_pipein:
  454.             direction = "from";
  455.             if (gawk_popen(str, rp) == NULL)
  456.                 fatal("can't open pipe (\"%s\") for input (%s)",
  457.                     str, strerror(errno));
  458.             break;
  459.         case Node_redirect_input:
  460.             direction = "from";
  461.             rp->iop = iop_open(str, "r", NULL);
  462.             break;
  463.         default:
  464.             cant_happen();
  465.         }
  466.         if (mode != NULL) {
  467.             errno = 0;
  468.             fd = devopen(str, mode);
  469.             if (fd > INVALID_HANDLE) {
  470.                 if (fd == fileno(stdin))
  471.                     rp->fp = stdin;
  472.                 else if (fd == fileno(stdout))
  473.                     rp->fp = stdout;
  474.                 else if (fd == fileno(stderr))
  475.                     rp->fp = stderr;
  476.                 else {
  477.                     rp->fp = fdopen(fd, (char *) mode);
  478.                     /* don't leak file descriptors */
  479.                     if (rp->fp == NULL)
  480.                         close(fd);
  481.                 }
  482.                 if (rp->fp != NULL && isatty(fd))
  483.                     rp->flag |= RED_NOBUF;
  484.             }
  485.         }
  486.         if (rp->fp == NULL && rp->iop == NULL) {
  487.             /* too many files open -- close one and try again */
  488.             if (errno == EMFILE || errno == ENFILE)
  489.                 close_one();
  490. #ifdef HAVE_MMAP
  491.             /* this works for solaris 2.5, not sunos */
  492.             else if (errno == 0)    /* HACK! */
  493.                 close_one();
  494. #endif
  495.             else {
  496.                 /*
  497.                  * Some other reason for failure.
  498.                  *
  499.                  * On redirection of input from a file,
  500.                  * just return an error, so e.g. getline
  501.                  * can return -1.  For output to file,
  502.                  * complain. The shell will complain on
  503.                  * a bad command to a pipe.
  504.                  */
  505.                 if (errflg != NULL)
  506.                     *errflg = errno;
  507.                 if (tree->type == Node_redirect_output
  508.                     || tree->type == Node_redirect_append)
  509.                     fatal("can't redirect %s `%s' (%s)",
  510.                         direction, str, strerror(errno));
  511.                 else {
  512.                     free_temp(tmp);
  513.                     return NULL;
  514.                 }
  515.             }
  516.         }
  517.     }
  518.     free_temp(tmp);
  519.     return rp;
  520. }
  521.  
  522. /* getredirect --- find the struct redirect for this file or pipe */
  523.  
  524. struct redirect *
  525. getredirect(str, len)
  526. char *str;
  527. int len;
  528. {
  529.     struct redirect *rp;
  530.  
  531.     for (rp = red_head; rp != NULL; rp = rp->next)
  532.         if (strlen(rp->value) == len && STREQN(rp->value, str, len))
  533.             return rp;
  534.  
  535.     return NULL;
  536. }
  537.  
  538. /* close_one --- temporarily close an open file to re-use the fd */
  539.  
  540. static void
  541. close_one()
  542. {
  543.     register struct redirect *rp;
  544.     register struct redirect *rplast = NULL;
  545.  
  546.     /* go to end of list first, to pick up least recently used entry */
  547.     for (rp = red_head; rp != NULL; rp = rp->next)
  548.         rplast = rp;
  549.     /* now work back up through the list */
  550.     for (rp = rplast; rp != NULL; rp = rp->prev)
  551.         if (rp->fp != NULL && (rp->flag & RED_FILE) != 0) {
  552.             rp->flag |= RED_USED;
  553.             errno = 0;
  554.             if (/* do_lint && */ fclose(rp->fp) != 0)
  555.                 warning("close of \"%s\" failed (%s).",
  556.                     rp->value, strerror(errno));
  557.             rp->fp = NULL;
  558.             break;
  559.         }
  560.     if (rp == NULL)
  561.         /* surely this is the only reason ??? */
  562.         fatal("too many pipes or input files open"); 
  563. }
  564.  
  565. /* do_close --- completely close an open file or pipe */
  566.  
  567. NODE *
  568. do_close(tree)
  569. NODE *tree;
  570. {
  571.     NODE *tmp;
  572.     register struct redirect *rp;
  573.  
  574.     tmp = force_string(tree_eval(tree->subnode));
  575.  
  576.     /* icky special case: close(FILENAME) called. */
  577.     if (tree->subnode == FILENAME_node
  578.         || (tmp->stlen == FILENAME_node->var_value->stlen
  579.         && STREQN(tmp->stptr, FILENAME_node->var_value->stptr, tmp->stlen))) {
  580.         (void) nextfile(TRUE);
  581.         free_temp(tmp);
  582.         return tmp_number((AWKNUM) 0.0);
  583.     }
  584.  
  585.     for (rp = red_head; rp != NULL; rp = rp->next) {
  586.         if (strlen(rp->value) == tmp->stlen
  587.             && STREQN(rp->value, tmp->stptr, tmp->stlen))
  588.             break;
  589.     }
  590.     if (rp == NULL) {    /* no match */
  591.         if (do_lint)
  592.             warning("close: `%.*s' is not an open file or pipe",
  593.                 tmp->stlen, tmp->stptr);
  594.         free_temp(tmp);
  595.         return tmp_number((AWKNUM) 0.0);
  596.     }
  597.     free_temp(tmp);
  598.     fflush(stdout);    /* synchronize regular output */
  599.     tmp = tmp_number((AWKNUM) close_redir(rp, FALSE));
  600.     rp = NULL;
  601.     return tmp;
  602. }
  603.  
  604. /* close_redir --- close an open file or pipe */
  605.  
  606. static int
  607. close_redir(rp, exitwarn)
  608. register struct redirect *rp;
  609. int exitwarn;
  610. {
  611.     int status = 0;
  612.     char *what;
  613.  
  614.     if (rp == NULL)
  615.         return 0;
  616.     if (rp->fp == stdout || rp->fp == stderr)
  617.         return 0;
  618.     errno = 0;
  619.     if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE))
  620.         status = pclose(rp->fp);
  621.     else if (rp->fp != NULL)
  622.         status = fclose(rp->fp);
  623.     else if (rp->iop != NULL) {
  624.         if ((rp->flag & RED_PIPE) != 0)
  625.             status = gawk_pclose(rp);
  626.         else {
  627.             status = iop_close(rp->iop);
  628.             rp->iop = NULL;
  629.         }
  630.     }
  631.  
  632.     what = ((rp->flag & RED_PIPE) != 0) ? "pipe" : "file";
  633.  
  634.     if (exitwarn) 
  635.         warning("no explicit close of %s `%s' provided",
  636.             what, rp->value);
  637.  
  638.     /* SVR4 awk checks and warns about status of close */
  639.     if (status != 0) {
  640.         char *s = strerror(errno);
  641.  
  642.         /*
  643.          * Too many people have complained about this.
  644.          * As of 2.15.6, it is now under lint control.
  645.          */
  646.         if (do_lint)
  647.             warning("failure status (%d) on %s close of \"%s\" (%s)",
  648.                 status, what, rp->value, s);
  649.  
  650.         if (! do_traditional) {
  651.             /* set ERRNO too so that program can get at it */
  652.             unref(ERRNO_node->var_value);
  653.             ERRNO_node->var_value = make_string(s, strlen(s));
  654.         }
  655.     }
  656.     if (rp->next != NULL)
  657.         rp->next->prev = rp->prev;
  658.     if (rp->prev != NULL)
  659.         rp->prev->next = rp->next;
  660.     else
  661.         red_head = rp->next;
  662.     free(rp->value);
  663.     free((char *) rp);
  664.     return status;
  665. }
  666.  
  667. /* flush_io --- flush all open output files */
  668.  
  669. int
  670. flush_io()
  671. {
  672.     register struct redirect *rp;
  673.     int status = 0;
  674.  
  675.     errno = 0;
  676.     if (fflush(stdout)) {
  677.         warning("error writing standard output (%s)", strerror(errno));
  678.         status++;
  679.     }
  680.     if (fflush(stderr)) {
  681.         warning("error writing standard error (%s)", strerror(errno));
  682.         status++;
  683.     }
  684.     for (rp = red_head; rp != NULL; rp = rp->next)
  685.         /* flush both files and pipes, what the heck */
  686.         if ((rp->flag & RED_WRITE) && rp->fp != NULL) {
  687.             if (fflush(rp->fp)) {
  688.                 warning("%s flush of \"%s\" failed (%s).",
  689.                     (rp->flag  & RED_PIPE) ? "pipe" :
  690.                     "file", rp->value, strerror(errno));
  691.                 status++;
  692.             }
  693.         }
  694.     return status;
  695. }
  696.  
  697. /* close_io --- close all open files, called when exiting */
  698.  
  699. int
  700. close_io()
  701. {
  702.     register struct redirect *rp;
  703.     register struct redirect *next;
  704.     int status = 0;
  705.  
  706.     errno = 0;
  707.     for (rp = red_head; rp != NULL; rp = next) {
  708.         next = rp->next;
  709.         /*
  710.          * close_redir() will print a message if needed
  711.          * if do_lint, warn about lack of explicit close
  712.          */
  713.         if (close_redir(rp, do_lint))
  714.             status++;
  715.         rp = NULL;
  716.     }
  717.     /*
  718.      * Some of the non-Unix os's have problems doing an fclose
  719.      * on stdout and stderr.  Since we don't really need to close
  720.      * them, we just flush them, and do that across the board.
  721.      */
  722.     if (fflush(stdout)) {
  723.         warning("error writing standard output (%s)", strerror(errno));
  724.         status++;
  725.     }
  726.     if (fflush(stderr)) {
  727.         warning("error writing standard error (%s)", strerror(errno));
  728.         status++;
  729.     }
  730.     return status;
  731. }
  732.  
  733. /* str2mode --- convert a string mode to an integer mode */
  734.  
  735. static int
  736. str2mode(mode)
  737. const char *mode;
  738. {
  739.     int ret;
  740.  
  741.     switch(mode[0]) {
  742.     case 'r':
  743.         ret = O_RDONLY;
  744.         break;
  745.  
  746.     case 'w':
  747.         ret = O_WRONLY|O_CREAT|O_TRUNC;
  748.         break;
  749.  
  750.     case 'a':
  751.         ret = O_WRONLY|O_APPEND|O_CREAT;
  752.         break;
  753.  
  754.     default:
  755.         ret = 0;        /* lint */
  756.         cant_happen();
  757.     }
  758.     return ret;
  759. }
  760.  
  761. /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
  762.  
  763. /*
  764.  * This separate version is still needed for output, since file and pipe
  765.  * output is done with stdio. iop_open() handles input with IOBUFs of
  766.  * more "special" files.  Those files are not handled here since it makes
  767.  * no sense to use them for output.
  768.  */
  769.  
  770. int
  771. devopen(name, mode)
  772. const char *name, *mode;
  773. {
  774.     int openfd;
  775.     const char *cp;
  776.     char *ptr;
  777.     int flag = 0;
  778.     struct stat buf;
  779.     extern double strtod();
  780.  
  781.     flag = str2mode(mode);
  782.  
  783.     if (STREQ(name, "-"))
  784.         openfd = fileno(stdin);
  785.     else
  786.         openfd = INVALID_HANDLE;
  787.  
  788.     if (do_traditional)
  789.         goto strictopen;
  790.  
  791.     if ((openfd = os_devopen(name, flag)) >= 0)
  792.         return openfd;
  793.  
  794.     if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
  795.         cp = name + 5;
  796.         
  797.         if (STREQ(cp, "stdin") && (flag & O_ACCMODE) == O_RDONLY)
  798.             openfd = fileno(stdin);
  799.         else if (STREQ(cp, "stdout") && (flag & O_ACCMODE) == O_WRONLY)
  800.             openfd = fileno(stdout);
  801.         else if (STREQ(cp, "stderr") && (flag & O_ACCMODE) == O_WRONLY)
  802.             openfd = fileno(stderr);
  803.         else if (STREQN(cp, "fd/", 3)) {
  804.             cp += 3;
  805.             openfd = (int) strtod(cp, &ptr);
  806.             if (openfd <= INVALID_HANDLE || ptr == cp)
  807.                 openfd = INVALID_HANDLE;
  808.         }
  809.     }
  810.  
  811. strictopen:
  812.     if (openfd == INVALID_HANDLE)
  813.         openfd = open(name, flag, 0666);
  814.     if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) 
  815.         if (S_ISDIR(buf.st_mode))
  816.             fatal("file `%s' is a directory", name);
  817.     return openfd;
  818. }
  819.  
  820.  
  821. /* spec_setup --- setup an IOBUF for a special internal file */
  822.  
  823. static void
  824. spec_setup(iop, len, allocate)
  825. IOBUF *iop;
  826. int len;
  827. int allocate;
  828. {
  829.     char *cp;
  830.  
  831.     if (allocate) {
  832.         emalloc(cp, char *, len+2, "spec_setup");
  833.         iop->buf = cp;
  834.     } else {
  835.         len = strlen(iop->buf);
  836.         iop->buf[len++] = '\n';    /* get_a_record clobbered it */
  837.         iop->buf[len] = '\0';    /* just in case */
  838.     }
  839.     iop->off = iop->buf;
  840.     iop->cnt = 0;
  841.     iop->secsiz = 0;
  842.     iop->size = len;
  843.     iop->end = iop->buf + len;
  844.     iop->fd = -1;
  845.     iop->flag = IOP_IS_INTERNAL;
  846.     iop->getrec = get_a_record;
  847. }
  848.  
  849. /* specfdopen --- open an fd special file */
  850.  
  851. static int
  852. specfdopen(iop, name, mode)
  853. IOBUF *iop;
  854. const char *name, *mode;
  855. {
  856.     int fd;
  857.     IOBUF *tp;
  858.  
  859.     fd = devopen(name, mode);
  860.     if (fd == INVALID_HANDLE)
  861.         return INVALID_HANDLE;
  862.     tp = iop_alloc(fd, name, NULL);
  863.     if (tp == NULL) {
  864.         /* don't leak fd's */
  865.         close(fd);
  866.         return INVALID_HANDLE;
  867.     }
  868.     *iop = *tp;
  869.     iop->flag |= IOP_NO_FREE;
  870.     free(tp);
  871.     return 0;
  872. }
  873.  
  874. #ifdef GETPGRP_VOID
  875. #define getpgrp_arg() /* nothing */
  876. #else
  877. #define getpgrp_arg() getpid()
  878. #endif
  879.  
  880. /* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */
  881.  
  882. static int
  883. pidopen(iop, name, mode)
  884. IOBUF *iop;
  885. const char *name, *mode;
  886. {
  887.     char tbuf[BUFSIZ];
  888.     int i;
  889.  
  890.     if (name[6] == 'g')
  891.         sprintf(tbuf, "%d\n", getpgrp(getpgrp_arg()));
  892.     else if (name[6] == 'i')
  893.         sprintf(tbuf, "%d\n", getpid());
  894.     else
  895.         sprintf(tbuf, "%d\n", getppid());
  896.     i = strlen(tbuf);
  897.     spec_setup(iop, i, TRUE);
  898.     strcpy(iop->buf, tbuf);
  899.     return 0;
  900. }
  901.  
  902. /* useropen --- "open" /dev/user */
  903.  
  904. /*
  905.  * /dev/user creates a record as follows:
  906.  *    $1 = getuid()
  907.  *    $2 = geteuid()
  908.  *    $3 = getgid()
  909.  *    $4 = getegid()
  910.  * If multiple groups are supported, then $5 through $NF are the
  911.  * supplementary group set.
  912.  */
  913.  
  914. static int
  915. useropen(iop, name, mode)
  916. IOBUF *iop;
  917. const char *name, *mode;
  918. {
  919.     char tbuf[BUFSIZ], *cp;
  920.     int i;
  921. #if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
  922.     GETGROUPS_T groupset[NGROUPS_MAX];
  923.     int ngroups;
  924. #endif
  925.  
  926.     sprintf(tbuf, "%d %d %d %d", getuid(), geteuid(), getgid(), getegid());
  927.  
  928.     cp = tbuf + strlen(tbuf);
  929. #if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
  930.     ngroups = getgroups(NGROUPS_MAX, groupset);
  931.     if (ngroups == -1)
  932.         fatal("could not find groups: %s", strerror(errno));
  933.  
  934.     for (i = 0; i < ngroups; i++) {
  935.         *cp++ = ' ';
  936.         sprintf(cp, "%d", (int) groupset[i]);
  937.         cp += strlen(cp);
  938.     }
  939. #endif
  940.     *cp++ = '\n';
  941.     *cp++ = '\0';
  942.  
  943.     i = strlen(tbuf);
  944.     spec_setup(iop, i, TRUE);
  945.     strcpy(iop->buf, tbuf);
  946.     return 0;
  947. }
  948.  
  949. /* iop_open --- handle special and regular files for input */
  950.  
  951. static IOBUF *
  952. iop_open(name, mode, iop)
  953. const char *name, *mode;
  954. IOBUF *iop;
  955. {
  956.     int openfd = INVALID_HANDLE;
  957.     int flag = 0;
  958.     struct stat buf;
  959.     static struct internal {
  960.         const char *name;
  961.         int compare;
  962.         int (*fp) P((IOBUF *, const char *, const char *));
  963.         IOBUF iob;
  964.     } table[] = {
  965.         { "/dev/fd/",        8,    specfdopen },
  966.         { "/dev/stdin",        10,    specfdopen },
  967.         { "/dev/stdout",    11,    specfdopen },
  968.         { "/dev/stderr",    11,    specfdopen },
  969.         { "/dev/pid",        8,    pidopen },
  970.         { "/dev/ppid",        9,    pidopen },
  971.         { "/dev/pgrpid",    11,    pidopen },
  972.         { "/dev/user",        9,    useropen },
  973.     };
  974.     int devcount = sizeof(table) / sizeof(table[0]);
  975.  
  976.     flag = str2mode(mode);
  977.  
  978.     /*
  979.      * FIXME: remove the stat call, and always process these files
  980.      * internally.
  981.      */
  982.     if (STREQ(name, "-"))
  983.         openfd = fileno(stdin);
  984.     else if (do_traditional)
  985.         goto strictopen;
  986.     else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
  987.         int i;
  988.  
  989.         for (i = 0; i < devcount; i++) {
  990.             if (STREQN(name, table[i].name, table[i].compare)) {
  991.                 iop = & table[i].iob;
  992.  
  993.                 if (iop->buf != NULL) {
  994.                     spec_setup(iop, 0, FALSE);
  995.                     return iop;
  996.                 } else if ((*table[i].fp)(iop, name, mode) == 0)
  997.                     return iop;
  998.                 else {
  999.                     warning("could not open %s, mode `%s'",
  1000.                         name, mode);
  1001.                     return NULL;
  1002.                 }
  1003.             }
  1004.         }
  1005.     }
  1006.  
  1007. strictopen:
  1008.     if (openfd == INVALID_HANDLE)
  1009.         openfd = open(name, flag, 0666);
  1010.     if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) 
  1011.         if ((buf.st_mode & S_IFMT) == S_IFDIR)
  1012.             fatal("file `%s' is a directory", name);
  1013.     return iop_alloc(openfd, name, iop);
  1014. }
  1015.  
  1016. #ifndef PIPES_SIMULATED        /* real pipes */
  1017.  
  1018. /* wait_any --- wait for a child process, close associated pipe */
  1019.  
  1020. static int
  1021. wait_any(interesting)
  1022. int interesting;    /* pid of interest, if any */
  1023. {
  1024.     RETSIGTYPE (*hstat)(), (*istat)(), (*qstat)();
  1025.     int pid;
  1026.     int status = 0;
  1027.     struct redirect *redp;
  1028.     extern int errno;
  1029.  
  1030.     hstat = signal(SIGHUP, SIG_IGN);
  1031.     istat = signal(SIGINT, SIG_IGN);
  1032.     qstat = signal(SIGQUIT, SIG_IGN);
  1033.     for (;;) {
  1034. #ifdef HAVE_SYS_WAIT_H    /* Posix compatible sys/wait.h */
  1035.         pid = wait(&status);
  1036. #else
  1037.         pid = wait((union wait *)&status);
  1038. #endif /* NeXT */
  1039.         if (interesting && pid == interesting) {
  1040.             break;
  1041.         } else if (pid != -1) {
  1042.             for (redp = red_head; redp != NULL; redp = redp->next)
  1043.                 if (pid == redp->pid) {
  1044.                     redp->pid = -1;
  1045.                     redp->status = status;
  1046.                     break;
  1047.                 }
  1048.         }
  1049.         if (pid == -1 && errno == ECHILD)
  1050.             break;
  1051.     }
  1052.     signal(SIGHUP, hstat);
  1053.     signal(SIGINT, istat);
  1054.     signal(SIGQUIT, qstat);
  1055.     return(status);
  1056. }
  1057.  
  1058. /* gawk_popen --- open an IOBUF on a child process */
  1059.  
  1060. static IOBUF *
  1061. gawk_popen(cmd, rp)
  1062. char *cmd;
  1063. struct redirect *rp;
  1064. {
  1065.     int p[2];
  1066.     register int pid;
  1067.  
  1068.     /*
  1069.      * used to wait for any children to synchronize input and output,
  1070.      * but this could cause gawk to hang when it is started in a pipeline
  1071.      * and thus has a child process feeding it input (shell dependant)
  1072.      */
  1073.     /*(void) wait_any(0);*/    /* wait for outstanding processes */
  1074.  
  1075.     if (pipe(p) < 0)
  1076.         fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno));
  1077.     if ((pid = fork()) == 0) {
  1078.         if (close(1) == -1)
  1079.             fatal("close of stdout in child failed (%s)",
  1080.                 strerror(errno));
  1081.         if (dup(p[1]) != 1)
  1082.             fatal("dup of pipe failed (%s)", strerror(errno));
  1083.         if (close(p[0]) == -1 || close(p[1]) == -1)
  1084.             fatal("close of pipe failed (%s)", strerror(errno));
  1085.         execl("/bin/sh", "sh", "-c", cmd, NULL);
  1086.         _exit(127);
  1087.     }
  1088.     if (pid == -1)
  1089.         fatal("cannot fork for \"%s\" (%s)", cmd, strerror(errno));
  1090.     rp->pid = pid;
  1091.     if (close(p[1]) == -1)
  1092.         fatal("close of pipe failed (%s)", strerror(errno));
  1093.     rp->iop = iop_alloc(p[0], cmd, NULL);
  1094.     if (rp->iop == NULL)
  1095.         (void) close(p[0]);
  1096.     return (rp->iop);
  1097. }
  1098.  
  1099. /* gawk_pclose --- close an open child pipe */
  1100.  
  1101. static int
  1102. gawk_pclose(rp)
  1103. struct redirect *rp;
  1104. {
  1105.     (void) iop_close(rp->iop);
  1106.     rp->iop = NULL;
  1107.  
  1108.     /* process previously found, return stored status */
  1109.     if (rp->pid == -1)
  1110.         return (rp->status >> 8) & 0xFF;
  1111.     rp->status = wait_any(rp->pid);
  1112.     rp->pid = -1;
  1113.     return (rp->status >> 8) & 0xFF;
  1114. }
  1115.  
  1116. #else    /* PIPES_SIMULATED */
  1117.  
  1118. /*
  1119.  * use temporary file rather than pipe
  1120.  * except if popen() provides real pipes too
  1121.  */
  1122.  
  1123. #if defined(VMS) || defined(OS2) || defined (MSDOS)
  1124.  
  1125. /* gawk_popen --- open an IOBUF on a child process */
  1126.  
  1127. static IOBUF *
  1128. gawk_popen(cmd, rp)
  1129. char *cmd;
  1130. struct redirect *rp;
  1131. {
  1132.     FILE *current;
  1133.  
  1134.     if ((current = popen(cmd, "r")) == NULL)
  1135.         return NULL;
  1136.     rp->iop = iop_alloc(fileno(current), cmd, NULL);
  1137.     if (rp->iop == NULL) {
  1138.         (void) fclose(current);
  1139.         current = NULL;
  1140.     }
  1141.     rp->ifp = current;
  1142.     return (rp->iop);
  1143. }
  1144.  
  1145. /* gawk_pclose --- close an open child pipe */
  1146.  
  1147. static int
  1148. gawk_pclose(rp)
  1149. struct redirect *rp;
  1150. {
  1151.     int rval, aval, fd = rp->iop->fd;
  1152.  
  1153.     rp->iop->fd = dup(fd);      /* kludge to allow close() + pclose() */
  1154.     rval = iop_close(rp->iop);
  1155.     rp->iop = NULL;
  1156.     aval = pclose(rp->ifp);
  1157.     rp->ifp = NULL;
  1158.     return (rval < 0 ? rval : aval);
  1159. }
  1160. #else    /* not (VMS || OS2 || MSDOS) */
  1161.  
  1162. static struct pipeinfo {
  1163.     char *command;
  1164.     char *name;
  1165. } pipes[_NFILE];
  1166.  
  1167. /* gawk_popen --- open an IOBUF on a child process */
  1168.  
  1169. static IOBUF *
  1170. gawk_popen(cmd, rp)
  1171. char *cmd;
  1172. struct redirect *rp;
  1173. {
  1174.     extern char *strdup P((const char *));
  1175.     int current;
  1176.     char *name;
  1177.     static char cmdbuf[256];
  1178.  
  1179.     /* get a name to use */
  1180.     if ((name = tempnam(".", "pip")) == NULL)
  1181.         return NULL;
  1182.     sprintf(cmdbuf, "%s > %s", cmd, name);
  1183.     system(cmdbuf);
  1184.     if ((current = open(name, O_RDONLY)) == INVALID_HANDLE)
  1185.         return NULL;
  1186.     pipes[current].name = name;
  1187.     pipes[current].command = strdup(cmd);
  1188.     rp->iop = iop_alloc(current, name, NULL);
  1189.     if (rp->iop == NULL)
  1190.         (void) close(current);
  1191.     return (rp->iop);
  1192. }
  1193.  
  1194. /* gawk_pclose --- close an open child pipe */
  1195.  
  1196. static int
  1197. gawk_pclose(rp)
  1198. struct redirect *rp;
  1199. {
  1200.     int cur = rp->iop->fd;
  1201.     int rval;
  1202.  
  1203.     rval = iop_close(rp->iop);
  1204.     rp->iop = NULL;
  1205.  
  1206.     /* check for an open file  */
  1207.     if (pipes[cur].name == NULL)
  1208.         return -1;
  1209.     unlink(pipes[cur].name);
  1210.     free(pipes[cur].name);
  1211.     pipes[cur].name = NULL;
  1212.     free(pipes[cur].command);
  1213.     return rval;
  1214. }
  1215. #endif    /* not (VMS || OS2 || MSDOS) */
  1216.  
  1217. #endif    /* PIPES_SIMULATED */
  1218.  
  1219. /* do_getline --- read in a line, into var and with redirection, as needed */
  1220.  
  1221. NODE *
  1222. do_getline(tree)
  1223. NODE *tree;
  1224. {
  1225.     struct redirect *rp = NULL;
  1226.     IOBUF *iop;
  1227.     int cnt = EOF;
  1228.     char *s = NULL;
  1229.     int errcode;
  1230.  
  1231.     while (cnt == EOF) {
  1232.         if (tree->rnode == NULL) {     /* no redirection */
  1233.             iop = nextfile(FALSE);
  1234.             if (iop == NULL)        /* end of input */
  1235.                 return tmp_number((AWKNUM) 0.0);
  1236.         } else {
  1237.             int redir_error = 0;
  1238.  
  1239.             rp = redirect(tree->rnode, &redir_error);
  1240.             if (rp == NULL && redir_error) { /* failed redirect */
  1241.                 if (! do_traditional) {
  1242.                     s = strerror(redir_error);
  1243.  
  1244.                     unref(ERRNO_node->var_value);
  1245.                     ERRNO_node->var_value =
  1246.                         make_string(s, strlen(s));
  1247.                 }
  1248.                 return tmp_number((AWKNUM) -1.0);
  1249.             }
  1250.             iop = rp->iop;
  1251.             if (iop == NULL)        /* end of input */
  1252.                 return tmp_number((AWKNUM) 0.0);
  1253.         }
  1254.         errcode = 0;
  1255.         cnt = (*(iop->getrec))(&s, iop, RS->stptr[0], RS_regexp, &errcode);
  1256.         if (errcode != 0) {
  1257.             if (! do_traditional) {
  1258.                 s = strerror(errcode);
  1259.  
  1260.                 unref(ERRNO_node->var_value);
  1261.                 ERRNO_node->var_value = make_string(s, strlen(s));
  1262.             }
  1263.             return tmp_number((AWKNUM) -1.0);
  1264.         }
  1265.         if (cnt == EOF) {
  1266.             if (rp != NULL) {
  1267.                 /*
  1268.                  * Don't do iop_close() here if we are
  1269.                  * reading from a pipe; otherwise
  1270.                  * gawk_pclose will not be called.
  1271.                  */
  1272.                 if ((rp->flag & RED_PIPE) == 0) {
  1273.                     (void) iop_close(iop);
  1274.                     rp->iop = NULL;
  1275.                 }
  1276.                 rp->flag |= RED_EOF;    /* sticky EOF */
  1277.                 return tmp_number((AWKNUM) 0.0);
  1278.             } else
  1279.                 continue;    /* try another file */
  1280.         }
  1281.         if (rp == NULL) {
  1282.             NR++;
  1283.             FNR++;
  1284.         }
  1285.         if (tree->lnode == NULL)    /* no optional var. */
  1286.             set_record(s, cnt, TRUE);
  1287.         else {            /* assignment to variable */
  1288.             Func_ptr after_assign = NULL;
  1289.             NODE **lhs;
  1290.  
  1291.             lhs = get_lhs(tree->lnode, &after_assign);
  1292.             unref(*lhs);
  1293.             *lhs = make_string(s, cnt);
  1294.             (*lhs)->flags |= MAYBE_NUM;
  1295.             /* we may have to regenerate $0 here! */
  1296.             if (after_assign != NULL)
  1297.                 (*after_assign)();
  1298.         }
  1299.     }
  1300.     return tmp_number((AWKNUM) 1.0);
  1301. }
  1302.  
  1303. /* pathopen --- pathopen with default file extension handling */
  1304.  
  1305. int
  1306. pathopen(file)
  1307. const char *file;
  1308. {
  1309.     int fd = do_pathopen(file);
  1310.  
  1311. #ifdef DEFAULT_FILETYPE
  1312.     if (! do_traditional && fd <= INVALID_HANDLE) {
  1313.         char *file_awk;
  1314.         int save = errno;
  1315. #ifdef VMS
  1316.         int vms_save = vaxc$errno;
  1317. #endif
  1318.  
  1319.         /* append ".awk" and try again */
  1320.         emalloc(file_awk, char *, strlen(file) +
  1321.             sizeof(DEFAULT_FILETYPE) + 1, "pathopen");
  1322.         sprintf(file_awk, "%s%s", file, DEFAULT_FILETYPE);
  1323.         fd = do_pathopen(file_awk);
  1324.         free(file_awk);
  1325.         if (fd <= INVALID_HANDLE) {
  1326.             errno = save;
  1327. #ifdef VMS
  1328.             vaxc$errno = vms_save;
  1329. #endif
  1330.         }
  1331.     }
  1332. #endif    /*DEFAULT_FILETYPE*/
  1333.  
  1334.     return fd;
  1335. }
  1336.  
  1337. /* do_pathopen --- search $AWKPATH for source file */
  1338.  
  1339. static int
  1340. do_pathopen(file)
  1341. const char *file;
  1342. {
  1343.     static const char *savepath = NULL;
  1344.     static int first = TRUE;
  1345.     const char *awkpath;
  1346.     char *cp, trypath[BUFSIZ];
  1347.     int fd;
  1348.  
  1349.     if (STREQ(file, "-"))
  1350.         return (0);
  1351.  
  1352.     if (do_traditional)
  1353.         return (devopen(file, "r"));
  1354.  
  1355.     if (first) {
  1356.         first = FALSE;
  1357.         if ((awkpath = getenv("AWKPATH")) != NULL && *awkpath)
  1358.             savepath = awkpath;    /* used for restarting */
  1359.         else
  1360.             savepath = defpath;
  1361.     }
  1362.     awkpath = savepath;
  1363.  
  1364.     /* some kind of path name, no search */
  1365.     if (ispath(file))
  1366.         return (devopen(file, "r"));
  1367.  
  1368.     do {
  1369.         trypath[0] = '\0';
  1370.         /* this should take into account limits on size of trypath */
  1371.         for (cp = trypath; *awkpath && *awkpath != envsep; )
  1372.             *cp++ = *awkpath++;
  1373.  
  1374.         if (cp != trypath) {    /* nun-null element in path */
  1375.             /* add directory punctuation only if needed */
  1376.             if (! isdirpunct(*(cp-1)))
  1377.                 *cp++ = '/';
  1378.             /* append filename */
  1379.             strcpy(cp, file);
  1380.         } else
  1381.             strcpy(trypath, file);
  1382.         if ((fd = devopen(trypath, "r")) > INVALID_HANDLE)
  1383.             return (fd);
  1384.  
  1385.         /* no luck, keep going */
  1386.         if(*awkpath == envsep && awkpath[1] != '\0')
  1387.             awkpath++;    /* skip colon */
  1388.     } while (*awkpath != '\0');
  1389.     /*
  1390.      * You might have one of the awk paths defined, WITHOUT the current
  1391.      * working directory in it. Therefore try to open the file in the
  1392.      * current directory.
  1393.      */
  1394.     return (devopen(file, "r"));
  1395. }
  1396.  
  1397. #ifdef TEST
  1398. int bufsize = 8192;
  1399.  
  1400. void
  1401. fatal(s)
  1402. char *s;
  1403. {
  1404.     printf("%s\n", s);
  1405.     exit(1);
  1406. }
  1407. #endif
  1408.  
  1409. /* iop_alloc --- allocate an IOBUF structure for an open fd */
  1410.  
  1411. static IOBUF *
  1412. iop_alloc(fd, name, iop)
  1413. int fd;
  1414. const char *name;
  1415. IOBUF *iop;
  1416. {
  1417.     struct stat sbuf;
  1418.  
  1419.     if (fd == INVALID_HANDLE)
  1420.         return NULL;
  1421.     if (iop == NULL)
  1422.         emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
  1423.     iop->flag = 0;
  1424.     if (isatty(fd))
  1425.         iop->flag |= IOP_IS_TTY;
  1426.     iop->size = optimal_bufsize(fd, & sbuf);
  1427.     if (do_lint && S_ISREG(sbuf.st_mode) && sbuf.st_size == 0)
  1428.         warning("data file `%s' is empty", name);
  1429.     iop->secsiz = -2;
  1430.     errno = 0;
  1431.     iop->fd = fd;
  1432.     iop->off = iop->buf = NULL;
  1433.     iop->cnt = 0;
  1434.     iop->name = name;
  1435.     iop->getrec = get_a_record;
  1436. #ifdef HAVE_MMAP
  1437.     if (S_ISREG(sbuf.st_mode) && sbuf.st_size > 0) {
  1438.         register char *cp;
  1439.  
  1440.         iop->buf = iop->off = mmap((caddr_t) 0, sbuf.st_size,
  1441.                     PROT_READ|PROT_WRITE, MAP_PRIVATE,
  1442.                     fd,  0L);
  1443.         /* cast is for buggy compilers (e.g. DEC OSF/1) */
  1444.         if (iop->buf == (caddr_t)MAP_FAILED) {
  1445.             iop->buf = iop->off = NULL;
  1446.             goto out;
  1447.         }
  1448.  
  1449.         iop->flag |= IOP_MMAPPED;
  1450.         iop->size = sbuf.st_size;
  1451.         iop->secsiz = 0;
  1452.         iop->end = iop->buf + iop->size;
  1453.         iop->cnt = sbuf.st_size;
  1454.         iop->getrec = mmap_get_record;
  1455.         (void) close(fd);
  1456.         iop->fd = INVALID_HANDLE;
  1457.  
  1458. #if defined(HAVE_MADVISE) && defined(MADV_SEQUENTIAL)
  1459.         madvise(iop->buf, iop->size, MADV_SEQUENTIAL);
  1460. #endif
  1461.         /*
  1462.          * The following is a really gross hack.
  1463.          * We want to ensure that we have a copy of the input
  1464.          * data that won't go away, on the off chance that someone
  1465.          * will truncate the data file we've just mmap'ed.
  1466.          * So, we go through and touch each page, forcing the
  1467.          * system to give us a private copy. A page size of 512
  1468.          * guarantees this will work, even on the least common
  1469.          * denominator system (like, oh say, a VAX).
  1470.          */
  1471.         for (cp = iop->buf; cp < iop->end; cp += 512)
  1472.             *cp = *cp;
  1473.     }
  1474. out:
  1475. #endif /* HAVE_MMAP */
  1476.     return iop;
  1477. }
  1478.  
  1479. /* These macros used by both record reading routines */
  1480. #define set_RT_to_null() \
  1481.     (void)(! do_traditional && (unref(RT_node->var_value), \
  1482.                RT_node->var_value = Nnull_string))
  1483.  
  1484. #define set_RT(str, len) \
  1485.     (void)(! do_traditional && (unref(RT_node->var_value), \
  1486.                RT_node->var_value = make_string(str, len)))
  1487.  
  1488. /*
  1489.  * get_a_record:
  1490.  * Get the next record.  Uses a "split buffer" where the latter part is
  1491.  * the normal read buffer and the head part is an "overflow" area that is used
  1492.  * when a record spans the end of the normal buffer, in which case the first
  1493.  * part of the record is copied into the overflow area just before the
  1494.  * normal buffer.  Thus, the eventual full record can be returned as a
  1495.  * contiguous area of memory with a minimum of copying.  The overflow area
  1496.  * is expanded as needed, so that records are unlimited in length.
  1497.  * We also mark both the end of the buffer and the end of the read() with
  1498.  * a sentinel character (the current record separator) so that the inside
  1499.  * loop can run as a single test.
  1500.  *
  1501.  * Note that since we know or can compute the end of the read and the end
  1502.  * of the buffer, the sentinel character does not get in the way of regexp
  1503.  * based searching, since we simply search up to that character, but not
  1504.  * including it.
  1505.  */
  1506.  
  1507. static int
  1508. get_a_record(out, iop, grRS, RSre, errcode)
  1509. char **out;        /* pointer to pointer to data */
  1510. IOBUF *iop;        /* input IOP */
  1511. register int grRS;    /* first char in RS->stptr */
  1512. Regexp *RSre;        /* regexp for RS */
  1513. int *errcode;        /* pointer to error variable */
  1514. {
  1515.     register char *bp = iop->off;
  1516.     char *bufend;
  1517.     char *start = iop->off;            /* beginning of record */
  1518.     int rs;
  1519.     static Regexp *RS_null_re = NULL;
  1520.     Regexp *rsre = NULL;
  1521.     int continuing = FALSE, continued = FALSE;    /* used for re matching */
  1522.     int onecase;
  1523.  
  1524.     /* first time through */
  1525.     if (RS_null_re == NULL) {
  1526.         RS_null_re = make_regexp("\n\n+", 3, TRUE, TRUE);
  1527.         if (RS_null_re == NULL)
  1528.             fatal("internal error: file `%s', line %d\n",
  1529.                 __FILE__, __LINE__);
  1530.     }
  1531.  
  1532.     if (iop->cnt == EOF) {    /* previous read hit EOF */
  1533.         *out = NULL;
  1534.         set_RT_to_null();
  1535.         return EOF;
  1536.     }
  1537.  
  1538.     if (grRS == FALSE)    /* special case:  RS == "" */
  1539.         rs = '\n';
  1540.     else
  1541.         rs = (char) grRS;
  1542.  
  1543.     onecase = (IGNORECASE && isalpha(rs));
  1544.     if (onecase)
  1545.         rs = casetable[rs];
  1546.  
  1547.     /* set up sentinel */
  1548.     if (iop->buf) {
  1549.         bufend = iop->buf + iop->size + iop->secsiz;
  1550.         *bufend = rs;        /* add sentinel to buffer */
  1551.     } else
  1552.         bufend = NULL;
  1553.  
  1554.     for (;;) {    /* break on end of record, read error or EOF */
  1555. /* buffer mgmt, chunk #1 */
  1556.         /*
  1557.          * Following code is entered on the first call of this routine
  1558.          * for a new iop, or when we scan to the end of the buffer.
  1559.          * In the latter case, we copy the current partial record to
  1560.          * the space preceding the normal read buffer.  If necessary,
  1561.          * we expand this space.  This is done so that we can return
  1562.          * the record as a contiguous area of memory.
  1563.          */
  1564.         if ((iop->flag & IOP_IS_INTERNAL) == 0 && bp >= bufend) {
  1565.             char *oldbuf = NULL;
  1566.             char *oldsplit = iop->buf + iop->secsiz;
  1567.             long len;    /* record length so far */
  1568.  
  1569.             len = bp - start;
  1570.             if (len > iop->secsiz) {
  1571.                 /* expand secondary buffer */
  1572.                 if (iop->secsiz == -2)
  1573.                     iop->secsiz = 256;
  1574.                 while (len > iop->secsiz)
  1575.                     iop->secsiz *= 2;
  1576.                 oldbuf = iop->buf;
  1577.                 emalloc(iop->buf, char *,
  1578.                     iop->size+iop->secsiz+2, "get_a_record");
  1579.                 bufend = iop->buf + iop->size + iop->secsiz;
  1580.                 *bufend = rs;
  1581.             }
  1582.             if (len > 0) {
  1583.                 char *newsplit = iop->buf + iop->secsiz;
  1584.  
  1585.                 if (start < oldsplit) {
  1586.                     memcpy(newsplit - len, start,
  1587.                             oldsplit - start);
  1588.                     memcpy(newsplit - (bp - oldsplit),
  1589.                             oldsplit, bp - oldsplit);
  1590.                 } else
  1591.                     memcpy(newsplit - len, start, len);
  1592.             }
  1593.             bp = iop->end = iop->off = iop->buf + iop->secsiz;
  1594.             start = bp - len;
  1595.             if (oldbuf != NULL) {
  1596.                 free(oldbuf);
  1597.                 oldbuf = NULL;
  1598.             }
  1599.         }
  1600. /* buffer mgmt, chunk #2 */
  1601.         /*
  1602.          * Following code is entered whenever we have no more data to
  1603.          * scan.  In most cases this will read into the beginning of
  1604.          * the main buffer, but in some cases (terminal, pipe etc.)
  1605.          * we may be doing smallish reads into more advanced positions.
  1606.          */
  1607.         if (bp >= iop->end) {
  1608.             if ((iop->flag & IOP_IS_INTERNAL) != 0) {
  1609.                 iop->cnt = EOF;
  1610.                 break;
  1611.             }
  1612.             iop->cnt = read(iop->fd, iop->end, bufend - iop->end);
  1613.             if (iop->cnt == -1) {
  1614.                 if (! do_traditional && errcode != NULL) {
  1615.                     *errcode = errno;
  1616.                     iop->cnt = EOF;
  1617.                     break;
  1618.                 } else
  1619.                     fatal("error reading input file `%s': %s",
  1620.                         iop->name, strerror(errno));
  1621.             } else if (iop->cnt == 0) {
  1622.                 /*
  1623.                  * hit EOF before matching RS, so end
  1624.                  * the record and set RT to ""
  1625.                  */
  1626.                 iop->cnt = EOF;
  1627.                 /* see comments below about this test */
  1628.                 if (! continuing) {
  1629.                     set_RT_to_null();
  1630.                     break;
  1631.                 }
  1632.             }
  1633.             if (iop->cnt != EOF) {
  1634.                 iop->end += iop->cnt;
  1635.                 *iop->end = rs;        /* reset the sentinel */
  1636.             }
  1637.         }
  1638. /* buffers are now setup and filled with data */
  1639. /* search for RS, #1, regexp based, or RS = "" */
  1640.         /*
  1641.          * Attempt to simplify the code a bit. The case where
  1642.          * RS = "" can also be described by a regexp, RS = "\n\n+".
  1643.          * The buffer managment and searching code can thus now
  1644.          * use a common case (the one for regexps) both when RS is
  1645.          * a regexp, and when RS = "". This particularly benefits
  1646.          * us for keeping track of how many newlines were matched
  1647.          * in order to set RT.
  1648.          */
  1649.         if (! do_traditional && RSre != NULL)    /* regexp */
  1650.             rsre = RSre;
  1651.         else if (grRS == FALSE)        /* RS = "" */
  1652.             rsre = RS_null_re;
  1653.         else
  1654.             rsre = NULL;
  1655.  
  1656.         /*
  1657.          * Look for regexp match of RS.  Non-match conditions are:
  1658.          *    1. No match at all
  1659.          *    2. Match of a null string
  1660.          *    3. Match ends at exact end of buffer
  1661.          * Number 3 is subtle; we have to add more to the buffer
  1662.          * in case the match would have extended further into the
  1663.          * file, since regexp match by definition always matches the
  1664.          * longest possible match.
  1665.          *
  1666.          * It is even more subtle than you might think. Suppose
  1667.          * the re matches at exactly the end of file. We don't know
  1668.          * that until we try to add more to the buffer. Thus, we
  1669.          * set a flag to indicate, that if eof really does happen,
  1670.          * don't break early.
  1671.          */
  1672.         continuing = FALSE;
  1673.         if (rsre != NULL) {
  1674.         again:
  1675.             /* cases 1 and 2 are simple, just keep going */
  1676.             if (research(rsre, start, 0, iop->end - start, TRUE) == -1
  1677.                 || RESTART(rsre, start) == REEND(rsre, start)) {
  1678.                 bp = iop->end;
  1679.                 continue;
  1680.             }
  1681.             /* case 3, regex match at exact end */
  1682.             if (start + REEND(rsre, start) >= iop->end) {
  1683.                 if (iop->cnt != EOF) {
  1684.                     bp = iop->end;
  1685.                     continuing = continued = TRUE;
  1686.                     continue;
  1687.                 }
  1688.             }
  1689.             /* got a match! */
  1690.             /*
  1691.              * Leading newlines at the beginning of the file
  1692.              * should be ignored. Whew!
  1693.              */
  1694.             if (grRS == FALSE && RESTART(rsre, start) == 0) {
  1695.                 start += REEND(rsre, start);
  1696.                 goto again;
  1697.             }
  1698.             bp = start + RESTART(rsre, start);
  1699.             set_RT(bp, REEND(rsre, start) - RESTART(rsre, start));
  1700.             *bp = '\0';
  1701.             iop->off = start + REEND(rsre, start);
  1702.             break;
  1703.         }
  1704. /* search for RS, #2, RS = <single char> */
  1705.         if (onecase) {
  1706.             while (casetable[(int) *bp++] != rs)
  1707.                 continue;
  1708.         } else {
  1709.             while (*bp++ != rs)
  1710.                 continue;
  1711.         }
  1712.         set_RT(bp - 1, 1);
  1713.  
  1714.         if (bp <= iop->end)
  1715.             break;
  1716.         else
  1717.             bp--;
  1718.  
  1719.         if ((iop->flag & IOP_IS_INTERNAL) != 0)
  1720.             iop->cnt = bp - start;
  1721.     }
  1722.     if (iop->cnt == EOF
  1723.         && (((iop->flag & IOP_IS_INTERNAL) != 0)
  1724.               || (start == bp && ! continued))) {
  1725.         *out = NULL;
  1726.         set_RT_to_null();
  1727.         return EOF;
  1728.     }
  1729.  
  1730.     if (do_traditional || rsre == NULL) {
  1731.         char *bstart;
  1732.  
  1733.         bstart = iop->off = bp;
  1734.         bp--;
  1735.         if (onecase ? casetable[(int) *bp] != rs : *bp != rs) {
  1736.             bp++;
  1737.             bstart = bp;
  1738.         }
  1739.         *bp = '\0';
  1740.     } else if (grRS == FALSE && iop->cnt == EOF) {
  1741.         /*
  1742.          * special case, delete trailing newlines,
  1743.          * should never be more than one.
  1744.          */
  1745.         while (bp[-1] == '\n')
  1746.             bp--;
  1747.         *bp = '\0';
  1748.     }
  1749.  
  1750.     *out = start;
  1751.     return bp - start;
  1752. }
  1753.  
  1754. #ifdef TEST
  1755. int
  1756. main(argc, argv)
  1757. int argc;
  1758. char *argv[];
  1759. {
  1760.     IOBUF *iop;
  1761.     char *out;
  1762.     int cnt;
  1763.     char rs[2];
  1764.  
  1765.     rs[0] = '\0';
  1766.     if (argc > 1)
  1767.         bufsize = atoi(argv[1]);
  1768.     if (argc > 2)
  1769.         rs[0] = *argv[2];
  1770.     iop = iop_alloc(0, "stdin", NULL);
  1771.     while ((cnt = get_a_record(&out, iop, rs[0], NULL, NULL)) > 0) {
  1772.         fwrite(out, 1, cnt, stdout);
  1773.         fwrite(rs, 1, 1, stdout);
  1774.     }
  1775.     return 0;
  1776. }
  1777. #endif
  1778.  
  1779. #ifdef HAVE_MMAP
  1780. /* mmap_get_record --- pull a record out of a memory-mapped file */
  1781.  
  1782. static int
  1783. mmap_get_record(out, iop, grRS, RSre, errcode)
  1784. char **out;        /* pointer to pointer to data */
  1785. IOBUF *iop;        /* input IOP */
  1786. register int grRS;    /* first char in RS->stptr */
  1787. Regexp *RSre;        /* regexp for RS */
  1788. int *errcode;        /* pointer to error variable */
  1789. {
  1790.     register char *bp = iop->off;
  1791.     char *start = iop->off;            /* beginning of record */
  1792.     int rs;
  1793.     static Regexp *RS_null_re = NULL;
  1794.     Regexp *rsre = NULL;
  1795.     int onecase;
  1796.     register char *end = iop->end;
  1797.     int cnt;
  1798.  
  1799.     /* first time through */
  1800.     if (RS_null_re == NULL) {
  1801.         RS_null_re = make_regexp("\n\n+", 3, TRUE, TRUE);
  1802.         if (RS_null_re == NULL)
  1803.             fatal("internal error: file `%s', line %d\n",
  1804.                 __FILE__, __LINE__);
  1805.     }
  1806.  
  1807.     if (iop->off >= iop->end) {    /* previous record was last */
  1808.         *out = NULL;
  1809.         set_RT_to_null();
  1810.         iop->cnt = EOF;        /* tested by higher level code */
  1811.         return EOF;
  1812.     }
  1813.  
  1814.     if (grRS == FALSE)    /* special case:  RS == "" */
  1815.         rs = '\n';
  1816.     else
  1817.         rs = (char) grRS;
  1818.  
  1819.     onecase = (IGNORECASE && isalpha(rs));
  1820.     if (onecase)
  1821.         rs = casetable[rs];
  1822.  
  1823.     /* if RS = "", skip leading newlines at the front of the file */
  1824.     if (grRS == FALSE && iop->off == iop->buf) {
  1825.         for (bp = iop->off; *bp == '\n'; bp++)
  1826.             continue;
  1827.  
  1828.         if (bp != iop->off)
  1829.             iop->off = start = bp;
  1830.     }
  1831.  
  1832.     /*
  1833.      * Regexp based searching. Either RS = "" or RS = <regex>
  1834.      * See comments in get_a_record.
  1835.      */
  1836.     if (! do_traditional && RSre != NULL)    /* regexp */
  1837.         rsre = RSre;
  1838.     else if (grRS == FALSE)        /* RS = "" */
  1839.         rsre = RS_null_re;
  1840.     else
  1841.         rsre = NULL;
  1842.  
  1843.     /*
  1844.      * Look for regexp match of RS.  Non-match conditions are:
  1845.      *    1. No match at all
  1846.      *    2. Match of a null string
  1847.      *    3. Match ends at exact end of buffer
  1848.      *
  1849.      * #1 means that the record ends the file
  1850.      * and there is no text that actually matched RS.
  1851.      *
  1852.      * #2: is probably like #1.
  1853.      *
  1854.      * #3 is simple; since we have the whole file mapped, it's
  1855.      * the last record in the file.
  1856.      */
  1857.     if (rsre != NULL) {
  1858.         if (research(rsre, start, 0, iop->end - start, TRUE) == -1
  1859.             || RESTART(rsre, start) == REEND(rsre, start)) {
  1860.             /* no matching text, we have the record */
  1861.             *out = start;
  1862.             iop->off = iop->end;    /* all done with the record */
  1863.             set_RT_to_null();
  1864.             /* special case, don't allow trailing newlines */
  1865.             if (grRS == FALSE && *(iop->end - 1) == '\n')
  1866.                 return iop->end - start - 1;
  1867.             else
  1868.                 return iop->end - start;
  1869.  
  1870.         }
  1871.         /* have a match */
  1872.         *out = start;
  1873.         bp = start + RESTART(rsre, start);
  1874.         set_RT(bp, REEND(rsre, start) - RESTART(rsre, start));
  1875.         *bp = '\0';
  1876.         iop->off = start + REEND(rsre, start);
  1877.         return bp - start;
  1878.     }
  1879.  
  1880.     /*
  1881.      * RS = "?", i.e., one character based searching.
  1882.      *
  1883.      * Alas, we can't just plug the sentinel character in at
  1884.      * the end of the mmapp'ed file ( *(iop->end) = rs; ). This
  1885.      * works if we're lucky enough to have a file that does not
  1886.      * take up all of its last disk block. But if we end up with
  1887.      * file whose size is an even multiple of the disk block size,
  1888.      * assigning past the end of it delivers a SIGBUS. So, we have to
  1889.      * add the extra test in the while loop at the front that looks
  1890.      * for going past the end of the mapped object. Sigh.
  1891.      */
  1892.     /* search for RS, #2, RS = <single char> */
  1893.     if (onecase) {
  1894.         while (bp < end && casetable[*bp++] != rs)
  1895.             continue;
  1896.     } else {
  1897.         while (bp < end && *bp++ != rs)
  1898.             continue;
  1899.     }
  1900.     cnt = (bp - start) - 1;
  1901.     if (bp >= iop->end) {
  1902.         /* at end, may have actually seen rs, or may not */
  1903.         if (*(bp-1) == rs)
  1904.             set_RT(bp - 1, 1);    /* real RS seen */
  1905.         else {
  1906.             cnt++;
  1907.             set_RT_to_null();
  1908.         }
  1909.     } else
  1910.         set_RT(bp - 1, 1);
  1911.  
  1912.     iop->off = bp;
  1913.     *out = start;
  1914.     return cnt;
  1915. }
  1916. #endif /* HAVE_MMAP */
  1917.  
  1918. /* set_RS --- update things as appropriate when RS is set */
  1919.  
  1920. void
  1921. set_RS()
  1922. {
  1923.     static NODE *save_rs = NULL;
  1924.  
  1925.     if (save_rs && cmp_nodes(RS_node->var_value, save_rs) == 0)
  1926.         return;
  1927.     unref(save_rs);
  1928.     save_rs = dupnode(RS_node->var_value);
  1929.     RS_is_null = FALSE;
  1930.     RS = force_string(RS_node->var_value);
  1931.     if (RS_regexp != NULL) {
  1932.         refree(RS_regexp);
  1933.         RS_regexp = NULL;
  1934.     }
  1935.     if (RS->stlen == 0)
  1936.         RS_is_null = TRUE;
  1937.     else if (RS->stlen > 1)
  1938.         RS_regexp = make_regexp(RS->stptr, RS->stlen, IGNORECASE, TRUE);
  1939.  
  1940.     set_FS_if_not_FIELDWIDTHS();
  1941. }
  1942.