/**************************************************************************/
// gio.cpp - see below
/***************************************************************************
* 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. *
**************************************************************************/
/***************************************************************************
* FILE: gio.cpp - generic input/output loading and saving function *
* - supports tables, linked lists etc *
* This never really got all parts finished, but it is very functional. *
* 100% written by Kalahn :) *
***************************************************************************/
#include "include.h"
bool gio_abort_fwrite_wordflag_with_undefined_flags=true;
#define OFFSETDATA(offset) *)((void*)((char *)data + (offset)))
#define GIODATA(dtype) (*(( dtype OFFSETDATA(gio_table[tableIndex].index)))
#define GIOARRAY(dtype) (*(( dtype OFFSETDATA(gio_table[tableIndex].index + ( (arrayIndex) * sizeof(dtype))) ))
#define GIOPARAMpvoid (gio_table[tableIndex].pvoid)
#define GIOPARAMpflag_type (gio_table[tableIndex].pflag_type)
#define GIOPARAMshort (gio_table[tableIndex].sval)
#define GIOPARAMint (gio_table[tableIndex].ival)
#define GIOPARAMlong (gio_table[tableIndex].lval)
#define GIOflags (gio_table[tableIndex].flags)
#define GIOHEADING (gio_table[tableIndex].heading)
/**************************************************************************/
// doesn't use the reserved file at this stage
FILE *openFileWrite(char *){
return NULL;
};
/**************************************************************************/
// Read a number from a file.
long fread_long( FILE *fp )
{
long number;
bool sign;
char c;
do{
c = getc( fp );
}
while ( is_space(c) );
number = 0;
sign = false;
if ( c == '+' )
{
c = getc( fp );
}
else if ( c == '-' )
{
sign = true;
c = getc( fp );
}
if ( !is_digit(c) )
{
bug("Fread_long: bad format.");
logf("non numeric character is '%c'",c);
do_abort( );
}
while ( is_digit(c) )
{
number = number * 10 + c - '0';
c = getc( fp );
}
if ( sign )
number = 0 - number;
if ( c == '|' )
number += fread_long( fp );
else if ( c != ' ' )
ungetc( c, fp );
return number;
}
/**************************************************************************/
bool is_stat( const struct flag_type *flag_table );
FILE *saveRecord(gio_type *gio_table, void *data, FILE *fp, int *status){
int tableIndex, arrayIndex;
// check if we actually want to skip this record
tableIndex=0;
if (gio_table[tableIndex].type==CUSTOM_DONT_SAVE_RECORD){
int result=((GIO_CUSTOM_RETURN_FUNCTION)GIOPARAMpvoid) (gio_table, tableIndex, data, fp);
if(result){ // don't save entry
if(status){
*status=0; // nothing saved
}
return NULL;
}
}
if (!fp){
logf("saveRecord: fp not initialised");
fp=openFileWrite("myfile.txt");
}
for (tableIndex=0; gio_table[tableIndex].type!=END; tableIndex++){
// skip fields which don't mean anything in this situation
if ( gio_table[tableIndex].type==CUSTOM_READ
|| gio_table[tableIndex].type==CUSTOM_DONT_SAVE_RECORD)
{
continue;
}
switch (gio_table[tableIndex].type){
default:
logf("saveRecord: unrecognised table type '%s'(%d)",
GIOHEADING, gio_table[tableIndex].type);
case END:
break;
case STR:
if(!IS_NULLSTR(GIODATA(char *)) || IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE))
{
hide_tilde(GIODATA(char *));
fprintf(fp, "%s %s%s~\n", GIOHEADING,
// put a leading . if string starts with a . or whitespace
((is_space(*GIODATA(char*))||*GIODATA(char*)=='.')?".":""),
fix_string(GIODATA(char*)) );
show_tilde(GIODATA(char*));
}
break;
case _INT:
if(GIODATA(int) || GIOPARAMint!=0 || IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE)){
fprintf(fp, "%s %d\n", GIOHEADING, GIODATA(int));
}
break;
case _LONG:
if(GIODATA(long) || GIOPARAMlong!=0 || IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE)){
fprintf(fp, "%s %ld\n", GIOHEADING, GIODATA(long));
}
break;
case SHINT:
if(GIODATA(short)!=0 || GIOPARAMshort!=0 || IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE)){
fprintf(fp, "%s %d\n" , GIOHEADING, GIODATA(short) );
}
break;
case _CHAR:
if(GIODATA(char) || IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE)){
fprintf(fp, "%s %c\n", GIOHEADING, GIODATA(char));
}
break;
case _BOOL:
fprintf(fp, "%s %s\n", GIOHEADING, GIODATA(bool)?"true":"false");
break;
case WFLAG: // wordflag
if( GIODATA(int)!=0 || is_stat( GIOPARAMpflag_type) || IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE)){
fwrite_wordflag( GIOPARAMpflag_type, GIODATA(int), GIOHEADING, fp);
}
break;
case SHWFLAG: // short wordflag
if( GIODATA(short)!=0 || is_stat( GIOPARAMpflag_type) || IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE)){
fwrite_wordflag( GIOPARAMpflag_type, GIODATA(short), GIOHEADING, fp);
}
break;
case STR_ARRAY: // parameter is the max size of the array
for (arrayIndex=0; arrayIndex<GIOPARAMint; arrayIndex++){
if ( IS_NULLSTR(GIOARRAY(char*)) || IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE)){
continue;
}
fprintf(fp, "%s[%d] %s~\n", GIOHEADING, arrayIndex, GIOARRAY(char*));
}
break;
case STR_ARRAYLIST: // when you reach the first null in the list stop
for (arrayIndex=0; arrayIndex<GIOPARAMint;arrayIndex++){
if (IS_NULLSTR(GIOARRAY(char*)) || IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE)){
break;
}
fprintf(fp, "%s[%d] %s~\n", GIOHEADING, arrayIndex, GIOARRAY(char*));
}
break;
case INT_ARRAY:
for (arrayIndex=0; arrayIndex<GIOPARAMint; arrayIndex++){
if(GIOARRAY(int)|| IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE)){
fprintf(fp, "%s[%d] %d\n", GIOHEADING, arrayIndex, GIOARRAY(int));
}
}
break;
case LONG_ARRAY:
for (arrayIndex=0; arrayIndex<GIOPARAMint; arrayIndex++){
if(GIOARRAY(long)|| IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE)){
fprintf(fp, "%s[%d] %ld\n", GIOHEADING, arrayIndex, GIOARRAY(long));
}
}
break;
case SHINT_ARRAY:
for (arrayIndex=0; arrayIndex<GIOPARAMint; arrayIndex++){
if(GIOARRAY(short)|| IS_SET(GIOflags,GIOFLAG_ALWAYS_WRITE)){
fprintf(fp, "%s[%d] %d\n", GIOHEADING, arrayIndex, GIOARRAY(short));
}
}
break;
case BOOL_ARRAY:
log_string("BOOL_ARRAY not supported yet");
break;
case CUSTOM_WRITE:
((GIO_CUSTOM_FUNCTION *)GIOPARAMpvoid) (gio_table, tableIndex, data, fp);
break;
case READ_TO_EOL: // do nothing, since it is a read only code
break;
case READ_TO_END_OF_STRING: // do nothing, since it is a read only code
break;
}
}
fprintf( fp, END_RECORD"\n\n");
if(status){
*status=1; // save okay
}
return fp;
};
/**************************************************************************/
// memory allocation is only done in here if the data value is NULL
// - fp must be valid and at the point ready to read
// - if data != NULL then we start by zeroing the whole structure
int loadRecord(gio_type *gio_table, void *data, FILE *fp){
int tableIndex, arrayIndex, structSize;
char *pStr;
char inHeader[MIL], inBool[MIL], arrayHeader[MIL];
bool checkForArray;
bool data_read=false;
int result = 0; // 1= okay, 2=eof no data
bool finished=false;
bool clearing_with_strdup=false;
if (!fp){
logf("loadRecord: fp not initialised");
do_abort();
}
// get the total size of the structure we are working with
for (tableIndex=0; gio_table[tableIndex].type!=END; tableIndex++){
//loop round till we get the to end of the list... the entry
// that is of type end contains the total size of the structure
// in its index value.
}
structSize=gio_table[tableIndex].index;
// create our data node if required
// doesn't use any form of magic numbers at this stage
if (!data){
data=malloc(structSize);
memset( data, 0, (size_t) structSize);
}else{
if (strcmp(GIOHEADING, "gio-noclear")
&& strcmp(GIOHEADING, "strdup_empty")){
// memset the structure to all zeros before starting if required
memset( data, 0, (size_t) structSize);
// logf("loadRecord: structSize = %d",structSize);
}else{
if(!strcmp(GIOHEADING, "strdup_empty")){
clearing_with_strdup=true;
}
// go thru manually clearing the values
for (tableIndex=0; gio_table[tableIndex].type!=END; tableIndex++)
{
switch (gio_table[tableIndex].type)
{
default:
break;
case STR:
if(clearing_with_strdup){
GIODATA(char*)=str_dup("");
}else{
GIODATA(char*)=NULL;
}
break;
case _INT:
GIODATA(int)= 0;
break;
case _LONG:
GIODATA(long)=0;
break;
case SHINT:
GIODATA(short)= 0;
break;
case _CHAR:
GIODATA(char)= '\0';
break;
case _BOOL:
GIODATA(bool)=false;
break;
case WFLAG: // wordflag
GIODATA(int)=0;
break;
case SHWFLAG: // short wordflag
GIODATA(short)=0;
break;
/* // strdup note supported with these
case STR_ARRAY: // parameter is the max size of the array
case STR_ARRAYLIST: // parameter is the max size of the array
case SHINT_ARRAY:
case INT_ARRAY:
break;
*/
}
}
}
// go thru manually setting all the default integer values
for (tableIndex=0; gio_table[tableIndex].type!=END; tableIndex++)
{
if(gio_table[tableIndex].type==_INT && GIOPARAMint!=0){
GIODATA(int)= GIOPARAMint;
}
if(gio_table[tableIndex].type==SHINT && GIOPARAMshort!=0){
GIODATA(short)= GIOPARAMshort;
}
}
}
// now read in the entry
fscanf(fp, "%s ", inHeader);
finished= false;
while (str_cmp(inHeader,END_RECORD) && !finished){
if(!str_cmp("EOF~", inHeader)){
if(data_read){
return 3;
}else{
return 2;
}
}
if (feof(fp)){
bugf("LoadRecord: Unexpected end of file found! inHeader='%s'", inHeader);
finished= true;
return 4;
}
if(!str_cmp("end", inHeader)){
return 1;
}
// check on off chance their might be an array header
if (inHeader[str_len(inHeader)-1]==']'){
strcpy(arrayHeader,inHeader);
pStr=strstr( arrayHeader, "[");
if (!pStr){
checkForArray=false;
}else{
if (sscanf(pStr+1, "%d]", &arrayIndex)==0){
checkForArray=false;
}else{
*pStr='\0';
checkForArray=true;
}
}
}else{
checkForArray=false;
}
// find the match in the GIO table
// - if you have duplicate entries, the second value will
// not be read
// - if exact search doesn't match, try prefix matching
for (tableIndex=0; gio_table[tableIndex].type!=END; tableIndex++){
if (!str_cmp(inHeader, GIOHEADING)
&& gio_table[tableIndex].type!=CUSTOM_WRITE){
checkForArray=false;
break;
}
if (checkForArray
&& !str_cmp(arrayHeader, GIOHEADING)
&&( gio_table[tableIndex].type== STR_ARRAY
|| gio_table[tableIndex].type== STR_ARRAYLIST
|| gio_table[tableIndex].type== INT_ARRAY
|| gio_table[tableIndex].type== LONG_ARRAY
|| gio_table[tableIndex].type== SHINT_ARRAY
|| gio_table[tableIndex].type== BOOL_ARRAY
))
{
checkForArray=true;
data_read=true;
break;
}
}
if(gio_table[tableIndex].type==END)
{
for (tableIndex=0; gio_table[tableIndex].type!=END; tableIndex++){
if (!str_prefix(inHeader, GIOHEADING)
&& gio_table[tableIndex].type!=CUSTOM_WRITE){
checkForArray=false;
break;
}
if (checkForArray
&& !str_cmp(arrayHeader, GIOHEADING)
&&( gio_table[tableIndex].type== STR_ARRAY
|| gio_table[tableIndex].type== STR_ARRAYLIST
|| gio_table[tableIndex].type== INT_ARRAY
|| gio_table[tableIndex].type== LONG_ARRAY
|| gio_table[tableIndex].type== SHINT_ARRAY
|| gio_table[tableIndex].type== BOOL_ARRAY
))
{
checkForArray=true;
break;
}
}
}
switch (gio_table[tableIndex].type){
default:
logf("loadRecord: unrecognised table type %d", gio_table[tableIndex].type);
case END:
logf("loadRecord: Unfound match for '%s' header, ignoring.", inHeader);
// skip the value - most likely to be a single value
fscanf(fp, "%s ", inHeader);
break;
case STR:
{
size_t skip;
// skip the number of blank spaces in the heading
if (str_len(inHeader)<str_len(GIOHEADING)){
skip=str_len(GIOHEADING)-str_len(inHeader);
while(skip>0){
char c=getc(fp);
if(is_space(c)){
skip--;
}else{// make sure we dont take too much
skip=0;
ungetc(c, fp);
}
}
}
pStr= fread_string(fp);
char *trim_dot;
if(*pStr=='.'){ // remove a leading . in a entry if found... saving adds
// one if the first char is whitespace or a .
trim_dot=str_dup(pStr+1);
free_string(pStr);
pStr=trim_dot;
}
show_tilde(pStr);
GIODATA(char*)= pStr;
}
break;
case _INT:
GIODATA(int)= fread_number(fp);;
break;
case _LONG:
GIODATA(long)= fread_long(fp);
break;
case SHINT:
GIODATA(short)= fread_number(fp);
break;
case _CHAR:
GIODATA(char)= fread_letter(fp);
break;
case _BOOL:
fscanf(fp, "%s ", inBool); // read the word
if (!str_cmp(inBool, "true")){
GIODATA(bool)=true;
}else if (!str_cmp(inBool, "false")){
GIODATA(bool)=false;
}else{
// unmatched - default to false
logf("loadRecord: BOOL type for '%s' header, unmatched logic '%s' setting to false.",
inHeader, inBool);
GIODATA(bool)=false;
}
break;
case WFLAG: // wordflag
GIODATA(int)=fread_wordflag( GIOPARAMpflag_type, fp);
break;
case SHWFLAG: // short wordflag
GIODATA(short)= fread_wordflag( GIOPARAMpflag_type, fp);
break;
case STR_ARRAY: // parameter is the max size of the array
case STR_ARRAYLIST: // same as STR_ARRAY for loading
GIOARRAY(char*)= fread_string(fp);
break;
case SHINT_ARRAY:
GIOARRAY(short)=fread_number(fp);
break;
case INT_ARRAY:
GIOARRAY(int)= fread_number(fp);
break;
case LONG_ARRAY:
GIOARRAY(long)= fread_long(fp);
break;
/*
case INT_ARRAY:
log_string("INT_ARRAY not supported yet");
break;
case BOOL_ARRAY:
log_string("BOOL_ARRAY not supported yet");
break;
*/
case READ_TO_EOL:
fread_to_eol(fp);
break;
case READ_TO_END_OF_STRING:
fread_string(fp);
break;
case CUSTOM_READ:
((GIO_CUSTOM_FUNCTION *)GIOPARAMpvoid) (gio_table, tableIndex, data, fp);
// TO ADD
break;
}
// read in the next header
fscanf(fp, "%s ", inHeader);
// logf("inheader='%s", inHeader);
}
return result;
};
/**************************************************************************/
// just flag_lookup but ignores the settable bit
int gioflag_lookup(const char *name, const struct flag_type *flag_table)
{
int flag;
// first try an exact match, then do a substring match
// exact
for (flag = 0; flag_table[flag].name != NULL; flag++)
{
if ( !str_cmp( name, flag_table[flag].name ))
return flag_table[flag].bit;
}
// substring
for (flag = 0; flag_table[flag].name != NULL; flag++)
{
if ( !str_prefix( name, flag_table[flag].name ))
return flag_table[flag].bit;
}
return NO_FLAG;
}
const char *get_flag_table_name( const struct flag_type *flag_table );
/**************************************************************************/
// written by Kalahn - July 98
int fread_wordflag( const struct flag_type *flag_table, FILE *fp)
{
char *wf_str, *ptr_str;
char single_word[MIL];
int result, flag;
// read in the string
wf_str = fread_string (fp);
fread_to_eol(fp);
// break down and find words one at a time
// convert all white spaces into ' ' for one arg first
ptr_str=wf_str;
do{
if (*ptr_str=='\t' || *ptr_str=='\n' || *ptr_str=='\r')
*ptr_str=' ';
}while (*++ptr_str);
// support stat tables
if ( is_stat( flag_table ) )
{
ptr_str=wf_str;
one_argument( ptr_str, single_word);
if ( ( result= gioflag_lookup( single_word, flag_table ) ) != NO_FLAG ){
return result;
}else{
logf("fread_wordflag(): Failed to match value for single word '%s', flag_table=%s.",
single_word, get_flag_table_name(flag_table));
logf("Complete string ='%s'", ptr_str);
return 0;
}
}
// loop thru all the words and match up what we can find
result=0;
ptr_str=wf_str;
while (!IS_NULLSTR(ptr_str)){
ptr_str = one_argument( ptr_str, single_word);
for (flag = 0; flag_table[flag].name != NULL; flag++)
{
if ( single_word[0]==flag_table[flag].name[0]
&& !str_cmp( single_word, flag_table[flag].name))
{
SET_BIT(result, flag_table[flag].bit);
break;
}
}
// if we didn't find the word in that table
if (!flag_table[flag].name){
logf("fread_wordflag(): unfound word flag match '%s'", single_word);
}
}
free_string (wf_str);
return (result);
}
/**************************************************************************/
// written by Kalahn - July 98
// note: If the final character in the heading is a space, then it will
// not be multiple lined
char *fwrite_wordflag( const struct flag_type *flag_table,
int bits, const char * heading, FILE *fp)
{
static int i;
static char buf[5][512];
int flag;
int bit_index;
int bit_value;
bool bit_found=false;
bool singlelineformat=false;
size_t heading_length=str_len(heading);
// rotate buffers
++i= i%5;
// initialise the buffer we are working on
buf[i][0] = '\0';
if(heading_length>0 && heading[heading_length-1]==' '){
singlelineformat=true;
}
// 2 different modes... if their is a stat table to be written
// a different mode is used from checking each bit is written
if (is_stat( flag_table )){
for (flag = 0; flag_table[flag].name && !bit_found; flag++)
{
if ( flag_table[flag].bit == bits ){
strcat( buf[i], flag_table[flag].name );
bit_found=true;
}
}
// report that we have a missing value in a table
if(!bit_found)
{
logf("fwrite_wordflag(): VALUE MISSING!!! heading='%s'\n"
" (value=%d, 1st table entry='%s')",
heading, bits, flag_table[0].name);
if(gio_abort_fwrite_wordflag_with_undefined_flags){
{ // do autonote missing value
char body[MSL];
sprintf(body, "The mud was aborted because for following reason:`1"
"fwrite_wordflag(): VALUE MISSING!!! heading='%s'`1"
" (value=%d, flag_table=%s, 1st table entry='%s')`1"
"This is usually fixed by adding in a text word for the missing value "
"(to the table which has a first entry as shown above.)",
heading, bits, get_flag_table_name(flag_table),
flag_table[0].name);
autonote(NOTE_SNOTE, "fwrite_wordflag()",
"mud aborted due to missing value!",
"code", body, true);
log_note(body);
}
do_abort();
}
}
}else{
// write bits the long way so we can record if a bit isn't written due
// to no matching bit in the flag table.
// Also write only one bit word for a single bit allowing multiple
// words for a bit value in a table (colour vs color) and single words in
// stored files.
bool insert_space=false;
for (bit_index=0; bit_index<32; bit_index++)
{
bit_found=false;
bit_value = 1<<bit_index;
if (!IS_SET(bit_value, bits))
continue;
for (flag = 0; flag_table[flag].name && !bit_found; flag++)
{
if ( IS_SET(bit_value, flag_table[flag].bit) )
{
if(singlelineformat){
if(insert_space){
strcat( buf[i], " ");
}
insert_space=true;
}else{
strcat( buf[i], "\n\t");
}
strcat( buf[i], flag_table[flag].name );
bit_found= true;
}
}
// report that we have a missing bit in a table
if(!bit_found)
{
logf("fwrite_wordflag(): BIT MISSING!!! '%c' heading='%s'\n"
" (bit_index=%d, bit_value=%d, flag_table=%s, 1st table entry='%s')",
(bit_index <= 'Z' - 'A'?'A' + bit_index :
'a' + bit_index - ( 'Z' - 'A' + 1 )), heading,
bit_index, bit_value, get_flag_table_name(flag_table),
flag_table[0].name);
if(gio_abort_fwrite_wordflag_with_undefined_flags){
{ // do autonote missing bit
char body[MSL];
sprintf(body, "The mud was aborted because for following reason:`1"
"fwrite_wordflag(): BIT MISSING!!! '%c' heading='%s'\n"
" (bit_index=%d, bit_value=%d, 1st table entry='%s')"
"This is usually fixed by adding the missing word for the bitflag."
"(to the table which has a first entry as shown above.)",
(bit_index <= 'Z' - 'A'?'A' + bit_index :
'a' + bit_index - ( 'Z' - 'A' + 1 )), heading,
bit_index, bit_value, flag_table[0].name);
autonote(NOTE_SNOTE, "fwrite_wordflag()",
"mud aborted due to a missing bitflag!",
"code", body, true);
log_note(body);
}
do_abort();
}
}
}
} // non stat table (multiple bit table)
strcat( buf[i], "~\n" );
if(fp && str_len(buf[i])>2){ // only write something if we have something to write
if(singlelineformat){
fprintf(fp, "%s%s", heading, buf[i]);
}else{
fprintf(fp, "%s %s", heading, buf[i]);
}
}
return (buf[i]);
}
/**************************************************************************/
// 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)
{
FILE *fp;
void *pdata;
int count=0;
int skipped=0;
char write_filename[MSL];
sprintf(write_filename,"%s.write", filename);
// find a free write filename - so if something stuffed up on
// the write, we don't go over it.
if(file_exists(write_filename)){
for(int i=0; i<20; i++){
sprintf(write_filename,"%s.write%d", filename, i);
if(!file_exists(write_filename)){
break;
}
}
}
unlink(write_filename);
logf("Starting gio_generic_savelist to %s.",
write_filename);
fclose( fpReserve );
if ( ( fp = fopen( write_filename, "w" ) ) == NULL )
{
bugf("gio_generic_savelist(): fopen '%s' for write - error %d (%s)",
write_filename, errno, strerror( errno));
bugf("An error occured! writing to '%s' which would become %s", write_filename,
filename);
fpReserve = fopen( NULL_FILE, "r" );
return false;
}
// Go thru linked list writing each node to disk
for ( pdata=listpointer; pdata; pdata= *(void **)(((char*) pdata )+nextoffset))
{
int status;
saveRecord( gio_table, pdata, fp, &status);
if(status){
count++;
}else{
skipped++;
}
}
int bytes_written=fprintf(fp, "EOF~\n");
fclose( fp );
if( bytes_written != str_len("EOF~\n") ){
bugf("gio_generic_savelist(): fprintf to '%s' incomplete - error %d (%s)",
write_filename, errno, strerror( errno));
bugf("Incomplete generic io write of %s, write aborted - check diskspace!", write_filename);
{
char msgbody[MSL];
sprintf(msgbody,"Incomplete write of %s, write aborted - check diskspace!\r\n", write_filename);
autonote(NOTE_SNOTE, "gio_generic_savelist()", "Problems saving a linked list using gio!", "code cc: imm",
msgbody, true);
}
}else{
// handle backup option
if(backup){
char buf[MIL];
sprintf(buf, "%s.giobak", filename);
logf("GIOBACKUP: Renaming old %s to %s", filename, buf);
unlink(buf);
rename(filename, buf);
}
logf("Renaming new %s to %s", write_filename, filename);
unlink(filename);
rename(write_filename, filename);
}
fpReserve = fopen( NULL_FILE, "r" );
if(skipped){
logf("Finished gio_generic_savelist [%d], skipped writing %d.", count, skipped);
}else{
logf("Finished gio_generic_savelist [%d].", count);
}
return true;
}
/**************************************************************************/
void * gio_generic_loadlist( int size, gio_type *gio_table,
char *filename, int nextoffset)
{
FILE *fp;
void *phead;
void *pdata=NULL;
void *plast=NULL;
int count=0;
if(!file_exists(filename)){
logf("File '%s' not found, cancelled gio list loading.", filename);
return NULL;
}
logf("gio_generic_loadlist() reading in from %s... ", filename);
fclose( fpReserve );
if ( ( fp = fopen( filename, "r" ) ) == NULL )
{
bugf("gio_generic_loadlist(): fopen '%s' for read - error %d (%s)",
filename, errno, strerror( errno));
bugf("An error occured! reading from %s", filename);
fpReserve = fopen( NULL_FILE, "r" );
return NULL;
}
// Go thru linked list reading each node from disk
plast=pdata;
pdata=malloc(size);
phead=pdata;
memset( pdata, 0, (size_t) size);
while (loadRecord(gio_table,pdata,fp)<2)
{
plast=pdata;
pdata=malloc(size);
*(void **)(((char*) plast )+nextoffset)=pdata;
memset( pdata, 0, (size_t) size);
count++;
}
if(plast)
{
*(void **)(((char*) plast )+nextoffset)=NULL;
}
fclose( fp );
fpReserve = fopen( NULL_FILE, "r" );
logf("Finished gio_generic_loadlist [%d].", count);
return phead;
}
/**************************************************************************/
// convert a text into a value ignoring if the wordtext is settable.
int wordflag_to_value( const struct flag_type *flag_table, const char *wordtext)
{
char *wf_str, *ptr_str;
char single_word[MIL];
int result, flag;
char buf[MIL];
strcpy(buf, wordtext);
// read in the string
wf_str = buf;
// break down and find words one at a time
// convert all white spaces into ' ' for one arg first
ptr_str=wf_str;
do{
if (*ptr_str=='\t' || *ptr_str=='\n' || *ptr_str=='\r')
*ptr_str=' ';
}while (*++ptr_str);
// support stat tables
if ( is_stat( flag_table ) )
{
ptr_str=wf_str;
one_argument( ptr_str, single_word);
if ( ( result= gioflag_lookup( single_word, flag_table ) ) != NO_FLAG ){
return result;
}else{
return 0;
}
}
// loop thru all the words and match up what we can find
result=0;
ptr_str=wf_str;
while (!IS_NULLSTR(ptr_str)){
ptr_str = one_argument( ptr_str, single_word);
for (flag = 0; flag_table[flag].name != NULL; flag++)
{
if ( single_word[0]==flag_table[flag].name[0]
&& !str_cmp( single_word, flag_table[flag].name))
{
SET_BIT(result, flag_table[flag].bit);
break;
}
}
// if we didn't find the word in that table
if (!flag_table[flag].name){
logf("fread_wordflag(): unfound wordflag '%s'... table firstword='%s'",
single_word, flag_table[0].name);
}
}
return (result);
}
/**************************************************************************/
/**************************************************************************/