home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 2 / fishmore-publicdomainlibraryvol.ii1991xetec.iso / dirs / gnuawk_406.lzh / GnuAwk / src.lzh / src / awk7.c < prev    next >
C/C++ Source or Header  |  1990-09-27  |  26KB  |  1,142 lines

  1. /*
  2.  * awk7.c - routines for dealing with record input and fields
  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. #include <fcntl.h>
  28. #if defined(MSDOS)
  29. #include "popen.h"
  30. #endif
  31. extern NODE *concat_exp();
  32.  
  33. static void do_file();
  34. static int get_rs();
  35. static IOBUF *nextfile();
  36. static int re_split();
  37. static int get_a_record();
  38. static int iop_close();
  39. static IOBUF *iop_alloc();
  40. static void close_one();
  41. static int close_fp();
  42.  
  43. static int getline_redirect = 0;/* "getline <file" being executed */
  44. static char *line_buf = NULL;    /* holds current input line */
  45. static int line_alloc = 0;    /* current allocation for line_buf */
  46. static char *parse_extent;    /* marks where to restart parse of record */
  47. static int parse_high_water=0;    /* field number that we have parsed so far */
  48. static char f_empty[] = "";
  49. static char *save_fs = " ";    /* save current value of FS when line is read,
  50.                  * to be used in deferred parsing
  51.                  */
  52.  
  53. extern NODE *ARGC_node;
  54. extern NODE *ARGV_node;
  55.  
  56. int field_num;            /* save number of field in get_lhs */
  57. NODE **fields_arr;        /* array of pointers to the field nodes */
  58. NODE node0;            /* node for $0 which never gets free'd */
  59. int node0_valid = 1;        /* $(>0) has not been changed yet */
  60.  
  61. void
  62. init_fields()
  63. {
  64.     emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
  65.     node0.type = Node_val;
  66.     node0.stref = 0;
  67.     node0.flags = (STR|PERM);    /* never free buf */
  68.     fields_arr[0] = &node0;
  69. }
  70.  
  71. /*
  72.  * Danger!  Must only be called for fields we know have just been blanked, or
  73.  * fields we know don't exist yet.  
  74.  */
  75.  
  76. /*ARGSUSED*/
  77. static void
  78. set_field(num, str, len, dummy)
  79. int num;
  80. char *str;
  81. int len;
  82. NODE *dummy;    /* not used -- just to make interface same as set_element */
  83. {
  84.     NODE *n;
  85.     int t;
  86.     static int nf_high_water = 0;
  87.  
  88.     if (num > nf_high_water) {
  89.         erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
  90.         nf_high_water = num;
  91.     }
  92.     /* fill in fields that don't exist */
  93.     for (t = parse_high_water + 1; t < num; t++)
  94.         fields_arr[t] = Nnull_string;
  95.     n = make_string(str, len);
  96.     fields_arr[num] = n;
  97.     parse_high_water = num;
  98. }
  99.  
  100. /* Someone assigned a value to $(something).  Fix up $0 to be right */
  101. static void
  102. rebuild_record()
  103. {
  104.     register int tlen;
  105.     register NODE *tmp;
  106.     NODE *ofs;
  107.     char *ops;
  108.     register char *cops;
  109.     register NODE **ptr, **maxp;
  110.  
  111.     maxp = 0;
  112.     tlen = 0;
  113.     ofs = force_string(OFS_node->var_value);
  114.     ptr = &fields_arr[parse_high_water];
  115.     while (ptr > &fields_arr[0]) {
  116.         tmp = force_string(*ptr);
  117.         tlen += tmp->stlen;
  118.         if (tmp->stlen && !maxp)
  119.             maxp = ptr;
  120.         ptr--;
  121.     }
  122.     if (maxp) {
  123.         tlen += ((maxp - fields_arr) - 1) * ofs->stlen;
  124.         emalloc(ops, char *, tlen + 1, "fix_fields");
  125.         cops = ops;
  126.         for (ptr = &fields_arr[1]; ptr <= maxp; ptr++) {
  127.             tmp = force_string(*ptr);
  128.             bcopy(tmp->stptr, cops, tmp->stlen);
  129.             cops += tmp->stlen;
  130.             if (ptr != maxp) {
  131.                 bcopy(ofs->stptr, cops, ofs->stlen);
  132.                 cops += ofs->stlen;
  133.             }
  134.         }
  135.     } else
  136.         ops = "";
  137.     tmp = make_string(ops, tlen);
  138.     deref = fields_arr[0];
  139.     do_deref();
  140.     fields_arr[0] = tmp;
  141. }
  142.  
  143. #ifndef SLOWIO
  144. #define    DO_END_OF_BUF    len = bp - start;\
  145.             while (len > iop->secsiz) {\
  146.                 erealloc(iop->secbuf, char *, iop->secsiz *= 2, "get");\
  147.             }\
  148.             bcopy(start, iop->secbuf, len);\
  149.             start = iop->secbuf;\
  150.             last = start + len;\
  151.             iop->cnt = read(iop->fd, iop->buf, iop->size);\
  152.             if (iop->cnt < 0)\
  153.                 return iop->cnt;\
  154.             end_data = iop->buf + iop->cnt;\
  155.             iop->off = bp = iop->buf;
  156.  
  157. #define    DO_END_OF_DATA    iop->cnt = read(iop->fd, end_data, end_buf - end_data);\
  158.             if (iop->cnt < 0)\
  159.                 return iop->cnt;\
  160.             end_data += iop->cnt;\
  161.             if (iop->cnt == 0)\
  162.                 break;\
  163.             iop->cnt = end_data - iop->buf;
  164.  
  165. static int
  166. get_a_record(res, iop)
  167. char **res;
  168. IOBUF *iop;
  169. {
  170.     register char *end_data;
  171.     register char *end_buf;
  172.     char *start;
  173.     register char *bp;
  174.     char *last;
  175.     int len;
  176.     register char rs = get_rs();
  177.  
  178.     end_data = iop->buf + iop->cnt;
  179.     if (iop->off >= end_data) {
  180.         iop->cnt = read(iop->fd, iop->buf, iop->size);
  181.         if (iop->cnt <= 0)
  182.             return iop->cnt = EOF;
  183.         end_data = iop->buf + iop->cnt;
  184.         iop->off = iop->buf;
  185.     }
  186.     start = bp = iop->off;
  187.     end_buf = iop->buf + iop->size;
  188.     if (rs == 0) {
  189.         while (!(*bp == '\n' && bp != iop->buf && bp[-1] == '\n')) {
  190.             if (++bp == end_buf) {
  191.                 DO_END_OF_BUF
  192.             }
  193.             if (bp == end_data) {
  194.                 DO_END_OF_DATA
  195.             }
  196.         }
  197.         if (*bp == '\n' && bp != start && bp[-1] == '\n')
  198.             bp--;
  199.         else if (bp != iop->buf && bp[-1] != '\n')
  200.             warning("record not terminated");
  201.         else
  202.             bp--;
  203.         iop->off = bp + 2;
  204.     } else {
  205.         while (*bp++ != rs) {
  206.             if (bp == end_buf) {
  207.                 DO_END_OF_BUF
  208.             }
  209.             if (bp == end_data) {
  210.                 DO_END_OF_DATA
  211.             }
  212.         }
  213.         if (*--bp != rs) {
  214.             warning("record not terminated");
  215.             bp++;
  216.         }
  217.         iop->off = bp + 1;
  218.     }
  219.     if (start == iop->secbuf) {
  220.         len = bp - iop->buf;
  221.         while (len > iop->secsiz) {
  222.             erealloc(iop->secbuf, char *, iop->secsiz *= 2, "get2");
  223.         }
  224.         bcopy(iop->buf, last, len);
  225.         bp = last + len;
  226.     }
  227.     *bp = '\0';
  228.     *res = start;
  229.     return bp - start;
  230. }
  231. #endif
  232.  
  233. /*
  234.  * This reads in a record from the input file
  235.  */
  236. static int
  237. inrec(iop)
  238. IOBUF *iop;
  239. {
  240.     int cnt;
  241.     int retval = 0;
  242.  
  243. #ifndef SLOWIO
  244.     cnt = get_a_record(&line_buf, iop);
  245. #else
  246.     cnt = get_a_record(fp, &line_buf, &line_alloc);
  247. #endif
  248.     if (cnt == EOF) {
  249.         cnt = 0;
  250.         retval = 1;
  251.     } else {
  252.         if (!getline_redirect) {
  253.             assign_number(&NR_node->var_value,
  254.                 NR_node->var_value->numbr + 1.0);
  255.             assign_number(&FNR_node->var_value,
  256.                 FNR_node->var_value->numbr + 1.0);
  257.         }
  258.     }
  259.     set_record(line_buf, cnt);
  260.  
  261.     return retval;
  262. }
  263.  
  264. /*
  265.  * setup $0, but defer parsing rest of line until reference is made to $(>0)
  266.  * or to NF.  At that point, parse only as much as necessary.
  267.  */
  268. void
  269. set_record(buf, cnt)
  270. char *buf;
  271. int cnt;
  272. {
  273.     register int i;
  274.  
  275.     assign_number(&NF_node->var_value, (AWKNUM)-1);
  276.     for (i = 1; i <= parse_high_water; i++) {
  277.         deref = fields_arr[i];
  278.         do_deref();
  279.     }
  280.     parse_high_water = 0;
  281.     node0_valid = 1;
  282.     if (buf == line_buf) {
  283.         deref = fields_arr[0];
  284.         do_deref();
  285.         save_fs = get_fs();
  286.         node0.type = Node_val;
  287.         node0.stptr = buf;
  288.         node0.stlen = cnt;
  289.         node0.stref = 1;
  290.         node0.flags = (STR|PERM);    /* never free buf */
  291.         fields_arr[0] = &node0;
  292.     }
  293. }
  294.  
  295. NODE **
  296. get_field(num, assign)
  297. int num;
  298. int assign;    /* this field is on the LHS of an assign */
  299. {
  300.     int n;
  301.  
  302.     /*
  303.      * if requesting whole line but some other field has been altered,
  304.      * then the whole line must be rebuilt
  305.      */
  306.     if (num == 0 && node0_valid == 0) {
  307.         /* first, parse remainder of input record */
  308.         n = parse_fields(HUGE-1, &parse_extent,
  309.             node0.stlen - (parse_extent - node0.stptr),
  310.             save_fs, set_field, (NODE *)NULL);
  311.         assign_number(&NF_node->var_value, (AWKNUM)n);
  312.         rebuild_record();
  313.         return &fields_arr[0];
  314.     }
  315.     if (num > 0 && assign)
  316.         node0_valid = 0;
  317.     if (num <= parse_high_water)    /* we have already parsed this field */
  318.         return &fields_arr[num];
  319.     if (parse_high_water == 0 && num > 0)    /* starting at the beginning */
  320.         parse_extent = fields_arr[0]->stptr;
  321.     /*
  322.      * parse up to num fields, calling set_field() for each, and saving
  323.      * in parse_extent the point where the parse left off
  324.      */
  325.     n = parse_fields(num, &parse_extent,
  326.         fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
  327.         save_fs, set_field, (NODE *)NULL);
  328.     if (num == HUGE-1)
  329.         num = n;
  330.     if (n < num) {    /* requested field number beyond end of record;
  331.              * set_field will just extend the number of fields,
  332.              * with empty fields
  333.              */
  334.         set_field(num, f_empty, 0, (NODE *) NULL);
  335.         /*
  336.          * if this field is onthe LHS of an assignment, then we want to
  337.          * set NF to this value, below
  338.          */
  339.         if (assign)
  340.             n = num;
  341.     }
  342.     /*
  343.      * if we reached the end of the record, set NF to the number of fields
  344.      * so far.  Note that num might actually refer to a field that
  345.      * is beyond the end of the record, but we won't set NF to that value at
  346.      * this point, since this is only a reference to the field and NF
  347.      * only gets set if the field is assigned to -- in this case n has
  348.      * been set to num above
  349.      */
  350.     if (*parse_extent == '\0')
  351.         assign_number(&NF_node->var_value, (AWKNUM)n);
  352.  
  353.     return &fields_arr[num];
  354. }
  355.  
  356. /*
  357.  * this is called both from get_field() and from do_split()
  358.  */
  359. int
  360. parse_fields(up_to, buf, len, fs, set, n)
  361. int up_to;    /* parse only up to this field number */
  362. char **buf;    /* on input: string to parse; on output: point to start next */
  363. int len;
  364. register char *fs;
  365. void (*set) ();    /* routine to set the value of the parsed field */
  366. NODE *n;
  367. {
  368.     char *s = *buf;
  369.     register char *field;
  370.     register char *scan;
  371.     register char *end = s + len;
  372.     int NF = parse_high_water;
  373.  
  374.     if (up_to == HUGE)
  375.         NF = 0;
  376.     if (*fs && *(fs + 1) != '\0') {    /* fs is a regexp */
  377.         struct re_registers reregs;
  378.  
  379.         scan = s;
  380.         while (re_split(scan, end - scan, fs, &reregs) != -1 &&
  381.             NF < up_to) {
  382.             (*set)(++NF, scan, reregs.start[0], n);
  383.             scan += reregs.end[0];
  384.         }
  385.         if (NF != up_to && scan <= end) {
  386.             (*set)(++NF, scan, end - scan, n);
  387.             scan = end;
  388.         }
  389.         *buf = scan;
  390.         return (NF);
  391.     }
  392.     for (scan = s; scan < end && NF < up_to; scan++) {
  393.         /*
  394.          * special case:  fs is single space, strip leading
  395.          * whitespace 
  396.          */
  397.         if (*fs == ' ') {
  398.             while ((*scan == ' ' || *scan == '\t') && scan < end)
  399.                 scan++;
  400.             if (scan >= end)
  401.                 break;
  402.         }
  403.         field = scan;
  404.         if (*fs == ' ')
  405.             while (*scan != ' ' && *scan != '\t' && scan < end)
  406.                 scan++;
  407.         else {
  408.             while (*scan != *fs && scan < end)
  409.                 scan++;
  410.             if (scan == end-1 && *scan == *fs) {
  411.                 (*set)(++NF, field, scan - field, n);
  412.                 field = scan;
  413.             }
  414.         }
  415.         (*set)(++NF, field, scan - field, n);
  416.         if (scan == end)
  417.             break;
  418.     }
  419.     *buf = scan;
  420.     return NF;
  421. }
  422.  
  423. static int
  424. re_split(buf, len, fs, reregs)
  425. char *buf, *fs;
  426. int len;
  427. struct re_registers *reregs;
  428. {
  429.     typedef struct re_pattern_buffer RPAT;
  430.     static RPAT *rp;
  431.     static char *last_fs = NULL;
  432.  
  433.     if ((last_fs != NULL && !STREQ(fs, last_fs))
  434.         || (rp && ! strict && ((IGNORECASE_node->var_value->numbr != 0)
  435.              ^ (rp->translate != NULL))))
  436.     {
  437.         /* fs has changed or IGNORECASE has changed */
  438.         free(rp->buffer);
  439.         free(rp->fastmap);
  440.         free((char *) rp);
  441.         free(last_fs);
  442.         last_fs = NULL;
  443.     }
  444.     if (last_fs == NULL) {    /* first time */
  445.         emalloc(rp, RPAT *, sizeof(RPAT), "re_split");
  446.         bzero((char *) rp, sizeof(RPAT));
  447.         emalloc(rp->buffer, char *, 8, "re_split");
  448.         rp->allocated = 8;
  449.         emalloc(rp->fastmap, char *, 256, "re_split");
  450.         emalloc(last_fs, char *, strlen(fs) + 1, "re_split");
  451.         (void) strcpy(last_fs, fs);
  452.         if (! strict && IGNORECASE_node->var_value->numbr != 0.0)
  453.             rp->translate = casetable;
  454.         else
  455.             rp->translate = NULL;
  456.         if (re_compile_pattern(fs, strlen(fs), rp) != NULL)
  457.             fatal("illegal regular expression for FS: `%s'", fs);
  458.     }
  459.     return re_search(rp, buf, len, 0, len, reregs);
  460. }
  461.  
  462. #ifdef SLOWIO
  463. static int                /* count of chars read or EOF */
  464. get_a_record(fp, bp, sizep)
  465. FILE *fp;
  466. char **bp;            /* *bp points to beginning of line on return */
  467. int *sizep;            /* *sizep is current allocation of *bp */
  468. {
  469.     register char *buf;    /* buffer; realloced if necessary */
  470.     int bsz;        /* current buffer size */
  471.     register char *cur;    /* current position in buffer */
  472.     register char *buf_end;    /* end of buffer */
  473.     register int rs;    /* rs is the current record separator */
  474.     register int c;
  475.  
  476.     bsz = *sizep;
  477.     buf = *bp;
  478.     if (!buf) {
  479.         emalloc(buf, char *, 128, "get_a_record");
  480.         bsz = 128;
  481.     }
  482.     rs = get_rs();
  483.     buf_end = buf + bsz;
  484.     cur = buf;
  485.     if (rs == 0) {
  486.         while ((c = getc(fp)) != EOF) {
  487.             if (c == '\n' && cur != buf && cur[-1] == '\n') {
  488.             cur--;
  489.             break;
  490.         }
  491.         *cur++ = c;
  492.         if (cur == buf_end) {
  493.             erealloc(buf, char *, bsz * 2, "get_a_record");
  494.             cur = buf + bsz;
  495.             bsz *= 2;
  496.             buf_end = buf + bsz;
  497.         }
  498.     }
  499.         if (c == EOF && cur != buf && cur[-1] == '\n')
  500.         cur--;
  501.     } else {
  502.         while ((c = getc(fp)) != EOF) {
  503.             if (c == rs)
  504.                 break;
  505.             *cur++ = c;
  506.             if (cur == buf_end) {
  507.                 erealloc(buf, char *, bsz * 2, "get_a_record");
  508.                 cur = buf + bsz;
  509.                 bsz *= 2;
  510.                 buf_end = buf + bsz;
  511.             }
  512.         }
  513.     }
  514.     *cur = '\0';
  515.     *bp = buf;
  516.     *sizep = bsz;
  517.     if (c == EOF && cur == buf)
  518.         return EOF;
  519.     return cur - buf;
  520. }
  521. #endif
  522.  
  523. NODE *
  524. do_getline(tree)
  525. NODE *tree;
  526. {
  527.     IOBUF *iop;
  528.     int cnt;
  529.     NODE **lhs;
  530.     int redir_error = 0;
  531.  
  532.     if (tree->rnode == NULL) {     /* no redirection */
  533.         iop = nextfile();
  534.         if (iop == NULL)        /* end of input */
  535.             return tmp_number((AWKNUM) 0.0);
  536.     }
  537.     if (tree->rnode != NULL) {    /* with redirection */
  538.         iop = redirect(tree->rnode, &redir_error)->iop;
  539.         if (iop == NULL && redir_error)    /* failed redirect */
  540.             return tmp_number((AWKNUM) -1.0);
  541.         getline_redirect++;
  542.     }
  543.     if (tree->lnode == NULL) {    /* no optional var. -- read in $0 */
  544.         if (inrec(iop) != 0) {
  545.             getline_redirect = 0;
  546.             return tmp_number((AWKNUM) 0.0);
  547.         }
  548.     } else {            /* read in a named variable */
  549.         char *s = NULL;
  550.         int n = 0;
  551.  
  552.         lhs = get_lhs(tree->lnode, 1);
  553. #ifdef SLOWIO
  554.         cnt = get_a_record(fp, &s, &n);
  555. #else
  556.         cnt = get_a_record(&s, iop);
  557. #endif
  558.         if (!getline_redirect) {
  559.             assign_number(&NR_node->var_value,
  560.                 NR_node->var_value->numbr + 1.0);
  561.             assign_number(&FNR_node->var_value,
  562.                 FNR_node->var_value->numbr + 1.0);
  563.         }
  564.         if (cnt == EOF) {
  565.             getline_redirect = 0;
  566.             free(s);
  567.             return tmp_number((AWKNUM) 0.0);
  568.         }
  569.         *lhs = make_string(s, strlen(s));
  570.         /*free(s);*/
  571.         do_deref();
  572.         /* we may have to regenerate $0 here! */
  573.         if (field_num == 0)
  574.             set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
  575.         field_num = -1;
  576.     }
  577.     getline_redirect = 0;
  578.     return tmp_number((AWKNUM) 1.0);
  579. }
  580.  
  581. /*
  582.  * We can't dereference a variable until after we've given it its new value.
  583.  * This variable points to the value we have to free up 
  584.  */
  585. NODE *deref;
  586.  
  587. /*
  588.  * This returns a POINTER to a node pointer. get_lhs(ptr) is the current
  589.  * value of the var, or where to store the var's new value 
  590.  */
  591.  
  592. NODE **
  593. get_lhs(ptr, assign)
  594. NODE *ptr;
  595. int assign;        /* this is being called for the LHS of an assign. */
  596. {
  597.     register NODE **aptr;
  598.     NODE *n;
  599.  
  600. #ifdef DEBUG
  601.     if (ptr == NULL)
  602.         cant_happen();
  603. #endif
  604.     deref = NULL;
  605.     field_num = -1;
  606.     switch (ptr->type) {
  607.     case Node_var:
  608.     case Node_var_array:
  609.         if (ptr == NF_node && (int) NF_node->var_value->numbr == -1)
  610.             (void) get_field(HUGE-1, assign); /* parse record */
  611.         deref = ptr->var_value;
  612. #ifdef DEBUG
  613.         if (deref->type != Node_val)
  614.             cant_happen();
  615.         if (deref->flags == 0)
  616.             cant_happen();
  617. #endif
  618.         return &(ptr->var_value);
  619.  
  620.     case Node_param_list:
  621.         n = stack_ptr[ptr->param_cnt];
  622. #ifdef DEBUG
  623.         deref = n->var_value;
  624.         if (deref->type != Node_val)
  625.             cant_happen();
  626.         if (deref->flags == 0)
  627.             cant_happen();
  628.         deref = 0;
  629. #endif
  630.         return &(n->var_value);
  631.  
  632.     case Node_field_spec:
  633.         field_num = (int) force_number(tree_eval(ptr->lnode));
  634.         free_result();
  635.         if (field_num < 0)
  636.             fatal("attempt to access field %d", field_num);
  637.         aptr = get_field(field_num, assign);
  638.         deref = *aptr;
  639.         return aptr;
  640.  
  641.     case Node_subscript:
  642.         n = ptr->lnode;
  643.         if (n->type == Node_param_list)
  644.             n = stack_ptr[n->param_cnt];
  645.         aptr = assoc_lookup(n, concat_exp(ptr->rnode));
  646.         deref = *aptr;
  647. #ifdef DEBUG
  648.         if (deref->type != Node_val)
  649.             cant_happen();
  650.         if (deref->flags == 0)
  651.             cant_happen();
  652. #endif
  653.         return aptr;
  654.     case Node_func:
  655.         fatal ("`%s' is a function, assignment is not allowed",
  656.             ptr->lnode->param);
  657.     }
  658.     return 0;
  659. }
  660.  
  661. void
  662. do_deref()
  663. {
  664.     if (deref == NULL)
  665.         return;
  666.     if (deref == Nnull_string) {
  667.         deref = 0;
  668.         return;
  669.     }
  670. #ifdef DEBUG
  671.     if (deref->flags == 0)
  672.         cant_happen();
  673. #endif
  674.     if ((deref->flags & MALLOC) || (deref->flags & TEMP)) {
  675. #ifdef DEBUG
  676.         if (deref->flags & PERM)
  677.             cant_happen();
  678. #endif
  679.         if (deref->flags & STR) {
  680.             if (deref->stref > 0 && deref->stref != 255)
  681.                 deref->stref--;
  682.             if (deref->stref > 0) {
  683.                 deref->flags &= ~TEMP;
  684.                 deref = 0;
  685.                 return;
  686.             }
  687.             free(deref->stptr);
  688.         }
  689.         freenode(deref);
  690.     }
  691.     deref = 0;
  692. }
  693.  
  694. static IOBUF *
  695. nextfile()
  696. {
  697.     static int i = 1;
  698.     static int files = 0;
  699.     static IOBUF *curfile = NULL;
  700.     char *arg;
  701.     char *cp;
  702.     int fd = -1;
  703.  
  704.     if (curfile != NULL && curfile->cnt != EOF)
  705.         return curfile;
  706.     for (; i < (int) (ARGC_node->lnode->numbr); i++) {
  707.         arg = (*assoc_lookup(ARGV_node, tmp_number((AWKNUM) i)))->stptr;
  708.         if (*arg == '\0')
  709.             continue;
  710.         cp = index(arg, '=');
  711.         if (cp != NULL) {
  712.             *cp++ = '\0';
  713.             variable(arg)->var_value = make_string(cp, strlen(cp));
  714.             *--cp = '=';    /* restore original text of ARGV */
  715.         } else {
  716.             files++;
  717.             if (STREQ(arg, "-"))
  718.                 fd = 0;
  719.             else
  720.                 fd = open(arg, O_RDONLY);
  721.             if (fd == -1)
  722.                 fatal("cannot open file `%s' for reading (%s)",
  723.                     arg, sys_errlist[errno]);
  724.                 /* NOTREACHED */
  725.             /* This is a kludge.  */
  726.             deref = FILENAME_node->var_value;
  727.             do_deref();
  728.             FILENAME_node->var_value =
  729.                 make_string(arg, strlen(arg));
  730.             FNR_node->var_value->numbr = 0.0;
  731.             i++;
  732.             break;
  733.         }
  734.     }
  735.     if (files == 0) {
  736.         files++;
  737.         /* no args. -- use stdin */
  738.         /* FILENAME is init'ed to "-" */
  739.         /* FNR is init'ed to 0 */
  740.         fd = 0;
  741.     }
  742.     if (fd == -1)
  743.         return NULL;
  744.     return curfile = iop_alloc(fd);
  745. }
  746.  
  747. static IOBUF *
  748. iop_alloc(fd)
  749. int fd;
  750. {
  751.     IOBUF *iop;
  752. /* rlp900927 -- moved stb declaration inside #if, below */
  753.  
  754.     /*
  755.      * System V doesn't have the file system block size in the
  756.      * stat structure. So we have to make some sort of reasonable
  757.      * guess. We use stdio's BUFSIZ, since that what it was
  758.      * meant for in the first place.
  759.      */
  760. #if defined(USG) || defined(MSDOS)
  761. #define    DEFBLKSIZE    BUFSIZ
  762. #else
  763.     struct stat stb;
  764. #define DEFBLKSIZE    stb.st_blksize
  765. #endif
  766.  
  767.     if (fd == -1)
  768.         return NULL;
  769.     emalloc(iop, IOBUF *, sizeof(IOBUF), "nextfile");
  770. /*** APPEND AFTER 768 IN x:awk7.c ***/
  771. #ifdef AMIGA
  772.     iop->size = DEFBLKSIZE;
  773. #else
  774. /*** APPEND AFTER 768 IN x:awk7.c ***/
  775.     if (isatty(fd))
  776.         iop->size = 128;
  777.     else if (fstat(fd, &stb) == -1)
  778.         fatal("can't stat fd %d", fd);
  779.     else if (lseek(fd, 0L, 0) == -1)
  780.         iop->size = DEFBLKSIZE;
  781.     else
  782.         iop->size = stb.st_size < DEFBLKSIZE ?
  783.                 stb.st_size+1 : DEFBLKSIZE;
  784. /*** APPEND AFTER 777 IN x:awk7.c ***/
  785. #endif
  786. /*** APPEND AFTER 777 IN x:awk7.c ***/
  787.     errno = 0;
  788.     iop->fd = fd;
  789.     emalloc(iop->buf, char *, iop->size, "nextfile");
  790.     iop->off = iop->buf;
  791.     iop->cnt = 0;
  792. /*** CHANGE 783 IN x:awk7.c TO [787,791] IN awk7.c ***/
  793. #ifdef AMIGA /* I don't completely understand this but it seems to work */
  794.     iop->secsiz = iop->size;
  795. #else
  796.     iop->secsiz = iop->size < 128 ? iop->size : 128; 
  797. #endif
  798. /*** CHANGE 783 IN x:awk7.c TO [787,791] IN awk7.c ***/
  799.     emalloc(iop->secbuf, char *, iop->secsiz, "nextfile");
  800.     return iop;
  801. }
  802.  
  803. void
  804. do_input()
  805. {
  806.     IOBUF *iop;
  807.     extern int exiting;
  808.  
  809.     while ((iop = nextfile()) != NULL) {
  810.         do_file(iop);
  811.         if (exiting)
  812.             break;
  813.     }
  814. }
  815.  
  816. static int
  817. iop_close(iop)
  818. IOBUF *iop;
  819. {
  820.     int ret;
  821.  
  822.     ret = close(iop->fd);
  823.     if (ret == -1)
  824.         warning("close of fd %d failed");
  825.     free(iop->buf);
  826.     free(iop->secbuf);
  827.     free((char *)iop);
  828.     return ret == -1 ? 1 : 0;
  829. }
  830.  
  831. static void
  832. do_file(iop)
  833. IOBUF *iop;
  834. {
  835.     /* This is where it spends all its time.  The infamous MAIN LOOP */
  836.     if (inrec(iop) == 0)
  837.         while (interpret(expression_value) && inrec(iop) == 0)
  838.             ;
  839.     (void) iop_close(iop);
  840. }
  841.  
  842. static int
  843. get_rs()
  844. {
  845.     register NODE *tmp;
  846.  
  847.     tmp = force_string(RS_node->var_value);
  848.     if (tmp->stlen == 0)
  849.         return 0;
  850.     return (int) *(tmp->stptr);
  851. }
  852. struct redirect *red_head = NULL;
  853.  
  854. /* Redirection for printf and print commands */
  855. struct redirect *
  856. redirect(tree, errflg)
  857. NODE *tree;
  858. int *errflg;
  859. {
  860.     register NODE *tmp;
  861.     register struct redirect *rp;
  862.     register char *str;
  863.     register FILE *fp;
  864.     int tflag;
  865.     char *direction = "to";
  866.  
  867.     tflag = 0;
  868.     switch (tree->type) {
  869.     case Node_redirect_append:
  870.         tflag = RED_APPEND;
  871.     case Node_redirect_output:
  872.         tflag |= (RED_FILE|RED_WRITE);
  873.         break;
  874.     case Node_redirect_pipe:
  875.         tflag = (RED_PIPE|RED_WRITE);
  876.         break;
  877.     case Node_redirect_pipein:
  878.         tflag = (RED_PIPE|RED_READ);
  879.         break;
  880.     case Node_redirect_input:
  881.         tflag = (RED_FILE|RED_READ);
  882.         break;
  883.     default:
  884.         fatal ("invalid tree type %d in redirect()\n", tree->type);
  885.         break;
  886.     }
  887.     tmp = force_string(tree_eval(tree->subnode));
  888.     str = tmp->stptr;
  889.     for (rp = red_head; rp != NULL; rp = rp->next)
  890.         if (rp->flag == tflag && STREQ(rp->value, str))
  891.             break;
  892.     if (rp == NULL) {
  893.         emalloc(rp, struct redirect *, sizeof(struct redirect),
  894.             "redirect");
  895.         emalloc(str, char *, strlen(tmp->stptr)+1, "redirect");
  896.         (void) strcpy(str, tmp->stptr);
  897.         rp->value = str;
  898.         rp->flag = tflag;
  899.         rp->offset = 0;
  900.         rp->fp = NULL;
  901.         rp->iop = NULL;
  902.         /* maintain list in most-recently-used first order */
  903.         if (red_head)
  904.             red_head->prev = rp;
  905.         rp->prev = NULL;
  906.         rp->next = red_head;
  907.         red_head = rp;
  908.     }
  909.     while (rp->fp == NULL && rp->iop == NULL) {
  910.         errno = 0;
  911.         switch (tree->type) {
  912.         case Node_redirect_output:
  913.             fp = rp->fp = fdopen(devopen(str, "w"), "w");
  914.             break;
  915.         case Node_redirect_append:
  916.             fp = rp->fp = fdopen(devopen(str, "a"), "a");
  917.             break;
  918. /*** APPEND AFTER 902 IN x:awk7.c ***/
  919. #ifndef AMIGA /* we don't know how to do this do we Amy */
  920. /*** APPEND AFTER 902 IN x:awk7.c ***/
  921.         case Node_redirect_pipe:
  922.             fp = rp->fp = popen(str, "w");
  923.             break;
  924.         case Node_redirect_pipein:
  925.             direction = "from";
  926.             /* this should bypass popen() */
  927.             rp->iop = iop_alloc(fileno(popen(str, "r")));
  928.             break;
  929. /*** APPEND AFTER 910 IN x:awk7.c ***/
  930. #endif
  931. /*** APPEND AFTER 910 IN x:awk7.c ***/
  932.         case Node_redirect_input:
  933.             direction = "from";
  934.             rp->iop = iop_alloc(devopen(str, "r"));
  935.             break;
  936.         }
  937.         if (fp == NULL && rp->iop == NULL) {
  938.             /* too many files open -- close one and try again */
  939.             if (errno == ENFILE || errno == EMFILE)
  940.                 close_one();
  941.             else {
  942.                 /*
  943.                  * Some other reason for failure.
  944.                  *
  945.                  * On redirection of input from a file,
  946.                  * just return an error, so e.g. getline
  947.                  * can return -1.  For output to file,
  948.                  * complain. The shell will complain on
  949.                  * a bad command to a pipe.
  950.                  */
  951.                 *errflg = 1;
  952.                 if (tree->type == Node_redirect_output
  953.                     || tree->type == Node_redirect_append)
  954.                     fatal("can't redirect %s `%s'\n",
  955.                         direction, str);
  956.                 else
  957.                     return NULL;
  958.             }
  959.         }
  960.     }
  961.     if (rp->offset != 0)    /* this file was previously open */
  962.         if (fseek(fp, rp->offset, 0) == -1)
  963.             fatal("can't seek to %ld on `%s'\n", rp->offset, str);
  964. #ifdef notdef
  965.     (void) flush_io();    /* a la SVR4 awk */
  966. #endif
  967.     free_temp(tmp);
  968.     return rp;
  969. }
  970.  
  971. static void
  972. close_one()
  973. {
  974.     register struct redirect *rp;
  975.     register struct redirect *rplast;
  976.  
  977.     /* go to end of list first, to pick up least recently used entry */
  978.     for (rp = red_head; rp != NULL; rp = rp->next)
  979.         rplast = rp;
  980.     /* now work back up through the list */
  981.     for (rp = rplast; rp != NULL; rp = rp->prev)
  982.         if (rp->fp && (rp->flag & RED_FILE)) {
  983.             rp->offset = ftell(rp->fp);
  984.             if (fclose(rp->fp))
  985.                 warning("close of \"%s\" failed (%s).",
  986.                     rp->value, sys_errlist[errno]);
  987.             rp->fp = NULL;
  988.             break;
  989.         }
  990.     if (rp == NULL)
  991.         /* surely this is the only reason ??? */
  992.         fatal("too many pipes or input files open"); 
  993. }
  994.  
  995. NODE *
  996. do_close(tree)
  997. NODE *tree;
  998. {
  999.     NODE *tmp;
  1000.     register struct redirect *rp;
  1001.  
  1002.     tmp = force_string(tree_eval(tree->subnode));
  1003.     for (rp = red_head; rp != NULL; rp = rp->next) {
  1004.         if (STREQ(rp->value, tmp->stptr))
  1005.             break;
  1006.     }
  1007.     free_temp(tmp);
  1008.     if (rp == NULL) /* no match */
  1009.         return tmp_number((AWKNUM) 0.0);
  1010.     return tmp_number((AWKNUM)close_fp(rp));
  1011. }
  1012.  
  1013. static int
  1014. close_fp(rp)
  1015. register struct redirect *rp;
  1016. {
  1017.     int status;
  1018.  
  1019.     if (rp->flag == (RED_PIPE|RED_WRITE))
  1020.         status = pclose(rp->fp);
  1021.     else
  1022.     if (rp->fp)
  1023.         status = fclose(rp->fp);
  1024.     else if (rp->iop)
  1025.         status = iop_close(rp->iop);
  1026.  
  1027.     /* SVR4 awk checks and warns about status of close */
  1028.     if (status)
  1029.         warning("%s close of \"%s\" failed (%s).",
  1030.             (rp->flag & RED_PIPE) ? "pipe" :
  1031.                 "file", rp->value,
  1032.             sys_errlist[errno]);
  1033.     if (rp->prev)
  1034.         rp->prev->next = rp->next;
  1035.     else
  1036.         red_head = rp->next;
  1037.     free(rp->value);
  1038.     free((char *)rp);
  1039.     return status;
  1040. }
  1041.  
  1042. int
  1043. flush_io ()
  1044. {
  1045.     register struct redirect *rp;
  1046.     int status = 0;
  1047.  
  1048.     if (fflush(stdout)) {
  1049.         warning("error writing standard output.");
  1050.         status++;
  1051.     }
  1052.     if (fflush(stderr)) {
  1053.         warning("error writing standard error.");
  1054.         status++;
  1055.     }
  1056.     for (rp = red_head; rp != NULL; rp = rp->next)
  1057.         /* flush both files and pipes, what the heck */
  1058.         if ((rp->flag & RED_WRITE) && rp->fp != NULL)
  1059.             if (fflush(rp->fp)) {
  1060.                 warning( "%s flush of \"%s\" failed (%s).",
  1061.                     (rp->flag  & RED_PIPE) ? "pipe" :
  1062.                     "file", rp->value, sys_errlist[errno]);
  1063.                 status++;
  1064.             }
  1065.     return status;
  1066. }
  1067.  
  1068. int
  1069. close_io ()
  1070. {
  1071.     register struct redirect *rp;
  1072.     int status = 0;
  1073.  
  1074.     for (rp = red_head; rp != NULL; rp = rp->next)
  1075.         if ((rp->fp && close_fp(rp)) || (rp->iop && iop_close(rp->iop)))
  1076.             status++;
  1077.     return status;
  1078. }
  1079.  
  1080. /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
  1081. int
  1082. devopen (name, mode)
  1083. char *name, *mode;
  1084. {
  1085.     int openfd = -1;
  1086.     FILE *fdopen ();
  1087.     char *cp;
  1088.     int flag;
  1089.  
  1090.     switch(mode[0]) {
  1091.     case 'r':    flag = O_RDONLY;
  1092.             break;
  1093.  
  1094.     case 'w':    flag = O_WRONLY|O_CREAT|O_TRUNC;
  1095.             break;
  1096.  
  1097.     case 'a':    flag = O_WRONLY|O_APPEND|O_CREAT;
  1098.             break;
  1099.     }
  1100.  
  1101. #if defined(STRICT) || defined(NO_DEV_FD)
  1102.     return (open (name, flag, 0666));
  1103. #else
  1104.     if (strict)
  1105.         return (open (name, flag, 0666));
  1106.  
  1107.     if (!STREQN (name, "/dev/", 5))
  1108.         return (open (name, flag, 0666));
  1109.     else
  1110.         cp = name + 5;
  1111.         
  1112.     /* XXX - first three tests ignore mode */
  1113.     if (STREQ(cp, "stdin"))
  1114.         return (0);
  1115.     else if (STREQ(cp, "stdout"))
  1116.         return (1);
  1117.     else if (STREQ(cp, "stderr"))
  1118.         return (2);
  1119.     else if (STREQN(cp, "fd/", 3)) {
  1120.         cp += 3;
  1121.         if (sscanf (cp, "%d", & openfd) == 1 && openfd >= 0)
  1122.             /* got something */
  1123.             return openfd;
  1124.         else
  1125.             return -1;
  1126.     } else
  1127.         return (open (name, flag, 0666));
  1128. #endif
  1129. }
  1130.  
  1131. /*** APPEND AFTER 1108 IN x:awk7.c ***/
  1132.  
  1133. #ifdef AMIGA /* those damned pipes again */
  1134. pclose(junk)
  1135. long junk;
  1136. {
  1137.     return(1);
  1138. }
  1139. #endif
  1140. /*** APPEND AFTER 1108 IN x:awk7.c ***/
  1141.  
  1142.