[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.7 and 1.8

version 1.7, 2006/04/02 00:55:32 version 1.8, 2011/09/16 18:12:09
Line 1 
Line 1 
 /*  /*
  * Copyright (C) 1984-2002  Mark Nudelman   * Copyright (C) 1984-2011  Mark Nudelman
  *   *
  * You may distribute under the terms of either the GNU General Public   * You may distribute under the terms of either the GNU General Public
  * License or the Less License, as specified in the README file.   * License or the Less License, as specified in the README file.
Line 21 
Line 21 
 #include <windows.h>  #include <windows.h>
 #endif  #endif
   
   #if HAVE_STAT_INO
   #include <sys/stat.h>
   extern dev_t curr_dev;
   extern ino_t curr_ino;
   #endif
   
 typedef POSITION BLOCKNUM;  typedef POSITION BLOCKNUM;
   
 public int ignore_eoi;  public int ignore_eoi;
Line 31 
Line 37 
  * in order from most- to least-recently used.   * in order from most- to least-recently used.
  * The circular list is anchored by the file state "thisfile".   * The circular list is anchored by the file state "thisfile".
  */   */
   struct bufnode {
           struct bufnode *next, *prev;
           struct bufnode *hnext, *hprev;
   };
   
 #define LBUFSIZE        8192  #define LBUFSIZE        8192
 struct buf {  struct buf {
         struct buf *next, *prev;          struct bufnode node;
         struct buf *hnext, *hprev;  
         BLOCKNUM block;          BLOCKNUM block;
         unsigned int datasize;          unsigned int datasize;
         unsigned char data[LBUFSIZE];          unsigned char data[LBUFSIZE];
 };  };
   #define bufnode_buf(bn)  ((struct buf *) bn)
   
 struct buflist {  
         /* -- Following members must match struct buf */  
         struct buf *buf_next, *buf_prev;  
         struct buf *buf_hnext, *buf_hprev;  
 };  
   
 /*  /*
  * The file state is maintained in a filestate structure.   * The file state is maintained in a filestate structure.
  * A pointer to the filestate is kept in the ifile structure.   * A pointer to the filestate is kept in the ifile structure.
  */   */
 #define BUFHASH_SIZE    64  #define BUFHASH_SIZE    64
 struct filestate {  struct filestate {
         struct buf *buf_next, *buf_prev;          struct bufnode buflist;
         struct buflist hashtbl[BUFHASH_SIZE];          struct bufnode hashtbl[BUFHASH_SIZE];
         int file;          int file;
         int flags;          int flags;
         POSITION fpos;          POSITION fpos;
Line 63 
Line 68 
         POSITION fsize;          POSITION fsize;
 };  };
   
 #define ch_bufhead      thisfile->buf_next  #define ch_bufhead      thisfile->buflist.next
 #define ch_buftail      thisfile->buf_prev  #define ch_buftail      thisfile->buflist.prev
 #define ch_nbufs        thisfile->nbufs  #define ch_nbufs        thisfile->nbufs
 #define ch_block        thisfile->block  #define ch_block        thisfile->block
 #define ch_offset       thisfile->offset  #define ch_offset       thisfile->offset
Line 73 
Line 78 
 #define ch_flags        thisfile->flags  #define ch_flags        thisfile->flags
 #define ch_file         thisfile->file  #define ch_file         thisfile->file
   
 #define END_OF_CHAIN    ((struct buf *)&thisfile->buf_next)  #define END_OF_CHAIN    (&thisfile->buflist)
 #define END_OF_HCHAIN(h) ((struct buf *)&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))
   
 #define FOR_BUFS_IN_CHAIN(h,bp) \  /*
         for (bp = thisfile->hashtbl[h].buf_hnext;  \   * Macros to manipulate the list of buffers in thisfile->buflist.
              bp != END_OF_HCHAIN(h);  bp = bp->hnext)   */
   #define FOR_BUFS(bn) \
           for (bn = ch_bufhead;  bn != END_OF_CHAIN;  bn = bn->next)
   
 #define HASH_RM(bp) \  #define BUF_RM(bn) \
         (bp)->hnext->hprev = (bp)->hprev; \          (bn)->next->prev = (bn)->prev; \
         (bp)->hprev->hnext = (bp)->hnext;          (bn)->prev->next = (bn)->next;
   
 #define HASH_INS(bp,h) \  #define BUF_INS_HEAD(bn) \
         (bp)->hnext = thisfile->hashtbl[h].buf_hnext; \          (bn)->next = ch_bufhead; \
         (bp)->hprev = END_OF_HCHAIN(h); \          (bn)->prev = END_OF_CHAIN; \
         thisfile->hashtbl[h].buf_hnext->hprev = (bp); \          ch_bufhead->prev = (bn); \
         thisfile->hashtbl[h].buf_hnext = (bp);          ch_bufhead = (bn);
   
   #define BUF_INS_TAIL(bn) \
           (bn)->next = END_OF_CHAIN; \
           (bn)->prev = ch_buftail; \
           ch_buftail->next = (bn); \
           ch_buftail = (bn);
   
   /*
    * Macros to manipulate the list of buffers in thisfile->hashtbl[n].
    */
   #define FOR_BUFS_IN_CHAIN(h,bn) \
           for (bn = thisfile->hashtbl[h].hnext;  \
                bn != END_OF_HCHAIN(h);  bn = bn->hnext)
   
   #define BUF_HASH_RM(bn) \
           (bn)->hnext->hprev = (bn)->hprev; \
           (bn)->hprev->hnext = (bn)->hnext;
   
   #define BUF_HASH_INS(bn,h) \
           (bn)->hnext = thisfile->hashtbl[h].hnext; \
           (bn)->hprev = END_OF_HCHAIN(h); \
           thisfile->hashtbl[h].hnext->hprev = (bn); \
           thisfile->hashtbl[h].hnext = (bn);
   
 static struct filestate *thisfile;  static struct filestate *thisfile;
 static int ch_ungotchar = -1;  static int ch_ungotchar = -1;
 static int maxbufs = -1;  static int maxbufs = -1;
Line 98 
Line 128 
 extern int autobuf;  extern int autobuf;
 extern int sigs;  extern int sigs;
 extern int secure;  extern int secure;
   extern int screen_trashed;
   extern int follow_mode;
 extern IFILE curr_ifile;  extern IFILE curr_ifile;
 #if LOGFILE  #if LOGFILE
 extern int logfile;  extern int logfile;
Line 109 
Line 141 
   
 /*  /*
  * Get the character pointed to by the read pointer.   * Get the character pointed to by the read pointer.
  * ch_get() is a macro which is more efficient to call  
  * than fch_get (the function), in the usual case  
  * that the block desired is at the head of the chain.  
  */   */
 #define ch_get()   ((ch_block == ch_bufhead->block && \  
                      ch_offset < ch_bufhead->datasize) ? \  
                         ch_bufhead->data[ch_offset] : fch_get())  
         int          int
 fch_get()  ch_get()
 {  {
         register struct buf *bp;          register struct buf *bp;
           register struct bufnode *bn;
         register int n;          register int n;
         register int slept;          register int slept;
         register int h;          register int h;
         POSITION pos;          POSITION pos;
         POSITION len;          POSITION len;
   
           if (thisfile == NULL)
                   return (EOI);
   
           /*
            * Quick check for the common case where
            * the desired char is in the head buffer.
            */
           if (ch_bufhead != END_OF_CHAIN)
           {
                   bp = bufnode_buf(ch_bufhead);
                   if (ch_block == bp->block && ch_offset < bp->datasize)
                           return bp->data[ch_offset];
           }
   
         slept = FALSE;          slept = FALSE;
   
         /*          /*
          * 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, bp)          FOR_BUFS_IN_CHAIN(h, 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.
                                  */                                   */
                                 goto read_more;                                  break;
                         goto found;                          goto found;
                 }                  }
         }          }
         /*          if (bn == END_OF_HCHAIN(h))
          * Block is not in a buffer.  
          * Take the least recently used buffer  
          * and read the desired block into it.  
          * If the LRU buffer has data in it,  
          * then maybe allocate a new buffer.  
          */  
         if (ch_buftail == END_OF_CHAIN || ch_buftail->block != -1)  
         {          {
                 /*                  /*
                  * There is no empty buffer to use.                   * Block is not in a buffer.
                  * Allocate a new buffer if:                   * Take the least recently used buffer
                  * 1. We can't seek on this file and -b is not in effect; or                   * and read the desired block into it.
                  * 2. We haven't allocated the max buffers for this file yet.                   * If the LRU buffer has data in it,
                    * then maybe allocate a new buffer.
                  */                   */
                 if ((autobuf && !(ch_flags & CH_CANSEEK)) ||                  if (ch_buftail == END_OF_CHAIN ||
                     (maxbufs < 0 || ch_nbufs < maxbufs))                          bufnode_buf(ch_buftail)->block != -1)
                         if (ch_addbuf())                  {
                                 /*                          /*
                                  * Allocation failed: turn off autobuf.                           * There is no empty buffer to use.
                                  */                           * Allocate a new buffer if:
                                 autobuf = OPT_OFF;                           * 1. We can't seek on this file and -b is not in effect; or
                            * 2. We haven't allocated the max buffers for this file yet.
                            */
                           if ((autobuf && !(ch_flags & CH_CANSEEK)) ||
                                   (maxbufs < 0 || ch_nbufs < maxbufs))
                                   if (ch_addbuf())
                                           /*
                                            * Allocation failed: turn off autobuf.
                                            */
                                           autobuf = OPT_OFF;
                   }
                   bn = ch_buftail;
                   bp = bufnode_buf(bn);
                   BUF_HASH_RM(bn); /* Remove from old hash chain. */
                   bp->block = ch_block;
                   bp->datasize = 0;
                   BUF_HASH_INS(bn, h); /* Insert into new hash chain. */
         }          }
         bp = ch_buftail;  
         HASH_RM(bp); /* Remove from old hash chain. */  
         bp->block = ch_block;  
         bp->datasize = 0;  
         HASH_INS(bp, h); /* Insert into new hash chain. */  
   
     read_more:      read_more:
         pos = (ch_block * LBUFSIZE) + bp->datasize;          pos = (ch_block * LBUFSIZE) + bp->datasize;
Line 267 
Line 314 
 #endif  #endif
 #endif  #endif
                         slept = TRUE;                          slept = TRUE;
   
   #if HAVE_STAT_INO
                           if (follow_mode == FOLLOW_NAME)
                           {
                                   /* See whether the file's i-number has changed.
                                    * If so, force the file to be closed and
                                    * reopened. */
                                   struct stat st;
                                   int r = stat(get_filename(curr_ifile), &st);
                                   if (r == 0 && (st.st_ino != curr_ino ||
                                           st.st_dev != curr_dev))
                                   {
                                           /* screen_trashed=2 causes
                                            * make_display to reopen the file. */
                                           screen_trashed = 2;
                                           return (EOI);
                                   }
                           }
   #endif
                 }                  }
                 if (sigs)                  if (sigs)
                         return (EOI);                          return (EOI);
         }          }
   
     found:      found:
         if (ch_bufhead != bp)          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.
                  */                   */
                 bp->next->prev = bp->prev;                  BUF_RM(bn);
                 bp->prev->next = bp->next;                  BUF_INS_HEAD(bn);
                 bp->next = ch_bufhead;  
                 bp->prev = END_OF_CHAIN;  
                 ch_bufhead->prev = bp;  
                 ch_bufhead = bp;  
   
                 /*                  /*
                  * Move to head of hash chain too.                   * Move to head of hash chain too.
                  */                   */
                 HASH_RM(bp);                  BUF_HASH_RM(bn);
                 HASH_INS(bp, h);                  BUF_HASH_INS(bn, h);
         }          }
   
         if (ch_offset >= bp->datasize)          if (ch_offset >= bp->datasize)
Line 350 
Line 412 
 sync_logfile()  sync_logfile()
 {  {
         register struct buf *bp;          register struct buf *bp;
           register struct bufnode *bn;
         int warned = FALSE;          int warned = FALSE;
         BLOCKNUM block;          BLOCKNUM block;
         BLOCKNUM nblocks;          BLOCKNUM nblocks;
Line 357 
Line 420 
         nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE;          nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE;
         for (block = 0;  block < nblocks;  block++)          for (block = 0;  block < nblocks;  block++)
         {          {
                 for (bp = ch_bufhead;  ;  bp = bp->next)                  int wrote = FALSE;
                   FOR_BUFS(bn)
                 {                  {
                         if (bp == END_OF_CHAIN)                          bp = bufnode_buf(bn);
                         {  
                                 if (!warned)  
                                 {  
                                         error("Warning: log file is incomplete",  
                                                 NULL_PARG);  
                                         warned = TRUE;  
                                 }  
                                 break;  
                         }  
                         if (bp->block == block)                          if (bp->block == block)
                         {                          {
                                 write(logfile, (char *) bp->data, bp->datasize);                                  write(logfile, (char *) bp->data, bp->datasize);
                                   wrote = TRUE;
                                 break;                                  break;
                         }                          }
                 }                  }
                   if (!wrote && !warned)
                   {
                           error("Warning: log file is incomplete",
                                   NULL_PARG);
                           warned = TRUE;
                   }
         }          }
 }  }
   
Line 388 
Line 450 
         BLOCKNUM block;          BLOCKNUM block;
 {  {
         register struct buf *bp;          register struct buf *bp;
           register struct bufnode *bn;
         register int h;          register int h;
   
         h = BUFHASH(block);          h = BUFHASH(block);
         FOR_BUFS_IN_CHAIN(h, bp)          FOR_BUFS_IN_CHAIN(h, bn)
         {          {
                   bp = bufnode_buf(bn);
                 if (bp->block == block)                  if (bp->block == block)
                         return (TRUE);                          return (TRUE);
         }          }
Line 410 
Line 474 
         BLOCKNUM new_block;          BLOCKNUM new_block;
         POSITION len;          POSITION len;
   
           if (thisfile == NULL)
                   return (0);
   
         len = ch_length();          len = ch_length();
         if (pos < ch_zero() || (len != NULL_POSITION && pos > len))          if (pos < ch_zero() || (len != NULL_POSITION && pos > len))
                 return (1);                  return (1);
Line 444 
Line 511 
 {  {
         POSITION len;          POSITION len;
   
           if (thisfile == NULL)
                   return (0);
   
         if (ch_flags & CH_CANSEEK)          if (ch_flags & CH_CANSEEK)
                 ch_fsize = filesize(ch_file);                  ch_fsize = filesize(ch_file);
   
Line 468 
Line 538 
         public int          public int
 ch_beg_seek()  ch_beg_seek()
 {  {
         register struct buf *bp, *firstbp;          register struct bufnode *bn;
           register struct bufnode *firstbn;
   
         /*          /*
          * Try a plain ch_seek first.           * Try a plain ch_seek first.
Line 480 
Line 551 
          * Can't get to position 0.           * Can't get to position 0.
          * Look thru the buffers for the one closest to position 0.           * Look thru the buffers for the one closest to position 0.
          */           */
         firstbp = bp = ch_bufhead;          firstbn = ch_bufhead;
         if (bp == END_OF_CHAIN)          if (firstbn == END_OF_CHAIN)
                 return (1);                  return (1);
         while ((bp = bp->next) != END_OF_CHAIN)          FOR_BUFS(bn)
                 if (bp->block < firstbp->block)          {
                         firstbp = bp;                  if (bufnode_buf(bn)->block < bufnode_buf(firstbn)->block)
         ch_block = firstbp->block;                          firstbn = bn;
           }
           ch_block = bufnode_buf(firstbn)->block;
         ch_offset = 0;          ch_offset = 0;
         return (0);          return (0);
 }  }
Line 497 
Line 570 
         public POSITION          public POSITION
 ch_length()  ch_length()
 {  {
           if (thisfile == NULL)
                   return (NULL_POSITION);
         if (ignore_eoi)          if (ignore_eoi)
                 return (NULL_POSITION);                  return (NULL_POSITION);
         return (ch_fsize);          return (ch_fsize);
Line 508 
Line 583 
         public POSITION          public POSITION
 ch_tell()  ch_tell()
 {  {
           if (thisfile == NULL)
                   return (NULL_POSITION);
         return (ch_block * LBUFSIZE) + ch_offset;          return (ch_block * LBUFSIZE) + ch_offset;
 }  }
   
Line 519 
Line 596 
 {  {
         register int c;          register int c;
   
           if (thisfile == NULL)
                   return (EOI);
         c = ch_get();          c = ch_get();
         if (c == EOI)          if (c == EOI)
                 return (EOI);                  return (EOI);
Line 538 
Line 617 
         public int          public int
 ch_back_get()  ch_back_get()
 {  {
           if (thisfile == NULL)
                   return (EOI);
         if (ch_offset > 0)          if (ch_offset > 0)
                 ch_offset --;                  ch_offset --;
         else          else
Line 576 
Line 657 
         public void          public void
 ch_flush()  ch_flush()
 {  {
         register struct buf *bp;          register struct bufnode *bn;
   
           if (thisfile == NULL)
                   return;
   
         if (!(ch_flags & CH_CANSEEK))          if (!(ch_flags & CH_CANSEEK))
         {          {
                 /*                  /*
Line 591 
Line 675 
         /*          /*
          * Initialize all the buffers.           * Initialize all the buffers.
          */           */
         for (bp = ch_bufhead;  bp != END_OF_CHAIN;  bp = bp->next)          FOR_BUFS(bn)
                 bp->block = -1;          {
                   bufnode_buf(bn)->block = -1;
           }
   
         /*          /*
          * Figure out the size of the file, if we can.           * Figure out the size of the file, if we can.
Line 639 
Line 725 
 ch_addbuf()  ch_addbuf()
 {  {
         register struct buf *bp;          register struct buf *bp;
           register struct bufnode *bn;
   
         /*          /*
          * Allocate and initialize a new buffer and link it           * Allocate and initialize a new buffer and link it
Line 649 
Line 736 
                 return (1);                  return (1);
         ch_nbufs++;          ch_nbufs++;
         bp->block = -1;          bp->block = -1;
         bp->next = END_OF_CHAIN;          bn = &bp->node;
         bp->prev = ch_buftail;  
         ch_buftail->next = bp;          BUF_INS_TAIL(bn);
         ch_buftail = bp;          BUF_HASH_INS(bn, 0);
         HASH_INS(bp, 0);  
         return (0);          return (0);
 }  }
   
Line 667 
Line 753 
   
         for (h = 0;  h < BUFHASH_SIZE;  h++)          for (h = 0;  h < BUFHASH_SIZE;  h++)
         {          {
                 thisfile->hashtbl[h].buf_hnext = END_OF_HCHAIN(h);                  thisfile->hashtbl[h].hnext = END_OF_HCHAIN(h);
                 thisfile->hashtbl[h].buf_hprev = END_OF_HCHAIN(h);                  thisfile->hashtbl[h].hprev = END_OF_HCHAIN(h);
         }          }
 }  }
   
Line 678 
Line 764 
         static void          static void
 ch_delbufs()  ch_delbufs()
 {  {
         register struct buf *bp;          register struct bufnode *bn;
   
         while (ch_bufhead != END_OF_CHAIN)          while (ch_bufhead != END_OF_CHAIN)
         {          {
                 bp = ch_bufhead;                  bn = ch_bufhead;
                 bp->next->prev = bp->prev;                  BUF_RM(bn);
                 bp->prev->next = bp->next;                  free(bufnode_buf(bn));
                 free(bp);  
         }          }
         ch_nbufs = 0;          ch_nbufs = 0;
         init_hashtbl();          init_hashtbl();
Line 731 
Line 816 
                  */                   */
                 thisfile = (struct filestate *)                  thisfile = (struct filestate *)
                                 calloc(1, sizeof(struct filestate));                                  calloc(1, sizeof(struct filestate));
                 thisfile->buf_next = thisfile->buf_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;
                 thisfile->fpos = 0;                  thisfile->fpos = 0;
Line 761 
Line 846 
 {  {
         int keepstate = FALSE;          int keepstate = FALSE;
   
         if (ch_flags & (CH_CANSEEK|CH_POPENED))          if (thisfile == NULL)
                   return;
   
           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.
Line 799 
Line 887 
         public int          public int
 ch_getflags()  ch_getflags()
 {  {
           if (thisfile == NULL)
                   return (0);
         return (ch_flags);          return (ch_flags);
 }  }
   
Line 807 
Line 897 
 ch_dump(struct filestate *fs)  ch_dump(struct filestate *fs)
 {  {
         struct buf *bp;          struct buf *bp;
           struct bufnode *bn;
         unsigned char *s;          unsigned char *s;
   
         if (fs == NULL)          if (fs == NULL)
Line 818 
Line 909 
                 fs->file, fs->flags, fs->fpos,                  fs->file, fs->flags, fs->fpos,
                 fs->fsize, fs->block, fs->offset);                  fs->fsize, fs->block, fs->offset);
         printf(" %d bufs:\n", fs->nbufs);          printf(" %d bufs:\n", fs->nbufs);
         for (bp = fs->buf_next; bp != (struct buf *)fs;  bp = bp->next)          for (bn = fs->next; bn != &fs->buflist;  bn = bn->next)
         {          {
                   bp = bufnode_buf(bn);
                 printf("%x: blk %x, size %x \"",                  printf("%x: blk %x, size %x \"",
                         bp, bp->block, bp->datasize);                          bp, bp->block, bp->datasize);
                 for (s = bp->data;  s < bp->data + 30;  s++)                  for (s = bp->data;  s < bp->data + 30;  s++)

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.8