[BACK]Return to ch.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Diff for /src/usr.bin/less/ch.c between version 1.10 and 1.11

version 1.10, 2014/04/25 13:38:21 version 1.11, 2015/11/05 22:08:43
Line 6 
Line 6 
  *   *
  * For more information, see the README file.   * For more information, see the README file.
  */   */
   /*
    * Modified for use with illumos.
    * Copyright 2014 Garrett D'Amore <garrett@damore.org>
    */
   
   
 /*  /*
  * Low level character input from the input file.   * Low level character input from the input file.
  * We use these special purpose routines which optimize moving   * We use these special purpose routines which optimize moving
Line 15 
Line 18 
  */   */
   
 #include "less.h"  #include "less.h"
 #if MSDOS_COMPILER==WIN32C  
 #include <errno.h>  
 #include <windows.h>  
 #endif  
   
 #if HAVE_STAT_INO  
 #include <sys/stat.h>  #include <sys/stat.h>
 extern dev_t curr_dev;  extern dev_t curr_dev;
 extern ino_t curr_ino;  extern ino_t curr_ino;
 #endif  extern int less_is_more;
   
 typedef POSITION BLOCKNUM;  typedef off_t BLOCKNUM;
   
 public int ignore_eoi;  int ignore_eoi;
   
 /*  /*
  * Pool of buffers holding the most recently used blocks of the input file.   * Pool of buffers holding the most recently used blocks of the input file.
Line 48 
Line 46 
         unsigned int datasize;          unsigned int datasize;
         unsigned char data[LBUFSIZE];          unsigned char data[LBUFSIZE];
 };  };
 #define bufnode_buf(bn)  ((struct buf *) bn)  #define bufnode_buf(bn)  ((struct buf *)bn)
   
 /*  /*
  * The file state is maintained in a filestate structure.   * The file state is maintained in a filestate structure.
Line 60 
Line 58 
         struct bufnode hashtbl[BUFHASH_SIZE];          struct bufnode hashtbl[BUFHASH_SIZE];
         int file;          int file;
         int flags;          int flags;
         POSITION fpos;          off_t fpos;
         int nbufs;          int nbufs;
         BLOCKNUM block;          BLOCKNUM block;
         unsigned int offset;          unsigned int offset;
         POSITION fsize;          off_t fsize;
 };  };
   
 #define ch_bufhead      thisfile->buflist.next  #define ch_bufhead      thisfile->buflist.next
Line 79 
Line 77 
   
 #define END_OF_CHAIN    (&thisfile->buflist)  #define END_OF_CHAIN    (&thisfile->buflist)
 #define END_OF_HCHAIN(h) (&thisfile->hashtbl[h])  #define END_OF_HCHAIN(h) (&thisfile->hashtbl[h])
 #define BUFHASH(blk)    ((blk) & (BUFHASH_SIZE-1))  #define BUFHASH(blk)    ((blk) & (BUFHASH_SIZE-1))
   
 /*  /*
  * Macros to manipulate the list of buffers in thisfile->buflist.   * Macros to manipulate the list of buffers in thisfile->buflist.
Line 87 
Line 85 
 #define FOR_BUFS(bn) \  #define FOR_BUFS(bn) \
         for (bn = ch_bufhead;  bn != END_OF_CHAIN;  bn = bn->next)          for (bn = ch_bufhead;  bn != END_OF_CHAIN;  bn = bn->next)
   
 #define BUF_RM(bn) \  #define BUF_RM(bn) \
         (bn)->next->prev = (bn)->prev; \          (bn)->next->prev = (bn)->prev; \
         (bn)->prev->next = (bn)->next;          (bn)->prev->next = (bn)->next;
   
 #define BUF_INS_HEAD(bn) \  #define BUF_INS_HEAD(bn) \
         (bn)->next = ch_bufhead; \          (bn)->next = ch_bufhead; \
         (bn)->prev = END_OF_CHAIN; \          (bn)->prev = END_OF_CHAIN; \
         ch_bufhead->prev = (bn); \          ch_bufhead->prev = (bn); \
         ch_bufhead = (bn);          ch_bufhead = (bn);
   
 #define BUF_INS_TAIL(bn) \  #define BUF_INS_TAIL(bn) \
         (bn)->next = END_OF_CHAIN; \          (bn)->next = END_OF_CHAIN; \
         (bn)->prev = ch_buftail; \          (bn)->prev = ch_buftail; \
         ch_buftail->next = (bn); \          ch_buftail->next = (bn); \
Line 106 
Line 104 
 /*  /*
  * Macros to manipulate the list of buffers in thisfile->hashtbl[n].   * Macros to manipulate the list of buffers in thisfile->hashtbl[n].
  */   */
 #define FOR_BUFS_IN_CHAIN(h,bn) \  #define FOR_BUFS_IN_CHAIN(h, bn) \
         for (bn = thisfile->hashtbl[h].hnext;  \          for (bn = thisfile->hashtbl[h].hnext;  \
              bn != END_OF_HCHAIN(h);  bn = bn->hnext)              bn != END_OF_HCHAIN(h);  bn = bn->hnext)
   
 #define BUF_HASH_RM(bn) \  #define BUF_HASH_RM(bn) \
         (bn)->hnext->hprev = (bn)->hprev; \          (bn)->hnext->hprev = (bn)->hprev; \
         (bn)->hprev->hnext = (bn)->hnext;          (bn)->hprev->hnext = (bn)->hnext;
   
 #define BUF_HASH_INS(bn,h) \  #define BUF_HASH_INS(bn, h) \
         (bn)->hnext = thisfile->hashtbl[h].hnext; \          (bn)->hnext = thisfile->hashtbl[h].hnext; \
         (bn)->hprev = END_OF_HCHAIN(h); \          (bn)->hprev = END_OF_HCHAIN(h); \
         thisfile->hashtbl[h].hnext->hprev = (bn); \          thisfile->hashtbl[h].hnext->hprev = (bn); \
Line 130 
Line 128 
 extern int screen_trashed;  extern int screen_trashed;
 extern int follow_mode;  extern int follow_mode;
 extern IFILE curr_ifile;  extern IFILE curr_ifile;
 #if LOGFILE  
 extern int logfile;  extern int logfile;
 extern char *namelogfile;  extern char *namelogfile;
 #endif  
   
 static int ch_addbuf();  static int ch_addbuf(void);
   
   
 /*  /*
  * Get the character pointed to by the read pointer.   * Get the character pointed to by the read pointer.
  */   */
         int  int
 ch_get()  ch_get(void)
 {  {
         register struct buf *bp;          struct buf *bp;
         register struct bufnode *bn;          struct bufnode *bn;
         register int n;          int n;
         register int slept;          int slept;
         register int h;          int h;
         POSITION pos;          off_t pos;
         POSITION len;          off_t len;
   
         if (thisfile == NULL)          if (thisfile == NULL)
                 return (EOI);                  return (EOI);
   
         /*          /*
          * Quick check for the common case where           * Quick check for the common case where
          * the desired char is in the head buffer.           * the desired char is in the head buffer.
          */           */
         if (ch_bufhead != END_OF_CHAIN)          if (ch_bufhead != END_OF_CHAIN) {
         {  
                 bp = bufnode_buf(ch_bufhead);                  bp = bufnode_buf(ch_bufhead);
                 if (ch_block == bp->block && ch_offset < bp->datasize)                  if (ch_block == bp->block && ch_offset < bp->datasize)
                         return bp->data[ch_offset];                          return (bp->data[ch_offset]);
         }          }
   
         slept = FALSE;          slept = FALSE;
Line 172 
Line 167 
          * Look for a buffer holding the desired block.           * Look for a buffer holding the desired block.
          */           */
         h = BUFHASH(ch_block);          h = BUFHASH(ch_block);
         FOR_BUFS_IN_CHAIN(h, bn)          FOR_BUFS_IN_CHAIN(h, bn) {
         {  
                 bp = bufnode_buf(bn);                  bp = bufnode_buf(bn);
                 if (bp->block == ch_block)                  if (bp->block == ch_block) {
                 {  
                         if (ch_offset >= bp->datasize)                          if (ch_offset >= bp->datasize)
                                 /*                                  /*
                                  * Need more data in this buffer.                                   * Need more data in this buffer.
Line 185 
Line 178 
                         goto found;                          goto found;
                 }                  }
         }          }
         if (bn == END_OF_HCHAIN(h))          if (bn == END_OF_HCHAIN(h)) {
         {  
                 /*                  /*
                  * Block is not in a buffer.                   * Block is not in a buffer.
                  * Take the least recently used buffer                   * Take the least recently used buffer
                  * and read the desired block into it.                   * and read the desired block into it.
                  * If the LRU buffer has data in it,                   * If the LRU buffer has data in it,
                  * then maybe allocate a new buffer.                   * then maybe allocate a new buffer.
                  */                   */
                 if (ch_buftail == END_OF_CHAIN ||                  if (ch_buftail == END_OF_CHAIN ||
                         bufnode_buf(ch_buftail)->block != -1)                      bufnode_buf(ch_buftail)->block != -1) {
                 {  
                         /*                          /*
                          * There is no empty buffer to use.                           * There is no empty buffer to use.
                          * Allocate a new buffer if:                           * Allocate a new buffer if:
                          * 1. We can't seek on this file and -b is not in effect; or                           * 1. We can't seek on this file and -b is not in
                          * 2. We haven't allocated the max buffers for this file yet.                           *    effect; or
                            * 2. We haven't allocated the max buffers for this
                            *    file yet.
                          */                           */
                         if ((autobuf && !(ch_flags & CH_CANSEEK)) ||                          if ((autobuf && !(ch_flags & CH_CANSEEK)) ||
                                 (maxbufs < 0 || ch_nbufs < maxbufs))                              (maxbufs < 0 || ch_nbufs < maxbufs))
                                 if (ch_addbuf())                                  if (ch_addbuf())
                                         /*                                          /*
                                          * Allocation failed: turn off autobuf.                                           * Allocation failed: turn off autobuf.
Line 219 
Line 212 
                 BUF_HASH_INS(bn, h); /* Insert into new hash chain. */                  BUF_HASH_INS(bn, h); /* Insert into new hash chain. */
         }          }
   
     read_more:  read_more:
         pos = (ch_block * LBUFSIZE) + bp->datasize;          pos = (ch_block * LBUFSIZE) + bp->datasize;
         if ((len = ch_length()) != NULL_POSITION && pos >= len)          if ((len = ch_length()) != -1 && pos >= len)
                 /*                  /*
                  * At end of file.                   * At end of file.
                  */                   */
                 return (EOI);                  return (EOI);
   
         if (pos != ch_fpos)          if (pos != ch_fpos) {
         {  
                 /*                  /*
                  * Not at the correct position: must seek.                   * Not at the correct position: must seek.
                  * If input is a pipe, we're in trouble (can't seek on a pipe).                   * If input is a pipe, we're in trouble (can't seek on a pipe).
Line 236 
Line 228 
                  */                   */
                 if (!(ch_flags & CH_CANSEEK))                  if (!(ch_flags & CH_CANSEEK))
                         return ('?');                          return ('?');
                 if (lseek(ch_file, (off_t)pos, SEEK_SET) == BAD_LSEEK)                  if (lseek(ch_file, (off_t)pos, SEEK_SET) == BAD_LSEEK) {
                 {                          error("seek error", NULL_PARG);
                         error("seek error", NULL_PARG);  
                         clear_eol();                          clear_eol();
                         return (EOI);                          return (EOI);
                 }                  }
                 ch_fpos = pos;                  ch_fpos = pos;
         }          }
   
         /*          /*
          * Read the block.           * Read the block.
          * If we read less than a full block, that's ok.           * If we read less than a full block, that's ok.
          * We use partial block and pick up the rest next time.           * We use partial block and pick up the rest next time.
          */           */
         if (ch_ungotchar != -1)          if (ch_ungotchar != -1) {
         {                  bp->data[bp->datasize] = (unsigned char)ch_ungotchar;
                 bp->data[bp->datasize] = ch_ungotchar;  
                 n = 1;                  n = 1;
                 ch_ungotchar = -1;                  ch_ungotchar = -1;
         } else          } else {
         {                  n = iread(ch_file, &bp->data[bp->datasize],
                 n = iread(ch_file, &bp->data[bp->datasize],                      (unsigned int)(LBUFSIZE - bp->datasize));
                         (unsigned int)(LBUFSIZE - bp->datasize));  
         }          }
   
         if (n == READ_INTR)          if (n == READ_INTR)
                 return (EOI);                  return (EOI);
         if (n < 0)          if (n < 0) {
         {                  error("read error", NULL_PARG);
 #if MSDOS_COMPILER==WIN32C                  clear_eol();
                 if (errno != EPIPE)  
 #endif  
                 {  
                         error("read error", NULL_PARG);  
                         clear_eol();  
                 }  
                 n = 0;                  n = 0;
         }          }
   
 #if LOGFILE  
         /*          /*
          * If we have a log file, write the new data to it.           * If we have a log file, write the new data to it.
          */           */
         if (!secure && logfile >= 0 && n > 0)          if (!secure && logfile >= 0 && n > 0)
                 write(logfile, (char *) &bp->data[bp->datasize], n);                  (void) write(logfile, (char *)&bp->data[bp->datasize], n);
 #endif  
   
         ch_fpos += n;          ch_fpos += n;
         bp->datasize += n;          bp->datasize += n;
Line 290 
Line 271 
          * If we have read to end of file, set ch_fsize to indicate           * If we have read to end of file, set ch_fsize to indicate
          * the position of the end of file.           * the position of the end of file.
          */           */
         if (n == 0)          if (n == 0) {
         {  
                 ch_fsize = pos;                  ch_fsize = pos;
                 if (ignore_eoi)                  if (ignore_eoi) {
                 {  
                         /*                          /*
                          * We are ignoring EOF.                           * We are ignoring EOF.
                          * Wait a while, then try again.                           * Wait a while, then try again.
                          */                           */
                         if (!slept)                          if (!slept) {
                         {  
                                 PARG parg;                                  PARG parg;
                                 parg.p_string = wait_message();                                  parg.p_string = wait_message();
                                 ierror("%s", &parg);                                  ierror("%s", &parg);
                         }                          }
 #if !MSDOS_COMPILER                          sleep(1);
                         sleep(1);  
 #else  
 #if MSDOS_COMPILER==WIN32C  
                         Sleep(1000);  
 #endif  
 #endif  
                         slept = TRUE;                          slept = TRUE;
   
 #if HAVE_STAT_INO                          if (follow_mode == FOLLOW_NAME) {
                         if (follow_mode == FOLLOW_NAME)                                  /*
                         {                                   * See whether the file's i-number has changed.
                                 /* See whether the file's i-number has changed.  
                                  * If so, force the file to be closed and                                   * If so, force the file to be closed and
                                  * reopened. */                                   * reopened.
                                    */
                                 struct stat st;                                  struct stat st;
                                 int r = stat(get_filename(curr_ifile), &st);                                  int r = stat(get_filename(curr_ifile), &st);
                                 if (r == 0 && (st.st_ino != curr_ino ||                                  if (r == 0 && (st.st_ino != curr_ino ||
                                         st.st_dev != curr_dev))                                      st.st_dev != curr_dev)) {
                                 {                                          /*
                                         /* screen_trashed=2 causes                                           * screen_trashed=2 causes
                                          * make_display to reopen the file. */                                           * make_display to reopen the file.
                                            */
                                         screen_trashed = 2;                                          screen_trashed = 2;
                                         return (EOI);                                          return (EOI);
                                 }                                  }
                         }                          }
 #endif  
                 }                  }
                 if (sigs)                  if (sigs)
                         return (EOI);                          return (EOI);
         }          }
   
     found:  found:
         if (ch_bufhead != bn)          if (ch_bufhead != bn) {
         {  
                 /*                  /*
                  * Move the buffer to the head of the buffer chain.                   * Move the buffer to the head of the buffer chain.
                  * This orders the buffer chain, most- to least-recently used.                   * This orders the buffer chain, most- to least-recently used.
Line 365 
Line 336 
 }  }
   
 /*  /*
  * ch_ungetchar is a rather kludgy and limited way to push   * ch_ungetchar is a rather kludgy and limited way to push
  * a single char onto an input file descriptor.   * a single char onto an input file descriptor.
  */   */
         public void  void
 ch_ungetchar(c)  ch_ungetchar(int c)
         int c;  
 {  {
         if (c != -1 && ch_ungotchar != -1)          if (c != -1 && ch_ungotchar != -1)
                 error("ch_ungetchar overrun", NULL_PARG);                  error("ch_ungetchar overrun", NULL_PARG);
         ch_ungotchar = c;          ch_ungotchar = c;
 }  }
   
 #if LOGFILE  
 /*  /*
  * Close the logfile.   * Close the logfile.
  * If we haven't read all of standard input into it, do that now.   * If we haven't read all of standard input into it, do that now.
  */   */
         public void  void
 end_logfile()  end_logfile(void)
 {  {
         static int tried = FALSE;          static int tried = FALSE;
   
         if (logfile < 0)          if (logfile < 0)
                 return;                  return;
         if (!tried && ch_fsize == NULL_POSITION)          if (!tried && ch_fsize == -1) {
         {  
                 tried = TRUE;                  tried = TRUE;
                 ierror("Finishing logfile", NULL_PARG);                  ierror("Finishing logfile", NULL_PARG);
                 while (ch_forw_get() != EOI)                  while (ch_forw_get() != EOI)
Line 407 
Line 375 
  * Invoked from the - command; see toggle_option().   * Invoked from the - command; see toggle_option().
  * Write all the existing buffered data to the log file.   * Write all the existing buffered data to the log file.
  */   */
         public void  void
 sync_logfile()  sync_logfile(void)
 {  {
         register struct buf *bp;          struct buf *bp;
         register struct bufnode *bn;          struct bufnode *bn;
         int warned = FALSE;          int warned = FALSE;
         BLOCKNUM block;          BLOCKNUM block;
         BLOCKNUM nblocks;          BLOCKNUM nblocks;
   
         nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE;          nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE;
         for (block = 0;  block < nblocks;  block++)          for (block = 0;  block < nblocks;  block++) {
         {  
                 int wrote = FALSE;                  int wrote = FALSE;
                 FOR_BUFS(bn)                  FOR_BUFS(bn) {
                 {  
                         bp = bufnode_buf(bn);                          bp = bufnode_buf(bn);
                         if (bp->block == block)                          if (bp->block == block) {
                         {                                  (void) write(logfile, (char *)bp->data,
                                 write(logfile, (char *) bp->data, bp->datasize);                                      bp->datasize);
                                 wrote = TRUE;                                  wrote = TRUE;
                                 break;                                  break;
                         }                          }
                 }                  }
                 if (!wrote && !warned)                  if (!wrote && !warned) {
                 {                          error("Warning: log file is incomplete", NULL_PARG);
                         error("Warning: log file is incomplete",  
                                 NULL_PARG);  
                         warned = TRUE;                          warned = TRUE;
                 }                  }
         }          }
 }  }
   
 #endif  
   
 /*  /*
  * Determine if a specific block is currently in one of the buffers.   * Determine if a specific block is currently in one of the buffers.
  */   */
         static int  static int
 buffered(block)  buffered(BLOCKNUM block)
         BLOCKNUM block;  
 {  {
         register struct buf *bp;          register struct buf *bp;
         register struct bufnode *bn;          register struct bufnode *bn;
         register int h;          register int h;
   
         h = BUFHASH(block);          h = BUFHASH(block);
         FOR_BUFS_IN_CHAIN(h, bn)          FOR_BUFS_IN_CHAIN(h, bn) {
         {  
                 bp = bufnode_buf(bn);                  bp = bufnode_buf(bn);
                 if (bp->block == block)                  if (bp->block == block)
                         return (TRUE);                          return (TRUE);
Line 466 
Line 426 
  * Seek to a specified position in the file.   * Seek to a specified position in the file.
  * Return 0 if successful, non-zero if can't seek there.   * Return 0 if successful, non-zero if can't seek there.
  */   */
         public int  int
 ch_seek(pos)  ch_seek(off_t pos)
         register POSITION pos;  
 {  {
         BLOCKNUM new_block;          BLOCKNUM new_block;
         POSITION len;          off_t len;
   
         if (thisfile == NULL)          if (thisfile == NULL)
                 return (0);                  return (0);
   
         len = ch_length();          len = ch_length();
         if (pos < ch_zero() || (len != NULL_POSITION && pos > len))          if (pos < ch_zero() || (len != -1 && pos > len))
                 return (1);                  return (1);
   
         new_block = pos / LBUFSIZE;          new_block = pos / LBUFSIZE;
         if (!(ch_flags & CH_CANSEEK) && pos != ch_fpos && !buffered(new_block))          if (!(ch_flags & CH_CANSEEK) && pos != ch_fpos &&
         {              !buffered(new_block)) {
                 if (ch_fpos > pos)                  if (ch_fpos > pos)
                         return (1);                          return (1);
                 while (ch_fpos < pos)                  while (ch_fpos < pos) {
                 {  
                         if (ch_forw_get() == EOI)                          if (ch_forw_get() == EOI)
                                 return (1);                                  return (1);
                         if (ABORT_SIGS())                          if (ABORT_SIGS())
Line 505 
Line 463 
 /*  /*
  * Seek to the end of the file.   * Seek to the end of the file.
  */   */
         public int  int
 ch_end_seek()  ch_end_seek(void)
 {  {
         POSITION len;          off_t len;
   
         if (thisfile == NULL)          if (thisfile == NULL)
                 return (0);                  return (0);
Line 517 
Line 475 
                 ch_fsize = filesize(ch_file);                  ch_fsize = filesize(ch_file);
   
         len = ch_length();          len = ch_length();
         if (len != NULL_POSITION)          if (len != -1)
                 return (ch_seek(len));                  return (ch_seek(len));
   
         /*          /*
Line 534 
Line 492 
  * We may not be able to seek there if input is a pipe and the   * We may not be able to seek there if input is a pipe and the
  * beginning of the pipe is no longer buffered.   * beginning of the pipe is no longer buffered.
  */   */
         public int  int
 ch_beg_seek()  ch_beg_seek(void)
 {  {
         register struct bufnode *bn;          struct bufnode *bn;
         register struct bufnode *firstbn;          struct bufnode *firstbn;
   
         /*          /*
          * Try a plain ch_seek first.           * Try a plain ch_seek first.
Line 553 
Line 511 
         firstbn = ch_bufhead;          firstbn = ch_bufhead;
         if (firstbn == END_OF_CHAIN)          if (firstbn == END_OF_CHAIN)
                 return (1);                  return (1);
         FOR_BUFS(bn)          FOR_BUFS(bn) {
         {  
                 if (bufnode_buf(bn)->block < bufnode_buf(firstbn)->block)                  if (bufnode_buf(bn)->block < bufnode_buf(firstbn)->block)
                         firstbn = bn;                          firstbn = bn;
         }          }
Line 566 
Line 523 
 /*  /*
  * Return the length of the file, if known.   * Return the length of the file, if known.
  */   */
         public POSITION  off_t
 ch_length()  ch_length(void)
 {  {
         if (thisfile == NULL)          if (thisfile == NULL)
                 return (NULL_POSITION);                  return (-1);
         if (ignore_eoi)          if (ignore_eoi)
                 return (NULL_POSITION);                  return (-1);
         if (ch_flags & CH_NODATA)          if (ch_flags & CH_NODATA)
                 return (0);                  return (0);
         return (ch_fsize);          return (ch_fsize);
Line 581 
Line 538 
 /*  /*
  * Return the current position in the file.   * Return the current position in the file.
  */   */
         public POSITION  off_t
 ch_tell()  ch_tell(void)
 {  {
         if (thisfile == NULL)          if (thisfile == NULL)
                 return (NULL_POSITION);                  return (-1);
         return (ch_block * LBUFSIZE) + ch_offset;          return ((ch_block * LBUFSIZE) + ch_offset);
 }  }
   
 /*  /*
  * Get the current char and post-increment the read pointer.   * Get the current char and post-increment the read pointer.
  */   */
         public int  int
 ch_forw_get()  ch_forw_get(void)
 {  {
         register int c;          int c;
   
         if (thisfile == NULL)          if (thisfile == NULL)
                 return (EOI);                  return (EOI);
         c = ch_get();          c = ch_get();
         if (c == EOI)          if (c == EOI)
                 return (EOI);                  return (EOI);
         if (ch_offset < LBUFSIZE-1)          if (ch_offset < LBUFSIZE-1) {
                 ch_offset++;                  ch_offset++;
         else          } else {
         {  
                 ch_block ++;                  ch_block ++;
                 ch_offset = 0;                  ch_offset = 0;
         }          }
Line 615 
Line 571 
 /*  /*
  * Pre-decrement the read pointer and get the new current char.   * Pre-decrement the read pointer and get the new current char.
  */   */
         public int  int
 ch_back_get()  ch_back_get(void)
 {  {
         if (thisfile == NULL)          if (thisfile == NULL)
                 return (EOI);                  return (EOI);
         if (ch_offset > 0)          if (ch_offset > 0) {
                 ch_offset --;                  ch_offset --;
         else          } else {
         {  
                 if (ch_block <= 0)                  if (ch_block <= 0)
                         return (EOI);                          return (EOI);
                 if (!(ch_flags & CH_CANSEEK) && !buffered(ch_block-1))                  if (!(ch_flags & CH_CANSEEK) && !buffered(ch_block-1))
Line 638 
Line 593 
  * Set max amount of buffer space.   * Set max amount of buffer space.
  * bufspace is in units of 1024 bytes.  -1 mean no limit.   * bufspace is in units of 1024 bytes.  -1 mean no limit.
  */   */
         public void  void
 ch_setbufspace(bufspace)  ch_setbufspace(int bufspace)
         int bufspace;  
 {  {
         if (bufspace < 0)          if (bufspace < 0) {
                 maxbufs = -1;                  maxbufs = -1;
         else          } else {
         {  
                 maxbufs = ((bufspace * 1024) + LBUFSIZE-1) / LBUFSIZE;                  maxbufs = ((bufspace * 1024) + LBUFSIZE-1) / LBUFSIZE;
                 if (maxbufs < 1)                  if (maxbufs < 1)
                         maxbufs = 1;                          maxbufs = 1;
Line 655 
Line 608 
 /*  /*
  * Flush (discard) any saved file state, including buffer contents.   * Flush (discard) any saved file state, including buffer contents.
  */   */
         public void  void
 ch_flush()  ch_flush(void)
 {  {
         register struct bufnode *bn;          struct bufnode *bn;
   
         if (thisfile == NULL)          if (thisfile == NULL)
                 return;                  return;
   
         if (!(ch_flags & CH_CANSEEK))          if (!(ch_flags & CH_CANSEEK)) {
         {  
                 /*                  /*
                  * If input is a pipe, we don't flush buffer contents,                   * If input is a pipe, we don't flush buffer contents,
                  * since the contents can't be recovered.                   * since the contents can't be recovered.
                  */                   */
                 ch_fsize = NULL_POSITION;                  ch_fsize = -1;
                 return;                  return;
         }          }
   
         /*          /*
          * Initialize all the buffers.           * Initialize all the buffers.
          */           */
         FOR_BUFS(bn)          FOR_BUFS(bn) {
         {  
                 bufnode_buf(bn)->block = -1;                  bufnode_buf(bn)->block = -1;
         }          }
   
Line 696 
Line 647 
 #if 1  #if 1
         /*          /*
          * This is a kludge to workaround a Linux kernel bug: files in           * This is a kludge to workaround a Linux kernel bug: files in
          * /proc have a size of 0 according to fstat() but have readable           * /proc have a size of 0 according to fstat() but have readable
          * data.  They are sometimes, but not always, seekable.           * data.  They are sometimes, but not always, seekable.
          * Force them to be non-seekable here.           * Force them to be non-seekable here.
          */           */
         if (ch_fsize == 0)          if (ch_fsize == 0) {
         {                  ch_fsize = -1;
                 ch_fsize = NULL_POSITION;  
                 ch_flags &= ~CH_CANSEEK;                  ch_flags &= ~CH_CANSEEK;
         }          }
 #endif  #endif
   
         if (lseek(ch_file, (off_t)0, SEEK_SET) == BAD_LSEEK)          if (lseek(ch_file, (off_t)0, SEEK_SET) == BAD_LSEEK) {
         {  
                 /*                  /*
                  * Warning only; even if the seek fails for some reason,                   * Warning only; even if the seek fails for some reason,
                  * there's a good chance we're at the beginning anyway.                   * there's a good chance we're at the beginning anyway.
Line 722 
Line 671 
  * Allocate a new buffer.   * Allocate a new buffer.
  * The buffer is added to the tail of the buffer chain.   * The buffer is added to the tail of the buffer chain.
  */   */
         static int  static int
 ch_addbuf()  ch_addbuf(void)
 {  {
         register struct buf *bp;          struct buf *bp;
         register struct bufnode *bn;          struct bufnode *bn;
   
         /*          /*
          * Allocate and initialize a new buffer and link it           * Allocate and initialize a new buffer and link it
          * onto the tail of the buffer list.           * onto the tail of the buffer list.
          */           */
         bp = (struct buf *) calloc(1, sizeof(struct buf));          bp = calloc(1, sizeof (struct buf));
         if (bp == NULL)          if (bp == NULL)
                 return (1);                  return (1);
         ch_nbufs++;          ch_nbufs++;
Line 747 
Line 696 
 /*  /*
  *   *
  */   */
         static void  static void
 init_hashtbl()  init_hashtbl(void)
 {  {
         register int h;          int h;
   
         for (h = 0;  h < BUFHASH_SIZE;  h++)          for (h = 0; h < BUFHASH_SIZE; h++) {
         {  
                 thisfile->hashtbl[h].hnext = END_OF_HCHAIN(h);                  thisfile->hashtbl[h].hnext = END_OF_HCHAIN(h);
                 thisfile->hashtbl[h].hprev = END_OF_HCHAIN(h);                  thisfile->hashtbl[h].hprev = END_OF_HCHAIN(h);
         }          }
Line 762 
Line 710 
 /*  /*
  * Delete all buffers for this file.   * Delete all buffers for this file.
  */   */
         static void  static void
 ch_delbufs()  ch_delbufs(void)
 {  {
         register struct bufnode *bn;          struct bufnode *bn;
   
         while (ch_bufhead != END_OF_CHAIN)          while (ch_bufhead != END_OF_CHAIN) {
         {  
                 bn = ch_bufhead;                  bn = ch_bufhead;
                 BUF_RM(bn);                  BUF_RM(bn);
                 free(bufnode_buf(bn));                  free(bufnode_buf(bn));
Line 780 
Line 727 
 /*  /*
  * Is it possible to seek on a file descriptor?   * Is it possible to seek on a file descriptor?
  */   */
         public int  int
 seekable(f)  seekable(int f)
         int f;  
 {  {
 #if MSDOS_COMPILER  
         extern int fd0;  
         if (f == fd0 && !isatty(fd0))  
         {  
                 /*  
                  * In MS-DOS, pipes are seekable.  Check for  
                  * standard input, and pretend it is not seekable.  
                  */  
                 return (0);  
         }  
 #endif  
         return (lseek(f, (off_t)1, SEEK_SET) != BAD_LSEEK);          return (lseek(f, (off_t)1, SEEK_SET) != BAD_LSEEK);
 }  }
   
Line 802 
Line 737 
  * Force EOF to be at the current read position.   * Force EOF to be at the current read position.
  * This is used after an ignore_eof read, during which the EOF may change.   * This is used after an ignore_eof read, during which the EOF may change.
  */   */
         public void  void
 ch_set_eof()  ch_set_eof(void)
 {  {
         ch_fsize = ch_fpos;          ch_fsize = ch_fpos;
 }  }
Line 812 
Line 747 
 /*  /*
  * Initialize file state for a new file.   * Initialize file state for a new file.
  */   */
         public void  void
 ch_init(f, flags)  ch_init(int f, int flags)
         int f;  
         int flags;  
 {  {
         /*          /*
          * See if we already have a filestate for this file.           * See if we already have a filestate for this file.
          */           */
         thisfile = (struct filestate *) get_filestate(curr_ifile);          thisfile = get_filestate(curr_ifile);
         if (thisfile == NULL)          if (thisfile == NULL) {
         {  
                 /*                  /*
                  * Allocate and initialize a new filestate.                   * Allocate and initialize a new filestate.
                  */                   */
                 thisfile = (struct filestate *)                  thisfile = calloc(1, sizeof (struct filestate));
                                 calloc(1, sizeof(struct filestate));  
                 thisfile->buflist.next = thisfile->buflist.prev = END_OF_CHAIN;                  thisfile->buflist.next = thisfile->buflist.prev = END_OF_CHAIN;
                 thisfile->nbufs = 0;                  thisfile->nbufs = 0;
                 thisfile->flags = 0;                  thisfile->flags = 0;
Line 835 
Line 766 
                 thisfile->block = 0;                  thisfile->block = 0;
                 thisfile->offset = 0;                  thisfile->offset = 0;
                 thisfile->file = -1;                  thisfile->file = -1;
                 thisfile->fsize = NULL_POSITION;                  thisfile->fsize = -1;
                 ch_flags = flags;                  ch_flags = flags;
                 init_hashtbl();                  init_hashtbl();
                 /*                  /*
Line 853 
Line 784 
 /*  /*
  * Close a filestate.   * Close a filestate.
  */   */
         public void  void
 ch_close()  ch_close(void)
 {  {
         int keepstate = FALSE;          int keepstate = FALSE;
   
         if (thisfile == NULL)          if (thisfile == NULL)
                 return;                  return;
   
         if (ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE))          if (ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE)) {
         {  
                 /*                  /*
                  * We can seek or re-open, so we don't need to keep buffers.                   * We can seek or re-open, so we don't need to keep buffers.
                  */                   */
                 ch_delbufs();                  ch_delbufs();
         } else          } else {
                 keepstate = TRUE;                  keepstate = TRUE;
         if (!(ch_flags & CH_KEEPOPEN))          }
         {          if (!(ch_flags & CH_KEEPOPEN)) {
                 /*                  /*
                  * We don't need to keep the file descriptor open                   * We don't need to keep the file descriptor open
                  * (because we can re-open it.)                   * (because we can re-open it.)
Line 880 
Line 810 
                 if (!(ch_flags & CH_POPENED))                  if (!(ch_flags & CH_POPENED))
                         close(ch_file);                          close(ch_file);
                 ch_file = -1;                  ch_file = -1;
         } else          } else {
                 keepstate = TRUE;                  keepstate = TRUE;
         if (!keepstate)          }
         {          if (!keepstate) {
                 /*                  /*
                  * We don't even need to keep the filestate structure.                   * We don't even need to keep the filestate structure.
                  */                   */
                 free(thisfile);                  free(thisfile);
                 thisfile = NULL;                  thisfile = NULL;
                 set_filestate(curr_ifile, (void *) NULL);                  set_filestate(curr_ifile, NULL);
         }          }
 }  }
   
 /*  /*
  * Return ch_flags for the current file.   * Return ch_flags for the current file.
  */   */
         public int  int
 ch_getflags()  ch_getflags(void)
 {  {
         if (thisfile == NULL)          if (thisfile == NULL)
                 return (0);                  return (0);
         return (ch_flags);          return (ch_flags);
 }  }
   
 #if 0  
         public void  
 ch_dump(struct filestate *fs)  
 {  
         struct buf *bp;  
         struct bufnode *bn;  
         unsigned char *s;  
   
         if (fs == NULL)  
         {  
                 printf(" --no filestate\n");  
                 return;  
         }  
         printf(" file %d, flags %x, fpos %x, fsize %x, blk/off %x/%x\n",  
                 fs->file, fs->flags, fs->fpos,  
                 fs->fsize, fs->block, fs->offset);  
         printf(" %d bufs:\n", fs->nbufs);  
         for (bn = fs->next; bn != &fs->buflist;  bn = bn->next)  
         {  
                 bp = bufnode_buf(bn);  
                 printf("%x: blk %x, size %x \"",  
                         bp, bp->block, bp->datasize);  
                 for (s = bp->data;  s < bp->data + 30;  s++)  
                         if (*s >= ' ' && *s < 0x7F)  
                                 printf("%c", *s);  
                         else  
                                 printf(".");  
                 printf("\"\n");  
         }  
 }  
 #endif  

Legend:
Removed from v.1.10  
changed lines
  Added in v.1.11