home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 287.lha / TY_v1.3 / src / ch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-07  |  7.5 KB  |  225 lines

  1. /*************************************************************************
  2.  ***                        ch.c                         (JJB TEMPLAR) ***
  3.  *** Date modifications begun: 7/8/89.                                 ***
  4.  *** Last modified: 13/8/89.                                           ***
  5.  *************************************************************************/
  6. /*** Low level character input from the input file. We use these       ***
  7.  *** special purpose routines which optimize moving both forward and   ***
  8.  *** backward from the current read pointer.                           ***
  9.  *************************************************************************/
  10.  
  11. #include "less.h"
  12. #include <exec/memory.h>
  13. #include <libraries/dos.h>
  14.  
  15. extern int  fast_line;
  16.  
  17. BPTR    file = NULL;    /* File descriptor of the input file */
  18.  
  19. /* Pool of buffers holding the most recently used blocks of the input file. */
  20. #define BUFSIZ  1024
  21. struct buf {
  22.    struct buf *next, *prev;
  23.    long block;
  24.    char data[BUFSIZ];
  25. };
  26. static struct buf *bufs = NULL;
  27. int     nbufs;
  28.  
  29. /* The buffer pool is kept as a doubly-linked circular list,
  30.    in order from most- to least-recently used.
  31.    The circular list is anchored by buf_anchor. */
  32. static struct {
  33.    struct buf *next, *prev;
  34. } buf_anchor;
  35. #define END_OF_CHAIN    ((struct buf *)&buf_anchor)
  36. #define buf_head        buf_anchor.next
  37. #define buf_tail        buf_anchor.prev
  38.  
  39. /* If we fail to allocate enough memory for buffers, we try to limp
  40.    along with a minimum number of buffers. */
  41. #define DEF_NBUFS       2       /* Minimum number of buffers */
  42.  
  43. /* Current position in file. Stored as block num. and offset into the block. */
  44. static long ch_block;
  45. static int  ch_offset;
  46.  
  47. /* Length of file, needed if input is a pipe. */
  48. static LONG ch_fsize;
  49.  
  50. /* Largest block number read if input is standard input (a pipe). */
  51. static long last_piped_block;
  52.  
  53.  
  54. /*=============================fch_get===================================*/
  55. /* Get the character pointed to by the read pointer. ch_get() is a macro
  56.    which is more efficient to call than fch_get (the function), in the
  57.    usual case that the block desired is at the head of the chain. */
  58. #define ch_get()   ((buf_head->block == ch_block) ? \
  59.          buf_head->data[ch_offset] : fch_get())
  60.  
  61. static int  fch_get() /*=================================================*/
  62. {
  63. register struct buf *bp;
  64. register char       *cp;
  65. register int        n;
  66. register int        end;
  67. LONG                pos;
  68.  
  69.   /* Look for a buffer holding the desired block. */
  70.     for (bp = buf_head;  bp != END_OF_CHAIN;  bp = bp->next)
  71.         if (bp->block == ch_block) goto found;
  72.  
  73.   /* Block is not in a buffer. Take the least recently used buffer
  74.      and read the desired block into it. */
  75.     bp = buf_tail;
  76.     bp->block = ch_block;
  77.     pos = ch_block * BUFSIZ;
  78.     Seek(file, pos, OFFSET_BEGINNING);
  79.  
  80.     end = Read(file, &bp->data[0], BUFSIZ);     /* Read block */
  81.     if (end < 0) {                              /* Check if bombed out */
  82.         error("read error",1);
  83.         cleanup(NULL,50);
  84.     }
  85.   /* Zap through and convert zeros to asterisks */
  86.     if (!fast_line) {
  87.         cp = &bp->data[0];
  88.         for (n = 0; n < end; n++,cp++) if (!(*cp)) *cp = '@';
  89.     }
  90.  
  91.   /* Set an EOF marker in the buffered data itself.
  92.      Then ensure the data is "clean": there are no
  93.      extra EOF chars in the data and that the "meta"
  94.      bit (the 0200 bit) is reset in each char. */
  95.     if (end < BUFSIZ) {
  96.         ch_fsize = pos + end;
  97.         bp->data[end] = EOF;
  98.     }
  99.  
  100. found:
  101.   /* if (buf_head != bp) {this is guaranteed by the ch_get macro} */
  102.     /* Move the buffer to the head of the buffer chain.
  103.        This orders the buffer chain, most- to least-recently used. */
  104.         bp->next->prev = bp->prev;
  105.         bp->prev->next = bp->next;
  106.  
  107.         bp->next = buf_head;
  108.         bp->prev = END_OF_CHAIN;
  109.         buf_head->prev = bp;
  110.         buf_head = bp;
  111.   /* } */
  112.     return((int) bp->data[ch_offset]);
  113. }
  114.  
  115. static int  buffered(block) /*===========================================*/
  116. long        block;          /* Is block in one of the buffers?           */
  117. {
  118. register struct buf *bp;
  119.  
  120.     for (bp = buf_head;  bp != END_OF_CHAIN;  bp = bp->next)
  121.         if (bp->block == block) return (1);
  122.     return(0);
  123. }
  124.  
  125. int     ch_seek(pos) /*==================================================*/
  126. register LONG   pos; /* Seek to a specific pos in file.                  */
  127. {                    /* Zero if successful, non-zero if fails.           */
  128. long    new_block;
  129.     new_block = pos / BUFSIZ;
  130.   /* Set read pointer. */
  131.     ch_block = new_block;
  132.     ch_offset = pos % BUFSIZ;
  133.     return(0);
  134. }
  135.  
  136. void    end_seek() /*====================================================*/
  137. {                  /* Seek to end of file.                               */
  138.     Seek(file, 0, OFFSET_END);
  139.     ch_seek(Seek(file, 0, OFFSET_END)); /* Second Seek returns final pos */
  140. }
  141.  
  142. LONG    ch_length() /*===================================================*/
  143. {
  144.     Seek(file, 0, OFFSET_END);
  145.     return(Seek(file, 0, OFFSET_END));
  146. }
  147.  
  148. LONG    ch_tell() /*=====================================================*/
  149. {                 /* Return cur position in file.                        */
  150.     return(ch_block * BUFSIZ + ch_offset);
  151. }
  152.  
  153. int     ch_forw_get() /*=================================================*/
  154. {                     /* Get char, post-int read pointer.                */
  155. register int    c;
  156.  
  157.     c = ch_get();
  158.     if ((c != EOF) && (++ch_offset >= BUFSIZ)) {
  159.         ch_offset = 0;
  160.         ch_block ++;
  161.     }
  162.     return(c);
  163. }
  164.  
  165. int     ch_back_get() /*=================================================*/
  166. {                     /* Pre-dec read pointer, get char.                 */
  167. register int    c;
  168.  
  169.     if (--ch_offset < 0) {
  170.         if (ch_block <= 0) {
  171.             ch_offset = 0;
  172.             return (EOF);
  173.         }
  174.         ch_offset = BUFSIZ - 1;
  175.         ch_block--;
  176.     }
  177.     c = ch_get();
  178.     return(c);
  179. }
  180.  
  181. void    ch_init(want_nbufs) /*===========================================*/
  182. int     want_nbufs;         /* Init buffer pool to all empty.            */
  183. {
  184. register struct buf *bp;
  185. char    message[80];
  186.  
  187.     if (nbufs < want_nbufs) {
  188.         /* We don't have enough buffers.
  189.            Free what we have (if any) and allocate some new ones. */
  190.         if (bufs) FreeMem((char *)bufs,sizeof(struct buf) * nbufs);
  191.         bufs = (struct buf *)AllocMem(want_nbufs * sizeof(struct buf),MEMF_CLEAR);
  192.         nbufs = want_nbufs;
  193.         if (bufs == NULL) {     /* Try for less buffers */
  194.             sprintf(message,"Cannot allocate %d buffers.  Using %d buffers.",nbufs,DEF_NBUFS);
  195.             error(message,1);
  196.  
  197.             bufs = (struct buf *)AllocMem(DEF_NBUFS * sizeof(struct buf),MEMF_CLEAR);
  198.             nbufs = DEF_NBUFS;
  199.             if (bufs == NULL) {     /* Dammit! No RAM for just small buffers */
  200.                 sprintf(message,"Cannot even allocate %d buffers!  Quitting.\n",DEF_NBUFS);
  201.                 error(message,1);
  202.                 cleanup(NULL,50);
  203.         }
  204.         }
  205.     }
  206.  
  207.   /* Initialize the buffers to empty. Set up the circular list. */
  208.     for (bp = &bufs[0];  bp < &bufs[nbufs];  bp++) {
  209.         bp->next = bp + 1;
  210.         bp->prev = bp - 1;
  211.         bp->block = -1L;
  212.     }
  213.     bufs[0].prev = bufs[nbufs-1].next = END_OF_CHAIN;
  214.     buf_head = &bufs[0];
  215.     buf_tail = &bufs[nbufs-1];
  216.     last_piped_block = -1;
  217.     ch_fsize = NULL_POSITION;
  218.     ch_seek(0);
  219. }
  220.  
  221. void    ch_memdump() /*==================================================*/
  222. {                    /* So cleanup() can catch memory to free, no check. */
  223.     if (bufs) FreeMem((char *)bufs,sizeof(struct buf) * nbufs);
  224. }
  225.