#include	<sys/types.h>
#include	<sys/file.h>
#include	<stdio.h>
#include	"btconf.h"
#include	"btree.h"
#include	"btintern.h"

/*
         (C) Copyright, 1988, 1989 Marcus J. Ranum
                    All rights reserved


          This software, its documentation,  and  supporting
          files  are  copyrighted  material  and may only be
          distributed in accordance with the terms listed in
          the COPYRIGHT document.

	$Log:	btopen.c,v $
 * Revision 1.1  90/06/08  16:11:48  mjr
 *  
 * 
 * Revision 1.1  90/06/06  15:03:47  mjr
 *  
 * 
 * Revision 1.1  90/06/03  16:23:12  mjr
 *  
 * 
 * Revision 1.1  90/05/18  23:20:38  mjr
 *  
 * 
 * Revision 1.1  90/05/15  13:18:32  mjr
 * Initial revision
 * 
 * Revision 1.1  90/05/05  15:04:36  mjr
 * Initial revision
 * 
 * Revision 1.1  90/03/23  15:03:48  mjr
 * Initial revision
 * 
*/


#ifndef	lint
static char *rcsid = "$Header: /atreus/mjr/hacks/mud/btlib/RCS/btopen.c,v 1.1 90/06/08 16:11:48 mjr Exp $";
#endif

extern	char	*malloc();
extern	off_t	lseek();


BT_INDEX	*
bt_open(path,flags,mode)
char	*path;
int	flags;
int	mode;
{
	BT_INDEX	*ret;
	struct bt_cache *cp1;
	struct bt_cache *cp2;
	int		r;

	if((ret = (BT_INDEX *)malloc(sizeof(BT_INDEX))) == NULL)
		return(NULL);

	/* clear error */
	bt_errno(ret) = BT_NOERROR;

	/* set funcp to something inoffensive */
	bt_cmpfn(ret) = 0;

	if((bt_fileno(ret) = open(path,(flags|O_RDWR),mode)) < 0)
		goto bombout;

	r = read(bt_fileno(ret),(char *)&ret->sblk,sizeof(struct bt_super));

	/* failure to read anything - initialize tree */
	if(r == 0) {
		char	*jnk;
		if((jnk = malloc((unsigned)BT_DFLTPSIZ)) != NULL) {
			ret->sblk.magic = BT_DFLTMAGIC;
			bt_pagesiz(ret) = BT_DFLTPSIZ;
			bt_dtype(ret) = BT_DFLTDTYPE;
			ret->sblk.levs = 1;
			ret->sblk.root = (off_t)BT_DFLTPSIZ;
			ret->sblk.free = BT_NULL;
			ret->sblk.high = (off_t)(2 * BT_DFLTPSIZ);

			/* mark super block as dirty and sync */
			ret->dirt = 1;

			/* write and pretend we read a legit superblock */
			if(bt_wsuper(ret) == BT_OK)
				r = sizeof(struct bt_super);

			/* now make jnk into an empty first page */
			KEYCNT(jnk) = 0;
			KEYLEN(jnk) = 0;
			LSIB(jnk) = RSIB(jnk) = BT_NULL;
			HIPT(jnk) = BT_NULL;

			/* now, since the cache is not set up yet, we */
			/* must directly write the page. */
			if(lseek(bt_fileno(ret),(off_t)BT_DFLTPSIZ,SEEK_SET) != (off_t)BT_DFLTPSIZ ||
				write(bt_fileno(ret),jnk,BT_DFLTPSIZ) != BT_DFLTPSIZ)
				r = 0;
			(void)free(jnk);
		}
	}

	/* yet another sanity check */
	if(r != sizeof(struct bt_super) || ret->sblk.magic != BT_DFLTMAGIC)
		goto bombout;

	/* initialize locator stack */
	ret->shih = ret->sblk.levs + 2;
	ret->stack = (struct bt_stack *)malloc((unsigned)(ret->shih * sizeof(struct bt_stack)));
	if(ret->stack == NULL)
		goto bombout;

	/* initialize cache */
	cp2 = ret->lru = NULL;
	for(r = 0; r < BT_MINCACHE + BT_DFLTCACHE; r++) {
		cp1 = (struct bt_cache *)malloc(sizeof(struct bt_cache)); 
		if(cp1 == NULL)
			goto bombout;

		if(ret->lru == NULL)
			ret->lru = cp1;
		cp1->prev = cp2;
		cp1->num = BT_NULL;
		cp1->next = NULL;
		cp1->flags = BT_CHE_CLEAN;
		if((cp1->p = (bt_chrp)malloc((unsigned)bt_pagesiz(ret))) == NULL)
			goto bombout;
		if(cp2 != NULL)
			cp2->next = cp1;

		cp2 = cp1;
	}
	ret->mru = cp1;

	/* set cache type flag */
	ret->cflg = BT_DFLTCFLAG;

	/* no valid current key */
	ret->cpag = BT_NULL;

	/* all is well */
	return(ret);

bombout:
	(void)bt_close(ret);
	return(NULL);
}