home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / unix / gawk.sit / source / io.c < prev    next >
Text File  |  1990-09-11  |  18KB  |  849 lines

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