/
umud/DOC/
umud/DOC/examples/
umud/DOC/internals/
umud/DOC/wizard/
umud/MISC/
umud/MISC/dbchk/
umud/RWHO/rwhod/
/*
	Copyright (C) 1991, Andrew Molitor. All rights reserved.
*/
/*
#define DEBUG
*/
/*
	This a a dbm emulation module for VMS, using indexed files to do
the database thang. It emulates new dbm.

*/

#include	<stdio.h>
#include	<ssdef.h>
#include	<rms.h>

#include	"vms_dbm.h"

static char	dbmbuff[MAX_RECORD];


DBM *
dbm_open(filename,flags,mode)
char	*filename;
int	flags;		/* Ignored. */
int	mode;		/* Ignored. */
{
	DBM	*newdb;
	char	*name;
	int	status;

	/* Make a new DBM struct */
#ifdef DEBUG
	printf("Opening DB file %s\n",filename);
#endif
	newdb = (DBM *) malloc(sizeof(struct rmsblocks));
	if(newdb == (DBM *)0){
		return((DBM *)0);
	}

	name = (char *) malloc(strlen(filename)+1);
	if(name == (char *)0){
		free((char *)newdb);
		return((DBM *)0);
	}
	strcpy(name,filename);

	/* Fill it in with stuff */

	/* FAB */

	newdb->fab = cc$rms_fab;
	(newdb->fab).fab$l_fna = name;
	(newdb->fab).fab$l_xab = &(newdb->xab);
	(newdb->fab).fab$b_fns = strlen(name);
	(newdb->fab).fab$b_bks = BUCKET_SIZE;
	(newdb->fab).fab$b_org = FAB$C_IDX;
	(newdb->fab).fab$w_mrs = MAX_RECORD;
	(newdb->fab).fab$b_rfm = FAB$C_VAR;
	(newdb->fab).fab$l_fop = FAB$M_CIF;
	(newdb->fab).fab$b_fac = FAB$M_PUT|FAB$M_GET|FAB$M_UPD|FAB$M_DEL;

	/* RAB */

	newdb->rab = cc$rms_rab;
	(newdb->rab).rab$l_fab = &(newdb->fab);
	(newdb->rab).rab$b_rac = RAB$C_KEY;
	(newdb->rab).rab$l_rop = RAB$V_UIF | RAB$V_LIM;
	(newdb->rab).rab$l_ubf = dbmbuff;
	(newdb->rab).rab$w_usz = MAX_RECORD;

	/* XAB */

	newdb->xab = cc$rms_xabkey;
	(newdb->xab).xab$b_dtp = XAB$C_STG;
  	(newdb->xab).xab$w_pos = 0;
	(newdb->xab).xab$b_siz = KEY_SIZE;
	(newdb->xab).xab$b_ref = 0;

	/* Try to open it */

	status = sys$create(&(newdb->fab));
	if((status & 1) == 0){ /* Failed open, try to create it */
#ifdef DEBUG
		printf("$open failed, status %d.\n",status);
#endif
		goto bag;
	}

	/* We're poppin'. Connect the rab up. */

	status = sys$connect(&(newdb->rab));
	if((status & 1) == 0){
#ifdef DEBUG
		printf("$connect failed, status %d\n",status);
#endif
		goto bag;
	}

	/* Ready to go, we hope */
#ifdef DEBUG
	printf("Succeeded.\n");
#endif
	return(newdb);
bag:
	free((char *)newdb);
	free((char *)name);
	return((DBM *)0);
}

dbm_close(db)
DBM	*db;
{
	sys$close(&(db->fab));
	free((db->fab).fab$l_fna);
	free((char *)db);
}

datum
dbm_fetch(db,key)
DBM	*db;
datum	key;
{
	int	status;
	int	i;
	datum	answer;
	char	keybuff[KEY_SIZE];
	char	*p,*s;

	/* Fill in the key part of the rab */

	p = keybuff; s = key.dptr;
	for(i = 0; i < KEY_SIZE && i < key.dsize; i++)
		*p++ = *s++;

	while(i++ < KEY_SIZE)
		*p++ = '\0';

	(db->rab).rab$l_kbf = keybuff;
	(db->rab).rab$b_ksz = KEY_SIZE;

	/* Now go get it */

	status = sys$get(&(db->rab));
	if((status & 1) == 0){
#ifdef DEBUG
		printf("$get failed, status %d\n",status);
#endif
		goto bag;
	}

	answer.dsize = (db->rab).rab$w_rsz - KEY_SIZE;
	answer.dptr = malloc(answer.dsize);
	if(answer.dptr == (char *)0){
		goto bag;
	}
	bcopy((db->rab).rab$l_rbf+KEY_SIZE, answer.dptr, answer.dsize);
	return(answer);
bag:
	answer.dptr = (char *)0;
	answer.dsize = 0;
	return(answer);
}

dbm_store(db,key,content,flags)
DBM	*db;
datum	key;
datum	content;
int	flags; /* Ignored */
{
	int	status;
	int	i;
	char	*p,*s;

	/* Build the record */
#ifdef DEBUG
	printf("dbm_store: data size = %d\n",content.dsize);
#endif
	/* Fill in KEY_SIZE bytes of key */

	p = dbmbuff;s = key.dptr;
	for(i = 0; i < key.dsize && i < KEY_SIZE; i++)
		*p++ = *s++;
	while(i++ < KEY_SIZE)
		*p++ = '\0';

	bcopy(content.dptr, dbmbuff+KEY_SIZE, content.dsize);
	(db->rab).rab$l_rbf = dbmbuff;
	(db->rab).rab$w_rsz = content.dsize + KEY_SIZE;

	(db->rab).rab$l_kbf = dbmbuff;
	(db->rab).rab$b_ksz = KEY_SIZE;
#ifdef DEBUG
	printf("Searching for record %s, size = %d\n",
		dbmbuff,(db->rab).rab$w_rsz);
#endif
	status = sys$find(&(db->rab));
	if(status == RMS$_NORMAL){
		status = sys$update(&(db->rab));
	} else if(status == RMS$_RNF){
#ifdef DEBUG
		printf("Record not found. Trying $put %d\n",status);
#endif
		status = sys$put(&(db->rab));
	}
	if((status & 1) == 0){
#ifdef DEBUG
		printf("$update/$put failed. status code %d\n",status);
#endif
		return(1);
	}
	return(0);
}

dbm_delete(db,key)
DBM	*db;
datum	key;
{
	int	status;
	int	i;
	datum	answer;
	char	keybuff[KEY_SIZE];
	char	*p,*s;

	/* Fill in the key part of the rab */

	p = keybuff; s = key.dptr;
	for(i = 0; i < KEY_SIZE && i < key.dsize; i++)
		*p++ = *s++;

	while(i++ < KEY_SIZE)
		*p++ = '\0';

	(db->rab).rab$l_kbf = keybuff;
	(db->rab).rab$b_ksz = KEY_SIZE;

	/* Now go KILL it */

	status = sys$find(&(db->rab));
	if((status & 1) == 0){
#ifdef DEBUG
		printf("$find in delete() failed, status %d\n",status);
#endif
		return(1);
	}
	status = sys$delete(&(db->rab));
	if((status & 1) == 0){
#ifdef DEBUG
		printf("$delete failed, status %d\n",status);
#endif
		return(1);
	}
	return(0);
}

datum
dbm_firstkey(db)
DBM	*db;
{
	int	status;
	datum	answer;

	status = sys$rewind(&(db->rab));
	if((status & 1) == 0){
#ifdef DEBUG
		printf("$rewind failed, status == %d\n",status);
#endif
		goto bag;
	}
	/* Set the file to sequential access */

	(db->rab).rab$b_rac = RAB$C_SEQ;
	status = sys$get(&(db->rab));
	if((status & 1) == 0){
#ifdef DEBUG
		printf("$get in firstkey() failed. status = %d\n",status);
#endif
		goto bag;
	}
	/* Save the key away */
	bcopy((db->rab).rab$l_rbf,db->currkey,KEY_SIZE);

	/* Put the file back to random access. */

	(db->rab).rab$b_rac = RAB$C_KEY;

	answer.dptr = db->currkey;
	answer.dsize = strlen(db->currkey);
	return(answer);
bag:
	(db->rab).rab$b_rac = RAB$C_KEY;
	answer.dptr = (char *)0;
	answer.dsize = 0;
	return(answer);
}

datum
dbm_nextkey(db)
DBM	*db;
{
	int status;
	datum answer;

	(db->rab).rab$l_kbf = db->currkey;
	(db->rab).rab$b_ksz = KEY_SIZE;

	/* Seek over to the current record */

	status = sys$find(&(db->rab));
	if((status & 1) == 0){
#ifdef DEBUG
		printf("$find in nextkey() failed. Status = %d\n",status);
#endif
		goto bag;
	}

	/* set file sequential */
	(db->rab).rab$b_rac = RAB$C_SEQ;

	/* Skip one */
	status = sys$find(&(db->rab));
	if(status == RMS$_EOF){ /* We're done! */
#ifdef DEBUG
		printf("EOF detected in nextkey.\n");
#endif
		status = sys$rewind(&(db->rab));
#ifdef DEBUG
		if((status & 1) == 0){
			printf("$rewind at EOF, in nextkey(), failed. status = %d\n",status);
		}
#endif
		goto bag;
	}
	status = sys$get(&(db->rab));
	if((status & 1) == 0){
#ifdef DEBUG
		printf("$get in nextkey() failed. status = %d\n",status);
#endif
		goto bag;
	}
	/* Save the key away */
	bcopy((db->rab).rab$l_rbf,db->currkey,KEY_SIZE);

	/* Put the file back to random access. */
	(db->rab).rab$b_rac = RAB$C_KEY;

	answer.dptr = db->currkey;
	answer.dsize = strlen(db->currkey);
	return(answer);
bag:
	answer.dptr = (char *)0;
	answer.dsize = 0;
	/* Put the file back to random access. */
	(db->rab).rab$b_rac = RAB$C_KEY;
	return(answer);
}