home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 11 / AUCD11B.iso / LANGUAGES / WraithSet / AwkStuff / MawkSrc / c / fin < prev    next >
Text File  |  1995-12-24  |  13KB  |  587 lines

  1.  
  2. /********************************************
  3. fin.c
  4. copyright 1991, 1992.  Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the AWK programming language.
  8.  
  9. Mawk is distributed without warranty under the terms of
  10. the GNU General Public License, version 2, 1991.
  11. ********************************************/
  12.  
  13. /*$Log: fin.c,v $
  14.  * Revision 1.10  1995/12/24  22:23:22  mike
  15.  * remove errmsg() from inside FINopen
  16.  *
  17.  * Revision 1.9  1995/06/06  00:18:29  mike
  18.  * change mawk_exit(1) to mawk_exit(2)
  19.  *
  20.  * Revision 1.8  1994/12/13  00:26:35  mike
  21.  * rt_nr and rt_fnr for run-time error messages
  22.  *
  23.  * Revision 1.7  1994/12/11  23:25:05  mike
  24.  * -Wi option
  25.  *
  26.  * Revision 1.6  1994/12/11  22:14:15  mike
  27.  * remove THINK_C #defines.  Not a political statement, just no indication
  28.  * that anyone ever used it.
  29.  *
  30.  * Revision 1.5  1994/10/08  19:15:42  mike
  31.  * remove SM_DOS
  32.  *
  33.  * Revision 1.4  1993/07/17  13:22:55  mike
  34.  * indent and general code cleanup
  35.  *
  36.  * Revision 1.3  1993/07/15  13:26:55  mike
  37.  * SIZE_T and indent
  38.  *
  39.  * Revision 1.2     1993/07/04  12:51:57  mike
  40.  * start on autoconfig changes
  41.  *
  42.  * Revision 1.1.1.1  1993/07/03     18:58:13  mike
  43.  * move source to cvs
  44.  *
  45.  * Revision 5.7     1993/01/01  21:30:48  mike
  46.  * split new_STRING() into new_STRING and new_STRING0
  47.  *
  48.  * Revision 5.6     1992/12/17  02:48:01  mike
  49.  * 1.1.2d changes for DOS
  50.  *
  51.  * Revision 5.5     1992/07/28  15:11:30  brennan
  52.  * minor change in finding eol, needed for MsDOS
  53.  *
  54.  * Revision 5.4     1992/07/10  16:17:10  brennan
  55.  * MsDOS: remove NO_BINMODE macro
  56.  *
  57.  * Revision 5.3     1992/07/08  16:14:27  brennan
  58.  * FILENAME and FNR retain last values in the
  59.  * END block.
  60.  *
  61.  * Revision 5.2     1992/02/21  13:30:08  brennan
  62.  * fixed bug that free'd FILENAME twice if
  63.  * command line was var=value only
  64.  *
  65.  * Revision 5.1     91/12/05  07:56:02  brennan
  66.  * 1.1 pre-release
  67.  *
  68. */
  69.  
  70. /* fin.c */
  71.  
  72. #include "mawk.h"
  73. #include "fin.h"
  74. #include "memory.h"
  75. #include "bi_vars.h"
  76. #include "field.h"
  77. #include "symtype.h"
  78. #include "scan.h"
  79.  
  80. #ifndef      NO_FCNTL_H
  81. #include <fcntl.h>
  82. #endif
  83.  
  84. /* This file handles input files.  Opening, closing,
  85.    buffering and (most important) splitting files into
  86.    records, FINgets().
  87. */
  88.  
  89. int PROTO(isatty, (int)) ;
  90.  
  91. static FIN *PROTO(next_main, (int)) ;
  92. static char *PROTO(enlarge_fin_buffer, (FIN *)) ;
  93. static void PROTO(set_main_to_stdin, (void)) ;
  94. int PROTO(is_cmdline_assign, (char *)) ; /* also used by init */
  95.  
  96. /* convert file-descriptor to FIN*.
  97.    It's the main stream if main_flag is set
  98. */
  99. FIN *
  100. FINdopen(fd, main_flag)
  101.    int fd, main_flag ;
  102. {
  103.    register FIN *fin = ZMALLOC(FIN) ;
  104.  
  105.    fin->fd = fd ;
  106.    fin->flags = main_flag ? (MAIN_FLAG | START_FLAG) : START_FLAG ;
  107.    fin->buffp = fin->buff = (char *) zmalloc(BUFFSZ + 1) ;
  108.    fin->nbuffs = 1 ;
  109.    fin->buff[0] = 0 ;
  110.  
  111.    if (isatty(fd) && rs_shadow.type == SEP_CHAR && rs_shadow.c == '\n'
  112.        || interactive_flag && fd == 0 )
  113.    {
  114.       /* interactive, i.e., line buffer this file */
  115.       if (fd == 0)  fin->fp = stdin ;
  116.       else if (!(fin->fp = fdopen(fd, "r")))
  117.       {
  118.      errmsg(errno, "fdopen failed") ; mawk_exit(2) ; 
  119.       }
  120.    }
  121.    else     fin->fp = (FILE *) 0 ;
  122.  
  123.    return fin ;
  124. }
  125.  
  126. /* open a FIN* by filename.
  127.    It's the main stream if main_flag is set.
  128.    Recognizes "-" as stdin.
  129. */
  130.  
  131. FIN *
  132. FINopen(filename, main_flag)
  133.    char *filename ;
  134.    int main_flag ;
  135. {
  136.    int fd ;
  137.    int oflag = O_RDONLY ;
  138.  
  139. #if  MSDOS
  140.    int bm = binmode() & 1 ;
  141.    if (bm)  oflag |= O_BINARY ;
  142. #endif
  143.  
  144.    if (filename[0] == '-' && filename[1] == 0)
  145.    {
  146. #if  MSDOS
  147.       if (bm)  setmode(0, O_BINARY) ;
  148. #endif
  149.       return FINdopen(0, main_flag) ;
  150.    }
  151.  
  152.    if ((fd = open(filename, oflag, 0)) == -1)
  153.       return (FIN *) 0 ;
  154.    else 
  155.       return FINdopen(fd, main_flag) ;
  156. }
  157.  
  158. /* frees the buffer and fd, but leaves FIN structure until
  159.    the user calls close() */
  160.  
  161. void
  162. FINsemi_close(fin)
  163.    register FIN *fin ;
  164. {
  165.    static char dead = 0 ;
  166.  
  167.    if (fin->buff != &dead)
  168.    {
  169.       zfree(fin->buff, fin->nbuffs * BUFFSZ + 1) ;
  170.  
  171.       if (fin->fd)
  172.      if (fin->fp)  fclose(fin->fp) ;
  173.      else  close(fin->fd) ;
  174.  
  175.       fin->buff = fin->buffp = &dead ;     /* marks it semi_closed */
  176.    }
  177.    /* else was already semi_closed */
  178. }
  179.  
  180. /* user called close() on input file */
  181. void
  182. FINclose(fin)
  183.    FIN *fin ;
  184. {
  185.    FINsemi_close(fin) ;
  186.    ZFREE(fin) ;
  187. }
  188.  
  189. /* return one input record as determined by RS,
  190.    from input file (FIN)  fin
  191. */
  192.  
  193. char *
  194. FINgets(fin, len_p)
  195.    FIN *fin ;
  196.    unsigned *len_p ;
  197. {
  198.    register char *p, *q ;
  199.    unsigned match_len ;
  200.    unsigned r ;
  201.  
  202. restart :
  203.  
  204.    if (!(p = fin->buffp)[0])    /* need a refill */
  205.    {
  206.       if (fin->flags & EOF_FLAG)
  207.       {
  208.      if (fin->flags & MAIN_FLAG)
  209.      {
  210.         fin = next_main(0) ;  goto restart ; 
  211.      }
  212.      else
  213.      {
  214.         *len_p = 0 ; return (char *) 0 ; 
  215.      }
  216.       }
  217.  
  218.       if (fin->fp)
  219.       {
  220.      /* line buffering */
  221.      if (!fgets(fin->buff, BUFFSZ + 1, fin->fp))
  222.      {
  223.         fin->flags |= EOF_FLAG ;
  224.         fin->buff[0] = 0 ;
  225.         fin->buffp = fin->buff ;
  226.         goto restart ;     /* might be main_fin */
  227.      }
  228.      else  /* return this line */
  229.      {
  230.         /* find eol */
  231.         p = fin->buff ;
  232.         while (*p != '\n' && *p != 0)  p++ ;
  233.  
  234.         *p = 0 ; *len_p = p - fin->buff ;
  235.         fin->buffp = p ;
  236.         return fin->buff ;
  237.      }
  238.       }
  239.       else
  240.       {
  241.      /* block buffering */
  242.      r = fillbuff(fin->fd, fin->buff, fin->nbuffs * BUFFSZ) ;
  243.      if (r == 0)
  244.      {
  245.         fin->flags |= EOF_FLAG ;
  246.         fin->buffp = fin->buff ;
  247.         goto restart ;     /* might be main */
  248.      }
  249.      else if (r < fin->nbuffs * BUFFSZ)
  250.      {
  251.         fin->flags |= EOF_FLAG ;
  252.      }
  253.  
  254.      p = fin->buffp = fin->buff ;
  255.  
  256.      if (fin->flags & START_FLAG)
  257.      {
  258.         fin->flags &= ~START_FLAG ;
  259.         if (rs_shadow.type == SEP_MLR)
  260.         {
  261.            /* trim blank lines from front of file */
  262.            while (*p == '\n')  p++ ;
  263.            fin->buffp = p ;
  264.            if (*p == 0)  goto restart ;
  265.         }
  266.      }
  267.       }
  268.    }
  269.  
  270. retry:
  271.  
  272.    switch (rs_shadow.type)
  273.    {
  274.       case SEP_CHAR:
  275.      q = strchr(p, rs_shadow.c) ;
  276.      match_len = 1 ;
  277.      break ;
  278.  
  279.       case SEP_STR:
  280.      q = str_str(p, ((STRING *) rs_shadow.ptr)->str,
  281.              match_len = ((STRING *) rs_shadow.ptr)->len) ;
  282.      break ;
  283.  
  284.       case SEP_MLR:
  285.       case SEP_RE:
  286.      q = re_pos_match(p, rs_shadow.ptr, &match_len) ;
  287.      /* if the match is at the end, there might still be
  288.            more to match in the file */
  289.      if (q && q[match_len] == 0 && !(fin->flags & EOF_FLAG))
  290.         q = (char *) 0 ;
  291.      break ;
  292.  
  293.       default:
  294.      bozo("type of rs_shadow") ;
  295.    }
  296.  
  297.    if (q)
  298.    {
  299.       /* the easy and normal case */
  300.       *q = 0 ;    *len_p = q - p ;
  301.       fin->buffp = q + match_len ;
  302.       return p ;
  303.    }
  304.  
  305.    if (fin->flags & EOF_FLAG)
  306.    {
  307.       /* last line without a record terminator */
  308.       *len_p = r = strlen(p) ; fin->buffp = p+r ;
  309.  
  310.       if (rs_shadow.type == SEP_MLR && fin->buffp[-1] == '\n'
  311.       && r != 0)
  312.       {
  313.      (*len_p)-- ;
  314.      *--fin->buffp = 0 ;
  315.       }
  316.       return p ;
  317.    }
  318.  
  319.    if (p == fin->buff)
  320.    {
  321.       /* current record is too big for the input buffer, grow buffer */
  322.       p = enlarge_fin_buffer(fin) ;
  323.    }
  324.    else
  325.    {
  326.       /* move a partial line to front of buffer and try again */
  327.       unsigned rr ;
  328.  
  329.       p = (char *) memcpy(fin->buff, p, r = strlen(p)) ;
  330.       q = p+r ;     rr = fin->nbuffs*BUFFSZ - r ;
  331.  
  332.       if ((r = fillbuff(fin->fd, q, rr)) < rr)
  333.      fin->flags |= EOF_FLAG ;
  334.    }
  335.    goto retry ;
  336. }
  337.  
  338. static char *
  339. enlarge_fin_buffer(fin)
  340.    FIN *fin ;
  341. {
  342.    unsigned r ;
  343.    unsigned oldsize = fin->nbuffs * BUFFSZ + 1 ;
  344.  
  345. #ifdef  MSDOS
  346.    /* I'm not sure this can really happen:
  347.      avoid "16bit wrap" */
  348.    if (fin->nbuffs == MAX_BUFFS)
  349.    {
  350.       errmsg(0, "out of input buffer space") ;
  351.       mawk_exit(2) ;
  352.    }
  353. #endif
  354.  
  355.    fin->buffp =
  356.       fin->buff = (char *) zrealloc(fin->buff, oldsize, oldsize + BUFFSZ) ;
  357.    fin->nbuffs++ ;
  358.  
  359.    r = fillbuff(fin->fd, fin->buff + (oldsize - 1), BUFFSZ) ;
  360.    if (r < BUFFSZ)  fin->flags |= EOF_FLAG ;
  361.  
  362.    return fin->buff ;
  363. }
  364.  
  365. /*--------
  366.   target is big enough to hold size + 1 chars
  367.   on exit the back of the target is zero terminated
  368.  *--------------*/
  369. unsigned
  370. fillbuff(fd, target, size)
  371.    int fd ;
  372.    register char *target ;
  373.    unsigned size ;
  374. {
  375.    register int r ;
  376.    unsigned entry_size = size ;
  377.  
  378.    while (size)
  379.       switch (r = read(fd, target, size))
  380.       {
  381.      case -1:
  382.         errmsg(errno, "read error") ;
  383.         mawk_exit(2) ;
  384.  
  385.      case 0:
  386.         goto out ;
  387.  
  388.      default:
  389.         target += r ; size -= r ;
  390.         break ;
  391.       }
  392.  
  393. out :
  394.    *target = 0 ;
  395.    return entry_size - size ;
  396. }
  397.  
  398. /* main_fin is a handle to the main input stream
  399.    == 0     never been opened   */
  400.  
  401. FIN *main_fin ;
  402. ARRAY Argv ;             /* to the user this is ARGV  */
  403. static double argi = 1.0 ;     /* index of next ARGV[argi] to try to open */
  404.  
  405.  
  406. static void
  407. set_main_to_stdin()
  408. {
  409.    cell_destroy(FILENAME) ;
  410.    FILENAME->type = C_STRING ;
  411.    FILENAME->ptr = (PTR) new_STRING("-") ;
  412.    cell_destroy(FNR) ;
  413.    FNR->type = C_DOUBLE ;
  414.    FNR->dval = 0.0 ; rt_fnr = 0 ;
  415.    main_fin = FINdopen(0, 1) ;
  416. }
  417.  
  418.  
  419. /* this gets called once to get the input stream going.
  420.    It is called after the execution of the BEGIN block
  421.    unless there is a getline inside BEGIN {}
  422. */
  423. void
  424. open_main()
  425. {
  426.    CELL argc ;
  427.  
  428. #if  MSDOS
  429.    int k = binmode() ;
  430.  
  431.    if (k & 1)  setmode(0, O_BINARY) ;
  432.    if ( k & 2 ) { setmode(1,O_BINARY) ; setmode(2,O_BINARY) ; }
  433. #endif
  434.  
  435.    cellcpy(&argc, ARGC) ;
  436.    if (argc.type != C_DOUBLE)  cast1_to_d(&argc) ;
  437.  
  438.    if (argc.dval == 1.0)  set_main_to_stdin() ;
  439.    else     next_main(1) ;
  440. }
  441.  
  442. /* get the next command line file open */
  443. static FIN *
  444. next_main(open_flag)
  445.    int open_flag ;         /* called by open_main() if on */
  446. {
  447.    register CELL *cp ;
  448.    CELL argc ;             /* copy of ARGC */
  449.    CELL c_argi ;         /* cell copy of argi */
  450.    CELL argval ;         /* copy of ARGV[c_argi] */
  451.  
  452.  
  453.    argval.type = C_NOINIT ;
  454.    c_argi.type = C_DOUBLE ;
  455.  
  456.    if (main_fin)  FINclose(main_fin) ;
  457.    /* FILENAME and FNR don't change unless we really open
  458.      a new file */
  459.  
  460.    /* make a copy of ARGC to avoid side effect */
  461.    if (cellcpy(&argc, ARGC)->type != C_DOUBLE)    cast1_to_d(&argc) ;
  462.  
  463.    while (argi < argc.dval)
  464.    {
  465.       c_argi.dval = argi ;
  466.       argi += 1.0 ;
  467.  
  468.       if (!(cp = array_find(Argv, &c_argi, NO_CREATE)))
  469.      continue ;         /* its deleted */
  470.  
  471.       /* make a copy so we can cast w/o side effect */
  472.       cell_destroy(&argval) ;
  473.       cp = cellcpy(&argval, cp) ;
  474.       if (cp->type < C_STRING)    cast1_to_s(cp) ;
  475.       if (string(cp)->len == 0)     continue ;
  476.       /* file argument is "" */
  477.  
  478.       /* it might be a command line assignment */
  479.       if (is_cmdline_assign(string(cp)->str))  continue ;
  480.  
  481.       /* try to open it -- we used to continue on failure,
  482.        but posix says we should quit */
  483.       if (!(main_fin = FINopen(string(cp)->str, 1)))  
  484.       {
  485.          errmsg(errno, "cannot open %s", string(cp)->str) ;
  486.      mawk_exit(2) ;
  487.       }
  488.  
  489.       /* success -- set FILENAME and FNR */
  490.       cell_destroy(FILENAME) ;
  491.       cellcpy(FILENAME, cp) ;
  492.       free_STRING(string(cp)) ;
  493.       cell_destroy(FNR) ;
  494.       FNR->type = C_DOUBLE ;
  495.       FNR->dval = 0.0 ; rt_fnr = 0 ;
  496.  
  497.       return main_fin ;
  498.    }
  499.    /* failure */
  500.    cell_destroy(&argval) ;
  501.  
  502.    if (open_flag)
  503.    {
  504.       /* all arguments were null or assignment */
  505.       set_main_to_stdin() ;
  506.       return main_fin ;
  507.    }
  508.  
  509.    /* real failure */
  510.    {
  511.       /* this is how we mark EOF on main_fin  */
  512.       static char dead_buff = 0 ;
  513.       static FIN dead_main =
  514.       {0, (FILE *) 0, &dead_buff, &dead_buff,
  515.        1, EOF_FLAG} ;
  516.  
  517.       return main_fin = &dead_main ;
  518.       /* since MAIN_FLAG is not set, FINgets won't call next_main() */
  519.    }
  520. }
  521.  
  522.  
  523. int
  524. is_cmdline_assign(s)
  525.    char *s ;
  526. {
  527.    register char *p ;
  528.    int c ;
  529.    SYMTAB *stp ;
  530.    CELL *cp ;
  531.    unsigned len ;
  532.    CELL cell ;             /* used if command line assign to pseudo field */
  533.    CELL *fp = (CELL *) 0 ;     /* ditto */
  534.  
  535.    if (scan_code[*(unsigned char *) s] != SC_IDCHAR)  return 0 ;
  536.  
  537.    p = s + 1 ;
  538.    while ((c = scan_code[*(unsigned char *) p]) == SC_IDCHAR
  539.       || c == SC_DIGIT)
  540.       p++ ;
  541.  
  542.    if (*p != '=')  return 0 ;
  543.  
  544.    *p = 0 ;
  545.    stp = find(s) ;
  546.  
  547.    switch (stp->type)
  548.    {
  549.       case ST_NONE:
  550.      stp->type = ST_VAR ;
  551.      stp->stval.cp = cp = ZMALLOC(CELL) ;
  552.      break ;
  553.  
  554.       case ST_VAR:
  555.       case ST_NR:        /* !! no one will do this */
  556.      cp = stp->stval.cp ;
  557.      cell_destroy(cp) ;
  558.      break ;
  559.  
  560.       case ST_FIELD:
  561.      /* must be pseudo field */
  562.      fp = stp->stval.cp ;
  563.      cp = &cell ;
  564.      break ;
  565.  
  566.       default:
  567.      rt_error(
  568.      "cannot command line assign to %s\n\ttype clash or keyword"
  569.             ,s) ;
  570.    }
  571.  
  572.    /* we need to keep ARGV[i] intact */
  573.    *p++ = '=' ;
  574.    len = strlen(p) + 1 ;
  575.    /* posix says escape sequences are on from command line */
  576.    p = rm_escape(strcpy((char *) zmalloc(len), p)) ;
  577.    cp->ptr = (PTR) new_STRING(p) ;
  578.    zfree(p, len) ;
  579.    check_strnum(cp) ;         /* sets cp->type */
  580.    if (fp)            /* move it from cell to pfield[] */
  581.    {
  582.       field_assign(fp, cp) ;
  583.       free_STRING(string(cp)) ;
  584.    }
  585.    return 1 ;
  586. }
  587.