dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// gio.h - Generic IO header to include to use the gio system
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with the dawn license *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 **************************************************************************/
#ifndef GIO_H
#define GIO_H

#ifndef END
// end of record
#define END_RECORD "END"
#endif
// end of file
#ifndef EOF
#define END_FILE "EOF~"
#endif

#define GIOFLAG_ALWAYS_WRITE	(A)

/**************************************************************************/
enum saveTypes { END, STR, _INT, _LONG, SHINT, _CHAR, _BOOL, WFLAG, SHWFLAG,
				STR_ARRAY, STR_ARRAYLIST, INT_ARRAY, LONG_ARRAY, 
				SHINT_ARRAY, BOOL_ARRAY,
				CUSTOM_READ,
				CUSTOM_WRITE,
				READ_TO_EOL, // used for ignore old single line fields
				READ_TO_END_OF_STRING, // used for ignore and old string entry
				CUSTOM_DONT_SAVE_RECORD, // a custom function used to ignore saving records
				VN_INT };

// END - marks the end of a table and also stores the size of the 
// structure in bytes as its index value
/**************************************************************************/
struct gio_type{
	int index; 
	const char *heading;
	saveTypes type;
	int flags;
	union {
		void *pvoid; // extra info, wordflag = table, bool = bit number
		flag_type *pflag_type;
		short sval;
		int	ival;
		long lval;		
	};
};
/**************************************************************************/
// prototypes
FILE *saveRecord(gio_type *gio_table, void *data, FILE *fp, int *status);
int   loadRecord(gio_type *gio_table, void *data, FILE *fp);

// custom function type
typedef void GIO_CUSTOM_FUNCTION (gio_type *gioTable, 
		int tableIndex, void *data, FILE *fp);

#define GIO_CUSTOM_FUNCTION_PROTOTYPE( funcname)	\
						void funcname(gio_type *, int , void *, FILE *)

// custom return function type - returns a status code
typedef int (*GIO_CUSTOM_RETURN_FUNCTION) (gio_type *gioTable, 
		int tableIndex, void *data, FILE *fp);

#define GIO_CUSTOM_RETURN_FUNCTION_PROTOTYPE( funcname)	\
						int funcname(gio_type *, int , void *, FILE *)

/**************************************************************************/
// ####### GENERIC IO MACROS ####### 

// start the generic IO table
// - this macro creates the header of a function that returns a gio_type pointer
//   to a static table embedded within the function.
//   the function name is based on the name of the datatype you tell it you are 
//   using... ie GIO_START(race_type_old) would generate a function which prototype 
//   would be  gio_type * gio_tlookup_race_type_old();
#define GIO_START(t) gio_type * gio_tlookup_ ## t (){ t gio_this_table_type; \
	int GIO_structSize=(int)sizeof(t); static gio_type gio_table[]= { 

#define GIO_PROTOTYPE(t) gio_type * gio_tlookup_ ## t ();

// GIO_GET_INDEX is used to find out how many bytes from the start of a 
//   structure the requested field is stored.
#define GIO_GET_INDEX(field) (int)(((char*) &gio_this_table_type.field) \
		-((char*) &gio_this_table_type)) 
// GIO_STRH(field, header) is used for string fields with a custom header
//  - basically adds an entry into the table bedded within the 
//    gio_type * gio_tlookup_?????(); function that would contain 
//    { index_of_the_field, header as a string , STR, 0 },
// You need to put ""'s around the header
#define GIO_STRH(field,header) { GIO_GET_INDEX(field), header, STR, 0, {NULL}},
#define GIO_STRH_FLAGS(field,header, flags) \
		{ GIO_GET_INDEX(field), header,  STR, flags, {NULL} },
// GIO_STR(field) is used for string fields with no custom header
#define GIO_STR(field) { GIO_GET_INDEX(field), #field, STR, 0, {(void *)NULL} },
#define GIO_STR_FLAGS(field, flags) \
		{ GIO_GET_INDEX(field), #field, STR, flags, {(void *)NULL} },

// string array
#define GIO_STR_ARRAY(field, max) { GIO_GET_INDEX(field), #field, STR_ARRAY, 0, {(void *)max}},
// string array with header
#define GIO_STR_ARRAYH(field, header, max) { GIO_GET_INDEX(field), header, STR_ARRAY, 0, {(void *)max}},

// string array list - when you reach the first null string, stop
#define GIO_STR_ARRAYLIST(field, max) \
	{ GIO_GET_INDEX(field), #field, STR_ARRAYLIST, 0, {(void *)max}},
// string array with header
#define GIO_STR_ARRAYLISTH(field, header, max) \
	{ GIO_GET_INDEX(field), header, STR_ARRAYLIST, 0, {(void *)max}},


// GIO_INTH(field, header) is used for integer fields with a custom header
#define GIO_INTH(field,header) { GIO_GET_INDEX(field), header, _INT, 0, {NULL}},
#define GIO_INTH_FLAGS(field,header, flags) \
		{ GIO_GET_INDEX(field), header, _INT, flags, {NULL}},
// GIO_INT(field) is used for integer fields with no custom header
#define GIO_INT(field) { GIO_GET_INDEX(field), #field, _INT, 0, {NULL}},
#define GIO_INT_FLAGS(field, flags) \
		{ GIO_GET_INDEX(field), #field, _INT, flags, {NULL}},

// GIO_INT_WITH_DEFAULT(field) is used for integer fields with no custom header
// that has a default value for loading, if it reads in 0, the value is set to this
#define GIO_INT_WITH_DEFAULT(field, default_value) \
	{ GIO_GET_INDEX(field), #field, _INT, 0, {(void *)default_value}},
#define GIO_INT_WITH_DEFAULT_FLAGS(field, default_value, flags) \
	{ GIO_GET_INDEX(field), #field, _INT, flags, {(void *)default_value}},

// GIO_LONGH(field, header) is used for long fields with a custom header
#define GIO_LONGH(field,header) { GIO_GET_INDEX(field), header, _LONG, 0, {NULL}},
#define GIO_LONGH_FLAGS(field,header, flags) \
		{ GIO_GET_INDEX(field), header, _LONG, flags, {NULL}},
// GIO_LONG(field) is used for long fields with no custom header
#define GIO_LONG(field) { GIO_GET_INDEX(field), #field, _LONG, 0, {NULL}},
#define GIO_LONG_FLAGS(field, flags) \
		{ GIO_GET_INDEX(field), #field, _LONG, flags, {NULL}},

// int array 
#define GIO_INT_ARRAY(field, max) { GIO_GET_INDEX(field), #field, INT_ARRAY, 0, {(void *)max}},
// int array with header
#define GIO_INT_ARRAYH(field, header, max) { GIO_GET_INDEX(field), header, INT_ARRAY, 0, {(void *)max}},

// long array 
#define GIO_LONG_ARRAY(field, max) { GIO_GET_INDEX(field), #field, LONG_ARRAY, 0, {(void *)max}},
// long array with header
#define GIO_LONG_ARRAYH(field, header, max) { GIO_GET_INDEX(field), header, LONG_ARRAY, 0, {(void *)max}},

// GIO_SHINTH(field, header) is used for short ints 
#define GIO_SHINTH(field,header) { GIO_GET_INDEX(field), header, SHINT, 0, {NULL}},
// GIO_SHINT(field) is used for short ints 
#define GIO_SHINT(field) { GIO_GET_INDEX(field), #field, SHINT, 0, {NULL}},

// GIO_SHINT_WITH_DEFAULT(field) is used for integer fields with no custom header
// that has a default value for loading, if it reads in 0, the value is set to this
#define GIO_SHINT_WITH_DEFAULT(field, default_value) \
	{ GIO_GET_INDEX(field), #field, SHINT, 0, {(void *)default_value}},

// shint array 
#define GIO_SHINT_ARRAY(field, max) { GIO_GET_INDEX(field), #field, SHINT_ARRAY, 0, {(void *)max}},
// shint array with header
#define GIO_SHINT_ARRAYH(field, header, max) { GIO_GET_INDEX(field), header, SHINT_ARRAY, 0, {(void *)max}},

// GIO_CHAR(field, header) is used for fields of type char
#define GIO_CHARH(field,header) { GIO_GET_INDEX(field), header, _CHAR, 0, {NULL}},
// GIO_CHAR(field) is used for fields of type char
#define GIO_CHAR(field) { GIO_GET_INDEX(field), #field, _CHAR, 0, {NULL}},

// GIO_BOOLH(field, header) is used for boolean fields with a custom header
// it will actually write a TRUE/FALSE in the file
#define GIO_BOOLH(field,header) { GIO_GET_INDEX(field), header, _BOOL, 0, {(void*)~0}},
// GIO_BOOL(field) is used for boolean fields with no custom header
#define GIO_BOOL(field) { GIO_GET_INDEX(field), #field, _BOOL, 0, {(void*)~0}},
// header and specify the bitmask to check on a long
#define GIO_BOOLHM(field,header,mask) { GIO_GET_INDEX(field), header, _BOOL, 0, {(void *)mask}},
// specify the bitmask to check on a long
#define GIO_BOOLM(field, mask) { GIO_GET_INDEX(field), #field, _BOOL, 0, {(void *)mask}},

// GIO_WFLAGH(field, header) is used for wordflag fields with a custom header
#define GIO_WFLAGH(field,header, table) { GIO_GET_INDEX(field), header, WFLAG, 0, {(void *)&table}},
// GIO_WFLAG(field) is used for wordflag fields with no custom header
#define GIO_WFLAG(field, table) { GIO_GET_INDEX(field), #field, WFLAG, 0, {(void *)&table}},

// GIO_SHWFLAGH(field, header) is used for wordflag fields with a custom header (sh_int input)
#define GIO_SHWFLAGH(field,header, table) { GIO_GET_INDEX(field), header, SHWFLAG, 0, {(void *)&table}},
// GIO_SHWFLAG(field) is used for wordflag fields with no custom header (sh_int input)
#define GIO_SHWFLAG(field, table) { GIO_GET_INDEX(field), #field, SHWFLAG, 0, {(void *)&table}},

// GIO_CUSTOM_READ allows you to specify a function to run for reading when the 
// header is encountered - the function will be given the GIO table index and the 
// fp as parameters.
#define GIO_CUSTOM_READ(field,function) \
	{ GIO_GET_INDEX(field), #field, CUSTOM_READ, 0, {(void *) function}},
#define GIO_CUSTOM_READH(field, header, function) \
		{ GIO_GET_INDEX(field), header, CUSTOM_READ, 0, {(void *) function}},

// GIO_CUSTOM_WRITE allows you to specify a function to run for reading when the 
// header is encountered - the function will be given the GIO table index and the 
// fp as parameters.
#define GIO_CUSTOM_WRITE(field,function) \
	{ GIO_GET_INDEX(field), #field, CUSTOM_WRITE, 0, {(void *) function}},
#define GIO_CUSTOM_WRITEH(field, header, function) \
		{ GIO_GET_INDEX(field), header, CUSTOM_WRITE, 0, {(void *) function}},


// GIO_READ_TO_EOL allows you to remove stuff and put in this entry
// to aid in the conversion process.
#define GIO_READ_TO_EOL(header) { 0, header, READ_TO_EOL, 0, {NULL}},

// GIO_READ_TO_END_OF_STRING allows you to remove stuff and put in 
// this entry to aid in the conversion process.
#define GIO_READ_TO_END_OF_STRING(header) { 0, header, READ_TO_END_OF_STRING, 0, {NULL}},

// GIO_CUSTOM_DONT_SAVE_RECORD allows you to specify a custom function to be run 
// just prior to deciding to write the data for a particular record into a GIO
// saving list. GIO_CUSTOM_DONT_SAVE_RECORD should be the first in the table.
// - the function will be given the GIO table index and the fp as parameters
//   and needs to return true to indicate the entry is to not be saved.
#define GIO_CUSTOM_DONT_SAVE_RECORD(function) \
	{ 0, "dontsavefunctionpointer", READ_TO_END_OF_STRING, 0, {(void *) function}},

// finishes off the generic IO table, then tells the function to return 
// a pointer to the embedded static table, after which it closes the function.
#define GIO_FINISH { GIO_structSize, "", END, 0, {NULL}} }; return gio_table; };

// NOCLEAR means the table entry isn't cleared when it is created
#define GIO_FINISH_NOCLEAR { GIO_structSize, "gio-noclear", END, 0, {NULL}} }; return gio_table; };

// GIO_FINISH_STRDUP_EMPTY  means strings get a str_dup("")
#define GIO_FINISH_STRDUP_EMPTY { GIO_structSize, "strdup_empty", END, 0, {NULL}} }; return gio_table; };

#define GIO_SAVE_RECORD(datatype, data, fp, status) \
	saveRecord( gio_tlookup_ ## datatype (), data, fp, status) 

#define GIO_LOAD_RECORD(datatype, data, fp) \
	loadRecord( gio_tlookup_ ## datatype (), data, fp) 

/**************************************************************************/
// gio_generic_savelist returns true if no errors on save
bool	gio_generic_savelist( void *listpointer, gio_type *gio_table, \
				char *filename, int nextoffset, bool backup);
void * gio_generic_loadlist( int size, gio_type *gio_table, \
							char *filename, int nextoffset);

#define GIO_GET_NEXTOFFSET(listpointer) (long)( ((char*)&(listpointer->next)) \
		-((char*)listpointer) )

#define GIOSAVE_LIST(listpointer, datatype, filename, backup) \
	gio_generic_savelist( listpointer, gio_tlookup_ ## datatype (), \
							filename, GIO_GET_NEXTOFFSET(listpointer), backup);

#define GIOLOAD_LIST(listpointer, datatype, filename) \
	listpointer=(datatype*)gio_generic_loadlist( sizeof(datatype), \
		gio_tlookup_ ## datatype (),  filename, \
		GIO_GET_NEXTOFFSET(listpointer));

int wordflag_to_value( const struct flag_type *flag_table, const char *wordtext);

#endif // GIO