home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 11 / AUCD11B.iso / LANGUAGES / WraithSet / AwkStuff / GawkSrc / c / io < prev    next >
Encoding:
Text File  |  1999-06-30  |  46.0 KB  |  1,959 lines

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