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 >
Wrap
Text File
|
1987-06-17
|
12KB
|
310 lines
/* 006 13-Dec-86 ovvbuf.c
Buffer management routines for ovview.c
Copyright (c) 1986 by Blue Sky Software. All rights reserved.
*/
#include <stdio.h>
#include <fcntl.h>
#include "ov.h"
#define MAX_VBUF 8 /* allow up to 8 in memory buffers */
#define VBUF_LEN 16*1024 /* a buffer is 16K - make a power of 2 */
typedef struct { /* define the View BUFfer DEScriptior */
int buflen;
long bufoff;
char far *bufp;
} VBUF_DES;
static int vidx; /* current VBUF descriptor in use */
static int vlast; /* last VBUF descriptor in use */
static int num_vbuf; /* highest buffer that can be alloc'd */
static VBUF_DES vbufd[MAX_VBUF]; /* the arrary of VBUF descriptors */
static long bufoff; /* offset in file of current buffer */
static unsigned int buflen; /* length of data in current buffer */
unsigned char far *bufp; /* begining of data in buffer */
unsigned char far *curp; /* current char location in buffer */
unsigned char far *endp; /* end of current buffer */
/*global*/ int ALTCALL vbuf_init(int );
/*global*/ int ALTCALL vbuf_free(void);
/*global*/ unsigned long ALTCALL vtell(void);
/*global*/ int ALTCALL vseek(int ,long );
/*global*/ int ALTCALL vnextch(int );
/*global*/ int ALTCALL vprevch(int );
static int ALTCALL pagefwd(int ,long );
static int ALTCALL pagebck(int ,long );
static int ALTCALL vswitch(int );
/*****************************************************************************
V B U F _ I N I T
*****************************************************************************/
int ALTCALL
vbuf_init(fh) /* initialize the buffer system */
int fh;
{
vlast = -1; /* set indexes, etc to force an */
num_vbuf = MAX_VBUF; /* so the initial read loads the */
pagefwd(fh,0L); /* first buffer from the file */
vswitch(0); /* make the 1st buffer active */
curp = bufp; /* at the 1st char in 1st buffer */
}
/*****************************************************************************
V B U F _ F R E E
*****************************************************************************/
int ALTCALL
vbuf_free() { /* release all memory buffers */
register int i;
register VBUF_DES *vp;
for (i = 0, vp = vbufd; i <= vlast; i++, vp++) { /* release all buffers */
free_f(vp->bufp);
vp->bufp = NULL;
}
}
/****************************************************************************
V T E L L
****************************************************************************/
unsigned long ALTCALL
vtell() { /* return file offset of current character */
return(bufoff + (curp - bufp));
}
/*****************************************************************************
V S E E K
*****************************************************************************/
int ALTCALL
vseek(fh,offset) /* seek to specified offset in file/buffers */
int fh;
long offset;
{
register int i;
long readoff, labs();
register VBUF_DES *vp;
/* "seek" is easy if offset is in current buffer - normal case I hope */
if (offset >= bufoff && offset < bufoff + VBUF_LEN) {
curp = bufp + (offset - bufoff);
return;
} else { /* not in current buffer, is it in any buffer? */
for (i = 0, vp = vbufd; i <= vlast; i++, vp++)
if (offset >= vp->bufoff && offset < vp->bufoff + VBUF_LEN) {
vswitch(i); /* switch to buffer with */
curp = bufp + (offset - bufoff); /* wanted offset */
return;
}
}
/* offset location isn't in memory, do it the old fashion way, read it */
readoff = offset & ~((long)(VBUF_LEN-1)); /* where to read from */
/* special case if seeking what would be the next or prev buffer, we
keep as much buffered in memory as possible */
if (labs(readoff - bufoff) == VBUF_LEN) { /* reading next or prev block? */
if (readoff > bufoff) { /* next block? */
pagefwd(fh,readoff); /* swap in next buffer */
vswitch(vidx+1); /* make it active */
} else { /* previous block */
pagebck(fh,readoff); /* swap in prev buffer */
vswitch(vidx-1); /* make it active */
}
} else { /* not reading next or prev buffer */
/* seeking to some random position in file, discard all current buffers
and start over from new position */
vidx = vlast = 0; /* discard all buffers */
vbufd[0].bufoff = bufoff = readoff; /* where to read from */
bufp = vbufd[0].bufp; /* where to read to */
l_seek(fh,readoff);
vbufd[0].buflen = buflen = readbuf(fh,bufp,VBUF_LEN);
endp = bufp + buflen;
}
curp = bufp + (offset - bufoff); /* got buffer, goto offset */
return;
}
/****************************************************************************
V N E X T C H
****************************************************************************/
int ALTCALL
vnextch(fh) /* return next character from file/buffers */
int fh;
{
/************** Following code is duplicated by some callers **************/
if (curp < endp) /* the normal case is just to return */
return(*curp++); /* the next character in the buffer */
/**************************************************************************/
if (buflen < VBUF_LEN) /* only last buffer can be < VBUF_LEN */
return(EOF);
if (vidx == vlast) /* read more from file? */
if (pagefwd(fh,bufoff+VBUF_LEN) == EOF) /* try paging into the file */
return(EOF); /* watch for EOF */
vswitch(vidx+1); /* switch to next buffer */
curp = bufp; /* at start of buffer */
return(*curp++); /* return 1st char in it */
}
/****************************************************************************
V P R E V C H
****************************************************************************/
int ALTCALL
vprevch(fh) /* return previous character from file/buffers */
int fh;
{
/************** Following code is duplicated by some callers **************/
if (curp > bufp) /* the normal case is just to return */
return(*--curp); /* the prev character in the buffer */
/**************************************************************************/
if (bufoff == 0) /* at top of file? (offset == 0) */
return(EOF);
if (vidx == 0) /* is this the oldest buffer? */
pagebck(fh,bufoff-VBUF_LEN); /* if so, page backward a buffer */
vswitch(vidx-1); /* switch to prev buffer */
curp = endp; /* at end of buffer */
return(*--curp); /* return last char in it */
}
/*****************************************************************************
P A G E F W D
*****************************************************************************/
static int ALTCALL
pagefwd(fh,offset) /* page forward into the file being read */
int fh;
long offset;
{
int i;
register VBUF_DES *vp;
char far *bp, far *malloc_f();
/* bump the index of the last buffer used, check if all buffer
descriptors are used, if so reuse the oldest, otherwise try
to allocate another buffer and use that */
getbuf: /* look ma, a label for a goto! */
if (vlast == num_vbuf-1) { /* all buffer descriptors used? */
bp = vbufd[0].bufp; /* remember where buffer is */
for (i = 0; i < num_vbuf-1; i++) /* throw away oldest buffer by */
vbufd[i] = vbufd[i+1]; /* moving others down over it */
vbufd[vlast].bufp = bp; /* reuse oldest buffer */
vidx--; /* descriptors were shifted 1 */
} else { /* try to allocate another buffer */
vlast++; /* move to the next descriptor */
/* if we haven't already done so, allocate another buffer for the
descriptor, failing that use a reduced number of buffers. We
need to be able to alloc at least 1 */
if (vbufd[vlast].bufp == NULL)
if ((vbufd[vlast].bufp = malloc_f(VBUF_LEN)) == NULL) {
if (vlast == 0)
show_error(0,15,1,"No memory for view buffer");
num_vbuf = vlast--; /* can't alloc another buffer, operate with */
goto getbuf; /* a reduced number (minimum 1) of buffers */
}
}
/* a descriptor/buffer is ready, fill it with data from the file */
vp = &vbufd[vlast]; /* speed things up */
l_seek(fh,vp->bufoff = offset); /* where to read from */
vp->buflen = readbuf(fh,vp->bufp,VBUF_LEN);
if (vp->buflen == 0) /* very unlikley, but maybe EOF */
return(EOF);
else
return(1);
}
/*****************************************************************************
P A G E B C K
*****************************************************************************/
static int ALTCALL
pagebck(fh,offset) /* page backward into the file being read */
int fh;
long offset;
{
char far *bp;
register int i;
/* reuse the "newest" buffer (last one in descriptor array) */
bp = vbufd[vlast].bufp; /* remember where buffer is */
for (i = vlast; i > 0; i--) /* throw away newest buffer by */
vbufd[i] = vbufd[i-1]; /* moving others over it */
vbufd[0].bufp = bp; /* reuse newest buffer */
vidx++; /* descriptors were shifted 1 */
/* a descriptor/buffer is ready, fill it with data from the file */
l_seek(fh,vbufd[0].bufoff = offset); /* where to read from */
vbufd[0].buflen = readbuf(fh,bp,VBUF_LEN);
}
/*****************************************************************************
V S W I T C H
*****************************************************************************/
static int ALTCALL
vswitch(idx) /* make buffer idx the current buffer */
int idx;
{
register VBUF_DES *vp;
vp = &vbufd[vidx = idx]; /* assign vidx, address of vidx descriptor */
bufp = vp->bufp; /* buffer location */
bufoff = vp->bufoff; /* file offset of buffer */
buflen = vp->buflen; /* len of data in buffer */
endp = bufp + buflen; /* 1 past the last valid data byte in buffer */
}