File:  [RetroPC.NET] / xmil / statsave.c
Revision 1.8: download - view: text, annotated - select for diffs
Tue Jun 3 05:07:30 2008 JST (17 years, 4 months ago) by yui
Branches: MAIN
CVS tags: HEAD
change to c style comment

#include	"compiler.h"
#include	"strres.h"
#include	"dosio.h"
#include	"scrnmng.h"
#include	"soundmng.h"
#include	"timemng.h"
#include	"z80core.h"
#include	"pccore.h"
#include	"iocore.h"
#include	"nevent.h"
#include	"ievent.h"
#include	"calendar.h"
#include	"statsave.h"
#include	"vram.h"
#include	"palettes.h"
#include	"makescrn.h"
#include	"sound.h"
#include	"fddfile.h"

#if defined(MACOS)
#define	CRCONST		str_cr
#elif defined(WIN32) || defined(X11) || defined(SLZAURUS)
#define	CRCONST		str_lf
#else
#define	CRCONST		str_crlf
#endif


typedef struct {
	char	name[16];
	char	vername[28];
	UINT32	ver;
} NP2FHDR;

typedef struct {
	char	index[10];
	UINT16	ver;
	UINT32	size;
} NP2FENT;

enum {
	STATFLAG_BIN			= 0,
	STATFLAG_TERM,
	STATFLAG_DISK,
	STATFLAG_EVT
};

typedef struct {
	UINT32	id;
	INTPTR	proc;
} PROCTBL;

typedef struct {
	UINT32	id;
	UINT	evt;
} ENUMTBL;

#define	PROCID(a, b, c, d)	(((d) << 24) + ((c) << 16) + ((b) << 8) + (a))

#include "statsave.tbl"


/* ---- */

/* 関数ポインタを intに変更。 */
static UINT32 proc2id(INTPTR func, const PROCTBL *tbl, UINT count) {

	while(count) {
		count--;
		if (func == tbl->proc) {
			return(tbl->id);
		}
		tbl++;
	}
	return(0);
}

static INTPTR id2proc(UINT32 id, const PROCTBL *tbl, UINT count) {

	while(count) {
		count--;
		if (id == tbl->id) {
			return(tbl->proc);
		}
		tbl++;
	}
	return((INTPTR)NULL);
}


/* ---- */

enum {
	SFFILEH_WRITE	= 0x0001,
	SFFILEH_BLOCK	= 0x0002,
	SFFILEH_ERROR	= 0x0004
};

typedef struct {
	_STFLAGH	sfh;
	UINT		stat;
	FILEH		fh;
	UINT		secpos;
	NP2FHDR		f;
} _SFFILEH, *SFFILEH;

static SFFILEH statflag_open(const OEMCHAR *filename,
												OEMCHAR *err, UINT errlen) {

	FILEH	fh;
	SFFILEH	ret;

	fh = file_open_rb(filename);
	if (fh == FILEH_INVALID) {
		goto sfo_err1;
	}
	ret = (SFFILEH)_MALLOC(sizeof(_SFFILEH), filename);
	if (ret == NULL) {
		goto sfo_err2;
	}
	if ((file_read(fh, &ret->f, sizeof(NP2FHDR)) == sizeof(NP2FHDR)) &&
		(!memcmp(&ret->f, &np2flagdef, sizeof(np2flagdef)))) {
		ZeroMemory(ret, sizeof(_SFFILEH));
		ret->fh = fh;
		ret->secpos = sizeof(NP2FHDR);
		if ((err) && (errlen > 0)) {
			err[0] = '\0';
			ret->sfh.err = err;
			ret->sfh.errlen = errlen;
		}
		return(ret);
	}
	_MFREE(ret);

sfo_err2:
	file_close(fh);

sfo_err1:
	return(NULL);
}

static int statflag_closesection(SFFILEH sffh) {

	UINT	leng;
	UINT8	zero[16];

	if (sffh == NULL) {
		goto sfcs_err1;
	}
	if (sffh->stat == (SFFILEH_BLOCK | SFFILEH_WRITE)) {
		leng = (0 - sffh->sfh.hdr.size) & 15;
		if (leng) {
			ZeroMemory(zero, sizeof(zero));
			if (file_write(sffh->fh, zero, leng) != leng) {
				goto sfcs_err2;
			}
		}
		if ((file_seek(sffh->fh, (long)sffh->secpos, FSEEK_SET)
												!= (long)sffh->secpos) ||
			(file_write(sffh->fh, &sffh->sfh.hdr, sizeof(sffh->sfh.hdr))
												!= sizeof(sffh->sfh.hdr))) {
			goto sfcs_err2;
		}
	}
	if (sffh->stat & SFFILEH_BLOCK) {
		sffh->stat &= ~SFFILEH_BLOCK;
		sffh->secpos += sizeof(sffh->sfh.hdr) +
									((sffh->sfh.hdr.size + 15) & (~15));
		if (file_seek(sffh->fh, (long)sffh->secpos, FSEEK_SET)
												!= (long)sffh->secpos) {
			goto sfcs_err2;
		}
	}
	return(STATFLAG_SUCCESS);

sfcs_err2:
	sffh->stat = SFFILEH_ERROR;

sfcs_err1:
	return(STATFLAG_FAILURE);
}

static int statflag_readsection(SFFILEH sffh) {

	int		ret;

	ret = statflag_closesection(sffh);
	if (ret != STATFLAG_SUCCESS) {
		return(ret);
	}
	if ((sffh->stat == 0) &&
		(file_read(sffh->fh, &sffh->sfh.hdr, sizeof(sffh->sfh.hdr))
												== sizeof(sffh->sfh.hdr))) {
		sffh->stat = SFFILEH_BLOCK;
		sffh->sfh.pos = 0;
		return(STATFLAG_SUCCESS);
	}
	sffh->stat = SFFILEH_ERROR;
	return(STATFLAG_FAILURE);
}

int statflag_read(STFLAGH sfh, void *buf, UINT size) {

	if ((sfh == NULL) || (buf == NULL) ||
		((sfh->pos + size) > sfh->hdr.size)) {
		goto sfr_err;
	}
	if (size) {
		if (file_read(((SFFILEH)sfh)->fh, buf, size) != size) {
			goto sfr_err;
		}
		sfh->pos += size;
	}
	return(STATFLAG_SUCCESS);

sfr_err:
	return(STATFLAG_FAILURE);
}

static SFFILEH statflag_create(const OEMCHAR *filename) {

	SFFILEH	ret;
	FILEH	fh;

	ret = (SFFILEH)_MALLOC(sizeof(_SFFILEH), filename);
	if (ret == NULL) {
		goto sfc_err1;
	}
	fh = file_create(filename);
	if (fh == FILEH_INVALID) {
		goto sfc_err2;
	}
	if (file_write(fh, &np2flagdef, sizeof(NP2FHDR)) == sizeof(NP2FHDR)) {
		ZeroMemory(ret, sizeof(_SFFILEH));
		ret->stat = SFFILEH_WRITE;
		ret->fh = fh;
		ret->secpos = sizeof(NP2FHDR);
		return(ret);
	}
	file_close(fh);
	file_delete(filename);

sfc_err2:
	_MFREE(ret);

sfc_err1:
	return(NULL);
}

static int statflag_createsection(SFFILEH sffh, const SFENTRY *tbl) {

	int		ret;

	ret = statflag_closesection(sffh);
	if (ret != STATFLAG_SUCCESS) {
		return(ret);
	}
	if (sffh->stat != SFFILEH_WRITE) {
		sffh->stat = SFFILEH_ERROR;
		return(STATFLAG_FAILURE);
	}
	CopyMemory(sffh->sfh.hdr.index, tbl->index, sizeof(sffh->sfh.hdr.index));
	sffh->sfh.hdr.ver = tbl->ver;
	sffh->sfh.hdr.size = 0;
	return(STATFLAG_SUCCESS);
}

int statflag_write(STFLAGH sfh, const void *buf, UINT size) {

	SFFILEH	sffh;

	if (sfh == NULL) {
		goto sfw_err1;
	}
	sffh = (SFFILEH)sfh;
	if (!(sffh->stat & SFFILEH_WRITE)) {
		goto sfw_err2;
	}
	if (!(sffh->stat & SFFILEH_BLOCK)) {
		sffh->stat |= SFFILEH_BLOCK;
		sfh->pos = 0;
		if (file_write(sffh->fh, &sfh->hdr, sizeof(sfh->hdr))
														!= sizeof(sfh->hdr)) {
			goto sfw_err2;
		}
	}
	if (size) {
		if ((buf == NULL) || (file_write(sffh->fh, buf, size) != size)) {
			goto sfw_err2;
		}
		sfh->pos += size;
		if (sfh->hdr.size < sfh->pos) {
			sfh->hdr.size = sfh->pos;
		}
	}
	return(STATFLAG_SUCCESS);

sfw_err2:
	sffh->stat = SFFILEH_ERROR;

sfw_err1:
	return(STATFLAG_FAILURE);
}

static void statflag_close(SFFILEH sffh) {

	if (sffh) {
		statflag_closesection(sffh);
		file_close(sffh->fh);
		_MFREE(sffh);
	}
}

void statflag_seterr(STFLAGH sfh, const OEMCHAR *str) {

	if ((sfh) && (sfh->errlen)) {
		milstr_ncat(sfh->err, str, sfh->errlen);
		milstr_ncat(sfh->err, CRCONST, sfh->errlen);
	}
}


/* common */

static int flagsave_common(STFLAGH sfh, const SFENTRY *tbl) {

	return(statflag_write(sfh, tbl->arg1, tbl->arg2));
}

static int flagload_common(STFLAGH sfh, const SFENTRY *tbl) {

	return(statflag_read(sfh, tbl->arg1, tbl->arg2));
}


/* event */

typedef struct {
	UINT32	next;
	SINT32	clock;
	SINT32	baseclock;
	UINT32	proc;
} NEVTITEM;

typedef struct {
	NEVTITEM	item[NEVENT_MAXEVENTS];
	UINT32		first;
} NEVTSAVE;

static UINT32 evt2id(NEVENTITEM next) {

	if (next == NEVENTITEM_NONE) {
		return((UINT32)-2);
	}
	else if (next == NEVENTITEM_TERM) {
		return((UINT32)-1);
	}
	else {
		return(next - nevent.item);
	}
}

static NEVENTITEM id2evt(UINT32 n) {

	if (n == (UINT32)-2) {
		return(NEVENTITEM_NONE);
	}
	else if (n == (UINT32)-1) {
		return(NEVENTITEM_TERM);
	}
	else if (n < NEVENT_MAXEVENTS) {
		return(nevent.item + n);
	}
	else {
		/* error! */
		return(NEVENTITEM_TERM);
	}
}

static int flagsave_evt(STFLAGH sfh, const SFENTRY *tbl) {

	NEVTSAVE	nevt;
	UINT		i;

	for (i=0; i<NEVENT_MAXEVENTS; i++) {
		nevt.item[i].next = evt2id(nevent.item[i].next);
		nevt.item[i].clock = nevent.item[i].clock;
		nevt.item[i].baseclock = nevent.item[i].baseclock;
		nevt.item[i].proc = proc2id((INTPTR)nevent.item[i].proc,
												evtproc, NELEMENTS(evtproc));
	}
	nevt.first = evt2id(nevent.first);
	(void)tbl;
	return(statflag_write(sfh, &nevt, sizeof(nevt)));
}

static int flagload_evt(STFLAGH sfh, const SFENTRY *tbl) {

	NEVTSAVE	nevt;
	int			ret;
	UINT		i;

	ret = statflag_read(sfh, &nevt, sizeof(nevt));

	for (i=0; i<NEVENT_MAXEVENTS; i++) {
		nevent.item[i].next = id2evt(nevt.item[i].next);
		nevent.item[i].clock = nevt.item[i].clock;
		nevent.item[i].baseclock = nevt.item[i].baseclock;
		nevent.item[i].proc = (NEVENTCB)id2proc(nevt.item[i].proc,
												evtproc, NELEMENTS(evtproc));
	}
	nevent.first = id2evt(nevt.first);
	(void)tbl;
	return(ret);
}


/* disk */

typedef struct {
	OEMCHAR	fname[MAX_PATH];
	UINT32	ftype;
	UINT	readonly;
	DOSDATE	date;
	DOSTIME	time;
} STATDISK;

static const OEMCHAR str_fddx[] = OEMTEXT("FDD%u");
static const OEMCHAR str_updated[] = OEMTEXT("%s: updated");
static const OEMCHAR str_notfound[] = OEMTEXT("%s: not found");

static int disksave(STFLAGH sfh, const _FDDFILE *fdd) {

	STATDISK	st;
	FILEH		fh;

	ZeroMemory(&st, sizeof(st));
	if (fdd->type != DISKTYPE_NOTREADY) {
		file_cpyname(st.fname, fdd->fname, NELEMENTS(st.fname));
		st.ftype = fdd->ftype;
		st.readonly = fdd->protect;
		fh = file_open_rb(st.fname);
		if (fh != FILEH_INVALID) {
			file_getdatetime(fh, &st.date, &st.time);
			file_close(fh);
		}
	}
	return(statflag_write(sfh, &st, sizeof(st)));
}

static int flagsave_disk(STFLAGH sfh, const SFENTRY *tbl) {

	int		ret;
	REG8	i;

	ret = STATFLAG_SUCCESS;
	for (i=0; i<MAX_FDDFILE; i++) {
		ret |= disksave(sfh, fddfile + i);
	}
	(void)tbl;
	return(ret);
}

static int diskcheck(STFLAGH sfh, const OEMCHAR *name) {

	int			ret;
	FILEH		fh;
	STATDISK	st;
	OEMCHAR		buf[256];
	DOSDATE		date;
	DOSTIME		time;

	ret = statflag_read(sfh, &st, sizeof(st));
	if (st.fname[0]) {
		fh = file_open_rb(st.fname);
		if (fh != FILEH_INVALID) {
			file_getdatetime(fh, &date, &time);
			file_close(fh);
			if ((memcmp(&st.date, &date, sizeof(date))) ||
				(memcmp(&st.time, &time, sizeof(time)))) {
				ret |= STATFLAG_DISKCHG;
				OEMSPRINTF(buf, str_updated, name);
				statflag_seterr(sfh, buf);
			}
		}
		else {
			ret |= STATFLAG_DISKCHG;
			OEMSPRINTF(buf, str_notfound, name);
			statflag_seterr(sfh, buf);
		}
	}
	return(ret);
}

static int flagcheck_disk(STFLAGH sfh, const SFENTRY *tbl) {

	int		ret;
	int		i;
	OEMCHAR	buf[8];

	ret = 0;
	for (i=0; i<MAX_FDDFILE; i++) {
		OEMSPRINTF(buf, str_fddx, i+1);
		ret |= diskcheck(sfh, buf);
	}
	(void)tbl;
	return(ret);
}

static int flagload_disk(STFLAGH sfh, const SFENTRY *tbl) {

	int			ret;
	UINT8		i;
	STATDISK	st;

	ret = STATFLAG_SUCCESS;
	for (i=0; i<MAX_FDDFILE; i++) {
		ret |= statflag_read(sfh, &st, sizeof(st));
		if (st.fname[0]) {
			fddfile_set(i, st.fname, st.ftype, st.readonly);
		}
	}
	(void)tbl;
	return(ret);
}


/* checker */

static int flagcheck_versize(STFLAGH sfh, const SFENTRY *tbl) {

	if ((sfh->hdr.ver == tbl->ver) && (sfh->hdr.size == tbl->arg2)) {
		return(STATFLAG_SUCCESS);
	}
	return(STATFLAG_FAILURE);
}

static int flagcheck_veronly(STFLAGH sfh, const SFENTRY *tbl) {

	if (sfh->hdr.ver == tbl->ver) {
		return(STATFLAG_SUCCESS);
	}
	return(STATFLAG_FAILURE);
}


/* interface */

int statsave_save(const OEMCHAR *filename) {

	SFFILEH		sffh;
	int			ret;
const SFENTRY	*tbl;
const SFENTRY	*tblterm;

	sffh = statflag_create(filename);
	if (sffh == NULL) {
		return(STATFLAG_FAILURE);
	}

	ret = STATFLAG_SUCCESS;
	tbl = xmiltbl;
	tblterm = tbl + (sizeof(xmiltbl)/sizeof(SFENTRY));
	while(tbl < tblterm) {
		ret |= statflag_createsection(sffh, tbl);
		switch(tbl->type) {
			case STATFLAG_BIN:
			case STATFLAG_TERM:
				ret |= flagsave_common(&sffh->sfh, tbl);
				break;

			case STATFLAG_DISK:
				ret |= flagsave_disk(&sffh->sfh, tbl);
				break;

			case STATFLAG_EVT:
				ret |= flagsave_evt(&sffh->sfh, tbl);
				break;
		}
		tbl++;
	}
	statflag_close(sffh);
	return(ret);
}

int statsave_check(const OEMCHAR *filename, OEMCHAR *buf, UINT size) {

	SFFILEH		sffh;
	int			ret;
	BRESULT		done;
const SFENTRY	*tbl;
const SFENTRY	*tblterm;

	sffh = statflag_open(filename, buf, size);
	if (sffh == NULL) {
		return(STATFLAG_FAILURE);
	}

	done = FALSE;
	ret = STATFLAG_SUCCESS;
	while((!done) && (ret != STATFLAG_FAILURE)) {
		ret |= statflag_readsection(sffh);
		tbl = xmiltbl;
		tblterm = tbl + (sizeof(xmiltbl)/sizeof(SFENTRY));
		while(tbl < tblterm) {
			if (!memcmp(sffh->sfh.hdr.index, tbl->index, 10)) {
				break;
			}
			tbl++;
		}
		if (tbl < tblterm) {
			switch(tbl->type) {
				case STATFLAG_BIN:
					ret |= flagcheck_versize(&sffh->sfh, tbl);
					break;

				case STATFLAG_TERM:
					done = TRUE;
					break;

				case STATFLAG_EVT:
					ret |= flagcheck_veronly(&sffh->sfh, tbl);
					break;

				case STATFLAG_DISK:
					ret |= flagcheck_disk(&sffh->sfh, tbl);
					break;

				default:
					ret |= STATFLAG_WARNING;
					break;
			}
		}
		else {
			ret |= STATFLAG_WARNING;
		}
	}
	statflag_close(sffh);
	return(ret);
}

int statsave_load(const OEMCHAR *filename) {

	SFFILEH		sffh;
	int			ret;
	BRESULT		done;
const SFENTRY	*tbl;
const SFENTRY	*tblterm;

	sffh = statflag_open(filename, NULL, 0);
	if (sffh == NULL) {
		return(STATFLAG_FAILURE);
	}

	/* PCCORE read! */
	ret = statflag_readsection(sffh);
	if ((ret != STATFLAG_SUCCESS) ||
		(memcmp(sffh->sfh.hdr.index, xmiltbl[0].index, 10))) {
		statflag_close(sffh);
		return(STATFLAG_FAILURE);
	}

	soundmng_stop();
	ret |= flagload_common(&sffh->sfh, xmiltbl);

	sound_changeclock();
	sound_reset();

	Z80_RESET();
	nevent_allreset();
	ievent_reset();
	calendar_reset();
	iocore_reset();

	done = FALSE;
	while((!done) && (ret != STATFLAG_FAILURE)) {
		ret |= statflag_readsection(sffh);
		tbl = xmiltbl + 1;
		tblterm = xmiltbl + (sizeof(xmiltbl)/sizeof(SFENTRY));
		while(tbl < tblterm) {
			if (!memcmp(sffh->sfh.hdr.index, tbl->index, 10)) {
				break;
			}
			tbl++;
		}
		if (tbl < tblterm) {
			switch(tbl->type) {
				case STATFLAG_BIN:
					ret |= flagload_common(&sffh->sfh, tbl);
					break;

				case STATFLAG_TERM:
					done = TRUE;
					break;

				case STATFLAG_DISK:
					ret |= flagload_disk(&sffh->sfh, tbl);
					break;

				case STATFLAG_EVT:
					ret |= flagload_evt(&sffh->sfh, tbl);
					break;

				default:
					ret |= STATFLAG_WARNING;
					break;
			}
		}
		else {
			ret |= STATFLAG_WARNING;
		}
	}
	statflag_close(sffh);

	memio_update();
	crtc_update();
	sndboard_update();

	pal_reset();
	makescrn_reset();

	soundmng_play();

	return(ret);
}


RetroPC.NET-CVS <cvs@retropc.net>