home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / gnu / gawk213s.lzh / GAWK213S / IO.C < prev    next >
C/C++ Source or Header  |  1993-07-29  |  19KB  |  853 lines

  1. /*
  2.  * io.c - routines for dealing with input and output and records
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 1, or (at your option)
  14.  * any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28. #ifndef O_RDONLY
  29. #include <fcntl.h>
  30. #endif
  31.  
  32. #ifndef atarist
  33. #define INVALID_HANDLE (-1)
  34. #else
  35. #define INVALID_HANDLE  (__SMALLEST_VALID_HANDLE - 1)
  36. #endif
  37.  
  38. static IOBUF *nextfile P((void));
  39. static int inrec P((IOBUF *iop, int getline_redirect));
  40. static int iop_close P((IOBUF *iop));
  41. struct redirect *redirect P((NODE *tree, int *errflg));
  42. static void close_one P((void));
  43. static int close_redir P((struct redirect *rp));
  44. #if (!defined(MSDOS)) && (!defined(atarist))
  45. static int wait_any P((int interesting));
  46. #endif
  47. static IOBUF *gawk_popen P((char *cmd, struct redirect *rp));
  48. static int gawk_pclose P((struct redirect *rp));
  49. static int do_pathopen P((char *file));
  50.  
  51. static struct redirect *red_head = NULL;
  52. static IOBUF *curfile = NULL;
  53.  
  54. extern int output_is_tty;
  55. extern NODE *ARGC_node;
  56. extern NODE *ARGV_node;
  57. extern NODE **fields_arr;
  58.  
  59. static IOBUF *
  60. nextfile()
  61. {
  62.     static int i = 1;
  63.     static int files = 0;
  64.     char *arg;
  65.     int fd = INVALID_HANDLE;
  66.  
  67.     if (curfile != NULL && curfile->cnt != EOF)
  68.         return curfile;
  69.     for (; i < (int) (ARGC_node->lnode->numbr); i++) {
  70.         arg = (*assoc_lookup(ARGV_node, tmp_number((AWKNUM) i)))->stptr;
  71.         if (*arg == '\0')
  72.             continue;
  73.         if (!arg_assign(arg)) {
  74.             files++;
  75.             fd = devopen(arg, "r");
  76.             if (fd == INVALID_HANDLE)
  77.                 fatal("cannot open file `%s' for reading (%s)",
  78.                     arg, strerror(errno));
  79.                 /* NOTREACHED */
  80.             /* This is a kludge.  */
  81.             unref(FILENAME_node->var_value);
  82.             FILENAME_node->var_value =
  83.                 make_string(arg, strlen(arg));
  84.             FNR = 0;
  85.             i++;
  86.             break;
  87.         }
  88.     }
  89.     if (files == 0) {
  90.         files++;
  91.         /* no args. -- use stdin */
  92.         /* FILENAME is init'ed to "-" */
  93.         /* FNR is init'ed to 0 */
  94.         fd = 0;
  95.     }
  96.     if (fd == INVALID_HANDLE)
  97.         return NULL;
  98.     return curfile = iop_alloc(fd);
  99. }
  100.  
  101. void
  102. set_FNR()
  103. {
  104.     FNR = (int) FNR_node->var_value->numbr;
  105. }
  106.  
  107. void
  108. set_NR()
  109. {
  110.     NR = (int) NR_node->var_value->numbr;
  111. }
  112.  
  113. /*
  114.  * This reads in a record from the input file
  115.  */
  116. static int
  117. inrec(iop, getline_redirect)
  118. IOBUF *iop;
  119. int getline_redirect;
  120. {
  121.     char *begin;
  122.     register int cnt;
  123.     int retval = 0;
  124.  
  125.     cnt = get_a_record(&begin, iop, *RS);
  126.     if (cnt == EOF) {
  127.         cnt = 0;
  128.         retval = 1;
  129.     } else if (!getline_redirect) {
  130.             NR += 1;
  131.             FNR += 1;
  132.     }
  133.     set_record(begin, cnt, 1);
  134.  
  135.     return retval;
  136. }
  137.  
  138. static int
  139. iop_close(iop)
  140. IOBUF *iop;
  141. {
  142.     int ret;
  143.  
  144.     if (iop == NULL)
  145.         return 0;
  146.     errno = 0;
  147.  
  148.     /* Work around bug in UNICOS popen, but it shouldn't hurt elsewhere */
  149.     if (iop->fd < 3)
  150.         ret = 0;
  151.     else
  152.         ret = close(iop->fd);
  153.     if (ret == -1)
  154.         warning("close of fd %d failed (%s)", iop->fd, strerror(errno));
  155.     free(iop->buf);
  156.     free(iop->secbuf);
  157.     if (iop == curfile)
  158.         curfile = NULL;    /* kludge -- gotta do better */
  159.     free((char *)iop);
  160.     return ret == -1 ? 1 : 0;
  161. }
  162.  
  163. void
  164. do_input()
  165. {
  166.     IOBUF *iop;
  167.     extern int exiting;
  168.  
  169.     while ((iop = nextfile()) != NULL) {
  170.         if (inrec(iop, 0) == 0)
  171.             while (interpret(expression_value) && inrec(iop, 0) == 0)
  172.                 ;
  173.         (void) iop_close(iop);
  174.         iop = NULL;
  175.         if (exiting)
  176.             break;
  177.     }
  178. }
  179.  
  180. /* Redirection for printf and print commands */
  181. struct redirect *
  182. redirect(tree, errflg)
  183. NODE *tree;
  184. int *errflg;
  185. {
  186.     register NODE *tmp;
  187.     register struct redirect *rp;
  188.     register char *str;
  189.     int tflag = 0;
  190.     int outflag = 0;
  191.     char *direction = "to";
  192.     char *mode;
  193.     int fd;
  194.  
  195.     switch (tree->type) {
  196.     case Node_redirect_append:
  197.         tflag = RED_APPEND;
  198.     case Node_redirect_output:
  199.         outflag = (RED_FILE|RED_WRITE);
  200.         tflag |= outflag;
  201.         break;
  202.     case Node_redirect_pipe:
  203.         tflag = (RED_PIPE|RED_WRITE);
  204.         break;
  205.     case Node_redirect_pipein:
  206.         tflag = (RED_PIPE|RED_READ);
  207.         break;
  208.     case Node_redirect_input:
  209.         tflag = (RED_FILE|RED_READ);
  210.         break;
  211.     default:
  212.         fatal ("invalid tree type %d in redirect()", tree->type);
  213.         break;
  214.     }
  215.     tmp = force_string(tree_eval(tree->subnode));
  216.     str = tmp->stptr;
  217.     for (rp = red_head; rp != NULL; rp = rp->next)
  218.         if (strlen(rp->value) == tmp->stlen
  219.             && STREQN(rp->value, str, tmp->stlen)
  220.             && ((rp->flag & ~RED_NOBUF) == tflag
  221.             || (outflag
  222.                 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag)))
  223.             break;
  224.     if (rp == NULL) {
  225.         emalloc(rp, struct redirect *, sizeof(struct redirect),
  226.             "redirect");
  227.         emalloc(str, char *, tmp->stlen+1, "redirect");
  228.         memcpy(str, tmp->stptr, tmp->stlen);
  229.         str[tmp->stlen] = '\0';
  230.         rp->value = str;
  231.         rp->flag = tflag;
  232.         rp->fp = NULL;
  233.         rp->iop = NULL;
  234.         rp->pid = 0;    /* unlikely that we're worried about init */
  235.         rp->status = 0;
  236.         /* maintain list in most-recently-used first order */
  237.         if (red_head)
  238.             red_head->prev = rp;
  239.         rp->prev = NULL;
  240.         rp->next = red_head;
  241.         red_head = rp;
  242.     }
  243.     while (rp->fp == NULL && rp->iop == NULL) {
  244.         mode = NULL;
  245.         errno = 0;
  246.         switch (tree->type) {
  247.         case Node_redirect_output:
  248.             mode = "w";
  249.             if (rp->flag & RED_USED)
  250.                 mode = "a";
  251.             break;
  252.         case Node_redirect_append:
  253.             mode = "a";
  254.             break;
  255.         case Node_redirect_pipe:
  256.             if ((rp->fp = popen(str, "w")) == NULL)
  257.                 fatal("can't open pipe (\"%s\") for output (%s)",
  258.                     str, strerror(errno));
  259.             rp->flag |= RED_NOBUF;
  260.             break;
  261.         case Node_redirect_pipein:
  262.             direction = "from";
  263.             if (gawk_popen(str, rp) == NULL)
  264.                 fatal("can't open pipe (\"%s\") for input (%s)",
  265.                     str, strerror(errno));
  266.             break;
  267.         case Node_redirect_input:
  268.             direction = "from";
  269.             rp->iop = iop_alloc(devopen(str, "r"));
  270.             break;
  271.         default:
  272.             cant_happen();
  273.         }
  274.         if (mode != NULL) {
  275.             fd = devopen(str, mode);
  276.             if (fd > INVALID_HANDLE) {
  277.                 if (fd == fileno(stdin))
  278.                     rp->fp = stdin;
  279.                 else if (fd == fileno(stdout))
  280.                     rp->fp = stdout;
  281.                 else if (fd == fileno(stderr))
  282.                     rp->fp = stderr;
  283.                 else    
  284.                     rp->fp = fdopen(fd, mode);
  285.                 if (isatty(fd))
  286.                     rp->flag |= RED_NOBUF;
  287.             }
  288.         }
  289.         if (rp->fp == NULL && rp->iop == NULL) {
  290.             /* too many files open -- close one and try again */
  291. #ifdef atarist
  292.             if (errno == EMFILE)
  293. #else
  294.             if (errno == ENFILE || errno == EMFILE)
  295. #endif
  296.                 close_one();
  297.             else {
  298.                 /*
  299.                  * Some other reason for failure.
  300.                  *
  301.                  * On redirection of input from a file,
  302.                  * just return an error, so e.g. getline
  303.                  * can return -1.  For output to file,
  304.                  * complain. The shell will complain on
  305.                  * a bad command to a pipe.
  306.                  */
  307.                 *errflg = 1;
  308.                 if (tree->type == Node_redirect_output
  309.                     || tree->type == Node_redirect_append)
  310.                     fatal("can't redirect %s `%s' (%s)",
  311.                         direction, str, strerror(errno));
  312.                 else {
  313.                     free_temp(tmp);
  314.                     return NULL;
  315.                 }
  316.             }
  317.         }
  318.     }
  319.     free_temp(tmp);
  320.     return rp;
  321. }
  322.  
  323. static void
  324. close_one()
  325. {
  326.     register struct redirect *rp;
  327.     register struct redirect *rplast = NULL;
  328.  
  329.     /* go to end of list first, to pick up least recently used entry */
  330.     for (rp = red_head; rp != NULL; rp = rp->next)
  331.         rplast = rp;
  332.     /* now work back up through the list */
  333.     for (rp = rplast; rp != NULL; rp = rp->prev)
  334.         if (rp->fp && (rp->flag & RED_FILE)) {
  335.             rp->flag |= RED_USED;
  336.             errno = 0;
  337.             if (fclose(rp->fp))
  338.                 warning("close of \"%s\" failed (%s).",
  339.                     rp->value, strerror(errno));
  340.             rp->fp = NULL;
  341.             break;
  342.         }
  343.     if (rp == NULL)
  344.         /* surely this is the only reason ??? */
  345.         fatal("too many pipes or input files open"); 
  346. }
  347.  
  348. NODE *
  349. do_close(tree)
  350. NODE *tree;
  351. {
  352.     NODE *tmp;
  353.     register struct redirect *rp;
  354.  
  355.     tmp = force_string(tree_eval(tree->subnode));
  356.     for (rp = red_head; rp != NULL; rp = rp->next) {
  357.         if (strlen(rp->value) == tmp->stlen
  358.             && STREQN(rp->value, tmp->stptr, tmp->stlen))
  359.             break;
  360.     }
  361.     free_temp(tmp);
  362.     if (rp == NULL) /* no match */
  363.         return tmp_number((AWKNUM) 0.0);
  364.     fflush(stdout);    /* synchronize regular output */
  365.     tmp = tmp_number((AWKNUM)close_redir(rp));
  366.     rp = NULL;
  367.     return tmp;
  368. }
  369.  
  370. static int
  371. close_redir(rp)
  372. register struct redirect *rp;
  373. {
  374.     int status = 0;
  375.  
  376.     if (rp == NULL)
  377.         return 0;
  378.     errno = 0;
  379.     if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE))
  380.         status = pclose(rp->fp);
  381.     else if (rp->fp)
  382.         status = fclose(rp->fp);
  383.     else if (rp->iop) {
  384.         if (rp->flag & RED_PIPE)
  385.             status = gawk_pclose(rp);
  386.         else {
  387.             status = iop_close(rp->iop);
  388.             rp->iop = NULL;
  389.         }
  390.     }
  391.     /* SVR4 awk checks and warns about status of close */
  392.     if (status)
  393.         warning("failure status (%d) on %s close of \"%s\" (%s).",
  394.             status,
  395.             (rp->flag & RED_PIPE) ? "pipe" :
  396.             "file", rp->value, strerror(errno));
  397.     if (rp->next)
  398.         rp->next->prev = rp->prev;
  399.     if (rp->prev)
  400.         rp->prev->next = rp->next;
  401.     else
  402.         red_head = rp->next;
  403.     free(rp->value);
  404.     free((char *)rp);
  405.     return status;
  406. }
  407.  
  408. int
  409. flush_io ()
  410. {
  411.     register struct redirect *rp;
  412.     int status = 0;
  413.  
  414.     errno = 0;
  415.     if (fflush(stdout)) {
  416.         warning("error writing standard output (%s).", strerror(errno));
  417.         status++;
  418.     }
  419.     errno = 0;
  420.     if (fflush(stderr)) {
  421.         warning("error writing standard error (%s).", strerror(errno));
  422.         status++;
  423.     }
  424.     for (rp = red_head; rp != NULL; rp = rp->next)
  425.         /* flush both files and pipes, what the heck */
  426.         if ((rp->flag & RED_WRITE) && rp->fp != NULL) {
  427.             errno = 0;
  428.             if (fflush(rp->fp)) {
  429.                 warning("%s flush of \"%s\" failed (%s).",
  430.                     (rp->flag  & RED_PIPE) ? "pipe" :
  431.                     "file", rp->value, strerror(errno));
  432.                 status++;
  433.             }
  434.         }
  435.     return status;
  436. }
  437.  
  438. int
  439. close_io ()
  440. {
  441.     register struct redirect *rp;
  442.     register struct redirect *next;
  443.     int status = 0;
  444.  
  445.     for (rp = red_head; rp != NULL; rp = next) {
  446.         next = rp->next;
  447.         if (close_redir(rp))
  448.             status++;
  449.         rp = NULL;
  450.     }
  451.     return status;
  452. }
  453.  
  454. /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
  455.  
  456. int
  457. devopen (name, mode)
  458. char *name, *mode;
  459. {
  460.     int openfd = INVALID_HANDLE;
  461.     FILE *fdopen ();
  462.     char *cp, *ptr;
  463.     int flag = 0;
  464.     struct stat buf;
  465.  
  466.     switch(mode[0]) {
  467.     case 'r':
  468.         flag = O_RDONLY;
  469.         break;
  470.  
  471.     case 'w':
  472.         flag = O_WRONLY|O_CREAT|O_TRUNC;
  473.         break;
  474.  
  475.     case 'a':
  476.         flag = O_WRONLY|O_APPEND|O_CREAT;
  477.         break;
  478.     default:
  479.         cant_happen();
  480.     }
  481.  
  482. #ifdef VMS
  483.     if ((openfd = vms_devopen(name)) >= 0)
  484.         return openfd;
  485. # define strcmp  strcasecmp    /* VMS filenames are not case sensitive; */
  486. # define strncmp strncasecmp    /*  strncmp() is used by STREQN() below. */
  487. #endif /*VMS*/
  488.  
  489.     if (STREQ(name, "-"))
  490.         openfd = fileno(stdin);
  491.     else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) {
  492.         cp = name + 5;
  493.         
  494.         /* XXX - first three tests ignore mode */
  495.         if (STREQ(cp, "stdin") && (flag & O_RDONLY))
  496.             openfd = fileno(stdin);
  497.         else if (STREQ(cp, "stdout") && (flag & O_WRONLY))
  498.             openfd = fileno(stdout);
  499.         else if (STREQ(cp, "stderr") && (flag & O_WRONLY))
  500.             openfd = fileno(stderr);
  501.         else if (STREQN(cp, "fd/", 3)) {
  502.             cp += 3;
  503.             openfd = strtol(cp, &ptr, 10);
  504.             if (openfd <= INVALID_HANDLE || ptr == cp)
  505.                 openfd = INVALID_HANDLE;
  506. #ifdef VMS
  507.         } else if (STREQ(cp, "null")) {
  508.             name = "NL:";    /* "/dev/null" => "NL:" */
  509.         } else if (STREQ(cp, "tty")) {
  510.             name = "TT:";    /* "/dev/tty" => "TT:" */
  511. # undef strcmp
  512. # undef strncmp
  513. #endif /*VMS*/
  514.         }
  515.     }
  516.  
  517.     if (openfd != INVALID_HANDLE)
  518.         return openfd;
  519.     else
  520.         return open(name, flag, 0666);
  521. }
  522.  
  523. #if defined(MSDOS) || defined(atarist)
  524. #define PIPES_SIMULATED
  525. #endif
  526.  
  527. #ifndef PIPES_SIMULATED
  528.     /* real pipes */
  529. static int
  530. wait_any(interesting)
  531. int interesting;    /* pid of interest, if any */
  532. {
  533.     SIGTYPE (*hstat)(), (*istat)(), (*qstat)();
  534.     int pid;
  535.     int status = 0;
  536.     struct redirect *redp;
  537.     extern int errno;
  538.  
  539.     hstat = signal(SIGHUP, SIG_IGN);
  540.     istat = signal(SIGINT, SIG_IGN);
  541.     qstat = signal(SIGQUIT, SIG_IGN);
  542.     for (;;) {
  543.         pid = wait(&status);
  544.         if (interesting && pid == interesting) {
  545.             break;
  546.         } else if (pid != -1) {
  547.             for (redp = red_head; redp != NULL; redp = redp->next)
  548.                 if (pid == redp->pid) {
  549.                     redp->pid = -1;
  550.                     redp->status = status;
  551.                     if (redp->fp) {
  552.                         pclose(redp->fp);
  553.                         redp->fp = 0;
  554.                     }
  555.                     if (redp->iop) {
  556.                         (void) iop_close(redp->iop);
  557.                         redp->iop = 0;
  558.                     }
  559.                     break;
  560.                 }
  561.         }
  562.         if (pid == -1 && errno == ECHILD)
  563.             break;
  564.     }
  565.     signal(SIGHUP, hstat);
  566.     signal(SIGINT, istat);
  567.     signal(SIGQUIT, qstat);
  568.     return(status);
  569. }
  570.  
  571. static IOBUF *
  572. gawk_popen(cmd, rp)
  573. char *cmd;
  574. struct redirect *rp;
  575. {
  576.     int p[2];
  577.     register int pid;
  578.  
  579.     (void) wait_any(0);    /* wait for outstanding processes */
  580.     if (pipe(p) < 0)
  581.         fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno));
  582.     if ((pid = fork()) == 0) {
  583.         if (close(1) == -1)
  584.             fatal("close of stdout in child failed (%s)",
  585.                 strerror(errno));
  586.         if (dup(p[1]) != 1)
  587.             fatal("dup of pipe failed (%s)", strerror(errno));
  588.         if (close(p[0]) == -1 || close(p[1]) == -1)
  589.             fatal("close of pipe failed (%s)", strerror(errno));
  590.         execl("/bin/sh", "sh", "-c", cmd, 0);
  591.         _exit(127);
  592.     }
  593.     if (pid == -1)
  594.         fatal("cannot fork for \"%s\" (%s)", cmd, strerror(errno));
  595.     rp->pid = pid;
  596.     if (close(p[1]) == -1)
  597.         fatal("close of pipe failed (%s)", strerror(errno));
  598.     return (rp->iop = iop_alloc(p[0]));
  599. }
  600.  
  601. static int
  602. gawk_pclose(rp)
  603. struct redirect *rp;
  604. {
  605.     (void) iop_close(rp->iop);
  606.     rp->iop = NULL;
  607.  
  608.     /* process previously found, return stored status */
  609.     if (rp->pid == -1)
  610.         return (rp->status >> 8) & 0xFF;
  611.     rp->status = wait_any(rp->pid);
  612.     rp->pid = -1;
  613.     return (rp->status >> 8) & 0xFF;
  614. }
  615.  
  616. #else    /* PIPES_SUMULATED */
  617.     /* use temporary file rather than pipe */
  618.  
  619. #ifdef VMS
  620. static IOBUF *
  621. gawk_popen(cmd, rp)
  622. char *cmd;
  623. struct redirect *rp;
  624. {
  625.     FILE *current;
  626.  
  627.     if ((current = popen(cmd, "r")) == NULL)
  628.         return NULL;
  629.     return (rp->iop = iop_alloc(fileno(current)));
  630. }
  631.  
  632. static int
  633. gawk_pclose(rp)
  634. struct redirect *rp;
  635. {
  636.     int rval, aval, fd = rp->iop->fd;
  637.     FILE *kludge = fdopen(fd, "r"); /* pclose needs FILE* w/ right fileno */
  638.  
  639.     rp->iop->fd = dup(fd);      /* kludge to allow close() + pclose() */
  640.     rval = iop_close(rp->iop);
  641.     aval = pclose(kludge);
  642.     return (rval < 0 ? rval : aval);
  643. }
  644. #else    /* VMS */
  645.  
  646. static
  647. struct {
  648.     char *command;
  649.     char *name;
  650. } pipes[_NFILE];
  651.  
  652. static IOBUF *
  653. gawk_popen(cmd, rp)
  654. char *cmd;
  655. struct redirect *rp;
  656. {
  657.     extern char *strdup(const char *);
  658.     int current;
  659.     char *name;
  660.     static char cmdbuf[256];
  661.  
  662.     /* get a name to use.  */
  663.     if ((name = tempnam(".", "pip")) == NULL)
  664.         return NULL;
  665.     sprintf(cmdbuf,"%s > %s", cmd, name);
  666.     system(cmdbuf);
  667.     if ((current = open(name,O_RDONLY)) == INVALID_HANDLE)
  668.         return NULL;
  669.     pipes[current].name = name;
  670.     pipes[current].command = strdup(cmd);
  671.     return (rp->iop = iop_alloc(current));
  672. }
  673.  
  674. static int
  675. gawk_pclose(rp)
  676. struct redirect *rp;
  677. {
  678.     int cur = rp->iop->fd;
  679.     int rval;
  680.  
  681.     rval = iop_close(rp->iop);
  682.     rp->iop = NULL;
  683.  
  684.     /* check for an open file  */
  685.     if (pipes[cur].name == NULL)
  686.         return -1;
  687.     unlink(pipes[cur].name);
  688.     free(pipes[cur].name);
  689.     pipes[cur].name = NULL;
  690.     free(pipes[cur].command);
  691.     return rval;
  692. }
  693. #endif    /* VMS */
  694.  
  695. #endif    /* PIPES_SUMULATED */
  696.  
  697. NODE *
  698. do_getline(tree)
  699. NODE *tree;
  700. {
  701.     struct redirect *rp = NULL;
  702.     IOBUF *iop;
  703.     int cnt;
  704.     NODE **lhs;
  705.     int redir_error = 0;
  706.     int getline_redirect = 0;
  707.  
  708.     if (tree->rnode == NULL) {     /* no redirection */
  709.         iop = nextfile();
  710.         if (iop == NULL)        /* end of input */
  711.             return tmp_number((AWKNUM) 0.0);
  712.     } else {
  713.         rp = redirect(tree->rnode, &redir_error);
  714.         if (rp == NULL && redir_error)    /* failed redirect */
  715.             return tmp_number((AWKNUM) -1.0);
  716.         iop = rp->iop;
  717.         getline_redirect++;
  718.     }
  719.     if (tree->lnode == NULL) {    /* no optional var. -- read in $0 */
  720.         if (inrec(iop, getline_redirect) != 0)
  721.             return tmp_number((AWKNUM) 0.0);
  722.     } else {            /* read in a named variable */
  723.         char *s = NULL;
  724.         Func_ptr after_assign = NULL;
  725.  
  726.         lhs = get_lhs(tree->lnode, &after_assign);
  727.         cnt = get_a_record(&s, iop, *RS);
  728.         if (!getline_redirect) {
  729.             NR += 1;
  730.             FNR += 1;
  731.         }
  732.         if (cnt == EOF) {
  733.             if (rp) {
  734.                 (void) iop_close(iop);
  735.                 rp->iop = NULL;
  736.             }
  737.             return tmp_number((AWKNUM) 0.0);
  738.         }
  739.         unref(*lhs);
  740.         *lhs = make_string(s, strlen(s));
  741.         /* we may have to regenerate $0 here! */
  742.         if (after_assign)
  743.             (*after_assign)();
  744.     }
  745.     return tmp_number((AWKNUM) 1.0);
  746. }
  747.  
  748. int
  749. pathopen (file)
  750. char *file;
  751. {
  752.     int fd = do_pathopen(file);
  753.  
  754. #ifdef DEFAULT_FILETYPE
  755.     if (!strict && fd <= INVALID_HANDLE) {
  756.         char *file_awk;
  757.         int save = errno;
  758. #ifdef VMS
  759.         int vms_save = vaxc$errno;
  760. #endif
  761.  
  762.         /* append ".awk" and try again */
  763.         emalloc(file_awk, char *, strlen(file) +
  764.             sizeof(DEFAULT_FILETYPE) + 1, "pathopen");
  765.         strcat(strcpy(file_awk, file), DEFAULT_FILETYPE);
  766.         fd = do_pathopen(file_awk);
  767.         free(file_awk);
  768.         if (fd <= INVALID_HANDLE) {
  769.             errno = save;
  770. #ifdef VMS
  771.             vaxc$errno = vms_save;
  772. #endif
  773.         }
  774.     }
  775. #endif    /*DEFAULT_FILETYPE*/
  776.  
  777.     return fd;
  778. }
  779.  
  780. static int
  781. do_pathopen (file)
  782. char *file;
  783. {
  784.     static char *savepath = DEFPATH;    /* defined in config.h */
  785.     static int first = 1;
  786.     char *awkpath, *cp;
  787.     char trypath[BUFSIZ];
  788.     int fd;
  789.  
  790.     if (STREQ(file, "-"))
  791.         return (0);
  792.  
  793.     if (strict)
  794.         return (open (file, 0));
  795.  
  796.     if (first) {
  797.         first = 0;
  798.         if ((awkpath = getenv ("AWKPATH")) != NULL && *awkpath)
  799.             savepath = awkpath;    /* used for restarting */
  800.     }
  801.     awkpath = savepath;
  802.  
  803.     /* some kind of path name, no search */
  804. #ifdef VMS    /* (strchr not equal implies either or both not NULL) */
  805.     if (strchr(file, ':') != strchr(file, ']')
  806.      || strchr(file, '>') != strchr(file, '/'))
  807. #else /*!VMS*/
  808. #ifdef MSDOS
  809.     if (strchr(file, '/') != strchr(file, '\\')
  810.      || strchr(file, ':') != NULL)
  811. #else
  812.     if (strchr(file, '/') != NULL)
  813. #endif    /*MSDOS*/
  814. #endif    /*VMS*/
  815.         return (devopen (file, "r"));
  816.  
  817.     do {
  818.         trypath[0] = '\0';
  819.         /* this should take into account limits on size of trypath */
  820.         for (cp = trypath; *awkpath && *awkpath != ENVSEP; )
  821.             *cp++ = *awkpath++;
  822.  
  823.         if (cp != trypath) {    /* nun-null element in path */
  824.             /* add directory punctuation only if needed */
  825. #ifdef VMS
  826.             if (strchr(":]>/", *(cp-1)) == NULL)
  827. #else
  828. #ifdef MSDOS
  829.             if (strchr(":\\/", *(cp-1)) == NULL)
  830. #else
  831.             if (*(cp-1) != '/')
  832. #endif
  833. #endif
  834.                 *cp++ = '/';
  835.             /* append filename */
  836.             strcpy (cp, file);
  837.         } else
  838.             strcpy (trypath, file);
  839.         if ((fd = devopen (trypath, "r")) >= 0)
  840.             return (fd);
  841.  
  842.         /* no luck, keep going */
  843.         if(*awkpath == ENVSEP && awkpath[1] != '\0')
  844.             awkpath++;    /* skip colon */
  845.     } while (*awkpath);
  846.     /*
  847.      * You might have one of the awk
  848.      * paths defined, WITHOUT the current working directory in it.
  849.      * Therefore try to open the file in the current directory.
  850.      */
  851.     return (devopen(file, "r"));
  852. }
  853.