home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 235_02 / ovvbuf.c < prev    next >
Text File  |  1987-06-17  |  12KB  |  310 lines

  1. /* 006  13-Dec-86  ovvbuf.c
  2.  
  3.         Buffer management routines for ovview.c
  4.  
  5.         Copyright (c) 1986 by Blue Sky Software.  All rights reserved.
  6. */
  7.  
  8. #include <stdio.h>
  9. #include <fcntl.h>
  10. #include "ov.h"
  11.  
  12. #define MAX_VBUF 8                     /* allow up to 8 in memory buffers */
  13. #define VBUF_LEN 16*1024               /* a buffer is 16K - make a power of 2 */
  14.  
  15. typedef struct {                       /* define the View BUFfer DEScriptior */
  16.    int buflen;
  17.    long bufoff;
  18.    char far *bufp;
  19. } VBUF_DES;
  20.  
  21. static int vidx;                       /* current VBUF descriptor in use     */
  22. static int vlast;                      /* last VBUF descriptor in use        */
  23. static int num_vbuf;                   /* highest buffer that can be alloc'd */
  24. static VBUF_DES vbufd[MAX_VBUF];       /* the arrary of VBUF descriptors     */
  25. static long bufoff;                    /* offset in file of current buffer   */
  26. static unsigned int buflen;            /* length of data in current buffer   */
  27. unsigned char far *bufp;               /* begining of data in buffer         */
  28. unsigned char far *curp;               /* current char location in buffer    */
  29. unsigned char far *endp;               /* end of current buffer              */
  30.  
  31. /*global*/  int ALTCALL vbuf_init(int );
  32. /*global*/  int ALTCALL vbuf_free(void);
  33. /*global*/  unsigned long ALTCALL vtell(void);
  34. /*global*/  int ALTCALL vseek(int ,long );
  35. /*global*/  int ALTCALL vnextch(int );
  36. /*global*/  int ALTCALL vprevch(int );
  37. static  int ALTCALL pagefwd(int ,long );
  38. static  int ALTCALL pagebck(int ,long );
  39. static  int ALTCALL vswitch(int );
  40.  
  41.  
  42. /*****************************************************************************
  43.                           V B U F _ I N I T
  44.  *****************************************************************************/
  45.  
  46. int ALTCALL
  47. vbuf_init(fh)          /* initialize the buffer system */
  48. int fh;
  49. {
  50.    vlast = -1;                         /* set indexes, etc to force an  */
  51.    num_vbuf = MAX_VBUF;                /* so the initial read loads the */
  52.    pagefwd(fh,0L);                     /* first buffer from the file    */
  53.    vswitch(0);                         /* make the 1st buffer active    */
  54.    curp = bufp;                        /* at the 1st char in 1st buffer */
  55. }
  56.  
  57.  
  58. /*****************************************************************************
  59.                           V B U F _ F R E E
  60.  *****************************************************************************/
  61.  
  62. int ALTCALL
  63. vbuf_free() {          /* release all memory buffers */
  64.  
  65.    register int i;
  66.    register VBUF_DES *vp;
  67.  
  68.    for (i = 0, vp = vbufd; i <= vlast; i++, vp++) {  /* release all buffers */
  69.       free_f(vp->bufp);
  70.       vp->bufp = NULL;
  71.    }
  72. }
  73.  
  74.  
  75. /****************************************************************************
  76.                               V T E L L
  77.  ****************************************************************************/
  78.  
  79. unsigned long ALTCALL
  80. vtell() {              /* return file offset of current character */
  81.  
  82.    return(bufoff + (curp - bufp));
  83. }
  84.  
  85.  
  86. /*****************************************************************************
  87.                                V S E E K
  88.  *****************************************************************************/
  89.  
  90. int ALTCALL
  91. vseek(fh,offset)       /* seek to specified offset in file/buffers */
  92. int fh;
  93. long offset;
  94. {
  95.    register int i;
  96.    long readoff, labs();
  97.    register VBUF_DES *vp;
  98.  
  99.    /* "seek" is easy if offset is in current buffer - normal case I hope */
  100.  
  101.    if (offset >= bufoff && offset < bufoff + VBUF_LEN) {
  102.  
  103.       curp = bufp + (offset - bufoff);
  104.       return;
  105.  
  106.    } else {    /* not in current buffer, is it in any buffer? */
  107.  
  108.       for (i = 0, vp = vbufd; i <= vlast; i++, vp++)
  109.          if (offset >= vp->bufoff && offset < vp->bufoff + VBUF_LEN) {
  110.             vswitch(i);                        /* switch to buffer with */
  111.             curp = bufp + (offset - bufoff);   /* wanted offset */
  112.             return;
  113.          }
  114.       }
  115.  
  116.    /* offset location isn't in memory, do it the old fashion way, read it */
  117.  
  118.    readoff = offset & ~((long)(VBUF_LEN-1));   /* where to read from  */
  119.  
  120.    /* special case if seeking what would be the next or prev buffer, we
  121.       keep as much buffered in memory as possible */
  122.  
  123.    if (labs(readoff - bufoff) == VBUF_LEN) {   /* reading next or prev block? */
  124.  
  125.       if (readoff > bufoff) {                  /* next block? */
  126.          pagefwd(fh,readoff);                  /* swap in next buffer */
  127.          vswitch(vidx+1);                      /* make it active */
  128.       } else {                                 /* previous block */
  129.          pagebck(fh,readoff);                  /* swap in prev buffer */
  130.          vswitch(vidx-1);                      /* make it active */
  131.       }
  132.  
  133.    } else {            /* not reading next or prev buffer */
  134.  
  135.       /* seeking to some random position in file, discard all current buffers
  136.          and start over from new position */
  137.  
  138.       vidx = vlast = 0;                        /* discard all buffers */
  139.       vbufd[0].bufoff = bufoff = readoff;      /* where to read from  */
  140.       bufp = vbufd[0].bufp;                    /* where to read to    */
  141.       l_seek(fh,readoff);
  142.       vbufd[0].buflen = buflen = readbuf(fh,bufp,VBUF_LEN);
  143.       endp = bufp + buflen;
  144.    }
  145.  
  146.   curp = bufp + (offset - bufoff);             /* got buffer, goto offset */
  147.   return;
  148. }
  149.  
  150.  
  151. /****************************************************************************
  152.                               V N E X T C H
  153.  ****************************************************************************/
  154.  
  155. int ALTCALL
  156. vnextch(fh)            /* return next character from file/buffers */
  157. int fh;
  158. {
  159.    /************** Following code is duplicated by some callers **************/
  160.  
  161.    if (curp < endp)            /* the normal case is just to return */
  162.       return(*curp++);         /*  the next character in the buffer */
  163.  
  164.    /**************************************************************************/
  165.  
  166.    if (buflen < VBUF_LEN)      /* only last buffer can be < VBUF_LEN */
  167.       return(EOF);
  168.  
  169.    if (vidx == vlast)                          /* read more from file? */
  170.       if (pagefwd(fh,bufoff+VBUF_LEN) == EOF)  /* try paging into the file */
  171.          return(EOF);                          /* watch for EOF */
  172.  
  173.    vswitch(vidx+1);                    /* switch to next buffer  */
  174.    curp = bufp;                        /* at start of buffer */
  175.  
  176.    return(*curp++);                    /* return 1st char in it */
  177. }
  178.  
  179.  
  180. /****************************************************************************
  181.                               V P R E V C H
  182.  ****************************************************************************/
  183.  
  184. int ALTCALL
  185. vprevch(fh)            /* return previous character from file/buffers */
  186. int fh;
  187. {
  188.    /************** Following code is duplicated by some callers **************/
  189.  
  190.    if (curp > bufp)            /* the normal case is just to return */
  191.       return(*--curp);         /*  the prev character in the buffer */
  192.  
  193.    /**************************************************************************/
  194.  
  195.    if (bufoff == 0)            /* at top of file? (offset == 0) */
  196.       return(EOF);
  197.  
  198.    if (vidx == 0)                      /* is this the oldest buffer? */
  199.       pagebck(fh,bufoff-VBUF_LEN);     /*   if so, page backward a buffer */
  200.  
  201.    vswitch(vidx-1);                    /* switch to prev buffer  */
  202.    curp = endp;                        /* at end of buffer */
  203.  
  204.    return(*--curp);                    /* return last char in it */
  205. }
  206.  
  207.  
  208. /*****************************************************************************
  209.                              P A G E F W D
  210.  *****************************************************************************/
  211.  
  212. static int ALTCALL
  213. pagefwd(fh,offset)     /* page forward into the file being read */
  214. int fh;
  215. long offset;
  216. {
  217.    int i;
  218.    register VBUF_DES *vp;
  219.    char far *bp, far *malloc_f();
  220.  
  221.    /* bump the index of the last buffer used, check if all buffer
  222.       descriptors are used, if so reuse the oldest, otherwise try
  223.       to allocate another buffer and use that */
  224.  
  225. getbuf:                /* look ma, a label for a goto! */
  226.  
  227.    if (vlast == num_vbuf-1) {          /* all buffer descriptors used? */
  228.  
  229.       bp = vbufd[0].bufp;        /* remember where buffer is */
  230.       for (i = 0; i < num_vbuf-1; i++) /* throw away oldest buffer by */
  231.          vbufd[i] = vbufd[i+1];        /*  moving others down over it */
  232.       vbufd[vlast].bufp = bp;    /* reuse oldest buffer */
  233.       vidx--;                          /* descriptors were shifted 1 */
  234.  
  235.    } else {            /* try to allocate another buffer */
  236.  
  237.       vlast++;                         /* move to the next descriptor */
  238.  
  239.       /* if we haven't already done so, allocate another buffer for the
  240.          descriptor, failing that use a reduced number of buffers.  We
  241.          need to be able to alloc at least 1 */
  242.  
  243.       if (vbufd[vlast].bufp == NULL)
  244.          if ((vbufd[vlast].bufp = malloc_f(VBUF_LEN)) == NULL) {
  245.             if (vlast == 0)
  246.                show_error(0,15,1,"No memory for view buffer");
  247.             num_vbuf = vlast--;   /* can't alloc another buffer, operate with */
  248.             goto getbuf;          /*  a reduced number (minimum 1) of buffers */
  249.          }
  250.    }
  251.  
  252.    /* a descriptor/buffer is ready, fill it with data from the file */
  253.  
  254.    vp = &vbufd[vlast];                         /* speed things up */
  255.    l_seek(fh,vp->bufoff = offset);             /* where to read from */
  256.    vp->buflen = readbuf(fh,vp->bufp,VBUF_LEN);
  257.  
  258.    if (vp->buflen == 0)                   /* very unlikley, but maybe EOF */
  259.       return(EOF);
  260.    else
  261.       return(1);
  262. }
  263.  
  264.  
  265. /*****************************************************************************
  266.                              P A G E B C K
  267.  *****************************************************************************/
  268.  
  269. static int ALTCALL
  270. pagebck(fh,offset)     /* page backward into the file being read */
  271. int fh;
  272. long offset;
  273. {
  274.    char far *bp;
  275.    register int i;
  276.  
  277.    /* reuse the "newest" buffer (last one in descriptor array) */
  278.  
  279.    bp = vbufd[vlast].bufp;             /* remember where buffer is */
  280.    for (i = vlast; i > 0; i--)         /* throw away newest buffer by */
  281.       vbufd[i] = vbufd[i-1];           /*  moving others over it */
  282.  
  283.    vbufd[0].bufp = bp;                 /* reuse newest buffer */
  284.    vidx++;                             /* descriptors were shifted 1 */
  285.  
  286.    /* a descriptor/buffer is ready, fill it with data from the file */
  287.  
  288.    l_seek(fh,vbufd[0].bufoff = offset);        /* where to read from */
  289.    vbufd[0].buflen = readbuf(fh,bp,VBUF_LEN);
  290. }
  291.  
  292.  
  293. /*****************************************************************************
  294.                              V S W I T C H
  295.  *****************************************************************************/
  296.  
  297. static int ALTCALL
  298. vswitch(idx)           /* make buffer idx the current buffer */
  299. int idx;
  300. {
  301.    register VBUF_DES *vp;
  302.  
  303.    vp = &vbufd[vidx = idx];    /* assign vidx, address of vidx descriptor */
  304.  
  305.    bufp = vp->bufp;            /* buffer location */
  306.    bufoff = vp->bufoff;        /* file offset of buffer */
  307.    buflen = vp->buflen;        /* len of data in buffer */
  308.    endp = bufp + buflen;       /* 1 past the last valid data byte in buffer */
  309. }
  310.