dos_compilers/Zortech C++ v30r1/SAMPLE/VBUF.C

381 lines
8.1 KiB
C++
Raw Normal View History

2024-07-02 17:01:21 +02:00
/*_ vbuf.c Tue Sep 12 1989 Modified by: Walter Bright */
/* Copyright (C) 1987-1989 by Northwest Software */
/* All Rights Reserved */
/* Written by Walter Bright */
/* Virtual buffered memory */
#include <stdio.h>
#include <string.h>
#ifdef __ZTC__
#include <stdlib.h>
#include <io.h>
#else
extern char* getenv();
#endif
#include "vbuf.h"
#include "mem.h"
#ifndef assert
#include <assert.h>
/*****************************
* Define a local assert function.
*/
#undef assert
#define assert(e) ((e) || local_assert(__LINE__))
static void near local_assert(line)
int line;
{
_assert("",__FILE__,line);
}
#endif
#define VFinmemory 1 /* 1 if buffer exists in memory */
#define VFondisk 2 /* 1 if buffer exists on disk */
#define VFdirty 4 /* 1 if disk buffer is obsolete */
#define vbuf_inmemory(vb_h) ((vb_h)->flags & VFinmemory)
int vbuf_inited = 0; /* != 0 if initialized */
static struct VBUF_S freehead = /* head of list of available buffers */
{ &freehead,&freehead,
};
static struct VBUF_S inusehead = /* list of in use buffers */
{ &inusehead,&inusehead,
};
static char* vm_tmp;
static int vm_fd = -1; /* file descriptor for vm.tmp */
static unsigned long vm_size = 0L; /* size of vm file */
#define vblist_append(dl,v) \
((v)->next = (dl)->next), \
((v)->prev = (dl)), \
((dl)->next = (v)), \
((v)->next->prev = (v))
#define vblist_prepend(dl,v) \
((v)->next = (dl)), \
((v)->prev = (dl)->prev), \
((dl)->prev = (v)), \
((v)->prev->next = (v))
#define vblist_remove(v) \
(((v)->prev->next = (v)->next), \
((v)->next->prev = (v)->prev))
/************************* LOCAL FUNCTIONS ***********************/
/****************************
* Open vm.
*/
static void vm_open()
{
vm_fd = creat(vm_tmp,0600);
if (vm_fd == -1) /* open failure */
{
printf("Error: can't open %s\n",vm_tmp);
exit(EXIT_FAILURE);
}
else
printf("Opening %s\n",vm_tmp);
}
/*****************************
* Allocate a disk buffer for the vb_h.
*/
static void getdiskbuffer(vb_h)
vbuf_handle_t vb_h;
{
if (freehead.next != &freehead) /* if available disk buffer */
{ vbuf_handle_t v = freehead.next;
vb_h->fd = v->fd;
vb_h->offset = v->offset;
vblist_remove(v);
mem_free(v);
}
else /* extend VM.TMP file */
{
if (vm_fd == -1)
vm_open(); /* create VM.TMP */
vb_h->fd = vm_fd;
vb_h->offset = vm_size;
vm_size += VBUF_SIZE;
}
vb_h->flags |= VFondisk | VFdirty;
}
/**************************
* Boot this vb out of memory, and free up the memory buffer.
*/
static void bootout(vb_h)
vbuf_handle_t vb_h;
{ int result;
if (vb_h->flags & VFdirty)
{
if (!(vb_h->flags & VFondisk))
getdiskbuffer(vb_h);
if (lseek(vb_h->fd,vb_h->offset,0) == -1L)
{
perror(vm_tmp);
vbuf_term();
exit(EXIT_FAILURE);
}
/*printf("write: fd = %d, offset = x%lx\n",vb_h->fd,vb_h->offset);*/
result = write(vb_h->fd,vb_h->memory,VBUF_SIZE);
if (result != VBUF_SIZE)
{ if (result < 0)
perror(vm_tmp);
else
fprintf(stderr,"%s: drive is full\n",vm_tmp);
vbuf_term();
exit(EXIT_FAILURE);
}
vb_h->flags &= ~VFdirty;
}
mem_free(vb_h->memory); /* free memory buffer */
vb_h->memory = NULL;
vb_h->flags &= ~VFinmemory; /* no longer in memory */
}
/*************************
* Read buffer back from disk.
*/
static void readback(vb_h)
vbuf_handle_t vb_h;
{
vb_h->memory = mem_malloc(VBUF_SIZE);
vb_h->flags |= VFinmemory;
if (lseek(vb_h->fd,vb_h->offset,0) == -1L)
{
perror(vm_tmp);
vbuf_term();
exit(EXIT_FAILURE);
}
/*printf("read : fd = %d, offset = x%lx\n",vb_h->fd,vb_h->offset);*/
if (read(vb_h->fd,vb_h->memory,VBUF_SIZE) == 0)
{
perror(vm_tmp);
vbuf_term();
exit(EXIT_FAILURE);
}
}
/************************* PUBLIC FUNCTIONS ***********************/
/***********************
* Initialize for virtual buffers.
*/
void vbuf_init()
{
char* sTmp;
char* s;
if (vbuf_inited == 0)
{
assert(mem_inited);
/* Set handler to call when out of memory */
mem_setexception(MEM_CALLFP,vbuf_needmemory);
sTmp = getenv("TMP");
if( sTmp == NULL )
sTmp = getenv("TEMP");
if( sTmp == NULL )
sTmp = "";
s = tempnam(sTmp,"ztc_");
vm_tmp = mem_strdup(s ? s : "VM.TMP");
free(s);
vbuf_inited++;
}
}
/***********************
* Terminate vbuf handler.
*/
void vbuf_term()
{
/*printf("vbuf_term()\n");*/
if (vbuf_inited)
{ vbuf_handle_t vb_h;
if (vm_fd != -1)
{ close(vm_fd);
unlink(vm_tmp);
}
#if TERMCODE
mem_free( vm_tmp );
while (freehead.next != &freehead)
{ vb_h = freehead.next;
freehead.next = vb_h->next;
mem_free(vb_h);
}
#endif
vbuf_inited = 0;
}
}
/****************************
* Allocate a new vbuf, clear it, and return a pointer to it.
* Returns 0 if can't allocate one.
*/
vbuf_handle_t vbuf_calloc()
{ vbuf_handle_t vb_h;
assert(vbuf_inited);
vb_h = (vbuf_handle_t) mem_calloc(sizeof(*vb_h));
if (vb_h)
{
vb_h->memory = mem_calloc(VBUF_SIZE);
if (vb_h->memory == NULL)
{ mem_free(vb_h);
vb_h = NULL;
}
else
{ vb_h->flags |= VFdirty | VFinmemory;
vblist_prepend(inusehead.next,vb_h);
}
}
/*printf("vbuf_calloc = %p\n",vb_h);*/
return vb_h;
}
/***************************/
vbuf_handle_t vbuf_filepage(fd,offset)
int fd;
unsigned long offset;
{ vbuf_handle_t vb_h;
assert(vbuf_inited);
vb_h = (vbuf_handle_t)mem_calloc(sizeof(struct VBUF_S));
if (vb_h)
{
vb_h->flags |= VFondisk;
vb_h->fd = fd;
vb_h->offset = offset;
vblist_prepend(inusehead.next,vb_h);
}
/*printf("vbuf_filepage(fd=%d, offset=x%lx) = %p\n",fd,offset,vb_h);*/
return vb_h;
}
/***************************
* Free up a vbuf.
*/
void vbuf_free(vb_h)
vbuf_handle_t vb_h;
{
/*printf("vbuf_free(%p)\n",vb_h);*/
if (vb_h->flags & VFinmemory)
{ mem_free(vb_h->memory);
vb_h->memory = NULL;
vb_h->flags &= ~VFinmemory;
}
vblist_remove(vb_h);
if (vb_h->flags & VFondisk && vb_h->fd == vm_fd)
vblist_append(&freehead,vb_h);
else
mem_free(vb_h);
}
/****************************
* Mark vbuf as being modified.
*/
#ifndef vbuf_dirty /* if not already a macro */
void vbuf_dirty(vb_h)
vbuf_handle_t vb_h;
{
vb_h->flags |= VFdirty;
}
#endif
/****************************
* Return a pointer to real memory associated with the handle.
* The pointer remains valid until the next call to vbuf_xxxx().
*/
vbuf_ptr_t pascal _vbuf_access(vb_h)
vbuf_handle_t vb_h;
{
if (!(vb_h->flags & VFinmemory))
{ readback(vb_h);
assert(vbuf_inmemory(vb_h));
}
/* Move vb_h to front of inuse list */
if (vb_h != inusehead.next)
{ vblist_remove(vb_h);
vblist_append(&inusehead,vb_h);
}
return vb_h->memory;
}
/****************************
* Lock a vbuf in memory.
*/
void vbuf_lock(vb_h)
vbuf_handle_t vb_h;
{
assert(vbuf_inmemory(vb_h) && vb_h->count >= 0);
vb_h->count++;
}
/****************************
* Unlock a vbuf from memory.
*/
void vbuf_unlock(vb_h)
vbuf_handle_t vb_h;
{
assert(vbuf_inmemory(vb_h) && vb_h->count > 0);
vb_h->count--;
assert( vb_h->count >= 0 );
}
/*****************************
* mem_xxxx() calls this when they run out of memory.
*/
int vbuf_needmemory()
{ static char inuse = 0;
int result;
vbuf_handle_t vb_h;
assert(vbuf_inited);
assert(inuse == 0);
inuse++; /* make sure that we don't double-fault */
for (vb_h = inusehead.prev; vb_h != &inusehead; vb_h = vb_h->prev)
{
if (vb_h->flags & VFinmemory && !vb_h->count)
{ bootout(vb_h);
result = MEM_RETRY;
goto ret;
}
}
if (vm_fd != -1) /* if VM.TMP file exists */
{ close(vm_fd);
unlink(vm_tmp); /* delete it */
}
result = MEM_ABORTMSG; /* out of memory, give up */
ret:
inuse--;
return result;
}