/* db.c : part of The Bastard disassembly environment =========================
 *
 * Contains routines for interfacing with the Typhoon database module. Typhoon
 * is pretty self-sufficient, so there will not be much here. 
 */
#include <bastard.h>
#include <typhoon.h>



/* NOTE: This file contains a lot of redundancy due to the different DB 
         tables. This should be rewritten or, perhaps, implemented as 
			Seer scripts that set table-specific info dynamically 
*/
			
int doTyphoon(){
		d_dbdpath("./.bdb"); d_dbfpath("./.bdb");
		initSequences();
		return(0);
}
void initSequences() {
	struct int_code ic;
	struct fin_code fc;
	struct xref x;
	struct comment cmt;
	struct function f;
	struct func_param fp;
	struct func_local fl;
	struct f_inline fi;
	struct inline_type it;
	struct structure s;
	struct struct_member sm;
	struct lib l;
	struct data_type dt;
	struct constant c;
	struct seer_macro m;
	
	if (disasm_env.flags & DB_LOADED) {
		if (d_keylast(INT_CODE_ID) == S_OKAY) {
			d_recread(&ic);
			seq.int_code = ic.id;
		} else seq.int_code = 0;
		if (d_keylast(FIN_CODE_ID) == S_OKAY) {
			d_recread(&fc);
			seq.fin_code = fc.id;
		} else seq.fin_code = 0 ;
		if (d_keylast(XREF_ID) == S_OKAY) {
			d_recread(&x);
			seq.xref = x.id;
		} else seq.comment = 0;
		if (d_keylast(COMMENT_ID) == S_OKAY) {
			d_recread(&c);
			seq.comment = c.id;
		} else seq.comment = 0;
		if (d_keylast(FUNCTION_ID) == S_OKAY) {
			d_recread(&f);
			seq.func = f.id;
		} else seq.func = 0;
		if (d_keylast(FUNC_PARAM_ID) == S_OKAY) {
			d_recread(&fp);
			seq.func_param = fp.id;
		} else seq.func_param = 0;
		if (d_keylast(FUNC_LOCAL_ID) == S_OKAY) {
			d_recread(&fl);
			seq.func_local = fl.id;
		} else seq.func_local = 0;
		if (d_keylast(F_INLINE_ID) == S_OKAY) {
			d_recread(&fi);
			seq.f_inline = fi.id;
		} else seq.f_inline = 0;
		if (d_keylast(INLINE_TYPE_ID) == S_OKAY) {
			d_recread(&it);
			seq.inline_type = it.id;
		} else seq.inline_type = 0;
		if (d_keylast(STRUCTURE_ID) == S_OKAY) {
			d_recread(&s);
			seq.structure = s.id;
		} else seq.structure = 0;
		if (d_keylast(STRUCT_MEMBER_ID) == S_OKAY) {
			d_recread(&sm);
			seq.struct_member = sm.id;
		} else seq.struct_member = 0;
		if (d_keylast(DATA_TYPE_ID) == S_OKAY) {
			d_recread(&dt);
			seq.data_type = dt.id;
		} else seq.data_type = 0;
		if (d_keylast(LIB_ID) == S_OKAY) {
			d_recread(&l);
			seq.library = l.id;
		} else seq.library = 0;
		if (d_keylast(CONSTANT_ID) == S_OKAY) {
			d_recread(&c);
			seq.constant = c.id;
		} else seq.constant = 0;
		if (d_keylast(SEER_MACRO_ID) == S_OKAY) {
			d_recread(&m);
			seq.seer_macro = m.id;
		} else seq.seer_macro = 0;
	} else {
		memset( &seq, 0, sizeof( struct DB_SEQUENCE ));
	}
	return;
}

/* ===================================================== LOW LEVEL ROUTINES */
/* These provide a low-level wrapper to the typhoon DB. The intent is to
 * allow the user/controlling process full control over the DB; however, 
 * it is assumed that anyone who uses these functions knows what they are
 * doing. */

/* TODO : keep track of curr_rec in these */
int DBIndexFirst(int index, void *dest){
	if (d_keyfrst(index) == S_OKAY) {
		d_recread(dest);
	}
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}
int DBIndexNext(int index, void *dest){
	if (d_keynext(index) == S_OKAY) {
		d_recread(dest);
	}
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}
int DBIndexPrev(int index, void *dest){
	if (d_keyprev(index) == S_OKAY) {
		d_recread(dest);
	}
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}
int DBIndexLast(int index, void *dest){
	if (d_keylast(index) == S_OKAY) {
		d_recread(dest);
	}
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}
int DBIndexFind(int index, void *value, void *dest){
	if (d_keyfind(index, value) == S_OKAY) {
		d_recread(dest);
	}
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}

int DBTableFirst(int table, void *dest){
	if (d_recfrst(table) == S_OKAY) {
		d_recread(dest);
	}
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}
	
int DBTableNext(int table, void *dest){
	if (d_recnext(table) == S_OKAY) {
		d_recread(dest);
	}
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}
int DBTablePrev(int table, void *dest){
	if (d_recprev(table) == S_OKAY) {
		d_recread(dest);
	}
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}
int DBTableLast(int table, void *dest){
	if (d_reclast(table) == S_OKAY) {
		d_recread(dest);
	}
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}
int DBRecordInsert(int table, void *src){
	d_fillnew(table, src);
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}

/* These use the specified index to find the record to update/delete */
int DBRecordUpdate(int index, void *value, void *src){
	if (d_keyfind(index, value) == S_OKAY) {
		d_recwrite(src);
	}
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}
	
int DBRecordDelete(int index, void *value){
	if (d_keyfind(index, value) == S_OKAY) {
		d_delete();
	}
	if (db_status != S_OKAY) return(SetLastError(dbError()));
	return(1);
}

/* ==================================================== GENERIC ACCESS */
/* These are the recommended DB search routines. They are one level below
 * the bastard API -- useful for debugging or for direct DB queries. Users
 * are expected to use these when the 'normal' API functions are too 
 * limiting.
 */
struct address * GetAddressObject(long rva){
	struct address *a = malloc(sizeof(struct address));
	if ( DBIndexFind(ADDRESS_RVA, &rva, a)) return(a);
	free(a);
	return((void *)SetLastError(4020));
}
	
struct code * GetCodeObject(long rva){
	struct code *c = malloc(sizeof( struct code));
	if (DBIndexFind(CODE_RVA, &rva, c) ) return(c);
	free(c);
	return((void *)SetLastError(4110));
}
	
struct section * GetSectionObject(char *name){
	struct section *s = malloc(sizeof( struct section));
	if (DBIndexFind(SECTION_NAME, &name, s) ) return(s);
	free(s);
	return((void *)SetLastError(4820));
}
	
struct xref * GetXrefObject(int id){
	struct xref *x = malloc(sizeof( struct xref));
	if (DBIndexFind(XREF_ID, &id, x) ) return(x);
	free(x);
	return((void *)SetLastError(5310));
}
	
struct int_code * GetIntCodeObject(int id){
	struct int_code *i = malloc(sizeof( struct int_code));
	if (DBIndexFind(INT_CODE_ID, &id, i) ) return(i);
	free(i);
	return((void *)SetLastError(4150));
}
	
struct fin_code * GetFinCodeObject(int id){
	struct fin_code *f = malloc(sizeof( struct fin_code));
	if (DBIndexFind(FIN_CODE_ID, &id, f) ) return(f);
	free(f);
	return((void *)SetLastError(4170));
}
	
struct export * GetExportObject(long rva){
	struct export *e = malloc(sizeof( struct export));
	if (DBIndexFind(EXPORT_RVA, &rva, e) ) return(e);
	free(e);
	return((void *)SetLastError(4450));
}
	
struct import * GetImportObject(long rva){
	struct import *i = malloc(sizeof( struct import));
	if (DBIndexFind(IMPORT_RVA, &rva, i) ) return(i);
	free(i);
	return((void *)SetLastError(4400));
}
	
struct string * GetStringObject(long rva){
	struct string *s = malloc(sizeof( struct string));
	if (DBIndexFind(STRING_RVA, &rva, s) ) return(s);
	free(s);
	return((void *)SetLastError(5000));
}

struct lib * GetLibObject(int id){
	struct lib *l = malloc(sizeof( struct lib));
	if (DBIndexFind(LIB_ID, &id, l) ) return(l);
	free(l);
	return((void *)SetLastError(4411));
}
	
struct name * GetNameObject(long rva){
	struct name *n = malloc(sizeof( struct name));
	if (DBIndexFind(NAME_RVA, &rva, n) ) return(n);
	free(n);
	return((void *)SetLastError(4710));
}
	
struct comment * GetCommentObject(int id){
	struct comment *c = malloc(sizeof( struct comment));
	if (DBIndexFind(COMMENT_ID, &id, c) ) return(c);
	free(c);
	return((void *)SetLastError(4730));
}
	
struct function * GetFunctionObject(int id){
	struct function *f = malloc(sizeof( struct function));
	if (DBIndexFind(FUNCTION_ID, &id, f) ) return(f);
	free(f);
	return((void *)SetLastError(4300));
}
	
struct func_param * GetFuncParamObject(int id){
	struct func_param *f = malloc(sizeof( struct func_param));
	if (DBIndexFind(FUNC_PARAM_ID, &id, f) ) return(f);
	free(f);
	return((void *)SetLastError(4330));
}
	
struct func_local * GetFuncLocalObject(int id){
	struct func_local *f = malloc(sizeof( struct func_local));
	if (DBIndexFind(FUNC_LOCAL_ID, &id, f) ) return(f);
	free(f);
	return((void *)SetLastError(4340));
}
	
struct f_inline * GetFInlineObject(int id){
	struct f_inline *f = malloc(sizeof( struct f_inline));
	if (DBIndexFind(F_INLINE_ID, &id, f) ) return(f);
	free(f);
	return((void *)GetLastError(4350));
}
	
struct inline_type * GetInlineTypeObject(int id){
	struct inline_type *i = malloc(sizeof( struct inline_type));
	if (DBIndexFind(INLINE_TYPE_ID, &id, i) ) return(i);
	free(i);
	return((void *)SetLastError(4370));
}
	
struct structure * GetStructureTypeObject(int id){
	struct structure *s = malloc(sizeof( struct structure));
	if (DBIndexFind(STRUCTURE_ID, &id, s) ) return(s);
	free(s);
	return((void *)SetLastError(5150));
}
	
struct struct_member * GetStructMemberObject(int id){
	struct struct_member *s = malloc(sizeof( struct struct_member));
	if (DBIndexFind(STRUCT_MEMBER_ID, &id, s) ) return(s);
	free(s);
	return((void *)SetLastError(5160));
}
	
struct data_type * GetDataTypeObject(int id){
	struct data_type *d = malloc(sizeof( struct data_type));
	if (DBIndexFind(DATA_TYPE_ID, &id, d) ) return(d);
	free(d);
	return((void *)SetLastError(5170));
}
	
struct constant * GetConstantObject(int id){
	struct constant *c = malloc(sizeof( struct constant));
	if (DBIndexFind(CONSTANT_ID, &id, c) ) return(c);
	free(c);
	return((void *)SetLastError(5100));
}
	
struct seer_macro * GetSeerMacroObject(int id){
	struct seer_macro *s = malloc(sizeof( struct seer_macro));
	if (DBIndexFind(SEER_MACRO_ID, &id, s) ) return(s);
	free(s);
	return((void *)SetLastError(4600));
}
/* ==================================================== CLI ROUTINES */

int dbError(){
	int err = 2000 + db_status;
	SetLastError(err);
	return(err);
}

void dbErrorMsg( ){
	PrintErrorMsg(dbError());
	return;
}

int TranslateDB( char *table ){
	strtoupper( table, strlen(table) + 1 );
	return( CharToConst(table));
}

/* DB interpeter commands */
void dbHELP( char *cmd ){
	char *help_cmd;
	int cmd_num;

	help_cmd = strtok(cmd, " ");
	if (help_cmd != NULL )
		cmd_num = TranslateSubCmd(help_cmd, DB_CMD, NUM_DB_CMD);
	else cmd_num = 0; //help will always be 0

	Message( DB_HELPSTR[cmd_num] );

	return;
};

void dbCMD( char *cmd, int command ){
	int x, tbl; 
	tbl = TranslateDB( cmd);	
	for (x = 0; x < 13; x++ )
		if ( dbPrintFuncs[x].table == tbl ) 
		 	(*dbPrintFuncs[x].func)(command);
	return;
};

/* utils */
int dbCount( int idx ){
	int n;
	d_recfrst(idx);
	while( db_status == S_OKAY){
		n++;
		d_recnext(idx);
	}
	return(n);
}

void dbPrintSection(int cmd){
	struct section sec;
	int n = 0;

	switch (cmd) {
	case DB_DESC:		/* DESC */
		printf("struct section {\n\tchar name[32];\n\tunsigned long rva;\n\t"
				 "unsigned short size;\n\tint flags;\n};\n");
		break;
	case DB_DUMP:		/* DUMP */
		printf("Name\t\tRVA\tSize\tFlags\n\n");
		d_keyfrst(SECTION_RVA);
		while (db_status == S_OKAY) {
				  dbPrintSection( DB_PRINT );
				  d_keynext(SECTION_RVA);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(SECTION_RVA);
		dbPrintSection( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(SECTION_RVA);
		dbPrintSection( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(SECTION));
		break;
	case DB_FIND:			/* FIND */
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&sec);
		printf("%s\t\t%lX\t%d\t%X\n", sec.name, sec.rva, sec.size, sec.flags);
		break;
	default:
	}
	return;
}
void dbPrintAddress(int cmd){
	struct address addr;
	int n = 0;

	switch (cmd) {
	case DB_DESC:
		printf("struct address {\n\tunsigned long rva;\n\tunsigned long pa;\n\t"
				 "unsigned short size;\n\tint flags;\n};\n");
		break;
	case DB_DUMP:
		printf("RVA\tPA\tSize\tFlags\n\n");
		d_keyfrst(ADDRESS_RVA);
		while (db_status == S_OKAY) {
			dbPrintAddress(DB_PRINT);
			d_keynext(ADDRESS_RVA);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(ADDRESS_RVA);
		dbPrintAddress( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(ADDRESS_RVA);
		dbPrintAddress( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(ADDRESS));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&addr);
		printf("%lX\t%lX\%d\t%X\n", 
				addr.rva, addr.pa, addr.size, addr.flags); 
		break;
	default:
	}
	return;
}
void dbPrintCode(int cmd){
	struct code c;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct code {\n\t unsigned long rva;\n\tunsigned short flags;\n\t"
				 "char mnemonic[16];\n\tchar dest[32];\n\tchar src[32];\n\t"
				 "char aux[32];\n\tint mnemType;\n\tint destType;\n\tint srcType;"
				 "\n\tint auxType;\n};\n");
		break;
	case 1:
		printf("RVA\tFlags\tMnem\tDest\tSrc\tAux\tMType\tDType\tSType\tAType\n");
		d_keyfrst(CODE_RVA);
		while (db_status == S_OKAY) {
				  dbPrintCode(DB_PRINT);
				  d_keynext(CODE_RVA);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(CODE_RVA);
		dbPrintCode( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(CODE_RVA);
		dbPrintCode( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(CODE));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&c);
		printf("%lX\t%X\t%s\t%s\t%s\t%s\t%d\t%d\t%d\t%d\n",
				c.rva, c.flags, c.mnemonic, c.dest, c.src, c.aux,
		 		c.mnemType, c.destType, c.srcType, c.auxType); 
		break;
	default:
	}
	return;
}
void dbPrintIntCode(int cmd){
	struct int_code c;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct int_code {\n\tunsigned long id;\n\tunsigned long rva;\n\t"
				 "int size;\n\tchar lvalue[32];\n\tchar rvalue[64];\n};\n");
		break;
	case 1:
		printf("ID\tRVA\tSize\tLValue\t\tRValue\n");
		d_keyfrst(INT_CODE_ID);
		while (db_status == S_OKAY) {
			dbPrintIntCode( DB_PRINT );
			d_keynext(INT_CODE_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(INT_CODE_ID);
		dbPrintIntCode( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(INT_CODE_ID);
		dbPrintIntCode( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(INT_CODE));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&c);
		printf("%lu\t%d\t%d\t%s\t\t%s\n",
					c.id, c.rva, c.size, c.lvalue, c.rvalue);
		break;
	default:
	}
	return;
}
void dbPrintFinCode(int cmd){
	struct fin_code c;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct fin_code {\n\tunsigned long id;\n\tunsigned long rva;\n\t"
				 "int size;\n\tchar line[256];\n};\n");
		break;
	case 1:
		printf("ID\tRVA\tSize\tLine\n");
		d_keyfrst(FIN_CODE_ID);
		while (db_status == S_OKAY) {
			dbPrintFinCode( DB_PRINT );
			d_keynext(FIN_CODE_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(FIN_CODE_ID);
		dbPrintFinCode( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(FIN_CODE_ID);
		dbPrintFinCode( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(FIN_CODE));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&c);
		printf("%lu\t%d\t%d\t%s\n", c.id, c.rva, c.size, c.line);
		break;
	default:
	}
	return;
}
void dbPrintName(int cmd){
	struct name n;
	int x = 0;

	switch (cmd) {
	case 0:
		printf("struct name {\n\tunsigned long rva;\n\tchar name[64];\n};\n");
		break;
	case 1:
		printf("Rva\tName\tType\n\n");
		d_keyfrst(NAME_RVA);
		while (db_status == S_OKAY) {
			dbPrintName( DB_PRINT );
			d_keynext(NAME_RVA);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(NAME_RVA);
		dbPrintName( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(NAME_RVA);
		dbPrintName( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(NAME));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&n);
		printf("%lX\t%s\n", n.rva, n.name, n.type); 
		break;
	default:
	}
	return;
}
void dbPrintComment(int cmd){
	struct comment c;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct comment {\n\tunsigned long id;\n\tint type;\n\t"
				 "char text[256];\n};\n");
		break;
	case 1:
		printf("ID\tRVA\tText\n\n");
		d_keyfrst(COMMENT_ID);
		while (db_status == S_OKAY) {
			dbPrintComment( DB_PRINT );
			d_keynext(COMMENT_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(COMMENT_ID);
		dbPrintComment( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(COMMENT_ID);
		dbPrintComment( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(COMMENT));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&c);
		printf("%lu\t%lX\t%s\n", c.id, c.type, c.text); 
		break;
	default:
	}
	return;
}
void dbPrintXref(int cmd){
	struct xref x;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct xref {\n\tint id;\n\tlong from_rva;\n\tlong to_rva;"
				 "\n\tint type;\n};\n");
		break;
	case 1:
		printf("ID\t\tFrom\t\tTo\tType\n\n");
		d_keyfrst(XREF_ID);
		while (db_status == S_OKAY) {
			dbPrintXref( DB_PRINT );
			d_keynext(XREF_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(XREF_ID);
		dbPrintXref( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(XREF_ID);
		dbPrintXref( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(XREF));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&x);
		printf("%lu\t%08X\t%08X\t%d\n", x.id,x.from_rva,x.to_rva,x.type); 
		break;
	default:
	}
	return;
}
void dbPrintImport(int cmd){
	struct import i;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct import {\n\tint lib;\n\tint type;"
				 "\n\tunsigned long rva;\n};\n");
		break;
	case 1:
		printf("Lib\t\tType\tRVA\n\n");
		d_keyfrst(IMPORT_RVA);
		while (db_status == S_OKAY) {
			dbPrintImport( DB_PRINT);
			d_keynext(IMPORT_RVA);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(IMPORT_RVA);
		dbPrintImport( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(IMPORT_RVA);
		dbPrintImport( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(IMPORT));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&i);
		printf("%d\t\t\t%d\t%lX\n", i.library, i.type, i.rva); 
		break;
	default:
	}
	return;
}
void dbPrintLib(int cmd){
	struct lib l;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct lib {\n\tint id;\n\tchar name;\n\tint ver_hi;\n\t"
				 "int ver_lo;\n};\n");
		break;
	case 1:
		printf("ID\tname\t\tversion\n\n");
		d_keyfrst(LIB_ID);
		while (db_status == S_OKAY) {
			dbPrintLib( DB_PRINT );
			d_keynext(LIB_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(LIB_ID);
		dbPrintLib( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(LIB_ID);
		dbPrintLib( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(LIB));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&l);
		printf("%d\t%s\t\t%d.%d\n", l.id, l.name, l.ver_hi, l.ver_lo); 
		break;
	default:
	}
	return;
}
void dbPrintExport(int cmd){
	struct export e;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct export {\n\tunsigned long rva;"
				 "\n};\n");
		break;
	case 1:
		printf("RVA\n\n");
		d_keyfrst(EXPORT_RVA);
		while (db_status == S_OKAY) {
			dbPrintExport( DB_PRINT );
			d_keynext(EXPORT_RVA);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(EXPORT_RVA);
		dbPrintExport( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(EXPORT_RVA);
		dbPrintExport( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(EXPORT));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&e);
		printf("%lX\n", e.rva); 
		break;
	default:
	}
	return;
}
void dbPrintString(int cmd){
	struct string s;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct string {\n\tunsigned long rva;\n\tint length;\n\t"
				 "char text[256];\n\t};\n");
		break;
	case 1:
		printf("ID\tRVA\tText\n\n");
		d_keyfrst(STRING_RVA);
		while (db_status == S_OKAY) {
			dbPrintString( DB_PRINT);
			d_keynext(STRING_RVA);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(STRING_RVA);
		dbPrintString( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(STRING_RVA);
		dbPrintString( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(STRING));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&s);
		printf("%lX\t%s\n", s.rva, s.length, s.text); 
		break;
	default:
	}
	return;
}
void dbPrintFunction(int cmd){
	struct function f;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct function {\n\tunsigned long id;\n\t"
				 "unsigned long rva;\n\tunsigned short size;\n};\n");
		break;
	case 1:
		printf("RVA\tSize\n\n");
		d_keyfrst(FUNCTION_RVA);
		while (db_status == S_OKAY) {
			dbPrintFunction( DB_PRINT );
			d_keynext(FUNCTION_RVA);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(FUNCTION_RVA);
		dbPrintFunction( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(FUNCTION_RVA);
		dbPrintFunction( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(FUNCTION));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&f);
		printf("%lX\t%d\n", f.rva, f.size); 
		break;
	default:
	}
	return;
}

void dbPrintFuncParam(int cmd){
	struct func_param f;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct func_param {\n\tunsigned long id;\n\tunsigned long func;"
				 "\n\tunsigned long type;\n\tint offset;\n\tchar name[32];\n};\n");
		break;
	case 1:
		printf("ID\tFunc\tType\tOffset\tName\n\n");
		d_keyfrst(FUNC_PARAM_ID);
		while (db_status == S_OKAY) {
			dbPrintFuncParam( DB_PRINT );
			d_keynext(FUNC_PARAM_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(FUNC_PARAM_ID);
		dbPrintFuncParam( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(FUNC_PARAM_ID);
		dbPrintFuncParam( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(FUNC_PARAM));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&f);
		printf("%lu\t%lu\t%lu\t%d\t%s\n", f.id, f.func, f.type, f.offset, 
								               f.name); 
		break;
	default:
	}
	return;
}

void dbPrintFuncLocal(int cmd){
	struct func_local f;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct func_local {\n\tunsigned long id;\n\tunsigned long func;"
				 "\n\tunsigned long type;\n\tint offset;\n\tchar name[32];\n};\n");
		break;
	case 1:
		printf("ID\tFunc\tType\tOffset\tName\n\n");
		d_keyfrst(FUNC_LOCAL_ID);
		while (db_status == S_OKAY) {
			dbPrintFuncLocal( DB_PRINT );
			d_keynext(FUNC_LOCAL_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(FUNC_LOCAL_ID);
		dbPrintFuncLocal( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(FUNC_LOCAL_ID);
		dbPrintFuncLocal( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(FUNC_LOCAL));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&f);
		printf("%lu\t%lu\t%lu\t%d\t%s\n", f.id, f.func, f.type, f.offset, 
								               f.name); 
		break;
	default:
	}
	return;
}

void dbPrintInlineType(int cmd){
	struct inline_type f;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct inline_type {\n\tunsigned long id;\n\tchar name[64];\n\t"
				 "unsigned long rva;\n\tunsigned short size;\n};\n");
		break;
	case 1:
		printf("ID\tName\t\tRVA\tSize\n\n");
		d_keyfrst(INLINE_TYPE_ID);
		while (db_status == S_OKAY) {
			dbPrintInlineType( DB_PRINT );
			d_keynext(INLINE_TYPE_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(INLINE_TYPE_ID);
		dbPrintInlineType( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(INLINE_TYPE_ID);
		dbPrintInlineType( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(INLINE_TYPE));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&f);
		printf("%lu\t%s\t\t%lX\t%d\n", f.id, f.name, f.rva, f.size); 
		break;
	default:
	}
	return;
}

void dbPrintInline(int cmd){
	struct f_inline f;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct f_inline {\n\tunsigned long id;\n\tint type;\n\n};\n");
		break;
	case 1:
		printf("ID\tType\n\n");
		d_keyfrst(F_INLINE_ID);
		while (db_status == S_OKAY) {
			dbPrintInline( DB_PRINT );
			d_keynext(F_INLINE_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(F_INLINE_ID);
		dbPrintInline( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(F_INLINE_ID);
		dbPrintInline( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(F_INLINE));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&f);
		printf("%lu\t%lu\n", f.id, f.type); 
		break;
	default:
	}
	return;
}

void dbPrintStructure(int cmd){
	struct structure s;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct structure {\n\tunsigned long id;\n\tchar name[32];\n\t"
				 "unsigned short size;\n};\n");
		break;
	case 1:
		printf("ID\tName\t\tSize\n\n");
		d_keyfrst(STRUCTURE_ID);
		while (db_status == S_OKAY) {
			dbPrintStructure( DB_PRINT );
			d_keynext(STRUCTURE_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(STRUCTURE_ID);
		dbPrintStructure( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(STRUCTURE_ID);
		dbPrintStructure( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(STRUCTURE));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&s);
		printf("%lu\t%s\t\t%d\n", s.id, s.name, s.size); 
		break;
	default:
	}
	return;
}

void dbPrintStructMember(int cmd){
	struct struct_member s;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct struct_member {\n\tunsigned long id;\n\t"
				 "unsigned long type;\n\tunsigned long structure\n\t"
				 "int order;\n\tchar name[32];\n};\n");
		break;
	case 1:
		printf("ID\tType\tStruct\tOrder\tName\n\n");
		d_keyfrst(STRUCT_MEMBER_ID);
		while (db_status == S_OKAY) {
			dbPrintStructMember( DB_PRINT);
			d_keynext(STRUCT_MEMBER_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(STRUCT_MEMBER_ID);
		dbPrintStructMember( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(STRUCT_MEMBER_ID);
		dbPrintStructMember( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(STRUCT_MEMBER));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&s);
		printf("%lu\t%lu\t%lu\t%d\t%s\n", s.id, s.type, s.structure, 
								               s.order, s.name); 
		break;
	default:
	}
	return;
}

void dbPrintDataType(int cmd){
	struct data_type d;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct data_type {unsigned long id;\n\tint size\n\t"
				 "char name[32];\n};\n");
		break;
	case 1:
		printf("ID\tSize\tName\n\n");
		d_keyfrst(DATA_TYPE_ID);
		while (db_status == S_OKAY) {
			dbPrintDataType( DB_PRINT);
			d_keynext(DATA_TYPE_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(DATA_TYPE_ID);
		dbPrintDataType( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(DATA_TYPE_ID);
		dbPrintDataType( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(DATA_TYPE));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&d);
		printf("%lu\t%d\t%s\n", d.id, d.size, d.name); 
		break;
	default:
	}
	return;
}

void dbPrintConstant(int cmd){
	struct constant c;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct constant {\n\tunsigned long id\n\t"
				 "char name[32];\n\tlong value;\n};\n");
		break;
	case 1:
		printf("ID\tName\t\tValue\n\n");
		d_keyfrst(CONSTANT_ID);
		while (db_status == S_OKAY) {
			dbPrintConstant(DB_PRINT);
			d_keynext(CONSTANT_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(CONSTANT_ID);
		dbPrintConstant( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(CONSTANT_ID);
		dbPrintConstant( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(CONSTANT));
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&c);
		printf("%lu\t%s\t\t%lX\n", c.id, c.name, c.value); 
		break;
	default:
	}
	return;
}
void dbPrintMacro(int cmd){
	struct seer_macro m;
	int n = 0;

	switch (cmd) {
	case 0:
		printf("struct seer_macro {\n\tunsigned long id\n\t"
				"char name[32];\n\tchar macro[256];\n};\n");
		break;
	case 1:
		printf("ID\tName\t\tMacro\n\n");
		d_keyfrst(SEER_MACRO_ID);
		while (db_status == S_OKAY) {
			dbPrintMacro(DB_PRINT);
			d_keynext(SEER_MACRO_ID);
		}
		printf("\n");
		break;
	case DB_MIN:			/* MIN */
		d_keyfrst(SEER_MACRO_ID);
		dbPrintMacro( DB_PRINT );
		break;
	case DB_MAX:			/* MAX */
		d_keylast(SEER_MACRO_ID);
		dbPrintMacro( DB_PRINT );
		break;
	case DB_COUNT:			/* COUNT */
		printf("Count: %d records\n", dbCount(SEER_MACRO) );
		break;
	case DB_PRINT:			/* PRINT CURRENT RECORD */
		d_recread(&m);
		printf("%lu\t%s\t\t%s\n", m.id, m.name, m.macro); 
		break;
	default:
	}
	return;
}

