/*
	C-MOS 領域を読み込み/保存する
	
		by ＲＫ
	
	1994.01.14 v0.01 
	1994.01.15 v0.02 隠し機能追加
	1994.01.17 v0.03 ↑の機能が危なっかしいのでちょっと修正
	1994.01.29 v0.04 ↑の機能に不安があり(?) 新しいココロミをしてみた。
	1994.02.12 v0.05 比較範囲を拡大した。
*/

#include	<ctype.h>
#include	<machine.h>
#include	"..\def.h"
#include	"..\..\FILEname.h"

#define		CON			stdout

#define		ADDR		0x3000
#define		DEFFILE		"cmos.dat"
#define		ERRCOL		fputs("\x1b[1;31m",CON)
#define		NORCOL		puts("\x1b[m")

#define		READ		1
#define		WRITE		2
#define		COMPARE		4
#define		RESET		128

/*		return code		*/
#define		DIFFER		254
#define		CHANGED		255

char	cmosdata[2049];

FILE	*fp;

char	file[80];
int 	mode;
int 	ret=0;

help()
{	puts("usage : cmosuty -rwc [path\\][filename]");
	puts("   r  CMOS ← ファイル");
	puts("   w  ファイル ← CMOS");
	puts("   c  ファイルと CMOS を比較");
	puts(" ファイル名を指定しなかった場合には、このプログラムと");
	puts(" 同じディレクトリの CMOS.DAT になります。");
	puts(" ファイル名のみ指定すると読み出しを行います。");
}

quote(char *msg)
{	fputs("`"	,CON);
	fputs(msg	,CON);
	fputs("'"	,CON);
}
open_cmosdata(char *fmode)
{
	fp=fopen(file,fmode);
	
	if (fp==NULL)
	{	fclose(fp);
		ERRCOL;
		if ( mode & WRITE )
			puts("ファイルに書き込めません!!");
		else
			puts("ファイルがありません!!");
		
		NORCOL;
		exit(1);
	}
}
close_cmosdata()
{
	fclose(fp);
}

write_cmosdata()
{	int 	i;
	
	for(i=0;i<2048;i++)
		cmosdata[i]=( inp( ADDR+(i*2) ) );
	
	open_cmosdata("wb");
	fwrite(cmosdata,2048,1,fp);
	close_cmosdata();
}

update_cmosdata()
{	int 	i;
	for(i=0;i<2048;i++)
		outp( ADDR+(i*2),cmosdata[i] );
	
	ret=CHANGED;
}
read_cmosfile()
{	int 	i;
	open_cmosdata("rb");
	i=fread(&cmosdata,1,2049,fp);	/* 2049 なのが妙かな? */
	close_cmosdata();
	
	if( i!= 2048 )
	{	ERRCOL;
		puts("ファイル読み込みにエラーが発生しました！");
		NORCOL;
		puts("指定のファイルが正しくないのでは？");
		exit(1);
	}
}

read_cmosdata()
{
	read_cmosfile();
	update_cmosdata();
}

int compare(int from,int to)
{
	while( cmosdata[from]==inp(ADDR+(from * 2)) && from++<=to );
	
	if( from > to)	return(0);
	
	return(1);
}

compare_cmosdata()
{	
	read_cmosfile();
	
		/* 起動ドライブの比較 */	/* ドライブ構成などの比較 */
	if( (compare(0x0c1,0x0c2)==0) && (compare(0x0ee,0x1e7)==0) &&
		(compare(0x580,0x599)==0) && (compare(0x615,0x7ff)==0) )
	{	puts("違いはありませんでした");
		mode=COMPARE;
	}
	else
	{	puts(" 内容が変更されています");
		ret=DIFFER;
	}
}

/* アセンブラなんてわからないんだけど(^_^;)こんなのでいいのかな･･･ */
char _asm_reset();
#define reset()	_asm_reset("\nMOV\tAL,255\nOUT\t2,AL\nOUT\t18,AL\nMOV\tAL,1\nOUT\t32,AL\nHLT\n" );

reset_towns()	/* はて、リセットはこんなのでいいのでしょうか... */
{
/*	outp(0x0002,0xff);
	outp(0x0012,0xff);*/	/* いちおう割り込みは禁止しておくが… */	/*
	
	outp(0x0020,1);
	
	outp(0x0020,0);
	while(1);
*/
	reset();
}

init_err_cmosdata()
{
	int 	i;		/* コード番号 */
	int 	dat[3][2]={	{0x1e8,0x28},{0x1e9,5},{0x1ee,2}	};
	
	for( i=0x1e8 ;i<0x3f8;i++)
		outp( ADDR+(i*2)  ,NULL);
	
	for( i=0;i<3;i++)
		outp( ADDR+(dat[i][0]*2), dat[i][1] );
	
	puts(" CMOS 内のエラー情報を消去しました");
	exit(0);
}

int main(int argc,char *argv[])
{
	int 	i=0,j;
	int 	a;
	
	puts("*** CMOS READ/WRITE  by RK ***");
	
	if (argc <2)
	{	help();
		exit(0);
	}
	/* オプション指定の分解 */
	while(++i<argc)
	{	if( argv[i][0]=='-')
		{	j=1;
			do
			{	a=tolower( argv[i][j] );
				if( a=='r' )
				{	mode |= READ;
					mode &= (WRITE^0xff);
				}
				else if ( a=='w' )
				{	mode |= WRITE;
					mode &= (READ^0xff);
				}
				else if ( a=='c' )
					mode |= COMPARE;
				else if ( a=='i' )
					init_err_cmosdata();
				else if ( a=='s' )
					mode |= RESET;
				else
				{/*	quote( &a );*/
					ERRCOL;
					puts(" parameter error !");
					NORCOL;
					help();
					exit(1);
				}
			}while( argv[i][++j] != NULL );	/* 連続して指定されている? */
		}
		else
			strcpy(file,argv[i]);			/* ファイル名? */
	}
	if( mode==0)
		mode |= READ;
	
	if( file[0]==NULL )	/* ファイルパス指定のないときは同じﾃﾞｨﾚｸﾄﾘにする */
		strcpy(file, FILE_get_path(argv[0]) );
	
	if( (file[strlen(file)-1])=='\\' )	/* \ で終わっているときは付加する */
		strcat(file,DEFFILE);
	
	quote(file);
	if ( mode & COMPARE )
	{	puts("CMOSデータと比較をします\n");
		compare_cmosdata();
	}
	if ( mode & READ )
	{	puts("CMOSデータをファイルから読み出します");
		
		if( (mode & COMPARE) )
			update_cmosdata();	/* 比較して違っていた？ */
		else
			read_cmosdata();
	}
	if ( mode & RESET )
	{	if (ret== CHANGED)
		{	puts("リセットします。ご注意ください！");
			reset_towns();
		}
		else
			puts("");
	}
	
	if ( mode==WRITE )
	{	puts("CMOSデータをファイルに書き込みます");
		write_cmosdata();
	}
	
	return(ret);
}

