/*	$Id: ini.c,v 1.22 2008/04/03 13:52:20 monaka Exp $	*/

#include "compiler.h"

#include "np2.h"
#include "dosio.h"
#include "ini.h"
#include "pccore.h"
#include "profile.h"
#include "strres.h"

#include "commng.h"
#include "joymng.h"
#include "kbdmng.h"
#include "soundmng.h"


typedef struct {
	const char	*title;
	const INITBL	*tbl;
	const INITBL	*tblterm;
	UINT		count;
} _INIARG, *INIARG;


static BOOL
inigetbmp(const BYTE *ptr, UINT pos)
{

	return ((ptr[pos >> 3] >> (pos & 7)) & 1);
}

static void
inisetbmp(BYTE *ptr, UINT pos, BOOL set)
{
	UINT8 bit;

	ptr += (pos >> 3);
	bit = 1 << (pos & 7);
	if (set) {
		*ptr |= bit;
	} else {
		*ptr &= ~bit;
	}
}

static void
inirdargs16(const char *src, const INITBL *ini)
{
	SINT16 *dst;
	int dsize;
	int i;
	char c;

	dst = (SINT16 *)ini->value;
	dsize = ini->arg;

	for (i = 0; i < dsize; i++) {
		while (*src == ' ') {
			src++;
		}
		if (*src == '\0') {
			break;
		}
		dst[i] = (SINT16)milstr_solveINT(src);
		while (*src != '\0') {
			c = *src++;
			if (c == ',') {
				break;
			}
		}
	}
}

static void
inirdargh8(const char *src, const INITBL *ini)
{
	BYTE *dst;
	int dsize;
	int i;
	BYTE val;
	BOOL set;
	char c;

	dst = (BYTE *)ini->value;
	dsize = ini->arg;

	for (i = 0; i < dsize; i++) {
		val = 0;
		set = FALSE;
		while (*src == ' ') {
			src++;
		}
		for (;;) {
			c = *src;
			if ((c == '\0') || (c == ' ')) {
				break;
			}
			else if ((c >= '0') && (c <= '9')) {
				val <<= 4;
				val += c - '0';
				set = TRUE;
			}
			else {
				c |= 0x20;
				if ((c >= 'a') && (c <= 'f')) {
					val <<= 4;
					val += c - 'a' + 10;
					set = TRUE;
				}
			}
			src++;
		}
		if (set == FALSE) {
			break;
		}
		dst[i] = val;
	}
}

static void
iniwrsetargh8(char *work, int size, const INITBL *ini)
{
	char tmp[8];
	const BYTE *ptr;
	UINT arg;
	UINT i;

	ptr = (BYTE *)(ini->value);
	arg = ini->arg;
	if (arg > 0) {
		SPRINTF(tmp, "%.2x ", ptr[0]);
		milstr_ncpy(work, tmp, size);
	}
	for (i = 1; i < arg; i++) {
		SPRINTF(tmp, "%.2x ", ptr[i]);
		milstr_ncat(work, tmp, size);
	}
}

/* ----- user */

static void
inirdbyte3(const char *src, const INITBL *ini)
{
	UINT i;

	for (i = 0; i < 3; i++) {
		if (src[i] == '\0') {
			break;
		}
		if ((((src[i] - '0') & 0xff) < 9) ||
		    (((src[i] - 'A') & 0xdf) < 26)) {
			((BYTE *)ini->value)[i] = src[i];
		}
	}
}

static void
inirdkb(const char *src, const INITBL *ini)
{

	if ((!milstr_extendcmp(src, "DOS"))
	 || (!milstr_cmp(src, "JIS"))
	 || (!milstr_cmp(src, "106"))
	 || (!milstr_cmp(src, "JP"))
	 || (!milstr_cmp(src, "PCAT"))
	 || (!milstr_cmp(src, "AT"))) {
		*(UINT8 *)ini->value = KEY_KEY106;
	} else if ((!milstr_extendcmp(src, "KEY101"))
	        || (!milstr_cmp(src, "ASCII"))
	        || (!milstr_cmp(src, "EN"))
	        || (!milstr_cmp(src, "US"))
	        || (!milstr_cmp(src, "101"))) {
		*(UINT8 *)ini->value = KEY_KEY101;
	}
}

static void
inirdsnddrv(const char *src, const INITBL *ini)
{

	*(UINT8 *)ini->value = snddrv_drv2num(src);
}

static void
inirdinterp(const char *src, const INITBL *ini)
{

	if (!milstr_cmp(src, "NEAREST")) {
		*(UINT8 *)ini->value = INTERP_NEAREST;
	} else if (!milstr_cmp(src, "TILES")) {
		*(UINT8 *)ini->value = INTERP_TILES;
	} else if (!milstr_cmp(src, "HYPER")) {
		*(UINT8 *)ini->value = INTERP_HYPER;
	} else {
		*(UINT8 *)ini->value = INTERP_BILINEAR;
	}
}

static void update_iniread_flag(const INITBL *p);

static BOOL
inireadcb(void *arg, const char *para, const char *key, const char *data)
{
	char work[512];
	const INITBL *p;
	BOOL rv;

	if (arg == NULL) {
		return(FAILURE);
	}
	if (milstr_cmp(para, ((INIARG)arg)->title)) {
		return(SUCCESS);
	}
	p = ((INIARG)arg)->tbl;
	while (p < ((INIARG)arg)->tblterm) {
		if (!milstr_cmp(key, p->item)) {
			rv = TRUE;
			switch (p->itemtype & INITYPE_MASK) {
			case INITYPE_STR:
				milstr_ncpy((char *)p->value, data, p->arg);
				break;

			case INITYPE_BOOL:
				*((BYTE *)p->value) = (!milstr_cmp(data, str_true))?1:0;
				break;

			case INITYPE_BITMAP:
				inisetbmp((BYTE *)p->value, p->arg, milstr_cmp(data, str_true) == 0);
				break;

			case INITYPE_ARGS16:
				milstr_ncpy(work, data, 512);
				inirdargs16(work, p);
				break;

			case INITYPE_ARGH8:
				milstr_ncpy(work, data, 512);
				inirdargh8(work, p);
				break;

			case INITYPE_SINT8:
			case INITYPE_UINT8:
				*((UINT8 *)p->value) = (UINT8)milstr_solveINT(data);
				break;

			case INITYPE_SINT16:
			case INITYPE_UINT16:
				*((UINT16 *)p->value) = (UINT16)milstr_solveINT(data);
				break;

			case INITYPE_SINT32:
			case INITYPE_UINT32:
				*((UINT32 *)p->value) = (UINT32)milstr_solveINT(data);
				break;

			case INITYPE_HEX8:
				*((UINT8 *)p->value) = (UINT8)milstr_solveHEX(data);
				break;

			case INITYPE_HEX16:
				*((UINT16 *)p->value) = (UINT16)milstr_solveHEX(data);
				break;

			case INITYPE_HEX32:
				*((UINT32 *)p->value) = (UINT32)milstr_solveHEX(data);
				break;

			case INITYPE_BYTE3:
				milstr_ncpy(work, data, 512);
				inirdbyte3(work, p);
				break;

			case INITYPE_KB:
				milstr_ncpy(work, data, 512);
				inirdkb(work, p);
				break;

			case INITYPE_SNDDRV:
				milstr_ncpy(work, data, 512);
				inirdsnddrv(work, p);
				break;

			case INITYPE_INTERP:
				milstr_ncpy(work, data, 512);
				inirdinterp(work, p);
				break;

			default:
				rv = FALSE;
				break;
			}
			if (rv) {
				update_iniread_flag(p);
			}
		}
		p++;
	}
	return (SUCCESS);
}

void
ini_read(const char *path, const char *title, const INITBL *tbl, UINT count)
{
	_INIARG	iniarg;

	if (path == NULL) {
		return;
	}
	iniarg.title = title;
	iniarg.tbl = tbl;
	iniarg.tblterm = tbl + count;
	profile_enum(path, &iniarg, inireadcb);
}


static void
iniwrsetstr(char *work, int size, const char *ptr)
{
	int i;
	char c;

	if (ptr[0] == ' ') {
		goto iwss_extend;
	}
	i = strlen(ptr);
	if ((i) && (ptr[i-1] == ' ')) {
		goto iwss_extend;
	}
	while (i > 0) {
		i--;
		if (ptr[i] == '\"') {
			goto iwss_extend;
		}
	}
	milstr_ncpy(work, ptr, size);
	return;

iwss_extend:
	if (size > 3) {
		size -= 3;
		*work++ = '\"';
		while (size > 0) {
			size--;
			c = *ptr++;
			if (c == '\"') {
				if (size > 0) {
					size--;
					work[0] = c;
					work[1] = c;
					work += 2;
				}
			}
			else {
				*work++ = c;
			}
		}
		work[0] = '\"';
		work[1] = '\0';
	}
}

static const char *
iniwrinterp(UINT8 interp)
{

	if (interp == INTERP_NEAREST)
		return "NEAREST";
	else if (interp == INTERP_TILES)
		return "TILES";
	else if (interp == INTERP_HYPER)
		return "HYPER";
	else
		return "BILINEAR";
}

static BOOL read_iniread_flag(const INITBL *p);

void
ini_write(const char *path, const char *title, const INITBL *tbl, UINT count, BOOL create)
{
	char		work[512];
	const INITBL	*p;
	const INITBL	*pterm;
	FILEH		fh;
	BOOL		set;

	fh = FILEH_INVALID;
	if (!create) {
		fh = file_open(path);
		if (fh != FILEH_INVALID)
			file_seek(fh, 0L, FSEEK_END);
	}
	if (fh == FILEH_INVALID) {
		fh = file_create(path);
		if (fh == FILEH_INVALID)
			return;
	}

	milstr_ncpy(work, "[", sizeof(work));
	milstr_ncat(work, title, sizeof(work));
	milstr_ncat(work, "]\n", sizeof(work));
	file_write(fh, work, strlen(work));

	p = tbl;
	pterm = tbl + count;
	while (p < pterm) {
		if (!(p->itemtype & INIFLAG_RO) || read_iniread_flag(p)) {
			work[0] = '\0';
			set = SUCCESS;
			switch (p->itemtype & INITYPE_MASK) {
			case INITYPE_STR:
				iniwrsetstr(work, sizeof(work), (char *)p->value);
				break;

			case INITYPE_BOOL:
				milstr_ncpy(work, (*((BYTE *)p->value)) ? str_true : str_false, sizeof(work));
				break;

			case INITYPE_BITMAP:
				milstr_ncpy(work, inigetbmp((BYTE *)p->value, p->arg) ? str_true : str_false, sizeof(work));
				break;

			case INITYPE_ARGH8:
				iniwrsetargh8(work, sizeof(work), p);
				break;

			case INITYPE_SINT8:
				SPRINTF(work, "%d", *((char *)p->value));
				break;

			case INITYPE_SINT16:
				SPRINTF(work, "%d", *((SINT16 *)p->value));
				break;

			case INITYPE_SINT32:
				SPRINTF(work, "%d", *((SINT32 *)p->value));
				break;

			case INITYPE_UINT8:
				SPRINTF(work, "%u", *((BYTE *)p->value));
				break;

			case INITYPE_UINT16:
				SPRINTF(work, "%u", *((UINT16 *)p->value));
				break;

			case INITYPE_UINT32:
				SPRINTF(work, "%u", *((UINT32 *)p->value));
				break;

			case INITYPE_HEX8:
				SPRINTF(work, "%x", *((BYTE *)p->value));
				break;

			case INITYPE_HEX16:
				SPRINTF(work, "%x", *((UINT16 *)p->value));
				break;

			case INITYPE_HEX32:
				SPRINTF(work, "%x", *((UINT32 *)p->value));
				break;

			case INITYPE_KB:
				if (*(UINT8 *)p->value == KEY_KEY101)
					milstr_ncpy(work, "101", sizeof(work));
				else
					milstr_ncpy(work, "106", sizeof(work));
				break;

			case INITYPE_SNDDRV:
				SPRINTF(work, "%s", snddrv_num2drv(*(UINT8 *)p->value));
				break;

			case INITYPE_INTERP:
				SPRINTF(work, "%s", iniwrinterp(*(UINT8 *)p->value));
				break;

			default:
				set = FAILURE;
				break;
			}
			if (set == SUCCESS) {
				file_write(fh, p->item, strlen(p->item));
				file_write(fh, " = ", 3);
				file_write(fh, work, strlen(work));
				file_write(fh, "\n", 1);
			}
		}
		p++;
	}
	file_close(fh);
}

extern char modulefile[];

static const char ini_title[] = "NekoProjectII";

enum {
	INIRO_STR	= INIFLAG_RO | INITYPE_STR,
	INIRO_BOOL	= INIFLAG_RO | INITYPE_BOOL,
	INIRO_BITMAP	= INIFLAG_RO | INITYPE_BITMAP,
	INIRO_UINT8	= INIFLAG_RO | INITYPE_UINT8,
	INIMAX_UINT8	= INIFLAG_MAX | INITYPE_UINT8,
	INIAND_UINT8	= INIFLAG_AND | INITYPE_UINT8,
	INIROMAX_SINT32	= INIFLAG_RO | INIFLAG_MAX | INITYPE_SINT32,
	INIROAND_HEX32	= INIFLAG_RO | INIFLAG_AND | INITYPE_HEX32,

	INIRO_BYTE3	= INIFLAG_RO | INITYPE_BYTE3,
	INIRO_KB	= INIFLAG_RO | INITYPE_KB
};

static const INITBL iniitem[] = {
	{"np2title", INIRO_STR,		np2oscfg.titles,	sizeof(np2oscfg.titles)},
	{"paddingx", INIROMAX_SINT32,	&np2oscfg.paddingx,	32},
	{"paddingy", INIROMAX_SINT32,	&np2oscfg.paddingy,	32},

	{"FDfolder", INITYPE_STR,	fddfolder,		MAX_PATH},
	{"HDfolder", INITYPE_STR,	hddfolder,		MAX_PATH},
	{"bmap_Dir", INITYPE_STR,	bmpfilefolder,		MAX_PATH},
	{"fontfile", INITYPE_STR,	np2cfg.fontfile,	MAX_PATH},
	{"biospath", INIRO_STR,		np2cfg.biospath,	MAX_PATH},
	{"hdrvroot", INIRO_STR,		np2cfg.hdrvroot,	MAX_PATH},
	{"hdrv_acc", INIRO_UINT8,	&np2cfg.hdrvacc,	0},

	{"pc_model", INITYPE_STR,	np2cfg.model,		sizeof(np2cfg.model)},

	{"clk_base", INITYPE_UINT32,	&np2cfg.baseclock,	0},
	{"clk_mult", INITYPE_UINT32,	&np2cfg.multiple,	0},

	{"DIPswtch", INITYPE_ARGH8,	np2cfg.dipsw,		3},
	{"MEMswtch", INITYPE_ARGH8,	np2cfg.memsw,		8},
	{"ExMemory", INIMAX_UINT8,	&np2cfg.EXTMEM,		13},
	{"ITF_WORK", INIRO_BOOL,	&np2cfg.ITF_WORK,	0},

	{"HDD1FILE", INITYPE_STR,	np2cfg.sasihdd[0],	MAX_PATH},
	{"HDD2FILE", INITYPE_STR,	np2cfg.sasihdd[1],	MAX_PATH},

	{"SampleHz", INITYPE_UINT16,	&np2cfg.samplingrate,	0},
	{"Latencys", INITYPE_UINT16,	&np2cfg.delayms,	0},
	{"SNDboard", INITYPE_HEX8,	&np2cfg.SOUND_SW,	0},
	{"BEEP_vol", INIAND_UINT8,	&np2cfg.BEEP_VOL,	3},
	{"xspeaker", INIRO_BOOL,	&np2cfg.snd_x,		0},

	{"SND14vol", INITYPE_ARGH8,	np2cfg.vol14,		6},
//	{"opt14BRD", INITYPE_ARGH8,	np2cfg.snd14opt,	3},
	{"opt26BRD", INITYPE_HEX8,	&np2cfg.snd26opt,	0},
	{"opt86BRD", INITYPE_HEX8,	&np2cfg.snd86opt,	0},
	{"optSPBRD", INITYPE_HEX8,	&np2cfg.spbopt,		0},
	{"optSPBVR", INITYPE_HEX8,	&np2cfg.spb_vrc,	0},
	{"optSPBVL", INIMAX_UINT8,	&np2cfg.spb_vrl,	24},
	{"optSPB_X", INITYPE_BOOL,	&np2cfg.spb_x,		0},
	{"optMPU98", INITYPE_HEX8,	&np2cfg.mpuopt,		0},

	{"volume_F", INIMAX_UINT8,	&np2cfg.vol_fm,		128},
	{"volume_S", INIMAX_UINT8,	&np2cfg.vol_ssg,	128},
	{"volume_A", INIMAX_UINT8,	&np2cfg.vol_adpcm,	128},
	{"volume_P", INIMAX_UINT8,	&np2cfg.vol_pcm,	128},
	{"volume_R", INIMAX_UINT8,	&np2cfg.vol_rhythm,	128},

	{"Seek_Snd", INITYPE_BOOL,	&np2cfg.MOTOR,		0},
	{"Seek_Vol", INIMAX_UINT8,	&np2cfg.MOTORVOL,	100},

	{"btnRAPID", INITYPE_BOOL,	&np2cfg.BTN_RAPID,	0},
	{"btn_MODE", INITYPE_BOOL,	&np2cfg.BTN_MODE,	0},
	{"Mouse_sw", INITYPE_BOOL,	&np2oscfg.MOUSE_SW,	0},
	{"MS_RAPID", INITYPE_BOOL,	&np2cfg.MOUSERAPID,	0},

	{"VRAMwait", INITYPE_ARGH8,	np2cfg.wait,		6},
	{"DspClock", INIAND_UINT8,	&np2oscfg.DISPCLK,	3},
	{"DispSync", INITYPE_BOOL,	&np2cfg.DISPSYNC,	0},
	{"Real_Pal", INITYPE_BOOL,	&np2cfg.RASTER,		0},
	{"RPal_tim", INIMAX_UINT8,	&np2cfg.realpal,	64},
	{"s_NOWAIT", INITYPE_BOOL,	&np2oscfg.NOWAIT,	0},
	{"SkpFrame", INITYPE_UINT8,	&np2oscfg.DRAW_SKIP,	0},
	{"uPD72020", INITYPE_BOOL,	&np2cfg.uPD72020,	0},
	{"GRCG_EGC", INIAND_UINT8,	&np2cfg.grcg,		3},
	{"color16b", INITYPE_BOOL,	&np2cfg.color16,	0},
	{"skipline", INITYPE_BOOL,	&np2cfg.skipline,	0},
	{"skplight", INITYPE_SINT16,	&np2cfg.skiplight,	0},
	{"LCD_MODE", INIAND_UINT8,	&np2cfg.LCD_MODE,	0x03},
	{"BG_COLOR", INIROAND_HEX32,	&np2cfg.BG_COLOR,	0xffffff},
	{"FG_COLOR", INIROAND_HEX32,	&np2cfg.FG_COLOR,	0xffffff},

	{"pc9861_e", INITYPE_BOOL,	&np2cfg.pc9861enable,	0},
	{"pc9861_s", INITYPE_ARGH8,	np2cfg.pc9861sw,	3},
	{"pc9861_j", INITYPE_ARGH8,	np2cfg.pc9861jmp,	6},

	{"calendar", INITYPE_BOOL,	&np2cfg.calendar,	0},
	{"USE144FD", INITYPE_BOOL,	&np2cfg.usefd144,	0},
	{"FDDRIVE1", INIRO_BITMAP,	&np2cfg.fddequip,	0},
	{"FDDRIVE2", INIRO_BITMAP,	&np2cfg.fddequip,	1},
	{"FDDRIVE3", INIRO_BITMAP,	&np2cfg.fddequip,	2},
	{"FDDRIVE4", INIRO_BITMAP,	&np2cfg.fddequip,	3},

	{"keyboard", INIRO_KB,		&np2oscfg.KEYBOARD,	0},
	{"F12_COPY", INITYPE_UINT8,	&np2oscfg.F12KEY,	0},
	{"Joystick", INITYPE_BOOL,	&np2oscfg.JOYPAD1,	0},
	{"Joy1_btn", INITYPE_ARGH8,	np2oscfg.JOY1BTN,	JOY_NBUTTON},
	{"Joy1_dev", INITYPE_STR,	&np2oscfg.JOYDEV[0],	MAX_PATH},
	{"Joy1amap", INITYPE_ARGH8,	np2oscfg.JOYAXISMAP[0],	JOY_NAXIS},
	{"Joy1bmap", INITYPE_ARGH8,	np2oscfg.JOYBTNMAP[0],	JOY_NBUTTON},

	{"confirm_", INITYPE_BOOL,	&np2oscfg.confirm,	0},

	{"mpu98map", INITYPE_STR,	np2oscfg.mpu.mout,	MAX_PATH},
	{"mpu98min", INITYPE_STR,	np2oscfg.mpu.min,	MAX_PATH},
	{"mpu98mdl", INITYPE_STR,	np2oscfg.mpu.mdl,	64},
	{"mpu98def", INITYPE_STR,	np2oscfg.mpu.def,	MAX_PATH},

	{"com1port", INIMAX_UINT8,	&np2oscfg.com[0].port,	COMPORT_MIDI},
	{"com1para", INITYPE_UINT8,	&np2oscfg.com[0].param,	0},
	{"com1_bps", INITYPE_UINT32,	&np2oscfg.com[0].speed,	0},
	{"com1mmap", INITYPE_STR,	np2oscfg.com[0].mout,	MAX_PATH},
	{"com1mmdl", INITYPE_STR,	np2oscfg.com[0].mdl,	64},
	{"com1mdef", INITYPE_STR,	np2oscfg.com[0].def,	MAX_PATH},

	{"com2port", INIMAX_UINT8,	&np2oscfg.com[1].port,	COMPORT_MIDI},
	{"com2para", INITYPE_UINT8,	&np2oscfg.com[1].param,	0},
	{"com2_bps", INITYPE_UINT32,	&np2oscfg.com[1].speed,	0},
	{"com2mmap", INITYPE_STR,	np2oscfg.com[1].mout,	MAX_PATH},
	{"com2mmdl", INITYPE_STR,	np2oscfg.com[1].mdl,	64},
	{"com2mdef", INITYPE_STR,	np2oscfg.com[1].def,	MAX_PATH},

	{"com3port", INIMAX_UINT8,	&np2oscfg.com[2].port,	COMPORT_MIDI},
	{"com3para", INITYPE_UINT8,	&np2oscfg.com[2].param,	0},
	{"com3_bps", INITYPE_UINT32,	&np2oscfg.com[2].speed,	0},
	{"com3mmap", INITYPE_STR,	np2oscfg.com[2].mout,	MAX_PATH},
	{"com3mmdl", INITYPE_STR,	np2oscfg.com[2].mdl,	64},
	{"com3mdef", INITYPE_STR,	np2oscfg.com[2].def,	MAX_PATH},

#if defined(SUPPORT_RESUME)
	{"e_resume", INITYPE_BOOL,	&np2oscfg.resume,	0},
#endif
#if defined(SUPPORT_STATSAVE)
	{"STATSAVE", INIRO_BOOL,	&np2oscfg.statsave,	0},
#endif
#if defined(GCC_CPU_ARCH_IA32)
	{"nousemmx", INITYPE_BOOL,	&np2oscfg.disablemmx,	0},
#endif
	{"toolwind", INITYPE_BOOL,	&np2oscfg.toolwin,	0},
	{"keydispl", INITYPE_BOOL,	&np2oscfg.keydisp,	0},
	{"soft_kbd", INITYPE_BOOL,	&np2oscfg.softkbd,	0},
	{"jast_snd", INITYPE_BOOL,	&np2oscfg.jastsnd,	0},

	{"sounddrv", INITYPE_SNDDRV,	&np2oscfg.snddrv,	0},
	{"MIDIOUTd", INITYPE_STR,	&np2oscfg.MIDIDEV[0],	MAX_PATH},
	{"MIDIIN_d", INITYPE_STR,	&np2oscfg.MIDIDEV[1],	MAX_PATH},
	{"MIDIWAIT", INITYPE_UINT32,	&np2oscfg.MIDIWAIT,	0},

	{"dinterp_", INITYPE_INTERP,	&np2oscfg.drawinterp,	0},
	{"fullscrn", INITYPE_UINT32,	&ignore_fullscreen_mode,0},
	{"F11_KEY_", INITYPE_UINT8,	&np2oscfg.F11KEY,	0},
	{"READONLY", INIRO_BOOL,	&np2oscfg.cfgreadonly,	0},

	{"I286SAVE", INIRO_BOOL,	&np2oscfg.I286SAVE,	0},
};
#define	INIITEMS	(sizeof(iniitem) / sizeof(iniitem[0]))


static BOOL iniread_flag[INIITEMS];

static int
calc_index(const INITBL *p)
{
	UINT offset;
	UINT idx;

	if (p) {
		offset = (char *)p - (char *)iniitem;
		if ((offset % sizeof(iniitem[0])) == 0) {
			idx = offset / sizeof(iniitem[0]);
			if (idx < INIITEMS) {
				return idx;
			}
		}
	}
	return -1;
}

static void
update_iniread_flag(const INITBL *p)
{
	int idx;

	idx = calc_index(p);
	if (idx >= 0) {
		iniread_flag[idx] = TRUE;
	}
}

static BOOL
read_iniread_flag(const INITBL *p)
{
	int idx;

	idx = calc_index(p);
	if (idx >= 0) {
		return iniread_flag[idx];
	}
	return FALSE;
}

NP2CFG np2cfg_default;
NP2OSCFG np2oscfg_default;

void
initload(void)
{
	char path[MAX_PATH];

	np2cfg_default = np2cfg;
	np2oscfg_default = np2oscfg;

	milstr_ncpy(path, modulefile, sizeof(path));
	ini_read(path, ini_title, iniitem, INIITEMS);
}

void
initsave(void)
{
	char path[MAX_PATH];

	milstr_ncpy(path, modulefile, sizeof(path));
	ini_write(path, ini_title, iniitem, INIITEMS, TRUE);
}
