/*
 * Copyright 1990 by Baylor College of Medicine ALL RIGHTS RESERVED. 
 *
 * This program is subject to a license agreement between 
 * Baylor College of Medicine and MIT. Any use inconsistent with
 * said license and any use by persons other than the faculty, 
 * students and staff at MIT or any use on a computer not operated 
 * as part of the Athena Computing Environment (ACE) is expressly 
 * prohibited.
 */
/****************************************************************
 * File: dbm_io.c  
 * Date: 01/29/91
 *
 * Description:
 *   This file contains the back-end implementation to dbsrv 
 *   utilizing the ndbm library functions. This was implemented
 *   in order to create a more portable version of dbsrv that
 *   is database independent.
 *
 * Revisions:
 ****************************************************************/
#include <stdio.h>
#include <ndbm.h>
#include <sys/types.h>
#include <time.h>
#include <fcntl.h>
#include <varargs.h>
#include <string.h>
#include <ctype.h>

#include <dbsrv.h>

/* various definitions */
#define MAXARG 100
#define QUOTE '\''

/* modes of operation */
#define PROC_EXE     1
#define PROC_LOAD    2

/* argument types */
#define MY_INT       1
#define MY_STRING    2

typedef struct _Arg
{
	int type;      /* type of argument */
	char *str;     /* string */
	int num;       /* number */
} Arg;

Arg args[MAXARG];
static int nargs = 0;
int nload;

typedef struct _ProcRec *ProcTable;

typedef struct _ProcRec
{
	char *name;          /* name of the procedure */
	int (*proc)();       /* pointer to the procedure */
	ProcTable next;      /* pointer to next procedure record */
} ProcRec;

static ProcTable proc_table = NULL;

static dbDatabase cur_db = NULL;

static int mode;

/* ndbm key and data storage and buffer space */
static char data_buf[3000];

/* this contains the current procedure name being executed */
static char current_proc[100];

static int reset = 1;

#ifndef PUBLIC
#define PUBLIC
#endif

#ifndef PRIVATE
#define PRIVATE static
#endif

/* global pointer to ndbm database */
DBM *db;

/****************************************************************
 *                   Various Utilities
 ****************************************************************/

PRIVATE
int
isnumber(s)
	char *s;
{
	int i = 0;

	if (s == NULL)
	{
		return 0;
	}

	while (s[i] != '\0')
	{
		if (isdigit(s[i]))
		{
			++i;
		}
		else
		{
			return 0;
		}
	}

	return 1;
}

/****************************************************************
 *      Argument Buffer Management Utilities
 ****************************************************************/

PRIVATE
void
add_arg_num(ival)
	int ival;
{
	if (nargs < MAXARG)
	{
		args[nargs].type = MY_INT;
		args[nargs++].num = ival;
	}
	else
	{
		fprintf(stderr,"Error(add_arg_num): not enough argument space\n");
	}
}

PRIVATE
void
add_arg_str(s)
	char *s;
{
	if (nargs < MAXARG)
	{
		args[nargs].type = MY_STRING;
		args[nargs++].str = strdup(s);
	}
	else
	{
		fprintf(stderr,"Error(add_arg_str): not enough argument space\n");
	}
}

PRIVATE
void
free_arg_list()
{
	int i;

	for (i = 0; i < nargs; i++)
	{
		if(args[i].type == MY_STRING)
		{
#ifdef FREE
			free(args[i].str);
#endif
		}
	}
	nargs = 0;
}

PRIVATE
void
print_arg_list(func_name)
	char *func_name;
{
	int i;
	printf("Argument List(%s): proc: %s\n",func_name,current_proc);
	for (i = 0; i < nargs; i++)
	{
		if (args[i].type == MY_INT)
		{
			printf("    %3d: %d\n",i,args[i].num);
		}
		else if (args[i].type == MY_STRING)
		{
			printf("    %3d: %s\n",i,args[i].str);
		}
		else
		{
			printf("    %3d: Null Argument\n",i);
		}
	}
}

PRIVATE
int
load_data(s)
	char *s;
{
	char buf[256];
	int i = 0;
	int ibuf = 0;
	int do_string = 0;
	int done = 0;
	int neg = 0;

#ifdef DEBUG
	printf("load_data: s=%s\n",s);
#endif

	if (s == NULL)
	{
		return;
	}

	while(done == 0)
	{
		if (s[i] == '\0')
		{
			if (ibuf > 0)
			{
				/* terminate string, add it to the argument list and were done */
				int ival;
				buf[ibuf] = 0;
				if (neg)
				{
					ival = -atoi(buf);
					neg = 0;
				}
				else
				{
					ival = atoi(buf);
				}
				args[nargs].type = MY_INT;
				args[nargs++].num = ival;
			}
			done = 1;
		}
		else if ((s[i] == '-') && (do_string == 0))
		{
			neg = 1;
			++i;
		}
		else if ((s[i] == ',') && (do_string == 0))
		{
			/* this indicates the end of the field, so load buffer */
			int ival;
			buf[ibuf] = 0;
			if (neg)
			{
				ival = -atoi(buf);
				neg = 0;
			}
			else
			{
				ival = atoi(buf);
			}
			args[nargs].type = MY_INT;
			args[nargs++].num = ival;
			/* reset buffer index */
			ibuf = 0;
			++i;
		}
		else if ((s[i] == ',') && (do_string == 1))
		{
			/* accept commas that appear in quoted strings */
			buf[ibuf++] = s[i++];
		}
		else if (s[i] == QUOTE)
		{
			if (s[i+1] == QUOTE)
			{
				if (do_string == 0)
				{
					if ((s[i+2] == ',') || (s[i+2] == '\0'))
					{
						/* in this case, the string is empty */
						add_arg_str("");
						ibuf = 0;
						++i;
						++i;
						++i;
					}
					else
					{
						/* should never happen */
						fprintf(stderr,"Error(load_data); double quotes but no string or comma\n");
						return -1;
					}
				}
				else
				{
					/* put quote in buffer and skip second quote */
					buf[ibuf++] = s[i++];
					i++;
				}
			}
			else
			{
				if (do_string == 0)
				{
					/* don't put beginning quote in buffer and activate string flag */
					do_string = 1;
					++i;
				}
				else
				{
					/* deactivate string flag */
					if (s[i+1] == ',')
					{
						buf[ibuf] = 0;
						add_arg_str(buf);
						ibuf = 0;
						do_string = 0;
						++i;
						++i;
					}
					else if (s[i+1] == '\0')
					{
						buf[ibuf] = 0;
						add_arg_str(buf);
						done = 1;
					}
				}
			}
		}
		else
		{
			/* just copy to the buffer */
			buf[ibuf++] = s[i++];
		}
	}
}

/****************************************************************
 *              Field Management Utilities
 ****************************************************************/

static
int
get_int_field(s,pos)
	char *s;
	int pos;
{
	char buf[256];
	int ibuf = 0;
	int nfield = 0;
	int i = 0;
	int do_string = 0;

	/* index to the beginning of the field */
	while(nfield < pos)
	{
		if ((s[i] == ',') && (do_string == 0))
		{
			++nfield;
		}
		else if (s[i] == QUOTE)
		{
			if (s[i+1] == QUOTE)
			{
				if (do_string == 0)
				{
					/* this should never happen */
					fprintf(stderr,"Error(get_int_field): two quotes not in a string\n");
				}
				++i;
			}
			else
			{
				if (do_string == 0)
				{
					do_string = 1;
				}
				else
				{
					do_string = 0;
				}
			}
		}
		++i;
	}

	/* copy string into buffer */
	while (s[i] != ',')
	{
		buf[ibuf++] = s[i++];
	}
	buf[ibuf] = 0;

	/* check if it is a number. if so, convert and return it */
	if (isnumber(buf))
	{
		return atoi(buf);
	}
	else
	{
		return -1;
	}
}

static
char *
get_str_field(s,pos)
	char *s;
	int pos;
{
	char buf[256];
	int ibuf = 0;
	int nfield = 0;
	int i = 0;
	int do_string = 0;

	/* index to the beginning of the field */
	while(nfield < pos)
	{
		if ((s[i] == ',') && (do_string == 0))
		{
			++nfield;
		}
		else if (s[i] == QUOTE)
		{
			if (s[i+1] == QUOTE)
			{
				if (do_string == 0)
				{
					/* this should never happen */
					fprintf(stderr,"Error(get_int_field): two quotes not in a string\n");
				}
				++i;
			}
			else
			{
				if (do_string == 0)
				{
					do_string = 1;
				}
				else
				{
					do_string = 0;
				}
			}
		}
		++i;
	}

	/* copy string into buffer */
	while (s[i] != ',')
	{
		/* only include a single quote */
		if (s[i] == QUOTE)
		{
			if (s[i+1] == QUOTE)
			{
				buf[ibuf++] = s[i++];
				i++;
			}
			else
			{
				i++;
			}
		}	
		else
		{
			buf[ibuf++] = s[i++];
		}
	}
	buf[ibuf] = 0;

	return strdup(buf);
}

static
int
get_key_int(s,pos)
	char *s;
	int pos;
{
	char buf[256];
	int ibuf = 0;
	int nfield = 0;
	int i = 0;

	/* index to the beginning of the field */
	while(nfield < pos)
	{
		if (s[i] == ' ')
		{
			++nfield;
		}
		i++;
	}

	while (1)
	{
		if (s[i] == ' ' || s[i] == '\0')
		{
			buf[ibuf] = 0;
			if (isnumber(buf))
			{
				return atoi(buf);
			}
			else
			{
				return -1;
			}
		}
		else
		{
			buf[ibuf++] = s[i++];
		}
	}
}

/****************************************************************
 *            Procedure Management Utilities
 ****************************************************************/

PRIVATE
int
sy_dispatch(pname)
	char *pname;
{
	ProcRec *table = proc_table;

	while (table != NULL)
	{
		if (strcmp(pname,table->name) == 0)
		{
			int err;
#ifdef DEBUG
			printf("sy_dipatch->%s\n",pname);
#endif
			err = (*table->proc)();
			return err;
		}
		table = table->next;
	}

	return 0;
}

PRIVATE
void
AddProc(name,proc)
	char *name;
	int (*proc)();
{
	ProcRec *table, *prev;

	table = proc_table;
	prev = NULL;

	while((table != NULL) && (table->proc != proc))
	{
		prev = table;
		table = table->next;
	}

	if (table == NULL)
	{
		table = (ProcTable)malloc(sizeof(ProcRec));
		if (table == NULL)
		{
			fprintf(stderr,"Error(AddProc): malloc failed\n");
		}
		table->name = name;
		table->proc = proc;

		if (prev == NULL)
		{
			table->next = proc_table;
			proc_table = table;
		}
		else
		{
			prev->next = table;
			table->next = NULL;
		}
	}
}

static 
int
Update_Object(nid,pid,oid,x,y,w,h,modify)
	int nid;      /* notebook id */
	int pid;      /* page id */
	int oid;      /* object id */
	int x;        /* x coordinate */
	int y;        /* y coordinate */
	int w;        /* width of object */
	int h;        /* height of object */
	char *modify; /* modify date */
{
	datum key,old,new;
	char buf[100];
	int aid;
	int type;
	char *create;

	/* set key */
	sprintf(buf,"Object %d %d %d",nid,pid,oid);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* retrieve existing entry */
	old = dbm_fetch(db,key);
	if (old.dptr == NULL)
	{
		return -1;
	}

	/* retrieve old fields */
	aid = get_int_field(old.dptr,3);
	create = get_str_field(old.dptr,4);
	type = get_int_field(old.dptr,6);

	/* free old entry */
#ifdef FREE
	free(old.dptr);
#endif

	/* set content */
	sprintf(data_buf,"%d,%d,%d,%d,\'%s\',\'%s\',%d,%d,%d,%d,%d",
		nid,pid,oid,aid,create,modify,type,x,y,w,h);
	new.dptr = data_buf;
	new.dsize = strlen(data_buf) + 1;

	/* add access entry to database */
	dbm_store(db,key,new,DBM_REPLACE);
	
	return 0;
}

static 
int
Create_Object(nid,pid,oid,aid,type,x,y,w,h,cdate)
	int nid;      /* notebook id */
	int pid;      /* page id */
	int oid;      /* object id */
	int aid;      /* author id */
	int type;     /* object type flag */
	int x;        /* x coordinate */
	int y;        /* y coordinate */
	int w;        /* width of object */
	int h;        /* height of object */
	char *cdate;  /* creation date */
{
	char buf[100];
	datum key,new;

	/* set key */
	sprintf(buf,"Object %d %d %d",nid,pid,oid);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"%d,%d,%d,%d,\'%s\',\'%s\',%d,%d,%d,%d,%d",
		nid,pid,oid,aid,cdate,cdate,type,x,y,w,h);
	new.dptr = data_buf;
	new.dsize = strlen(data_buf) + 1;

	/* add access entry to database */
	dbm_store(db,key,new,DBM_INSERT);
	
	return 0;
}

static
int
Load_Object(nid,pid,oid)
	int nid;
	int pid;
	int oid;
{
	datum key,info;
	char buf[100];

	/* build key for object */
	sprintf(buf,"Object %d %d %d",nid,pid,oid);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	info = dbm_fetch(db,key);
	if (info.dptr == NULL)
	{
		return -1;
	}

	/* load the object record into the argument list */
	load_data(info.dptr);

	/* free data fetched */
#ifdef FREE
	free(info.dptr);
#endif

	return 0;
}

static
datum
find_key(root_key)
	char *root_key;
{
	int len = strlen(root_key);
	datum key;

	if (reset == 1)
	{
		int i;
		reset = 0;
		/* for reset, we start the searsh using dbm_firstkey */
		for (key = dbm_firstkey(db); key.dptr != NULL; key = dbm_nextkey(db))
		{
			if (strncmp(key.dptr,root_key,len) == 0)
			{
				return key;
			}
			/* free the key obtained */
#ifdef FREE
			free(key.dptr);
#endif
		}
	}
	else
	{
		int i;
		/* now we search beginning with nextkey */
		for (key = dbm_nextkey(db); key.dptr != NULL; key = dbm_nextkey(db))
		{
			if (strncmp(key.dptr,root_key,len) == 0)
			{
				return key;
			}
			/* free the key obtained */
#ifdef FREE
			free(key.dptr);
#endif
		}
	}

	/* next key not found */
	return key;
}

/****************************************************************
 *                  Command Procedures
 ****************************************************************/

static
int
Update_Notebook()
{
	datum key,old,new;
	char buf[100];
	int aid;
	char *create;

	/* set key */
	sprintf(buf,"Notebook %d",args[0].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* retrieve existing entry */
	old = dbm_fetch(db,key);
	if (old.dptr == NULL)
	{
		return -1;
	}

	/* retrieve old fields */
	aid = get_int_field(old.dptr,2);
	create = get_str_field(old.dptr,3);

	/* free old entry we fetched */
#ifdef FREE
	free(old.dptr);
#endif

	/* Notebook: nid,title,aid,create,modify,home_page_id */
	sprintf(data_buf,"%d,\'%s\',%d,\'%s\',\'%s\',%d",
		args[0].num,
		args[1].str,
		aid,
		create,
		args[2].str,
		args[3].num);
	new.dptr = data_buf;
	new.dsize = strlen(data_buf) + 1;

	/* replace notebook entry to database */
	dbm_store(db,key,new,DBM_REPLACE);

	return 0;
}

static
int
Update_Page()
{
	datum key,old,new;
	char buf[100];
	int aid;
	char *create;

	/* set key */
	sprintf(buf,"Page %d %d",args[0].num,args[1].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* retrieve existing entry */
	old = dbm_fetch(db,key);
	if (old.dptr == NULL)
	{
		return -1;
	}

	/* retrieve old fields */
	aid = get_int_field(old.dptr,3);
	create = get_str_field(old.dptr,4);

	/* free old entry we fetched */
#ifdef FREE
	free(key.dptr);
#endif

	/* Page: nid,pid,title,aid,create,modify,w,h,color */
	sprintf(data_buf,"%d,%d,\'%s\',%d,\'%s\',\'%s\',%d,%d,\'%s\'",
		args[0].num,
		args[1].num,
		args[2].str,
		aid,
		create,
		args[6].str,
		args[3].num,
		args[4].num,
		args[5].str);
	new.dptr = data_buf;
	new.dsize = strlen(data_buf) + 1;

	/* add page entry to database */
	dbm_store(db,key,new,DBM_REPLACE);

	return 0;
}

static
int
Update_Image_Object()
{
	datum key,new;
	char buf[100];

	/* update object: (nid,pid,oid,x,y,w,h) */
	Update_Object(args[0].num,args[1].num,args[2].num,args[3].num,args[4].num,
		args[5].num,args[6].num,args[9].str);
	
	/* set key */
	sprintf(buf,"Image %d %d %d",args[0].num,args[1].num,args[2].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"%d,%d",args[7].num,args[8].num);
	new.dptr = data_buf;
	new.dsize = strlen(data_buf) + 1;

	/* update entry */
	dbm_store(db,key,new,DBM_REPLACE);

	return 0;
}

static
int
Update_Txt_Object()
{
	datum key,new;
	char buf[100];

	/* update object: (nid,pid,oid,x,y,w,h) */
	Update_Object(args[0].num,args[1].num,args[2].num,args[3].num,args[4].num,
		args[5].num,args[6].num,args[9].str);

	/* set key */
	sprintf(buf,"Text %d %d %d",args[0].num,args[1].num,args[2].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"\'%s\',\'%s\'",args[7].str,args[8].str);
	new.dptr = data_buf;
	new.dsize = strlen(data_buf) + 1;

	/* update entry */
	dbm_store(db,key,new,DBM_REPLACE);

	return 0;
}

static
int
Update_Link_Object()
{
	datum key,new;
	char buf[100];

	/* update object: (nid,pid,oid,x,y,w,h) */
	Update_Object(args[0].num,args[1].num,args[2].num,args[3].num,args[4].num,
		args[5].num,args[6].num,args[12].str);

	/* set key */
	sprintf(buf,"Link %d %d %d",args[0].num,args[1].num,args[2].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"%d,%d,\'%s\',\'%s\',\'%s\'",
		args[7].num,
		args[8].num,
		args[9].str,
		args[10].str,
		args[11].str);
	new.dptr = data_buf;
	new.dsize = strlen(data_buf) + 1;

	/* add link entry to database */
	dbm_store(db,key,new,DBM_REPLACE);

	return 0;
}

static
int
Update_Action_Link_Object()
{
	datum key,new; 
	char buf[100];

	/* update object: (nid,pid,oid,x,y,w,h) */
	Update_Object(args[0].num,args[1].num,args[2].num,args[3].num,args[4].num,
		args[5].num,args[6].num,args[11].str);

	/* set key */
	sprintf(buf,"Action %d %d %d",args[0].num,args[1].num,args[2].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"\'%s\',\'%s\',\'%s\',\'%s\'",
		args[7].str,
		args[8].str,
		args[9].str,
		args[10].str);
	new.dptr = data_buf;
	new.dsize = strlen(data_buf) + 1;

	/* add Action entry to database */
	dbm_store(db,key,new,DBM_REPLACE);

	return 0;
}

static
int
Update_Txt_Contents()
{
	datum key,new;
	char buf[100];

	/* set key */
	sprintf(buf,"Txt_Contents %d %d %d",args[0].num,args[1].num,args[2].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"%s",args[3].str);
	new.dptr = data_buf;
	new.dsize = strlen(data_buf) + 1;

	/* update entry */
	dbm_store(db,key,new,DBM_REPLACE);

	return 0;
}

static
int
Retrieve_Authors()
{
	datum key,info;

	/* check mode of operation */
	if (mode != PROC_LOAD) return;

	key = find_key("Author");
	if (key.dptr == NULL)
	{
		return -1;
	}

	/* fetch author entry */
	info = dbm_fetch(db,key);
	if (info.dptr == NULL)
	{
		return -1;
	}

	/* load the data into the argument list */
	args[nargs].type = MY_INT;
	args[nargs++].num = atoi(info.dptr);

	/* free memory */
#ifdef FREE
	free(key.dptr);
	free(info.dptr);
#endif

	return 0;
}

static
int
Retrieve_Accesses()
{
	datum key,data;

	/* check mode of operation */
	if (mode != PROC_LOAD) return;

	key = find_key("Access");
	if (key.dptr == NULL)
	{
		return -1;
	}

	/* fetch access entry */
	data = dbm_fetch(db,key);
	if (data.dptr == NULL)
	{
		return -1;
	}

	/* load the data into the argument list */
	load_data(data.dptr);

	/* free memory */
#ifdef FREE
	free(key.dptr);
	free(data.dptr);
#endif

	return 0;
}

static
int
Retrieve_Notebooks()
{
	datum key,info;

	/* check mode of operation */
	if (mode != PROC_LOAD) return;

	key = find_key("Notebook");
	if (key.dptr == NULL)
	{
		return -1;
	}

	/* fetch notebook entry */
	info = dbm_fetch(db,key);
	if (info.dptr == NULL)
	{
		return -1;
	}

	/* load the notebook data into the argument list */
	load_data(info.dptr);

	/* free memory */
#ifdef FREE1
	free(key.dptr);
	free(info.dptr);
#endif

	return 0;
}

static
int
Retrieve_Pages()
{
	datum key,info;

	/* check mode of operation */
	if (mode != PROC_LOAD) return;

	key = find_key("Page");
	if (key.dptr == NULL)
	{
		return -1;
	}

	/* fetch page entry */
	info = dbm_fetch(db,key);
	if (info.dptr == NULL)
	{
		return -1;
	}

	/* load the page data into the argument list */
	load_data(info.dptr);

	/* free memory */
#ifdef FREE
	free(key.dptr);
	free(info.dptr);
#endif

	return 0;
}

static
int
Retrieve_Image_Objects()
{
	int nid,pid,oid;
	datum key,info;
	char buf[100];

	/* check mode of operation */
	if (mode != PROC_LOAD) return;

	/* find next image key */
	key = find_key("Image");
	if (key.dptr == NULL)
	{
		return -1;
	}

	/* extract id's from key found */
	nid = get_key_int(key.dptr,1);
	pid = get_key_int(key.dptr,2);
	oid = get_key_int(key.dptr,3);

	/* free key otained */
#ifdef FREE
	free(key.dptr);
#endif

	/* load generic object info for key */
	Load_Object(nid,pid,oid);

	/* build key for Image */
	sprintf(buf,"Image %d %d %d",nid,pid,oid);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* fetch image data */
	info = dbm_fetch(db,key);
	if (info.dptr == NULL)
	{
		return -1;
	}

	/* load image info */
	load_data(info.dptr);

	/* free memory */
#ifdef FREE
	free(info.dptr);
#endif

	return 0;
}

static
int
Retrieve_Txt_Objects()
{
	int nid,pid,oid;
	datum key;
	char buf[255];

	/* check mode of operation */
	if (mode != PROC_LOAD) return;

	/* find next key for text object */
	key = find_key("Text");
	if (key.dptr == NULL)
	{
		return -1;
	}

	/* extract id's from key found */
	nid = get_key_int(key.dptr,1);
	pid = get_key_int(key.dptr,2);
	oid = get_key_int(key.dptr,3);

	/* free key found */
#ifdef FREE
	free(key.dptr);
#endif

	/* load object info for text object */
	Load_Object(nid,pid,oid);

	{
		datum key2,info2;
		char buf2[100];

		/* set key for text information */
		sprintf(buf2,"Text %d %d %d",nid,pid,oid);
		key2.dptr = buf2;
		key2.dsize = strlen(buf2) + 1;

		/* retrieve specific text properties */
		info2 = dbm_fetch(db,key2);
		if (info2.dptr == NULL)
		{
			return -1;
		}

		/* load text properties */
		load_data(info2.dptr);

		/* free memory */
#ifdef FREE
		free(info2.dptr);
#endif
	}

	{
		datum key3, info3;
		char buf3[100];

		/* set key for text content information */
		sprintf(buf3,"Txt_Contents %d %d %d",nid,pid,oid);
		key3.dptr = buf3;
		key3.dsize = strlen(buf3) + 1;

		/* fetch entry containing text information */
		info3 = dbm_fetch(db,key3);
		if (info3.dptr == NULL)
		{
			return -1;
		}

		/* add string to argument list */
		add_arg_str(info3.dptr);
	}

	return 0;
}

static
int
Retrieve_Link_Objects()
{
	int nid,pid,oid;
	datum key,data;
	char buf[100];

	/* check mode of operation */
	if (mode != PROC_LOAD) return;

	key = find_key("Link");
	if (key.dptr == NULL)
	{
		return -1;
	}

	/* extract id's from key found */
	nid = get_key_int(key.dptr,1);
	pid = get_key_int(key.dptr,2);
	oid = get_key_int(key.dptr,3);

	/* free memory */
#ifdef FREE
	free(key.dptr);
#endif

	/* load generic object info for link */
	Load_Object(nid,pid,oid);

	/* set key for text content information */
	sprintf(buf,"Link %d %d %d",nid,pid,oid);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	data = dbm_fetch(db,key);
	if (data.dptr == NULL)
	{
		return -1;
	}

	/* load link info */
	load_data(data.dptr);

	/* free memory */
#ifdef FREE
	free(data.dptr);
#endif

	return 0;
}

static
int
Retrieve_Action_Link_Objects()
{
	int nid,pid,oid;
	datum key,data;
	char buf[100];

	/* check mode of operation */
	if (mode != PROC_LOAD) return;

	key = find_key("Action");
	if (key.dptr == NULL)
	{
		return -1;
	}

	/* extract id's from key found */
	nid = get_key_int(key.dptr,1);
	pid = get_key_int(key.dptr,2);
	oid = get_key_int(key.dptr,3);

	/* free memory */
#ifdef FREE
	free(key.dptr);
#endif

	/* load generic object information */
	Load_Object(nid,pid,oid);

	/* set key for text content information */
	sprintf(buf,"Action %d %d %d",nid,pid,oid);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	data = dbm_fetch(db,key);
	if (data.dptr == NULL)
	{
		return -1;
	}

	/* load action info */
	load_data(data.dptr);

	/* free memory */
#ifdef FREE
	free(data.dptr);
#endif

	return 0;
}

static
int
Delete_Notebook()
{
	datum key;
	char buf[100];

	/* set key */
	sprintf(buf,"Notebook %d",args[0].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* delete the entry for this notebook */
	dbm_delete(db,key);

	return 0;
}

static
int
Delete_Page()
{
	datum key;
	char buf[100];

	/* set key */
	sprintf(buf,"Page %d %d",args[0].num,args[1].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* delete the entry for page */
	dbm_delete(db,key);

	return 0;
}

static
int
Delete_Image_Object()
{
	datum key;
	char buf[100];

	/* set key */
	sprintf(buf,"Image %d %d %d",args[0].num,args[1].num,args[2].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* delete the entry for image */
	dbm_delete(db,key);

	return 0;
}

static
int
Delete_Txt_Object()
{
	datum key;
	char buf[100];

	/* set key */
	sprintf(buf,"Text %d %d %d",args[0].num,args[1].num,args[2].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* delete the entry for text */
	dbm_delete(db,key);

	return 0;
}

static
int
Delete_Link_Object()
{
	datum key;
	char buf[100];

	/* set key */
	sprintf(buf,"Link %d %d %d",args[0].num,args[1].num,args[2].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* delete the entry for link */
	dbm_delete(db,key);

	return 0;
}

static
int
Delete_Action_Link_Object()
{
	datum key;
	char buf[100];

	/* set key */
	sprintf(buf,"Action %d %d %d",args[0].num,args[1].num,args[2].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* delete the entry for link */
	dbm_delete(db,key);

	return 0;
}

static
int
Create_Notebook()
{
	datum key,data;
	char buf[100];

	/* set key */
	sprintf(buf,"Notebook %d",args[0].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* Notebook: nid,title,aid,create,modify,hpid */
	sprintf(data_buf,"%d,\'%s\',%d,\'%s\',\'%s\',%d",
		args[0].num,
		args[3].str,
		args[1].num,
		args[2].str,
		args[2].str,
		args[4].num);
	data.dptr = data_buf;
	data.dsize = strlen(data_buf) + 1;

	/* add notebook entry to database */
	dbm_store(db,key,data,DBM_INSERT);
		
	return 0;
}

static
int
Create_Page()
{
	datum key,data;
	char buf[100];

	/* set key */
	sprintf(buf,"Page %d %d",args[2].num,args[0].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* Page: nid,pid,title,aid,create,modify,w,h,color */
	sprintf(data_buf,"%d,%d,\'%s\',%d,\'%s\',\'%s\',%d,%d,\'%s\'",
		args[2].num,
		args[0].num,
		args[3].str,
		args[1].num,
		args[7].str,
		args[7].str,
		args[4].num,
		args[5].num,
		args[6].str);
	data.dptr = data_buf;
	data.dsize = strlen(data_buf) + 1;

	/* add page entry to database */
	dbm_store(db,key,data,DBM_INSERT);

	return 0;
}

static
int
Create_Image_Object()
{
	datum key,data;
	char buf[100];

	/* create generic object */
	Create_Object(args[2].num,args[3].num,args[0].num,args[1].num,0,
		args[4].num,args[5].num,args[6].num,args[7].num,args[10].str);

	/* set key */
	sprintf(buf,"Image %d %d %d",args[2].num,args[3].num,args[0].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"%d,%d",args[8].num,args[9].num);
	data.dptr = data_buf;
	data.dsize = strlen(data_buf) + 1;

	/* add access entry to database */
	dbm_store(db,key,data,DBM_INSERT);
	
	return 0;
}

static
int
Create_Txt_Object()
{
	datum key,data;
	char buf[100];

	/* create generic object */
	Create_Object(args[2].num,args[3].num,args[0].num,args[1].num,1,
		args[4].num,args[5].num,args[6].num,args[7].num,args[10].str);

	/* set key */
	sprintf(buf,"Text %d %d %d",args[2].num,args[3].num,args[0].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"\'%s\',\'%s\'",args[8].str,args[9].str);
	data.dptr = data_buf;
	data.dsize = strlen(data_buf) + 1;

	/* add access entry to database */
	dbm_store(db,key,data,DBM_INSERT);

	return 0;
}

static
int
Create_Link_Object()
{
	datum key,data;
	char buf[100];

	/* create generic object */
	Create_Object(args[2].num,args[3].num,args[0].num,args[1].num,2,
		args[4].num,args[5].num,args[6].num,args[7].num,args[13].str);

	/* set key */
	sprintf(buf,"Link %d %d %d",args[2].num,args[3].num,args[0].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"%d,%d,\'%s\',\'%s\',\'%s\'",
		args[8].num,
		args[9].num,
		args[10].str,
		args[11].str,
		args[12].str);
	data.dptr = data_buf;
	data.dsize = strlen(data_buf) + 1;

	/* add link entry to database */
	dbm_store(db,key,data,DBM_INSERT);

	return 0;
}

static
int
Create_Action_Link_Object()
{
	datum key,data;
	char buf[100];

	/* create generic object */
	Create_Object(args[2].num,args[3].num,args[0].num,args[1].num,3,
		args[4].num,args[5].num,args[6].num,args[7].num,args[12].str);

	/* set key */
	sprintf(buf,"Action %d %d %d",args[2].num,args[3].num,args[0].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"\'%s\',\'%s\',\'%s\',\'%s\'",
		args[8].str,
		args[9].str,
		args[10].str,
		args[11].str);
	data.dptr = data_buf;
	data.dsize = strlen(data_buf) + 1;

	/* add Action entry to database */
	dbm_store(db,key,data,DBM_INSERT);

	return 0;
}

static
int
Add_Author()
{
	datum key,data;
	char buf[100];

	/* set key */
	sprintf(buf,"Author %d",args[0].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"%d",args[0].num);
	data.dptr = data_buf;
	data.dsize = strlen(data_buf) + 1;

	/* add author entry to database */
	dbm_store(db,key,data,DBM_INSERT);

	return 0;
}

static
int
Rmv_Access()
{
	datum key;
	char buf[100];

	/* set key */
	sprintf(buf,"Access %d %d",args[0].num,args[1].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* remove access entry from database */
	dbm_delete(db,key);

	return 0;
}

static
int
Add_Access()
{
	datum key,data;
	char buf[100];

	/* set key */
	sprintf(buf,"Access %d %d",args[0].num,args[1].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"%d,%d,%d",args[2].num,args[0].num,args[1].num);
	data.dptr = data_buf;
	data.dsize = strlen(data_buf) + 1;

	/* add access entry to database */
	dbm_store(db,key,data,DBM_INSERT);

	return 0;
}

static
int
Update_Access()
{
	datum key,data;
	char buf[100];

	/* set key */
	sprintf(buf,"Access %d %d",args[0].num,args[1].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* set content */
	sprintf(data_buf,"%d,%d,%d",args[2].num,args[0].num,args[1].num);
	data.dptr = data_buf;
	data.dsize = strlen(data_buf) + 1;

	/* replace access entry to database */
	dbm_store(db,key,data,DBM_REPLACE);

	return 0;
}

static
int
Update_Object_LW()
{
	datum key,old,new;
	int aid, type, x, y, w, h;
	char *create;
	char buf[100];

	/* set key */
	sprintf(buf,"Object %d %d %d",args[0].num,args[1].num,args[2].num);
	key.dptr = buf;
	key.dsize = strlen(buf) + 1;

	/* retrieve existing entry */
	old = dbm_fetch(db,key);
	if (old.dptr == NULL)
	{
		return -1;
	}

	/* retrieve old fields */
	aid = get_int_field(old.dptr,3);
	create = get_str_field(old.dptr,4);
	type = get_int_field(old.dptr,6);
	x = get_int_field(old.dptr,7);
	y = get_int_field(old.dptr,8);
	w = get_int_field(old.dptr,9);
	h = get_int_field(old.dptr,10);

	/* free old entry */
#ifdef FREE
	free(old.dptr);
#endif

	/* set content */
	sprintf(data_buf,"%d,%d,%d,%d,\'%s\',\'%s\',%d,%d,%d,%d,%d",
		args[0].num,
		args[1].num,
		args[2].num,
		aid,
		create,
		args[3].str,
		type,
		x,
		y,
		w,
		h);
	new.dptr = data_buf;
	new.dsize = strlen(data_buf) + 1;

	/* add access entry to database */
	dbm_store(db,key,new,DBM_REPLACE);
	return 0;
}

/****************************************************************
 *                  Public Functions
 ****************************************************************/

/****************************************************************
 * Function: sy_open 
 * Date: 01/29/91
 *
 * Description:
 *   This function closes the connection with the database.
 * Arguments:
 * Revisions:
 ****************************************************************/
PUBLIC
int
sy_open(log_name,passwd,server,application)
	char *log_name;
	char *passwd;
	char *server;
	char *application;
{
	/* add procedures */
	AddProc("Update_Notebook",Update_Notebook);
	AddProc("Update_Page",Update_Page);
	AddProc("Update_Image_Object",Update_Image_Object);
	AddProc("Update_Txt_Object",Update_Txt_Object);
	AddProc("Update_Link_Object",Update_Link_Object);
	AddProc("Update_Action_Link_Object",Update_Action_Link_Object);
	AddProc("Update_Txt_Contents",Update_Txt_Contents);
	AddProc("Retrieve_Authors",Retrieve_Authors);
	AddProc("Retrieve_Accesses",Retrieve_Accesses);
	AddProc("Retrieve_Notebooks",Retrieve_Notebooks);
	AddProc("Retrieve_Pages",Retrieve_Pages);
	AddProc("Retrieve_Image_Objects",Retrieve_Image_Objects);
	AddProc("Retrieve_Txt_Objects",Retrieve_Txt_Objects);
	AddProc("Retrieve_Link_Objects",Retrieve_Link_Objects);
	AddProc("Retrieve_Action_Link_Objects",Retrieve_Action_Link_Objects);
	AddProc("Delete_Notebook",Delete_Notebook);
	AddProc("Delete_Page",Delete_Page);
	AddProc("Delete_Image_Object",Delete_Image_Object);
	AddProc("Delete_Txt_Object",Delete_Txt_Object);
	AddProc("Delete_Link_Object",Delete_Link_Object);
	AddProc("Delete_Action_Link_Object",Delete_Action_Link_Object);
	AddProc("Create_Notebook",Create_Notebook);
	AddProc("Create_Page",Create_Page);
	AddProc("Create_Image_Object",Create_Image_Object);
	AddProc("Create_Txt_Object",Create_Txt_Object);
	AddProc("Create_Link_Object",Create_Link_Object);
	AddProc("Create_Action_Link_Object",Create_Action_Link_Object);
	AddProc("Add_Author",Add_Author);
	AddProc("Rmv_Access",Rmv_Access);
	AddProc("Add_Access",Add_Access);
	AddProc("Update_Access",Update_Access);
	AddProc("Update_Object_LW",Update_Object_LW);

	return 0;
}

/****************************************************************
 * Function: sy_close 
 * Date: 01/29/91
 *
 * Description:
 *   This function closes the connection with the database.
 *
 * Arguments:
 * Revisions:
 ****************************************************************/
PUBLIC
int
sy_close()
{
	if (db != NULL)
	{
		dbm_close(db);
	}
	return 0;
}

/****************************************************************
 * Function: sy_call_exec
 * Date: 01/29/91
 *
 * Description:
 * Arguments:
 * Revisions:
 ****************************************************************/
PUBLIC
int
sy_call_exec(db_ptr,pname,fmt,va_alist)
	dbDatabase db_ptr ;
	char *pname ;
	char *fmt ;
	va_dcl
{
	va_list pvar ;
	va_start(pvar) ;

	/* open dbm database for current db_ptr */
	if (cur_db == NULL || cur_db != db_ptr)
	{
		char buffer[512];

		cur_db = db_ptr;
		
		/* close the other database if open */
		if (db != NULL)
		{
			dbm_close(db);
		}

		/* open database */
		sprintf(buffer,"%s/%s/vns",pc.data_dir,db_ptr->name);
		db = dbm_open(buffer,O_CREAT | O_RDWR,0700);
	}

	/* set the reset flag */
	reset = 1;

	/* make sure the argument list has been freed */
	free_arg_list();

	/* store the procedure name for later use */
	strcpy(current_proc,pname);

	/* process variable arguments */
	while (*fmt)
	{
		switch(*fmt++)
		{
			case 'd':
			{
				int i = va_arg(pvar,int);
				add_arg_num(i);
				break;
			}
			case 'q':
			{
				char *p = va_arg(pvar,char *);
				add_arg_str(p);
				break;
			}
		}
	}
	va_end(pvar) ;

#ifdef DEBUG
	print_arg_list("sy_call_exec");
#endif

	/* set the mode */
	mode = PROC_EXE;

	/* dispatch the procedure */
	sy_dispatch(pname);

	return 0;
}

/****************************************************************
 * Function: sy_get_one_row
 * Date: 01/29/91
 *
 * Description:
 * Arguments:
 * Revisions:
 ****************************************************************/
PUBLIC
int
sy_get_one_row()
{
	int err;

	/* free the arg list before loading */
	free_arg_list();

	/* set mode for loading */
	mode = PROC_LOAD;

	/*
	 * dispatch and call the current retrieval procedure. 
	 * The procedure will load the argument list accessed 
	 * by get_int_result and get_str_result.
	 */
	err = sy_dispatch(current_proc);
	if (err < 0)
	{
		return err;
	}

#ifdef DEBUG
	print_arg_list("sy_get_one_row");
#endif

	/* reset load counter */
	nload = 0;
	
	return 0;
}

/****************************************************************
 * Function: get_int_result
 * Date: 01/29/91
 *
 * Description:
 *
 * Arguments:
 * Revisions:
 ****************************************************************/
PUBLIC
int
get_int_result()
{
	if (args[nload].type == MY_INT)
	{
		int res = args[nload++].num;
		return res;
	}
	else
	{
		fprintf(stderr,"Error(get_int_result): Bad argument type\n");
		return -1;
	}
}

/****************************************************************
 * Function: get_str_result 
 * Date: 01/29/91
 *
 * Description:
 * Arguments:
 * Revisions:
 ****************************************************************/
PUBLIC
int
get_str_result(s)
	char *s;
{
	if (args[nload].type == MY_STRING)
	{
		/* we copy the string because s[255] is passed */
		strcpy(s,args[nload++].str);
		return 0;
	}
	else
	{
		fprintf(stderr,"Error(get_int_result): Bad argument type\n");
		s[0] = 0;
		return -1;
	}
}

