Category : C Source Code
Archive   : BTREE3.ZIP
Filename : BTREE.C

 
Output of file : BTREE.C contained in archive : BTREE3.ZIP
/*
* btree.c - hacked by ...!gatech!kd4nc!n4hgf!wht
*
* Copyright (C) 1988, Marcus J. Ranum, William Welch Medical Library
* $ Author: mjr
* $ Log: btree.c,v
* $ Revision 1.1 88/06/01 21:35:07 mjr Initial revision.
* The original code was placed in the public domain. This is not,
* since I wish to retain some control over it. No restrictions are placed on
* modification, or use of this code, as long as the copyrights are not
* removed. There are some areas that really could use improving (like
* handling free nodes better) and I hope that if someone makes improvements
* they will keep me up to date on them (e-mail please, I am not on usenet).
* Marcus J. Ranum, William Welch Medical Library, 1988 [email protected] ||
* uunet!mimsy!aplcen!osiris!welchvax!mjr
*
* Defined functions:
*
* _btlink(alpha1,node1,alpha2,node2) * btdelete(node_num,bt)
* _btnext(node_num,node,bt) * btfind(key,node_num,reckey,recno,bt)
* _btprevious(node_num,node,bt) * bthead(node_num,key,recno,bt)
* _btmove(node_num,node,bt, dir) * btinsert(argkey,recno,bt)
* _flush_cache_node(bt,cache_node) * btnext(node_num,key,recno,bt)
* _linknbr(alpha,node1,node_num) * btopen(path,flags,mode,keysize)
* _nbrlink(node_num,alpha,node1) * btperror(str)
* _nodebal(alpha,node1,node2,node3) * btprevious(node_num,key,recno,bt)
* _popl(bt) * btsetrec(node_num,newrec,bt)
* _popr(bt) * bttail(node_num,key,recno,bt)
* _pushl(bt,node_num)
* _pushr(bt,node_num)
* _rnode(node_num,npt,bt)
* _wnode(node_num,npt,bt)
* _wsuper(bt) btclose(bt)
* _btflush(bt)
*
* Modification History:
* 12-23-1989-17:29-mfl-re-wrote the cache memory allocation steps
* 12-23-1989-17:29-mfl-replaced _bthead &_bttail with _btmove
* 12-09-1989-17:29-wht-get working on SCO UNIX -- just #defines
* 12-17-1988-17:51-wht-write sblk only at close-writes were inefficient
* 12-17-1988-17:51-wht-cache now read-write... writes were inefficient
* 12-17-1988-12:09-wht-allow open of existing index to specify zero keysize
* 12-16-1988-20:38-wht-variable max key length
* 12-16-1988-17:15-wht-static procs no longer static, but with '_' prefix

/* #define DEBUG uncomment this for debugging output */
#include
#include
#include

#define MAIN /* enables btree declarations in 'btree.h' */
#include "btree.h"
#undef MAIN

/* write the btree superblock to disk */
int
_wsuper(bt)
struct btree *bt;
{
register int save_bterrno = bterrno;

if (bt->rdonly)
return (0);

#ifdef DEBUG
fprintf(stderr, "BTREE: write superblock fd=%d\n", bt->fd);
#endif

bterrno = BT_BAD_WSUPER;
if (lseek(bt->fd, 0L, 0) < 0)
return (BT_ERR);

if (write(bt->fd, (char *) & bt->sblk, BT_SSIZ) != BT_SSIZ)
return (BT_ERR);

bterrno = save_bterrno;
return (0);
}



/* dynamically allocate a control structure for an open btree */
struct btree *
btopen(path, flags, mode, keysize)
char *path;
register int flags;
register int mode;

register int keysize;
{
struct btree *bt;
struct btnode_m *cache, *cacheptr;
register int r;
extern char *malloc();

if (keysize) {
keysize++; /* allow for null at end of record */
if (keysize & 1)
keysize++; /* keep key size even */
}
if (keysize > BT_KSIZ) {
fprintf(stderr, "BTREE: key size for %s (%d) exceeds max of %d\n",
path, keysize, BT_KSIZ);
exit(1);
}

/* lets be dynamic, shall we ? */
if ((bt = (struct btree *) malloc(sizeof(struct btree ))) == (BTREE * ) 0) {
bterrno = BT_BAD_MEMORY;
return ((BTREE * ) 0);
}
if ((bt->fd = open(path, flags, mode)) > -1) {
#ifdef DEBUG
fprintf(stderr, "BTREE: %s opened via fd #%d\n", path, bt->fd);
#endif
r = read(bt->fd, (char *) & bt->sblk, BT_SSIZ);

/* if read nothing, must be a new guy, right ? */
if (r == 0) {
bt->sblk.magic = BT_MAGIC;
bt->sblk.free = 1;
bt->sblk.root = 0;
bt->sblk.list = 0;
if (keysize)
bt->sblk.keysize = keysize;
else {
fprintf(stderr, "BTREE: cannot create index with zero length key\n");
exit(1);
}

if (_wsuper(bt) == 0)
r = BT_SSIZ;
} else if (r == BT_SSIZ) {
bterrno = 0;
if (bt->sblk.magic != BT_MAGIC)
bterrno = BT_BAD_MAGIC;
else if (keysize && (keysize != bt->sblk.keysize))
bterrno = BT_BAD_KSIZ;
if (bterrno) {
close(bt->fd);
free((char *) bt);
return ((BTREE * ) 0);
}
}
/* cleverly check ret value from either read or write */
if (r != BT_SSIZ) {
bterrno = BT_BAD_SBLK;
close(bt->fd);
free((char *) bt);
return ((BTREE * ) 0);
}
} else {
/* couldnt even open the bloody file */
free((char *) bt);
return ((BTREE * ) 0);
}

#ifdef DEBUG
fprintf(stderr, "BTREE: initialize disk cache memory\n");
#endif
/* initialize the disk cache memory (allocate the whole thing) */
cache = (struct btnode_m *) malloc(sizeof(struct btnode_m)*BT_CSIZ);
if (cache == (struct btnode_m *) 0) {
fprintf(stderr, "BTREE: insufficient memory for disk cache\n");
exit(1);
}
cacheptr = cache; /* point to start of cache */
for (r = 0; r < BT_CSIZ; r++) {
bt->cache[r] = cacheptr++; /* point to cache block */
bt->cache[r]->node_num = -1; /* reset node number */
bt->cache[r]->dirty = 0; /* mark it clean */
}
bt->rdonly = ((flags & (O_WRONLY | O_RDWR)) == O_RDONLY);

return (bt);
}


/* close and deallocate the control structure */
btclose(bt)
struct btree *bt;
{
register int err = 0;

if (!bt->rdonly) {
if (err = _btflush(bt))
fprintf(stderr, "BTREE: index file close error\n");
}
close(bt->fd);
free((char *) bt->cache[0]); /* this should free all cache */
free((char *) bt);
return (err);
}


int
_flush_cache_node(bt, cache_node)
struct btree *bt;
register struct btnode_m *cache_node;
{
register int save_bterrno = bterrno;

if ((cache_node->node_num == -1) || (!cache_node->dirty))
return (0);
bterrno = BT_BAD_FLUSH;
if (lseek(bt->fd, (((long) cache_node->node_num * BT_NSIZ) + BT_SSIZ), 0) < 0)
return (BT_ERR);
if (write(bt->fd, (char *) & cache_node->n, BT_NSIZ) != BT_NSIZ)
return (BT_ERR);
cache_node->dirty = 0;
bterrno = save_bterrno;
return (0);
}


int
_btflush(bt)
struct btree *bt;
{
register int icache;
register struct btnode_m *cache_node;

for (icache = 0; icache < BT_CSIZ; icache++) {
cache_node = bt->cache[icache];
if (_flush_cache_node(bt, cache_node))
return (BT_ERR);
}
if (_wsuper(bt))
return (BT_ERR);
return (0);
}


/* write a node to cache */
int
_wnode(node_num, npt, bt)
register short node_num;
struct btnode_m *npt;
register struct btree *bt;
{
unsigned int hash = (unsigned int) node_num &(BT_CSIZ-1);
register struct btnode_m *cache_node = bt->cache[hash];
extern int errno;

if (!node_num)
return (0);

errno = 0;
if (bt->rdonly) {
errno = EPERM; /* would be reported later */
return (BT_ERR);
}
bterrno = BT_BAD_WNODE;
if (cache_node->node_num != node_num) {
if (_flush_cache_node(bt, cache_node))
return (BT_ERR);
}
/* update cache if the write succeeded */
(void) bcopy((char *) npt, (char *) cache_node, sizeof(struct btnode_m ));
cache_node->node_num = node_num;
cache_node->dirty = 1;
bterrno = 0;
return (0);
}


/* read a node from disk */
int
_rnode(node_num, npt, bt)
register short node_num;
register struct btnode_m *npt;
register struct btree *bt;
{
register rdcount;
register long readpos;
unsigned int hash = (unsigned int) node_num &(BT_CSIZ-1);
register struct btnode_m *cache_node = bt->cache[hash];
extern int errno;

if (!node_num) {
(void) bzero((char *) npt, sizeof(struct btnode_m ));
return (0);
}
errno = 0;
bterrno = BT_BAD_RNODE;
if (cache_node->node_num != node_num) {
/* if no cache hit, load from disk */
cache_no_hits++;
if (!bt->rdonly) {
if (_flush_cache_node(bt, cache_node))
return (BT_ERR);
}

if (lseek(bt->fd, (readpos = ((long) node_num * BT_NSIZ) + BT_SSIZ), 0) < 0)
return (BT_ERR);
if ((rdcount = read(bt->fd, (char *) & cache_node->n, BT_NSIZ)) != BT_NSIZ) {
#ifdef DEBUG
if (rdcount >= 0)
fprintf(stderr, "BTREE: rdcount for node %u was %u (should be %d) @ %ld\n",
node_num, rdcount, BT_NSIZ, readpos);
#endif
return (BT_ERR);
}
cache_node->node_num = node_num;
cache_node->dirty = 0;
} else
cache_hits++;

(void) bcopy((char *) cache_node, (char *) npt, sizeof(struct btnode_m ));

bterrno = 0;
return (0);
}


int
_pushl(bt, node_num)
struct btree *bt;
register short node_num;
{
if (++(bt->lstak.sptr) >= STACK_SIZ) {
bterrno = BT_BAD_STACK;
exit(0);
}
bt->lstak.ele[bt->lstak.sptr] = node_num;
bt->lstak.lev[bt->lstak.sptr] = ++bt->slev;
return;
}


int
_pushr(bt, node_num)
struct btree *bt;
register short node_num;
{
if (++(bt->rstak.sptr) >= STACK_SIZ) {
bterrno = BT_BAD_STACK;
exit(0);
}
bt->rstak.ele[bt->rstak.sptr] = node_num;
bt->rstak.lev[bt->rstak.sptr] = ++bt->slev;
return;
}



short
_popr(bt)
struct btree *bt;
{
bt->slev = bt->rstak.lev[bt->rstak.sptr];

while (bt->lstak.lev[bt->lstak.sptr] > bt->slev)
(bt->lstak.sptr)--;

if (bt->rstak.sptr == 0)
return (0);

bt->slev--;
return (bt->rstak.ele[(bt->rstak.sptr)--]);
}



short
_popl(bt)
struct btree *bt;
{
bt->slev = bt->lstak.lev[bt->lstak.sptr];

while (bt->rstak.lev[bt->rstak.sptr] > bt->slev)
(bt->rstak.sptr)--;

if (bt->lstak.sptr == 0)
return (0);

bt->slev--;
return (bt->lstak.ele[(bt->lstak.sptr)--]);
}


void
_btlink(alpha1, node1, alpha2, node2)
register int alpha1;
register int alpha2;
struct btnode *node1;
struct btnode *node2;
{
if (alpha1 == -1 && alpha2 == -1)
node1->lptr = node2->lptr;
else if (alpha1 == -1 && alpha2 == 1)
node1->lptr = node2->rptr;
else if (alpha1 == 1 && alpha2 == -1)
node1->rptr = node2->lptr;
else
node1->rptr = node2->rptr;
}



/* number a link according to alpha */
void
_nbrlink(node_num, alpha, node1)
short *node_num;
register int alpha;
struct btnode *node1;
{
*node_num = (alpha == 1) ? node1->rptr : node1->lptr;
}



/* set a link according to alpha */
void
_linknbr(alpha, node1, node_num)
register int alpha;
struct btnode *node1;
register short node_num;
{

if (alpha == 1)
node1->rptr = node_num;
else
node1->lptr = node_num;
}



void
_nodebal(alpha, node1, node2, node3)
register int alpha;
struct btnode *node1;
struct btnode *node2;
struct btnode *node3;
{
if (node1->balance == alpha) {
node2->balance = -alpha;
node3->balance = 0;
} else if (node1->balance == 0)
node2->balance = node3->balance = 0;
else {
node2->balance = 0;
node3->balance = alpha;
}
}



/* change the record number in a node */
btsetrec(node_num, newrec, bt)
register short node_num;
long newrec;
struct btree *bt;
{
struct btnode_m tnode;

if (_rnode(node_num, &tnode, bt))
return (BT_ERR);

tnode.n.recno = newrec;

if (_wnode(node_num, &tnode, bt))
return (BT_ERR);

return (0);
}


/* insert the node into the tree */
btinsert(argkey, recno, bt)
char *argkey;
long recno;
struct btree *bt;
{
register int compare;
short trec1;
short trec2;
short trec3;
short trec4;
short top;
struct btnode_m tnode1;
struct btnode_m tnode2;
struct btnode_m tnode3;
struct btnode_m tnode4;


/* the very first node gets inserted specially */
if (bt->sblk.root == 0) {
bt->sblk.root = 1;
tnode1.n.balance = tnode1.n.rptr = tnode1.n.lptr = 0;
tnode1.n.deleted = BT_ACTIVE;
tnode1.n.recno = recno;

strncpy(tnode1.key, argkey, bt->sblk.keysize - 1);
tnode1.key[bt->sblk.keysize - 1] = '\0';
if (_wnode(1, &tnode1, bt) < 0)
return (BT_ERR);

bt->sblk.free++;
bt->sblk.list++;
return (0);
}
top = -1;
trec1 = bt->sblk.root;
trec4 = bt->sblk.root;
while (1) {
if (_rnode(trec1, &tnode1, bt)) {
#ifdef DEBUG
fprintf(stderr, "BTREE: btinsert: trec1(1) read error\n");
#endif
return (BT_ERR);
}
if ((compare = strcmp(argkey, tnode1.key)) < 0) {
/* (move left) */
trec2 = tnode1.n.lptr;

if (trec2 == 0) {
/* insert here */
trec2 = bt->sblk.free++;
tnode1.n.lptr = trec2;
break; /* loop exit */
} else {
/* look again from this node */
if (_rnode(trec2, &tnode2, bt)) {
#ifdef DEBUG
fprintf(stderr, "BTREE: btinsert: trec2(1) read error\n");
#endif
return (BT_ERR);
}
if (tnode2.n.balance != 0) {
top = trec1;
trec4 = trec2;
}
}
trec1 = trec2;
} else {
/* (move right) */
trec2 = tnode1.n.rptr;

if (trec2 == 0) {
/* insert here */
trec2 = bt->sblk.free++;
tnode1.n.rptr = trec2;
break; /* loop exit */
} else {
/* look again from this node */
if (_rnode(trec2, &tnode2, bt)) {
#ifdef DEBUG
fprintf(stderr, "BTREE: btinsert: trec2(2) read error\n");
#endif
return (BT_ERR);
}
if (tnode2.n.balance != 0) {
top = trec1;
trec4 = trec2;
}
trec1 = trec2;
}
}
}

/* Step 5 (insert key at tnode2) */
tnode2.n.lptr = tnode2.n.rptr = 0;
tnode2.n.balance = 0;
tnode2.n.deleted = BT_ACTIVE;
tnode2.n.recno = recno;
strncpy(tnode2.key, argkey, bt->sblk.keysize - 1);
tnode2.key[bt->sblk.keysize - 1] = '\0';

if (_wnode(trec2, &tnode2, bt))
return (BT_ERR);
if (_wnode(trec1, &tnode1, bt))
return (BT_ERR);
if (_rnode(trec4, &tnode4, bt)) {
#ifdef DEBUG
fprintf(stderr, "BTREE: btinsert: trec4(1) read error\n");
#endif
return (BT_ERR);
}
/* (adjust balance factors) */
if (strcmp(argkey, tnode4.key) < 0)
trec3 = trec1 = tnode4.n.lptr;
else
trec3 = trec1 = tnode4.n.rptr;

while (trec1 != trec2) {
if (_rnode(trec1, &tnode1, bt)) {
#ifdef DEBUG
fprintf(stderr, "BTREE: btinsert: trec1(2) read error\n");
#endif
return (BT_ERR);
}
if (strcmp(argkey, tnode1.key) < 0) {
tnode1.n.balance = -1;
if (_wnode(trec1, &tnode1, bt) < 0)
return (BT_ERR);
trec1 = tnode1.n.lptr;
} else {
tnode1.n.balance = 1;
if (_wnode(trec1, &tnode1, bt) < 0)
return (BT_ERR);
trec1 = tnode1.n.rptr;
}
}

compare = (strcmp(argkey, tnode4.key) < 0) ? -1 : 1;
if (tnode4.n.balance == 0) {
bt->sblk.list++;
tnode4.n.balance = compare;
if (_wnode(trec4, &tnode4, bt) < 0)
return (BT_ERR);
return (0);
} else if (tnode4.n.balance == -compare) {
bt->sblk.list++;
tnode4.n.balance = 0;
if (_wnode(trec4, &tnode4, bt) < 0)
return (BT_ERR);
return (0);
} else {
/* (tree out of balance) */
bt->sblk.list++;
if (_rnode(trec4, &tnode4, bt)) {
#ifdef DEBUG
fprintf(stderr, "BTREE: btinsert: trec4(2) read error\n");
#endif
return (BT_ERR);
}
if (_rnode(trec3, &tnode3, bt)) {
#ifdef DEBUG
fprintf(stderr, "BTREE: btinsert: trec3(1) read error\n");
#endif
return (BT_ERR);
}
if (tnode3.n.balance == compare) {
/* (single rotate) */
trec1 = trec3;
_btlink(compare, (BTNODE * ) & tnode4, -compare, (BTNODE * ) & tnode3);
_linknbr(-compare, (BTNODE * ) & tnode3, trec4);
tnode4.n.balance = tnode3.n.balance = 0;
} else {
/* (double rotate) */
_nbrlink(&trec1, -compare, (BTNODE * ) & tnode3);
if (_rnode(trec1, &tnode1, bt)) {
#ifdef DEBUG
fprintf(stderr, "BTREE: btinsert: trec1(3) read error\n");
#endif
return (BT_ERR);
}
_btlink(-compare, (BTNODE * ) & tnode3, compare, (BTNODE * ) & tnode1);
_linknbr(compare, (BTNODE * ) & tnode1, trec3);
_btlink(compare, (BTNODE * ) & tnode4, -compare, (BTNODE * ) & tnode1);
_linknbr(-compare, (BTNODE * ) & tnode1, trec4);
_nodebal(compare, (BTNODE * ) & tnode1, (BTNODE * ) & tnode4, (BTNODE * ) & tnode3);
tnode1.n.balance = 0;
if (_wnode(trec1, &tnode1, bt))
return (BT_ERR);
}

if (top == -1)
bt->sblk.root = trec1;
else {
/* balanced at top of a sub-tree */
if (_rnode(top, &tnode2, bt) < 0) {
#ifdef DEBUG
fprintf(stderr, "BTREE: btinsert: top(1) read error\n");
#endif
return (BT_ERR);
}
if (trec4 == tnode2.n.rptr)
tnode2.n.rptr = trec1;
else
tnode2.n.lptr = trec1;
if (_wnode(top, &tnode2, bt))
return (BT_ERR);
}
if (_wnode(trec4, &tnode4, bt))
return (BT_ERR);
if (_wnode(trec3, &tnode3, bt))
return (BT_ERR);
return (0);
}
}


/* drop a node */
btdelete(node_num, bt)
register short node_num;
struct btree *bt;
{
struct btnode_m node;

if (node_num == 0) {
bterrno = BT_BAD_ROOT;
return (BT_ERR);
} else {
if (_rnode(node_num, &node, bt))
return (BT_ERR);
node.n.deleted = BT_DELETED;
if (_wnode(node_num, &node, bt))
return (BT_ERR);
else
bt->sblk.list--;
}
return (0);
}


/* find the next node */
btnext(node_num, key, recno, bt)
short *node_num;
char **key;
long *recno;
struct btree *bt;
{
static struct btnode_m node;
register int retn;
if (_rnode(*node_num, &node, bt))
return (BT_ERR);
retn = _btnext(node_num, &node, bt);
*key = node.key;
*recno = node.n.recno;
return (retn);

}


/* find the next node */
_btnext(node_num, node, bt)
short *node_num;
register struct btnode_m *node;
struct btree *bt;
{
short _popl();
short _popr();
short s_nod;

s_nod = *node_num;

if (*node_num == 0) {
/* undefined current node - wind to beginning of file */
return (_btmove(node_num, node, bt, BT_HEAD));
}

do {
if (node->n.rptr == 0) {
/* can't move right */
if (bt->lstak.sptr == 0) {
/* none in stack */
if (_rnode(*node_num, node, bt))
return (BT_ERR);
return (BT_EOF);
} else {
/* can't go right &stack full (pop stack) */
s_nod = _popl(bt);
if (_rnode(s_nod, node, bt) < 0)
return (BT_ERR);
}
} else {
/* move right */
_pushr(bt, s_nod);
s_nod = node->n.rptr;
if (_rnode(s_nod, node, bt))
return (BT_ERR);

while (node->n.lptr != 0) {
/* bottom left */
_pushl(bt, s_nod);
/* of this sub-tree */
s_nod = node->n.lptr;
if (_rnode(s_nod, node, bt))
return (BT_ERR);
}
}
} while (node->n.deleted == BT_DELETED);

*node_num = s_nod;
return (0);
}


/* go to the tail of the file */
bttail(node_num, key, recno, bt)
short *node_num;
char **key;
long *recno;
struct btree *bt;
{
static struct btnode_m node;
register int retn = _btmove(node_num, &node, bt, BT_TAIL);
*key = node.key;
*recno = node.n.recno;
return (retn);
}


/* go to the head of the file */
bthead(node_num, key, recno, bt)
short *node_num;
char **key;
long *recno;
struct btree *bt;
{
static struct btnode_m node;
register int retn = _btmove(node_num, &node, bt, BT_HEAD);
*key = node.key;
*recno = node.n.recno;
return (retn);
}


/* move to the head or tail of the file */
_btmove(node_num, node, bt, dir)
struct btree *bt;
short *node_num, dir;
register struct btnode_m *node;
{
short s_nod;
short t_nod;

bt->rstak.sptr = 0;
bt->lstak.sptr = 0;
bt->rstak.ele[0] = 0;
bt->lstak.ele[0] = 0;

/* begin at list head */
s_nod = bt->sblk.root;

if (_rnode(s_nod, node, bt))
return (BT_ERR);

while (1) {
/* decide on direction */
t_nod = ((dir == BT_TAIL) ? node->n.rptr : node->n.lptr);

if (t_nod != 0) {
if (dir == BT_TAIL) {
_pushr(bt, s_nod);
s_nod = node->n.rptr;
} else {
_pushl(bt, s_nod);
s_nod = node->n.lptr;
}
if (_rnode(s_nod, node, bt))
return (BT_ERR);
} else {
if (node->n.deleted == BT_DELETED) {
/* skip all deleted nodes */
while (node->n.deleted == BT_DELETED) {
if (dir == BT_TAIL) {
if (_btnext(&s_nod, node, bt) == BT_EOF) {
if (_btprevious(&s_nod, node, bt) < 0)
return (BT_ERR);
*node_num = s_nod;
return (0);
}
} else {
if (_btprevious(&s_nod, node, bt) == BT_EOF) {
if (_btnext(&s_nod, node, bt) < 0)
return (BT_ERR);
*node_num = s_nod;
return (0);
}
}
}
*node_num = s_nod;
return (0);
} else {
/* at end of a branch */

*node_num = s_nod;
return (0);
}
}
}
}



/* find a key */
btfind(key, node_num, reckey, recno, bt)
char *key;
short *node_num;
char **reckey;
long *recno;
struct btree *bt;
{
register int direction;
short s_nod;
static struct btnode_m node;

bt->rstak.sptr = 0;
bt->lstak.sptr = 0;
bt->rstak.ele[0] = 0;
bt->lstak.ele[0] = 0;

bt->slev = 0; /* tree level at start of search */

/* begin at list head */
s_nod = bt->sblk.root;

if (_rnode(s_nod, &node, bt))
return (BT_ERR);

bterrno = 0;

while (node.n.deleted == BT_DELETED || (direction = strcmp(key, node.key)) != 0) {

if (bterrno == BT_EOF) /* hit end of file */
break;

if (direction > 0) { /* search to right */
if (node.n.rptr != 0) {
_pushr(bt, s_nod);
s_nod = node.n.rptr;
if (_rnode(s_nod, &node, bt))
return (BT_ERR);
} else /* end of a branch */
bterrno = BT_EOF;
} else { /* search to left */
if (node.n.lptr != 0) {
_pushl(bt, s_nod);
s_nod = node.n.lptr;
if (_rnode(s_nod, &node, bt))
return (BT_ERR);
} else /* end of a branch */
bterrno = BT_EOF;
}

/* skip all deleted nodes */
while (node.n.deleted == BT_DELETED) {
if (_btnext(&s_nod, &node, bt) == BT_EOF) {
if (_btprevious(&s_nod, &node, bt) < 0)
return (BT_ERR);
bterrno = BT_EOF;
break;
}
}
}
*recno = node.n.recno;
*reckey = node.key;
*node_num = s_nod;
return (strcmp(key, node.key) == 0 ? 0 : BT_NREC);
}


/* find the previous node */
btprevious(node_num, key, recno, bt)
short *node_num;
char **key;
long *recno;
struct btree *bt;
{
static struct btnode_m node;
register int retn;
if (_rnode(*node_num, &node, bt))
return (BT_ERR);
retn = _btprevious(node_num, &node, bt);
*key = node.key;
*recno = node.n.recno;
return (retn);
}


/* get the previous node */
_btprevious(node_num, node, bt)
short *node_num;
register struct btnode_m *node;
struct btree *bt;
{
short _popr();
short _popl();
short s_nod;

s_nod = *node_num;

/* if we are called without a node, wind to the end of file */
if (*node_num == 0)
return (_btmove(node_num, node, bt, BT_TAIL));

do {
if (node->n.lptr == 0) {
/* can't move left */
if (bt->rstak.sptr == 0) {
/* none in stack */
if (_rnode(*node_num, node, bt))
return (BT_ERR);
return (BT_EOF);
/* don't reset node_num */
} else {
/* can't go left &stack full (pop stack) */
s_nod = _popr(bt);
if (_rnode(s_nod, node, bt))
return (BT_ERR);
}
} else {
/* left then to bottom right - is previous */
_pushl(bt, s_nod);
s_nod = node->n.lptr;
if (_rnode(s_nod, node, bt))
return (BT_ERR);
while (node->n.rptr != 0) {
/* bottom right */
_pushr(bt, s_nod);
/* of this sub-tree */
s_nod = node->n.rptr;
if (_rnode(s_nod, node, bt))
return (BT_ERR);
}
}
} while (node->n.deleted == BT_DELETED);

*node_num = s_nod;
return (0);
}


/* print the btree error message */
void
btperror(str)
char *str;
{
extern int errno;

/* is it ours ?? */
if (bterrno) {
fprintf(stderr, "BTREE: %s: %s\n", str, bterrs[bterrno]);
bterrno = 0;
}
if (errno) {
fprintf(stderr, "BTREE: (OS error) ");
perror(str);
errno = 0;
}
}




  3 Responses to “Category : C Source Code
Archive   : BTREE3.ZIP
Filename : BTREE.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/