game/bin/
game/data/
/*
 * Copyright (C) 1991, Andrew Molitor. All rights reserved.
 * $Id: vms_dbm.c,v 1.2 1995/11/22 23:33:17 root Exp $
 */
/*
 * #define DEBUG
 */
/*
 * This a a dbm emulation module for VMS, using indexed files to do
 * the database thang. It emulates new dbm.
 * 
 */

#include	"autoconf.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);
}