home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Shareware - Software Farm 2
/
wosw_2.zip
/
wosw_2
/
DATABASE
/
DPG.ZIP
/
FILES.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-21
|
22KB
|
881 lines
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <io.h>
#include <string.h>
#include <assert.h>
#include "video.h"
#include "files.h"
#define MAXKEY 32 /* Maximum depth a tree can achieve */
#define NODESIZE 512 /* Physical size of each node */
/* Macros to access values from nodes in memory */
#define nentries (*(short *)(node + NODESIZE - sizeof (short)))
#define nodeptr(i) ((long *)node)[i]
#define recptr(i) ((long *)node)[i + m]
#define entry(i) (node + (m*2 - 1)*sizeof (long) + (i)*length)
#define nentries2 (*(short *)(node2 + NODESIZE - sizeof (short)))
#define nodeptr2(i) ((long *)node2)[i]
#define recptr2(i) ((long *)node2)[i + m]
#define entry2(i) (node2 + (m*2 - 1)*sizeof (long) + (i)*length)
#define nentries3 (*(short *)(node3 + NODESIZE - sizeof (short)))
#define nodeptr3(i) ((long *)node3)[i]
#define recptr3(i) ((long *)node3)[i + m]
#define entry3(i) (node3 + (m*2 - 1)*sizeof (long) + (i)*length)
/* Storage for nodes in memory */
static char node[NODESIZE];
static char node2[NODESIZE];
static char node3[NODESIZE];
static m; /* Maximum branching factor */
static length; /* Length of keys */
static indexfile; /* Handle for index file */
static miscoff; /* Offset of data in miscfile */
static long newnodeptr; /* Pointer to newly created node */
int miscfile;
/* Read data from file with error checking */
void Read (int file,long p,void *buf,int bytes)
{
lseek (file,p,SEEK_SET);
if (read (file,buf,bytes) != bytes)
{
printf ("Read Error\n");
exit (1);
}
}
/* Write data to file with error checking */
void Write (int file,long p,void *buf,int bytes)
{
lseek (file,p,SEEK_SET);
if (write (file,buf,bytes) != bytes)
{
printf ("Write Error\n");
exit (1);
}
}
/* Calculate the maximum branching factor given the key length for the
current index file */
static void calcm (void)
{
m = (NODESIZE + length + sizeof (long) - sizeof (short)) /
(length + 2*sizeof (long));
}
/* Allocate a new node */
static long allocnode (void)
{
long p;
long next;
/* Pointer to first node on free list */
Read (miscfile,miscoff + 3*sizeof (long),&p,sizeof p);
if (p < 0) /* If no nodes on free list, add one to end of file */
return filelength (indexfile);
/* Return first node on free list and update list pointer */
Read (indexfile,p,&next,sizeof next);
Write (miscfile,miscoff + 3*sizeof (long),&next,sizeof next);
return p;
}
/* Add a node to free list */
static void freenode (long t)
{
long p;
Read (miscfile,miscoff + 3*sizeof (long),&p,sizeof p);
Write (indexfile,t,&p,sizeof p);
Write (miscfile,miscoff + 3*sizeof (long),&t,sizeof t);
}
/* Delete a record from linked list of records, and add it to list of
free data records */
void delete (int file,long ptr,void *rec,long _miscoff)
{
long listptr[3];
long next;
long prev;
miscoff = _miscoff;
next = ((long *)rec)[0]; /* Pointer to next record */
prev = ((long *)rec)[1]; /* Pointer to previous record */
/* Remove record from linked list */
if (next >= 0)
Write (file,next + sizeof (long),&prev,sizeof prev);
if (prev >= 0)
Write (file,prev,&next,sizeof next);
Read (miscfile,miscoff,listptr,sizeof listptr);
if (listptr[1] == ptr)
listptr[1] = next;
if (listptr[2] == ptr)
listptr[2] = prev;
/* Add record to free list */
Write (file,ptr,&listptr[0],sizeof listptr[0]);
listptr[0] = ptr;
Write (miscfile,miscoff,listptr,sizeof listptr);
}
/* Delete a data record from an indexed file */
void deleteindex (int file,long ptr,void *rec,long _miscoff,
char *key,int _length,int _indexfile)
{
long t,t2;
int n;
int lo,hi;
int i,j,k;
int c;
int iv[MAXKEY];
long chain[MAXKEY];
indexfile = _indexfile;
miscoff = _miscoff;
length = _length;
calcm ();
/* Delete record from linked list */
delete (file,ptr,rec,miscoff);
t = 0;
n = -1;
for (;;)
{
Read (indexfile,t,node,NODESIZE);
lo = 0;
hi = nentries - 1;
while (lo <= hi)
{
i = (lo + hi) / 2;
c = memicmp (entry (i),key,length);
if (c == 0)
break;
if (c < 0)
lo = i + 1;
else
hi = i - 1;
}
if (c == 0)
break;
n++;
assert (n < MAXKEY);
iv[n] = lo;
chain[n] = t;
t = nodeptr (lo);
assert (t >= 0);
}
if (nodeptr (0) >= 0)
{
t2 = t;
lo++;
n++;
assert (n < MAXKEY);
iv[n] = lo;
chain[n] = t;
t = nodeptr (lo);
assert (t >= 0);
Read (indexfile,t,node,NODESIZE);
do
{
n++;
assert (n < MAXKEY);
iv[n] = 0;
chain[n] = t;
t = nodeptr (0);
assert (t >= 0);
Read (indexfile,t,node,NODESIZE);
}
while (nodeptr (0) >= 0);
Write (indexfile,t2 + (m+lo)*sizeof (long),&recptr (lo),sizeof (long));
Write (indexfile,t2 + m*2*sizeof (long) + lo*length,entry (lo),length);
}
memmove (&nodeptr (lo),&nodeptr (lo + 1),(nentries - lo)*sizeof (long));
memmove (&recptr (lo),&recptr (lo + 1),(nentries - lo - 1)*sizeof (long));
memmove (entry (lo),entry (lo + 1),(nentries - lo - 1)*length);
nentries--;
Write (indexfile,t,node,NODESIZE);
/* While current node has too few entries */
while (nentries < (m - 1) / 2 && n > 0)
{
/* Read father node */
Read (indexfile,chain[n - 1],node3,NODESIZE);
/* Index for father key */
i = iv[n - 1] - 1;
/* If current node is leftmost, merge with right brother */
if (i < 0)
{
/* Read brother node */
t2 = nodeptr3 (1);
Read (indexfile,t2,node2,NODESIZE);
/* If merged node would have few enough entries */
if (nentries + nentries2 < m - 1)
{
/* Move over brother node keys */
memmove (&nodeptr2 (nentries + 1),&nodeptr2 (0),(nentries2 + 1)*sizeof (long));
memmove (&recptr2 (nentries + 1),&recptr2 (0),nentries2*sizeof (long));
memmove (entry2 (nentries + 1),entry2 (0),nentries2*length);
nentries2 += nentries + 1;
/* Copy current node keys into brother node */
memcpy (&nodeptr2 (0),&nodeptr (0),(nentries + 1)*sizeof (long));
memcpy (&recptr2 (0),&recptr (0),nentries*sizeof (long));
memcpy (entry2 (0),entry (0),nentries*length);
/* Put father key into brother node */
recptr2 (nentries) = recptr3 (0);
memcpy (entry2 (nentries),entry3 (0),length);
/* Delete father key from father node */
memmove (&nodeptr3 (0),&nodeptr3 (1),nentries3*sizeof (long));
memmove (&recptr3 (0),&recptr3 (1),(nentries3 - 1)*sizeof (long));
memmove (entry3 (0),entry3 (1),(nentries3 - 1)*length);
nentries3--;
/* Free current node */
freenode (t);
/* If father node is root node and empty, delete it */
if (n == 1 && nentries3 == 0)
{
/* Free prior location of brother node */
freenode (t2);
/* Write brother node into root node's location */
Write (indexfile,0,node2,NODESIZE);
}
else /* Write back nodes */
{
/* Write back brother node */
Write (indexfile,t2,node2,NODESIZE);
/* Write back father node */
Write (indexfile,chain[n - 1],node3,NODESIZE);
}
/* Finish */
break;
}
else /* Redistribute keys between two nodes */
{
/* Middle key to be used as replacement for father key */
j = (nentries2 + nentries) / 2 - nentries - 1;
/* Copy in father key */
recptr (nentries) = recptr3 (0);
memcpy (entry (nentries),entry3 (0),length);
/* Copy keys from brother node to current node */
memcpy (&nodeptr (nentries + 1),&nodeptr2 (0),(j + 1)*sizeof (long));
memcpy (&recptr (nentries + 1),&recptr2 (0),j*sizeof (long));
memcpy (entry (nentries + 1),entry2 (0),j*length);
/* Copy middle key into father node */
recptr3 (0) = recptr2 (j);
memcpy (entry3 (0),entry2 (j),length);
nentries += j + 1;
/* Move down entries in brother node */
memmove (&nodeptr2 (0),&nodeptr2 (j + 1),(nentries2 - j)*sizeof (long));
memmove (&recptr2 (0),&recptr2 (j + 1),(nentries2 - j - 1)*sizeof (long));
memmove (entry2 (0),entry2 (j + 1),(nentries2 - j - 1)*length);
nentries2 -= j + 1;
/* Write back current node */
Write (indexfile,t,node,NODESIZE);
/* Write back brother node */
Write (indexfile,t2,node2,NODESIZE);
/* Write back father node */
Write (indexfile,chain[n - 1],node3,NODESIZE);
/* Step up to father node and continue */
memcpy (node,node3,NODESIZE);
n--;
t = chain[n];
}
}
else /* Merge with left brother */
{
/* Read brother node */
t2 = nodeptr3 (i);
Read (indexfile,t2,node2,NODESIZE);
/* If merged node would have few enough entries */
if (nentries + nentries2 < m - 1)
{
/* Put father key into brother node */
recptr2 (nentries2) = recptr3 (i);
memcpy (entry2 (nentries2),entry3 (i),length);
nentries2++;
/* Merge current node keys into brother node */
memcpy (&nodeptr2 (nentries2),&nodeptr (0),(nentries + 1)*sizeof (long));
memcpy (&recptr2 (nentries2),&recptr (0),nentries*sizeof (long));
memcpy (entry2 (nentries2),entry (0),nentries*length);
nentries2 += nentries;
/* Delete father key from father node */
memmove (&nodeptr3 (i + 1),&nodeptr3 (i + 2),(nentries3 - i)*sizeof (long));
memmove (&recptr3 (i),&recptr3 (i + 1),(nentries3 - i - 1)*sizeof (long));
memmove (entry3 (i),entry3 (i + 1),(nentries3 - i - 1)*length);
nentries3--;
/* Free current node */
freenode (t);
/* Write back brother node */
Write (indexfile,t2,node2,NODESIZE);
/* Write back father node */
Write (indexfile,chain[n - 1],node3,NODESIZE);
/* Finish */
break;
}
else /* Redistribute keys between two nodes */
{
/* Middle key to be used as replacement for father key */
j = (nentries2 + nentries) / 2;
/* Number of keys to transfer from brother to current node */
k = nentries2 - j;
/* Move over keys in current node to make room */
memmove (&nodeptr (k + 1),&nodeptr (0),(nentries + 1)*sizeof (long));
memmove (&recptr (k + 1),&recptr (0),nentries*sizeof (long));
memmove (entry (k + 1),entry (0),nentries*length);
nentries += k + 1;
/* Copy in father key */
recptr (k) = recptr3 (i);
memcpy (entry (k),entry3 (i),length);
/* Copy keys from brother node to current node */
memcpy (&nodeptr (0),&nodeptr2 (j + 1),(k + 1)*sizeof (long));
memcpy (&recptr (0),&recptr2 (j + 1),k*sizeof (long));
memcpy (entry (0),entry2 (j + 1),k*length);
nentries2 -= k + 1;
/* Copy middle key into father node */
recptr3 (i) = recptr2 (j);
memcpy (entry3 (i),entry2 (j),length);
/* Write back current node */
Write (indexfile,t,node,NODESIZE);
/* Write back brother node */
Write (indexfile,t2,node2,NODESIZE);
/* Write back father node */
Write (indexfile,chain[n - 1],node3,NODESIZE);
/* Step up to father node and continue */
memcpy (node,node3,NODESIZE);
n--;
t = chain[n];
}
}
}
}
/* Allocate a new data record, and add to linked list */
void create (int file,long *ptr,void *rec,int size,long _miscoff)
{
long listptr[3];
long p;
miscoff = _miscoff;
Read (miscfile,miscoff,listptr,sizeof listptr);
if (listptr[0] < 0) /* If free list is empty */
p = filelength (file); /* get new record from end of file */
else /* get first record from free list */
{
p = listptr[0];
Read (file,p,listptr,sizeof (long));
}
if (listptr[2] < 0) /* If linked list is empty, initialize it */
{
listptr[1] = p;
listptr[2] = p;
}
else /* add record to linked list */
{
((long *)rec)[1] = listptr[2];
Write (file,listptr[2],&p,sizeof (long));
listptr[2] = p;
}
Write (file,p,rec,size);
Write (miscfile,miscoff,listptr,sizeof listptr);
*ptr = p;
}
/* Recursively insert key in B-tree and return error if any */
static insert (long t,long *rptr,char *rkey,long ptr,char *key)
{
long newptr;
char newkey[MAXKEY];
int lo,hi;
int i,j;
int c;
long n1;
if (t < 0) /* Run out of tree so have to back up */
{
*rptr = ptr;
memcpy (rkey,key,length);
return 0;
}
Read (indexfile,t,node,NODESIZE);
/* Find where to insert new key in current node */
lo = 0;
hi = nentries - 1;
while (lo <= hi)
{
i = (lo + hi) / 2;
c = memicmp (entry (i),key,length);
if (c == 0) /* Key already exists, so return error */
return 1;
if (c < 0)
lo = i + 1;
else
hi = i - 1;
}
/* Recursively insert key below current node */
if (insert (nodeptr (i),&newptr,newkey,ptr,key))
return 1;
/* If insertion has propagated up from node below */
if (newptr >= 0)
{
Read (indexfile,t,node,NODESIZE);
/* Again find key in current node */
lo = 0;
hi = nentries - 1;
while (lo <= hi)
{
i = (lo + hi) / 2;
c = memicmp (entry (i),newkey,length);
assert (c != 0);
if (c < 0)
lo = i + 1;
else
hi = i - 1;
}
if (nentries == m - 1) /* If node is too full, split it */
{
n1 = allocnode ();
j = m / 2;
if (lo <= j)
j--;
*rptr = recptr (j);
memcpy (rkey,entry (j),length);
memmove (&nodeptr (j),&nodeptr (j + 1),(nentries - j)*sizeof (long));
memmove (&recptr (j),&recptr (j + 1),(nentries - j - 1)*sizeof (long));
memmove (entry (j),entry (j + 1),(nentries - j - 1)*length);
if (lo <= j + 1)
j++;
memmove (&nodeptr (lo + 1),&nodeptr (lo),(nentries - lo)*sizeof (long));
memmove (&recptr (lo + 1),&recptr (lo),(nentries - lo - 1)*sizeof (long));
memmove (entry (lo + 1),entry (lo),(nentries - lo - 1)*length);
nodeptr (lo) = newnodeptr;
recptr (lo) = newptr;
memcpy (entry (lo),newkey,length);
nentries = j;
Write (indexfile,n1,node,NODESIZE);
nentries = m - 1 - j;
memcpy (&nodeptr (0),&nodeptr (j),(nentries + 1)*sizeof (long));
memcpy (&recptr (0),&recptr (j),nentries*sizeof (long));
memcpy (entry (0),entry (j),nentries*length);
Write (indexfile,t,node,NODESIZE);
newnodeptr = n1;
return 0;
}
else /* Simply insert in current node */
{
memmove (&nodeptr (lo + 1),&nodeptr (lo),(nentries - lo + 1)*sizeof (long));
memmove (&recptr (lo + 1),&recptr (lo),(nentries - lo)*sizeof (long));
memmove (entry (lo + 1),entry (lo),(nentries - lo)*length);
nodeptr (lo) = newnodeptr;
recptr (lo) = newptr;
memcpy (entry (lo),newkey,length);
nentries++;
Write (indexfile,t,node,NODESIZE);
}
}
*rptr = -1;
return 0;
}
/* Allocate a new data record and insert index key in B-tree */
void createindex (int file,long *ptr,void *rec,int size,long _miscoff,
char *key,int _length,int _indexfile,int x,int y,int directions)
{
long listptr[3];
long p;
long newptr;
char newkey[MAXKEY];
int lo,hi;
int i,j;
int c;
long n1,n2;
long splitptr;
char splitkey[MAXKEY];
indexfile = _indexfile;
miscoff = _miscoff;
length = _length;
calcm ();
Read (miscfile,miscoff,listptr,sizeof listptr);
if (listptr[0] < 0) /* If free list is empty */
p = filelength (file); /* get new record from end of file */
else /* get first record from free list */
{
p = listptr[0];
Read (file,p,listptr,sizeof (long));
}
REDO:
/* Ask user for key value */
editstr (key,length,x,y,directions);
if (dir == DIR_ESC) /* User hit ESC, so cancel */
{
*ptr = -1;
return;
}
if (filelength (indexfile)) /* If index file not empty */
{
newnodeptr = -1;
if (insert (0,&newptr,newkey,p,key))
{
beep ();
goto REDO;
}
if (newptr >= 0)
{
Read (indexfile,0,node,NODESIZE);
lo = 0;
hi = nentries - 1;
while (lo <= hi)
{
i = (lo + hi) / 2;
c = memicmp (entry (i),newkey,length);
assert (c != 0);
if (c < 0)
lo = i + 1;
else
hi = i - 1;
}
if (nentries == m - 1)
{
n1 = allocnode ();
n2 = allocnode ();
j = m / 2;
if (lo <= j)
j--;
splitptr = recptr (j);
memcpy (splitkey,entry (j),length);
memmove (&nodeptr (j),&nodeptr (j + 1),(nentries - j)*sizeof (long));
memmove (&recptr (j),&recptr (j + 1),(nentries - j - 1)*sizeof (long));
memmove (entry (j),entry (j + 1),(nentries - j - 1)*length);
if (lo <= j + 1)
j++;
memmove (&nodeptr (lo + 1),&nodeptr (lo),(nentries - lo)*sizeof (long));
memmove (&recptr (lo + 1),&recptr (lo),(nentries - lo - 1)*sizeof (long));
memmove (entry (lo + 1),entry (lo),(nentries - lo - 1)*length);
nodeptr (lo) = newnodeptr;
recptr (lo) = newptr;
memcpy (entry (lo),newkey,length);
nentries = j;
Write (indexfile,n1,node,NODESIZE);
nentries = m - 1 - j;
memcpy (&nodeptr (0),&nodeptr (j),(nentries + 1)*sizeof (long));
memcpy (&recptr (0),&recptr (j),nentries*sizeof (long));
memcpy (entry (0),entry (j),nentries*length);
Write (indexfile,n2,node,NODESIZE);
nentries = 1;
nodeptr (0) = n1;
nodeptr (1) = n2;
recptr (0) = splitptr;
memcpy (entry (0),splitkey,length);
}
else
{
memmove (&nodeptr (lo + 1),&nodeptr (lo),(nentries - lo + 1)*sizeof (long));
memmove (&recptr (lo + 1),&recptr (lo),(nentries - lo)*sizeof (long));
memmove (entry (lo + 1),entry (lo),(nentries - lo)*length);
nodeptr (lo) = newnodeptr;
recptr (lo) = newptr;
memcpy (entry (lo),newkey,length);
nentries++;
}
Write (indexfile,0,node,NODESIZE);
}
}
else /* Special case for no existing keys */
{
memset (node,0xff,sizeof node);
nentries = 1;
recptr (0) = p;
memcpy (entry (0),key,length);
Write (indexfile,0,node,sizeof node);
}
if (listptr[2] < 0) /* If linked list is empty, initialize it */
{
listptr[1] = p;
listptr[2] = p;
}
else /* add record to linked list */
{
((long *)rec)[1] = listptr[2];
Write (file,listptr[2],&p,sizeof (long));
listptr[2] = p;
}
Write (file,p,rec,size);
Write (miscfile,miscoff,listptr,sizeof listptr);
*ptr = p;
}
/* Find data record in file given key value */
void find (int file,int _indexfile,long *ptr,void *rec,int size,int _length,
char *key)
{
int lo,hi,i,c;
indexfile = _indexfile;
length = _length;
calcm ();
*ptr = -1;
if (filelength (indexfile) == 0) /* Special case for no keys in index */
return;
Read (indexfile,0,node,NODESIZE);
for (;;)
{
/* Try to find key in current node */
lo = 0;
hi = nentries - 1;
while (lo <= hi)
{
i = (lo + hi) / 2;
c = memicmp (entry (i),key,length);
if (c == 0) /* Found key, so read data record */
{
*ptr = recptr (i);
Read (file,*ptr,rec,size);
return;
}
if (c < 0)
lo = i + 1;
else
hi = i - 1;
}
if (nodeptr (i) < 0) /* Bottom of tree, so give up */
return;
Read (indexfile,nodeptr (i),node,NODESIZE);
}
}
/* Get key value from user and try to find corresponding data record */
void select (int file,int _indexfile,long *ptr,void *rec,int size,char *key,
int _length,int x,int y,int directions)
{
indexfile = _indexfile;
length = _length;
REDO:
/* Ask user for key value */
editstr (key,length,x,y,directions);
if (dir == DIR_ESC) /* User hit ESC, so cancel */
return;
find (file,indexfile,ptr,rec,size,length,key);
if (*ptr < 0) /* not found, so ask user for new key value */
{
beep ();
goto REDO;
}
}
/* Link a data record onto another one */
void reclink (int fromfile,long fromptr,long *fromptrs,int fromoffset,
int tofile,long toptr,long *toptrs,int tooffset)
{
fromptrs[0] = toptr;
fromptrs[2] = toptrs[1];
if (toptrs[1] < 0)
toptrs[0] = toptrs[1] = fromptr;
else
{
Write (fromfile,toptrs[1] + fromoffset + sizeof (long),&fromptr,sizeof (long));
toptrs[1] = fromptr;
}
}
/* Unlink a data record from another one */
void recunlink (int fromfile,long fromptr,long *fromptrs,int fromoffset,
int tofile,long toptr,long *toptrs,int tooffset)
{
if (toptrs[0] == fromptr)
toptrs[0] = fromptrs[1];
else
Write (fromfile,fromptrs[2] + fromoffset + sizeof (long),&fromptrs[1],sizeof (long));
if (toptrs[1] == fromptr)
toptrs[1] = fromptrs[2];
else
Write (fromfile,fromptrs[1] + fromoffset + 2*sizeof (long),&fromptrs[2],sizeof (long));
fromptrs[0] = fromptrs[1] = fromptrs[2] = -1;
}
/* Open a file if it exists, otherwise create it, with error checking */
opencreate (char *filename)
{
int f;
f = open (filename,O_RDWR);
if (f >= 0)
return f;
f = open (filename,O_CREAT | O_TRUNC | O_RDWR,0777);
if (f < 0)
{
printf ("Can't create file %s.\n",filename);
exit (1);
}
return f;
}
/* Functions to initialize data in miscfile */
void mwrite (void *buf,int bytes)
{
if (write (miscfile,buf,bytes) != bytes)
{
printf ("Error writing to file misc.dat\n");
exit (1);
}
}
void mblank3 (void)
{
static long data[] = { -1,-1,-1 };
mwrite (data,sizeof data);
}
void mblank4 (void)
{
static long data[] = { -1,-1,-1,-1 };
mwrite (data,sizeof data);
}