/**************************************************************************/ // 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