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