/
teeny/db/
teeny/dbm/
teeny/doc/
teeny/includes/
#include <stdio.h>
#include <ctype.h>

#include "teeny.h"
#include "db.h"

/*
Copyright(C) 1990, Andrew Molitor, All Rights Reserved.
This software may be freely used, modified, and redistributed,
as long as this copyright message is left intact, and this
software is not used to develop any commercial product, or used
in any product that is provided on a pay-for-use basis.

No warranties whatsoever. This is not guaranteed to compile, nor,
in the event that it does compile to binaries, are these binaries
guaranteed to perform any function whatsoever.
*/

/*
	Provides a simple text dump format for TeenyMUD. a la TinyMUD.
This should be considered as more or less an adjunct component of the database
proper, since it roots around directly with DB structures.

Dump format:

	Preamble of lines starting with !'s. These are comments.

	A line starting with %, and followed by a number. This number is the
total number of objects contained in the dump (including garbage)

	A sequence of objects. Real objects start with a line like #127 to
indicate object number, and are followed by a sequence of lines, one per field,
describing the object data. Garbage objects are coded by a single line like
@1283.

	A line at the end **** END OF DUMP ****
*/

extern struct dsc **main_index;
extern int total_objects;
extern int actual_objects;
extern int garbage_count;
extern struct obj_data *lookup_obj();


text_load(name)
char *name;
{
	FILE *in;
	char work[BUFFSIZ+16];
	int objcount,objnum,i;
	int garbagecount;
	int done;
	int flags,creatednum,objflags;

	if((in = fopen(name,"r")) == NULL){
		warning("text_load","could not open dump file");
		return(-1);
	}

	/* Read and ignore the preamble */

	do {
		if(fgets(work,BUFFSIZ+16,in) == NULL){
			warning("text_load","bad preamble");
			goto fail;
		}
	} while(work[0] == '!');

	if(work[0] != '%'){
		warning("text_load","could not get object count");
		goto fail;
	}

	objcount = atoi(work+1);
	if(objcount <= 0){
		warning("text_load","DB of size <= 0? No way..");
		goto fail;
	}

	/* Set up a blank DB */

	initialize_db(objcount+SLACK,objcount+SLACK);

	/*
	We kludge the garbage objects a bit. We track them, and
	every time we find a garbage object, we count it. We don't
	touch garbage_objects, though, so the db code thinks there
	aren't any until the end when we tell it all of a sudden.
	This means the db code will keep numbers in synch for us.
	*/

	garbagecount = 0;

	/* Do it to it. Loop away sucking in objects and building them */

	done = 0;
	for(i = 0; i < objcount && !done;i++){
		if(fgets(work,BUFFSIZ+16,in) == NULL) goto fail;

		switch(work[0]){
		case '#':	/* Actual object */
			objnum = atoi(work+1);
			if(objnum != i){
				warning("text_load","input DB is out of synch");
				goto fail;
			}
			if(fgets(work,BUFFSIZ+16,in) == NULL) goto fail;
			flags = atoi(work);
			creatednum = create_obj(flags & TYPE_MASK);

			if(creatednum != objnum){
				warning("text_load"
					,"input db and internal db out of synch.");
				goto fail;
			}

			/* Set up the object flags, being CAREFUL */

			if(get_int_elt(i,FLAGS,&objflags) == -1) goto fail;
			flags = (flags & ~INTERNAL_FLAGS)
					| (objflags & INTERNAL_FLAGS);
			if(set_int_elt(i,FLAGS,flags) == -1) goto fail;

			/* Now suck in all the data elements */

			getstring(i,NAME,in);
			getnumber(i,NEXT,in);

			getnumber(i,PENNIES,in);
			getnumber(i,LOC,in);
			getnumber(i,HOME,in);
			getnumber(i,OWNER,in);
			getnumber(i,CONTENTS,in);
			getnumber(i,EXITS,in);
#ifdef TIMESTAMPS
			getnumber(i,TIMESTAMP,in);
#endif

			getlock(i,in);

			getstring(i,SUC,in);
			getstring(i,OSUC,in);
			getstring(i,FAIL,in);
			getstring(i,OFAIL,in);
			getstring(i,DESC,in);

			break;
		case '@':	/* Garbage object */
			garbagecount++;
			total_objects++;  /* Fake out the DB */
			main_index[i] = (struct dsc *) NULL;
			break;
		case '*':	/* End of file */
			done = 1;
			break;
		}
	}

	garbage_count = garbagecount;
	actual_objects -= garbagecount;

	/* total_objects is already correct */

	(void)fclose(in);
	return(0);
fail:
	(void)fclose(in);
	warning("text_load","load failed");
	return(-1);
}

/*

	Generic routines for reading junk in to an object.

*/

getstring(obj,code,f)
int obj;
int code;
FILE *f;
{
	char work[BUFFSIZ+16];
	char *p;
	int ret;

	if(fgets(work,BUFFSIZ+16,f) == NULL){
		warning("get_string","unexpected EOF in text_load");
		return;
	}
	for(p = work;*p != '\n' && *p;p++)
		;
	*p = '\0';
	if(p == work){
		ret = set_str_elt(obj,code,(char *)NULL);
	} else {
		ret = set_str_elt(obj,code,work);
	}
	if(ret == -1){
		warning("getstring","error setting string elt in test_load");
	}
}

getnumber(obj,code,f)
int obj;
int code;
FILE *f;
{
	char work[BUFFSIZ+16];
	int num;

	if(fgets(work,BUFFSIZ+16,f) == NULL){
		warning("getnumber","unexpected EOF in text_load");
		return;
	}
	if( (!isdigit(work[0])) && !(work[0] == '-' && isdigit(work[1])) ){
		warning("getnumber","bad integer read in text_load");
		return;
	}
	num = atoi(work);
	if(set_int_elt(obj,code,num) == -1){
		warning("getnumber","could not set int elt in text_load");
	}
}

getlock(obj,f)
int obj;
FILE *f;
{
	char work[BUFFSIZ+16],*p;
	int size,*lock,i;

	if(fgets(work,BUFFSIZ+16,f) == NULL){
		warning("get_string","unexpected EOF in text_load");
		return;
	}

	/* OK. Locks are slightly complex. We malloc memory HERE for it */

	if(work[0] == '\n'){
		if(set_lock_elt(obj,LOCK,(int *)NULL) == -1)
			warning("getlock","error setting lock elt in text_load");
		return;
	}

	size = atoi(work);
	if(size <= 0){
		warning("getlock","bad lock field in text database");
		return;
	}

	lock = (int *) ty_malloc(sizeof(int) * (size+1),"getlock");
	lock[0] = size;

	p = work;
	for(i = 1;i <= size;i++){
		while(!isspace(*p) && *p) p++;
		while(isspace(*p)) p++;

		if(*p == '\0'){
			warning("getlock","bad lock field in text database");
			return;
		}
		lock[i] = atoi(p);
	}
	if(set_lock_elt(obj,LOCK,lock) == -1)
		warning("getlock","error setting lock elt in text_load");
}

/*
	Dump out the database in text format.
*/

text_dump(name)
char *name;
{
	FILE *out;
	char work[32],*p;
	int obj;
	struct dsc *thedsc;
	struct obj_data *theobj;

	if((out = fopen(name,"w")) == NULL){
		warning("text_dump","could not open dump file");
		return;
	}

	/* Write out a header. */

	fputs("!\n!TeenyMUD dump\n!\n",out);
	work[0] = '%';
	p = ty_itoa(work+1,total_objects);
	*p++ = '\n';*p = '\0';
	fputs(work,out);

	/* Now dump the DB. */

	for(obj = 0; obj < total_objects; obj++){
		if(exists_object(obj)){

			/* Go get the object, and dump it */

			work[0] = '#';
			p = ty_itoa(work+1,obj);
			*p++ = '\n';*p = '\0';
			fputs(work,out);

			thedsc = main_index[obj];
			theobj = lookup_obj(obj);

			putnumber(DSC_FLAGS(thedsc),out);
			putstring(DSC_NAME(thedsc),out);
			putnumber(thedsc->list_next,out);

			putnumber(theobj->pennies,out);
			putnumber(theobj->loc,out);
			putnumber(theobj->home_drpto,out);
			putnumber(theobj->owner,out);
			putnumber(theobj->contents,out);
			putnumber(theobj->exits,out);
#ifdef TIMESTAMPS
			putnumber(theobj->timestamp,out);
#endif

			putlock(theobj->lock,out);

			putstring(theobj->suc,out);
			putstring(theobj->osuc,out);
			putstring(theobj->fail,out);
			putstring(theobj->ofail,out);
			putstring(theobj->desc,out);

		} else {

			/* This object does not exist. Make a garbage entry */

			work[0] = '@';
			p = ty_itoa(work+1,obj);
			*p++ = '\n';*p = '\0';
			fputs(work,out);
		}
	}

	/* Write a trailer */

	fputs("**** END OF DUMP ****\n",out);
	(void)fclose(out);
}


/*
	General output routines for text_dump()
*/

putnumber(num,f)
int num;
FILE *f;
{
	char work[16],*p;

	p = ty_itoa(work,num);
	*p++ = '\n'; *p = '\0';
	fputs(work,f);
}
putstring(str,f)
char *str;
FILE *f;
{
	if(str != NULL){
		fputs(str,f);
	}
	fputs("\n",f);
}
putlock(lock,f)
int *lock;
FILE *f;
{
	int count,i,space;
	char work[BUFFSIZ],*p,*q;

	if(lock == NULL || lock[0] == 0){
		fputs("\n",f);
		return;
	}
	space = BUFFSIZ;
	count = lock[0];  /* How many FOLLOW */
	p = work;

	p = ty_itoa(p,count); *p++ = ' ';
	space -= p - work;

	for(i = 1; count > 0 && space > 8;count--,i++){
		q = p;
		p = ty_itoa(p,lock[i]); *p++ = ' ';
		space -= p-q;
	}
	p--; *p++ = '\n'; *p = '\0';
	fputs(work,f);
}