/*
**		    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 READWRITE	2

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 writek (unit,key,buffer,size)
  int unit, key, size ;
  char *buffer ;
{
	struct mkey k ;
	extern long int PutRec () ;

	if ( size < 1 || key < 0 || unit == EXISTING )
		return (ERROR) ;

	MapKey (key,&k) ;

	if ( GetBlk (k.b) != k.b )
		if ( MakBlk (k.b) != k.b )
			error ("Writek","unable to create key %d!",key) ;

	if ( Iblk.i_siz[k.e] > 0 )
		error ("Writek","key %d already exists!",key) ;

	Iblk.i_loc[k.e] = PutRec (buffer,size) ;
	Iblk.i_siz[k.e] = size ;
	Modified++ ;
	return (size) ;
}

int dupk (unit,oldkey,newkey)
  int unit ;
  int oldkey, newkey ;
{
	struct mkey k ;
	long int loc ;
	register int siz ;

	if ( unit == EXISTING )
		return (ERROR) ;

	MapKey (oldkey,&k) ;

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

	MapKey (newkey,&k) ;

	if ( GetBlk (k.b) != k.b )
		if ( MakBlk (k.b) != k.b )
			error ("Dupk","unable to create key %d!",newkey) ;

	if ( Iblk.i_siz[k.e] > 0 )
		error ("Dupk","key %d already exists!",newkey) ;

	Iblk.i_loc[k.e] = loc ;
	Iblk.i_siz[k.e] = siz ;
	Modified++ ;

	return (siz) ;
}

int creatk (name)
  char *name ;
{
	register int i ;

	(void) MakNam (name) ;

	if ( ( kfd = creat (knam,0600) ) < 0 ||
	     ( rfd = creat (rnam,0600) ) < 0 )
		error ("Creatk","unable to create files %s!",name) ;

	for ( i = 0 ; i < MAXIBLK ; i++ )
		Sblk[i] = EMPTY ;

	(void) lseek (kfd,0L,0) ;
	if ( write (kfd,Sblk,sizeof(Sblk)) != sizeof(Sblk) )
		error ("Creatk","%s -- error on initializing!",knam) ;

	(void) close (kfd) ;
	(void) close (rfd) ;

	if ( ( kfd = open (knam,READWRITE) ) < 0 ||
	     ( rfd = open (rnam,READWRITE) ) < 0 )
		error ("Creatk","%s -- error reopening!",name) ;

	return (NEW) ;
}

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 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) ;
}

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) ;
}

long int PutRec (buf,size)
  char *buf ;
  int size ;
{
	long int loc ;

	loc = RecLoc ;
	(void) lseek (rfd,loc,0) ;
	if ( write (rfd,buf,size) != size )
		return (ERROR) ;
	RecLoc += ((long) size) ;
	return (loc) ;
}

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 ;
}

int MakBlk (b)
  int b ;
{
	register int i ;

	if ( Modified )
		return (ERROR) ;

	for ( i = 0 ; i < MAXENTRIES ; i++ )
	{
		Iblk.i_loc[i] = 0 ;
		Iblk.i_siz[i] = 0 ;
	}

	Sblk[b] = IndLoc++ ;
	CurBlk = b ;
	return (b) ;
}

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

	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) ;
}
