home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / m / mawk11as.zip / FIN.C < prev    next >
C/C++ Source or Header  |  1991-12-18  |  12KB  |  485 lines

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