/*
**		    Copyright (c) 1985	Ken Wellsch
**
**     Permission is hereby granted to all users to possess, use, copy,
**     distribute, and modify the programs and files in this package
**     provided it is not for direct commercial benefit and secondly,
**     that this notice and all modification information be kept and
**     maintained in the package.
**
*/

#include <sys/file.h>

#define MAXENTRIES	16
#define MAXIBLK		1024
#define EMPTY		-1
#define ERROR		-1

#define EXISTING	0
#define NEW		1

#define READONLY	0

struct mkey
{
	int b ;
	int e ;
} ;

struct iblk
{
	long int i_loc[MAXENTRIES] ;
	short int i_siz[MAXENTRIES] ;
} ;

struct iblk Iblk ;

short int Sblk[MAXIBLK] ;

char knam[20], rnam[20] ;

int Modified = 0 ;
int CurBlk = -1 ;
long int RecLoc = 0L ;
short int IndLoc = 0 ;
int kfd = -1 ;
int rfd = -1 ;

int readk (unit,key,buffer,size)
  int unit, key, size ;
  char *buffer ;
{
	struct mkey k ;

	MapKey (key,&k) ;

	if ( GetBlk (k.b) != k.b || Iblk.i_siz[k.e] == 0 )
		return (ERROR) ;

	if ( Iblk.i_siz[k.e] > size )
		error ("Readk","buffer too small (%d<%d)!",size,Iblk.i_siz[k.e]) ;

	return (GetRec(Iblk.i_loc[k.e],buffer,Iblk.i_siz[k.e])) ;
}

int closek (unit)
  int unit ;
{
	(void) close (rfd) ;

	if ( unit == NEW )
	{
		(void) lseek (kfd,0L,0) ;
		if ( write (kfd,Sblk,sizeof(Sblk)) != sizeof(Sblk) )
			error ("Closef","error on updating super block!") ;
	}

	if ( Modified )
		if ( PutBlk(CurBlk) != CurBlk )
			error ("Closef","error updating modified block!") ;

	(void) close (kfd) ;

	return (0) ;
}

int openk (name)
  char *name ;
{
	(void) MakNam (name) ;

	if ( ( kfd = open (knam,READONLY) ) < 0 ||
	     ( rfd = open (rnam,READONLY) ) < 0 )
		return (ERROR) ;

	if ( read (kfd,Sblk,sizeof(Sblk)) != sizeof(Sblk) )
		error ("Openk","unable to read super block!") ;

	return (EXISTING) ;
}

int MapKey (key,k)
  int key ;
  struct mkey *k ;

{
	k->b = key / MAXENTRIES ;
	k->e = key % MAXENTRIES ;
	return ;
}

int GetBlk (b)
  int b ;
{
	long int loc ;
	extern long int MapBlk() ;

	if ( b == CurBlk )
		return (b) ;
	
	if ( Modified )
	{
		if ( PutBlk (CurBlk) != CurBlk )
			return (ERROR) ;
		Modified = 0 ;
	}

	loc = MapBlk (b) ;
	if ( loc == ERROR )
		return (ERROR) ;

	(void) lseek (kfd,loc,0) ;
	if ( read (kfd,&Iblk,sizeof(Iblk)) != sizeof(Iblk) )
		return (ERROR) ;
	CurBlk = b ;
	return (b) ;
}

int GetRec (loc,buf,size)
  long int loc ;
  char *buf ;
  short int size ;
{
	(void) lseek (rfd,loc,0) ;
	if ( read (rfd,buf,size) != size )
		return (ERROR) ;
	buf[size] = 0 ;
	return (size) ;
}

int PutBlk (b)
  int b ;
{
	long int loc ;
	extern long int MapBlk() ;

	loc = MapBlk (b) ;
	if ( loc == ERROR )
		return (ERROR) ;

	(void) lseek (kfd,loc,0) ;
	if ( write (kfd,&Iblk,sizeof(Iblk)) != sizeof(Iblk) )
		return (ERROR) ;
	return (b) ;
}

int MakNam (name)
  char *name ;
{
	(void) strncpy (knam,name,20) ;
	(void) strncpy (rnam,name,20) ;
	(void) strncat (knam,".key",20) ;
	(void) strncat (rnam,".rec",20) ;

	return ;
}

long int MapBlk (b)
  int b ;
{
	long int loc ;

	if ( Sblk[b] == EMPTY )
		return (ERROR) ;
	loc = ((long) Sblk[b]) * sizeof(Iblk) + sizeof(Sblk) ;
	return (loc) ;
}
