/********************************************************************
 *																	*
 *							ＤＩＳＫＤＵＰ							*
 *																	*
 *						オンメモリ型 DISKCOPY						*
 *																	*
 *							diskdup.exp								*
 *																	*
 *							for FM-TOWNS							*
 *																	*
 *			Copyright (c) ちにゃと ＆ Ｔｙｍｉｃ 1992. 1993.		*
 *																	*
 *							メイン ソース							*
 *																	*
 ********************************************************************/

#define	__PRGMAIN__				/* ﾌｧｲﾙ ID */


/********************************************************************
	インクルードファイル
*********************************************************************/

/* HI-C ﾗｲﾌﾞﾗﾘ ﾍｯﾀﾞｰ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <dos.h>

/* T-BIOS C ﾗｲﾌﾞﾗﾘ ﾍｯﾀﾞｰ */
#include <fmcfrb.h>

/* ｿｰｽ ﾍｯﾀﾞｰ */
#include "diskdup.h"
#include "ddupgui.h"
#include "option.h"


/********************************************************************
	変数
*********************************************************************/

char Title1[] = "DiskDup Ver "VER;
char Title2[] = "Copyright (C) ちにゃと＆ＴＹＭＩＣ 1992.1993.";

static char *HelpMsg[] = {
	"パラメ−タ−は先頭に - か / をつけます",
	"大文字でも小文字でも構いません",
	"-S -s 読み込んだﾃﾞｨｽｸの内容のﾃﾞ-ﾀﾌｧｲﾙを作成します",
	"-L -l  ﾃﾞ-ﾀﾌｧｲﾙを読み込んでﾃﾞｭﾌﾟﾘｹ-ﾄをします",
	"-F -f  ﾌｫ-ﾏｯﾄを行いながらﾃﾞｭﾌﾟﾘｹ-ﾄします",
	"-D -d  ﾌｫ-ﾏｯﾄをせずにﾃﾞｭﾌﾟﾘｹ-ﾄします",
	"-I -i  ｴﾗ-時以外に選択/確認を行いません",
	"-H -h -?  ﾍﾙﾌﾟﾒｯｾ-ｼﾞを表示します",
	"ﾌｧｲﾙ名  ﾃﾞ-ﾀﾌｧｲﾙ名を指定します ﾄﾞﾗｲﾌﾞ名ﾊﾟｽ名も含みます",
	"例1  -F -I  ﾌｫ-ﾏｯﾄをします｡又選択/確認を行いません",
	"例2  -S  MAOUDX_A.DSK",
	" ﾃﾞ-ﾀﾌｧｲﾙを指定されたﾌｧｲﾙ名で作成します",
};
#define HELPMSG_MAX		sizeof( HelpMsg ) / sizeof( char* )

static char InMstAMsg[] = "マスターディスクをＡドライブにセットして下さい";
static char InCpyAMsg[] = "コピーディスクをＡドライブにセットして下さい";
static char InCpyBMsg[] = "コピーディスクをＢドライブにセットして下さい";
static char FormProcMsg[] = "フォーマットをしながらコピーを行います";
static char EndMsg[] = "終了します";

char *ErrMsgTbl[] = {			/* ｴﾗｰ ﾒｯｾｰｼﾞ ﾃｰﾌﾞﾙ */
	"",
	"モード設定エラーが発生しました",
	"読み込みエラーが発生しました",
	"書き込みエラーが発生しました",
	"ドライブエラーが発生しました",
	"未対応のディスクです",
	"ドライブの準備が出来ていません",
	"書き込み禁止のためコピー出来ません",
	"フォーマットでエラーが発生しました",
};

static char *DiskTypeMsgTbl[] = {	/* ﾃﾞｨｽｸ ﾀｲﾌﾟ ﾒｯｾｰｼﾞ ﾃｰﾌﾞﾙ */
	"",
	"１・２Ｍ ２ＨＤ 読み込み中",
	"７２０ｋ ２ＤＤ 読み込み中",
	"６４０ｋ ２ＤＤ 読み込み中",
	"１・２Ｍ ２ＨＣ 読み込み中",
};

static uint ChkMode1Tbl[] = {	/* ｾｸﾀ ID 読み込み用 mode1 ﾃﾞｰﾀ ﾃｰﾌﾞﾙ */
	0x0003,						/* MFM 2HD 1024 */
	0x0012,						/* MFM 2DD  512 */
	0x0080,						/*  FM 2HD  128 */
	0x0090,						/*  FM 2DD  128 */
};
#define ChkMode1Tbl_Size		sizeof( ChkMode1Tbl ) / sizeof( uint )

static FORMPARA  PreAmbl[] = {	/* ﾌﾟﾚ ｱﾝﾌﾞﾙ 圧縮 ﾃﾞｰﾀ */
	0x004e, 80,					/* GAP0 */
	0x0000, 12,					/* SYNC */
	0x00f6, 3,					/* INDEX MARK 1 */
	0x00fc, 1,					/* INDEX MARK 2 */
	0x004e, 50,					/* GAP1 */
};
#define PreAmblCnt				sizeof( PreAmbl ) / sizeof( FORMPARA )

static FORMPARA  PosAmbl[] = {	/* ﾎﾟｽﾄ ｱﾝﾌﾞﾙ 圧縮 ﾃﾞｰﾀ */
	0x004e, 600,				/* GAP4 */
};
#define PosAmblCnt				sizeof( PosAmbl ) / sizeof( FORMPARA )

static FORMPARA  SecData1024[] = {	/* 1024 ｾｸﾀ 圧縮 ﾃﾞｰﾀ */
	0x0000, 12,					/* SYNC */
	0x00f5, 3,					/* AM1_1 */
	0x00fe, 1,					/* AM1_2 */
	0x0000, 1,					/* ID TRACK NUMBER */
	0x0000, 1,					/* ID SIDE NUMBER */
	0x0000, 1,					/* ID SECTOR NUMBER */
	0x0003, 1,					/* ID SECTOR LENGTH */
	0x00f7, 1,					/* CRC */
	0x00fe, 1,					/* CRC */
	0x004e, 22,					/* GAP2 */
	0x0000, 12,					/* SYNC */
	0x00f5, 3,					/* AM2_1 */
	0x00fb, 1,					/* AM2_2 */
	0x00e5, 1024,				/* DATA */
	0x00f7, 1,					/* CRC */
	0x00fe, 1,					/* CRC */
	0x004e, 116,				/* GAP3 */
};
#define SecData1024Cnt			sizeof( SecData1024 ) / sizeof( FORMPARA )

static FORMPARA  SecData512[] = {	/* 512 ｾｸﾀ 圧縮 ﾃﾞｰﾀ */
	0x0000, 12,					/* SYNC */
	0x00f5, 3,					/* AM1_1 */
	0x00fe, 1,					/* AM1_2 */
	0x0000, 1,					/* ID TRACK NUMBER */
	0x0000, 1,					/* ID SIDE NUMBER */
	0x0000, 1,					/* ID SECTOR NUMBER */
	0x0002, 1,					/* ID SECTOR LENGTH */
	0x00f7, 1,					/* CRC */
	0x00fe, 1,					/* CRC */
	0x004e, 22,					/* GAP2 */
	0x0000, 12,					/* SYNC */
	0x00f5, 3,					/* AM2_1 */
	0x00fb, 1,					/* AM2_2 */
	0x00e5, 512,				/* DATA */
	0x00f7, 1,					/* CRC */
	0x00fe, 1,					/* CRC */
	0x004e, 116,				/* GAP3 */
};

static int FormatFlg = TRUE;		/* ﾌｫｰﾏｯﾄ 実行 ﾌﾗｸﾞ */
static char *DiskData;				/* ﾃﾞｨｽｸ 読み込み ﾊﾞｯﾌｧ ﾎﾟｲﾝﾀ */
static char FormDataBuf[1024*12];	/* ﾌｫｰﾏｯﾄ ﾃﾞｰﾀ ﾊﾞｯﾌｧ */
static int disktype = 0;			/* ﾃﾞｨｽｸ ﾀｲﾌﾟ */

int option = 0;						/* ｵﾌﾟｼｮﾝ ﾃﾞｰﾀ */


/************************************************************************
【メイン処理】

		概要	ﾒｲﾝ 関数
		用法	無し
		引数	int		argc
				char	**argv
		戻り値	無し
		注意	ﾒﾓﾘ ｱﾛｹｰﾄ 後の ﾌﾟﾛｾｽ 脱出は PrgExit1 関数を使用
************************************************************************/

void main( int argc, char *argv[] )
{
	union REGS		regs;
	struct SREGS	sregs;
	int				tmpi;

	/* GUI 初期設定 及び ﾀｲﾄﾙ 表示 */
	setscreen();
	putworkbox();

	/* forRBIOS 常駐 ﾁｪｯｸ */
	if ( FRB_getstatus() != 0 ) {
		flagerr = 1;
		strcpy( str, "forRBIOSが組み込まれていません" );
		putmessage();
		ready();
		flagerr = 0;
		PrgExit2();
	}

	/* 共用 ﾒﾓﾘ 容量 ﾁｪｯｸ */
	_segread( &sregs );
	regs.x.ax = 0x250d;
	_int86x( 0x21, &regs, &regs, &sregs );
	if ( regs.x.cx < sizeof( FormDataBuf ) ) {
		flagerr = 1;
		strcpy( str, "ごめんなさいリアルメモリ不足です" );
		putmessage();
		ready();
		flagerr = 0;
		PrgExit2();
	}

	/* ﾒﾓﾘ ｱﾛｹ-ｼｮﾝ */
	if ( ( DiskData = (char *)malloc( DISKSIZE ) ) == NULL ) {
		flagerr = 1;
		strcpy( str, "ごめんなさいメモリ不足です" );
		putmessage();
		ready();
		flagerr = 0;
		PrgExit2();
	}

	/* ｵﾌﾟｼｮﾝ 解析 */
	option = optionset( argc, argv );

	if ( option == -1 ) {
		flagerr = 1;
		strcpy( str, "ｵﾌﾟｼｮﾝが違います" );
		putmessage();
		ready();
		option = -2;
	}

	if ( ( option & 3 ) == 3 ) {
		flagerr = 1;
		strcpy( str, "ﾃﾞ-ﾀﾌｧｲﾙの読み込みと作成が同時に指定されました" );
		putmessage();
		ready();
		PrgExit1();
	}

	if ( option == -2 ) {
		flagerr = 1;
		for ( tmpi = 0; tmpi < HELPMSG_MAX; tmpi++ ) {
			strcpy( str, HelpMsg[tmpi] );
			putmessage();
			ready();
		}
		PrgExit1();
	}

/* debug *******************************
	sprinf( str, "flagld = %d", flagld );
	putmessage();
	ready();

	sprintf( str, "flagsv = %d", flagsv );
	putmessage();
	ready();

	sprintf( str, "flaggofmt = %d", flaggofmt );
	putmessage();
	ready();

	sprintf( str, "flagunfmt = %d", flagunfmt );
	putmessage();
	ready();

	sprintf( str, "flagipt = %d", flagipt );
	putmessage();
	ready();
/***************************************/

	/* ｺﾋﾟｰ ﾌﾟﾛｸﾞﾗﾑ ｽﾀｰﾄ */
	CopyPrgMain();

	/* 処理終了 */
	PrgExit1();
}

/************************************************************************
【プログラム終了処理】

		概要	ﾌﾟﾛｸﾞﾗﾑ を終了して DOS へ戻る。
		用法	PrgExit?();
		引数	無し
		戻り値	無し
		注意	ﾒﾓﾘ ｱﾛｹｰﾄ ﾎﾟｲﾝﾀ は DiskData を使用
************************************************************************/

void PrgExit1( void )
{
	/* 2HD 1.2M ﾓｰﾄﾞ に設定 */
	SetDiskDrvMode( FD0_DRVNO, TYPE_2HD_12 );
	SetDiskDrvMode( FD1_DRVNO, TYPE_2HD_12 );

	/* ﾒﾓﾘ 開放 */
	free( DiskData );

	PrgExit2();
}

void PrgExit2( void )
{
	/* ﾌﾟﾛｾｽ 脱出 */
	exit( 0 );
}


/************************************************************************
【コピープログラムメイン処理】

		概要	ﾌﾟﾛｯﾋﾟｰ ﾃﾞｨｽｸ の ﾃﾞｨｽｸ ｺﾋﾟｰ を行う。
		用法	CopyPrgMain();
		引数	無し
		戻り値	無し
		注意	無し
************************************************************************/

void CopyPrgMain( void )
{
	uint	status;		/* ﾄﾞﾗｲﾌﾞ ｽﾃｰﾀｽ */
	int		drvno;		/* ｺﾋﾟｰ 先 ﾃﾞﾊﾞｲｽ 番号 */
	int		i;			/* 切り替え sw */

	if ( option & 1 ) {
		flagerr = 1;
		strcpy( str, " ﾃﾞ-ﾀﾌｧｲﾙを読み込みんでデュプリします" );
		putmessage();
		flagerr = 0;
		if ( select() == 1 ) {
			flagerr = 1;
			strcpy( str, EndMsg );
			putmessage();
			ready();
			return;
		}

		disktype = loaddata( DiskData );
	    if ( ( disktype > TYPE_NOT ) && ( disktype < TYPE_END ) ) {
			flagerr = 1;
			strcpy( str, " ﾃﾞ-ﾀﾌｧｲﾙを読み込みました" );
			putmessage();
			flagerr = 0;
			ready();
		}
		else {
			flagerr = 1;
			strcpy( str, " ﾃﾞ-ﾀﾌｧｲﾙを読み込み出来ませんでした" );
			putmessage();
			ready();
			flagerr = 0;
			strcpy( str, EndMsg );
			putmessage();
			ready();
			return;
		}
	}
	else {
		for ( ;; ) {
			/* ﾃﾞｨｽｸ ｾｯﾄ ﾒｯｾｰｼﾞ 表示 */
			flagerr = 1;
			strcpy( str, InMstAMsg );
			putmessage();
			if ( select() == 1 ) {
				strcpy( str, EndMsg );
				putmessage();
				if ( select() == -1 ) {
					return;
				}
				continue;
			}

			flagerr = 0;

			/* ｽﾃｰﾀｽ 読み込み */
			DKB_rdstatus( FD0_DRVNO, &status );
			if ( status & 0x01 ) {
				ErrMsgPutWord( ERRNOTDISK );	/* ﾄﾞﾗｲﾌﾞ ﾉｯﾄ ﾚﾃﾞｨｰ */
				continue;
			}

			/* ﾌｫｰﾏｯﾄ ﾀｲﾌﾟ ﾁｪｯｸ */
			disktype = ChkFormatType( FD0_DRVNO );
			if ( disktype == NG ) {
				ErrMsgPutWord( ERRDISKSET );		/* ﾃﾞｨｽｸ 設定 ｴﾗｰ */
				continue;
			}
			if ( disktype == TYPE_NOT ) {
				ErrMsgPutWord( ERRDISKTYPE );		/* 未対応 ﾃﾞｨｽｸ ｴﾗｰ */
				continue;
			}

			/* ﾓｰﾄﾞ 設定 */
			if ( SetDiskDrvMode( FD0_DRVNO, disktype ) != 0 ) {
				ErrMsgPutWord( ERRMODESET );		/* ﾓｰﾄﾞ ｾｯﾄ ｴﾗｰ */
				continue;
			}

			/* ﾌｫｰﾏｯﾄ ﾀｲﾌﾟ 表示 */
			clrmessage();
			flagerr = 1;
			strcpy( str, DiskTypeMsgTbl[disktype] );
			putmessage();
			flagerr = 0;
			/* ﾏｽﾀ- ﾃﾞｨｽｸ 読み込み */
			if ( ReadDiskAll( FD0_DRVNO, DiskData, disktype ) == 0 ) {
				break;	
			}
		}
	}

	/* ﾃﾞｨｽｸ ｺﾋﾟｰ */
	if ( option & 2 ) {
		flagerr = 1;
		strcpy( str, " ﾃﾞ-ﾀﾌｧｲﾙを作成します" );
		putmessage();
		flagerr = 0;

		if ( select() == 1 ) {
			flagerr = 1;
			strcpy( str, EndMsg );
			putmessage();
			flagerr = 0;
			ready();
			return;
		}
		if ( savedata( DiskData, disktype ) == 0 ) {
			flagerr = 1;
			strcpy( str, " ﾃﾞ-ﾀﾌｧｲﾙを作成しました" );
			putmessage();
			flagerr = 0;
			ready();
			strcpy( str, EndMsg );
			putmessage();
			ready();
		}
		else {
			flagerr = 1;
			strcpy( str, " ﾃﾞ-ﾀﾌｧｲﾙの作成に失敗しました" );
			putmessage();
			flagerr = 0;
			strcpy( str, EndMsg );
			putmessage();
			ready();
		}
		return ;
	}
	else {
		if ( option & 1 )
			drvno = FD0_DRVNO;	/* A ﾄﾞﾗｲﾌﾞ 設定 */
		else
			drvno = FD1_DRVNO;	/* B ﾄﾞﾗｲﾌﾞ 設定 */

		for ( ;; ) {
			/* ﾃﾞｨｽｸ ｾｯﾄ ﾒｯｾｰｼﾞ 表示 */
			strcpy( str, (drvno == FD0_DRVNO ? InCpyAMsg : InCpyBMsg) );
			putmessage();
			if ( select() == 1 ) {
				flagerr = 1;
				strcpy( str, EndMsg );
				putmessage();
				if ( select() == -1 ) {
					return;
				}
				continue;
			}

			flagerr = 0;

			/* ｼﾘﾝﾀﾞ 0 ｼ-ｸ & ﾘｾｯﾄ */
			if ( DKB_restore( drvno ) != 0 ) {
				ErrMsgPutWord( ERRNOTDISK );	/* ﾄﾞﾗｲﾌﾞ ﾉｯﾄ ﾚﾃﾞｨｰ */
				flagerr = 1;
				continue;
			}

			/* ﾓｰﾄﾞ 設定 */
			if ( SetDiskDrvMode( drvno, disktype ) != 0 ) {
				ErrMsgPutWord( ERRMODESET );	/* ﾓｰﾄﾞ ｾｯﾄ ｴﾗｰ */
				flagerr = 1;
				continue;
			}

			if ( option & 8 ) {
				if ( option & 4 )
					i = 0;
				else
					i = 2;
			}
			else {
				if ( option & 4 )
					i = 1;
				else
					i = 0;
			}

			switch ( i ) {
				case 0:
					/* ﾌｫｰﾏｯﾄ 実行確認表示 */
					strcpy( str, FormProcMsg );
					putmessage();
					if ( select() != 1 ) {
						FormatFlg = TRUE;		/* ﾌｫｰﾏｯﾄ 実行 */
						clrmessage();
						flagerr = 1;
						strcpy( str, "フォーマット＆コピー中" );
						putmessage();
						flagerr = 0;
						break;
					}
					else
						/* case 1: へ*/

				case 1:
					FormatFlg = FALSE;		/* ﾌｫｰﾏｯﾄ ｽｷｯﾌﾟ */
					clrmessage();
					flagerr = 1;
					strcpy( str, "コピー中" );
					putmessage();
					flagerr = 0;
					break;

				case 2:
				default:
					FormatFlg = TRUE;		/* ﾌｫｰﾏｯﾄ 実行 */
					clrmessage();
					flagerr = 1;
					strcpy( str, "フォーマット＆コピー中" );
					putmessage();
					flagerr = 0;
					break;
			}

			/* ﾃﾞｨｽｸ 書き込み */
			if ( WriteDiskAll( drvno, DiskData, disktype ) != 0 ) {
				flagerr = 1;
				continue;
			}

			/* A ←→ B 変換 */
			drvno = ( drvno == FD0_DRVNO ? FD1_DRVNO : FD0_DRVNO );
		}
	}
}


/************************************************************************
【ディスクモード設定】

		概要	ﾃﾞｨｽｸ ﾄﾞﾗｲﾌﾞ ﾓｰﾄﾞ の設定を行う。
		用法	SetDiskDrvMode( devno, sw );
		引数	int		devno			: ﾃﾞﾊﾞｲｽ 番号
				int		sw				: TYPE_2HD_12
										: TYPE_2DD_720
										: TYPE_2DD_640
										: TYPE_2HC_12
		戻り値	int		0x0000			: 正常終了
						0x0002			: ﾃﾞﾊﾞｲｽ 番号 ｴﾗｰ
						0x8???			: ﾊｰﾄﾞ ｴﾗｰ
						NG				: その他の ｴﾗｰ
		注意	無し
************************************************************************/

int SetDiskDrvMode( int devno, int sw )
{
	uint	mode1,		/* ﾓｰﾄﾞ 1 */
			mode2;		/* ﾓｰﾄﾞ 2 */

	/* ﾓ-ﾄﾞ 設定 */
	switch ( sw ) {
		case TYPE_2HD_12:		/* 2HD 1.2M */
			mode1 =	MODE1_12;	/* MFM 2HD 1024 */
			mode2 = MODE2_12;	/* 2 ﾍｯﾄﾞ 8 ｾｸﾀ */
			break;

		case TYPE_2DD_720:		/* 2DD 720K */
			mode1 =	MODE1_720;	/* MFM 2DD 512 */
			mode2 = MODE2_720;	/* 2 ﾍｯﾄﾞ 9 ｾｸﾀ */
			break;

		case TYPE_2DD_640:		/* 2DD 640K */
			mode1 =	MODE1_640;	/* MFM 2DD 512 */
			mode2 = MODE2_640;	/* 2 ﾍｯﾄﾞ 8 ｾｸﾀ */
			break;

		case TYPE_2HC_12:		/* 2HC 1.2M */
			mode1 =	MODE1_12C;	/* MFM 2HD 512 */
			mode2 = MODE2_12C;	/* 2 ﾍｯﾄﾞ 15 ｾｸﾀ */
			break;

		default:
			return NG;
	}

	return DKB_setmode( devno, mode1, mode2 );
}


/************************************************************************
【ディスク読み込み】

		概要	ﾃﾞｨｽｸ の 全 ﾄﾗｯｸ (ｼﾘﾝﾀﾞ) 分の 読み込みを行う。
		用法	ReadDiskAll( devno, buf, sw );
		引数	int		devno			: ﾃﾞﾊﾞｲｽ 番号
				char	*buf			: 読み込み ﾊﾞｯﾌｧ ﾎﾟｲﾝﾀ
				int		sw				: TYPE_2HD_12
										: TYPE_2DD_720
										: TYPE_2DD_640
										: TYPE_2HC_12
		戻り値	int		0x0000			: 正常終了
						0x0002			: ﾃﾞﾊﾞｲｽ 番号 ｴﾗｰ
						0x8???			: ﾊｰﾄﾞ ｴﾗｰ
						NG				: その他の ｴﾗｰ
		注意	無し
************************************************************************/

int ReadDiskAll( int devno, char *buf, int sw )
{
	int		cylno,			/* 読み込み ｼﾘﾝﾀﾞ 番号 */
			headno,			/* 読み込み ﾍｯﾄﾞ 番号 */
			seccnt,			/* 読み込み ｾｸﾀ 数 */
			secnum,			/* 残り ｾｸﾀ 数 */
			maxcylinder,	/* ｼﾘﾝﾀﾞ 最大数 */
			sectorlen,		/* ｾｸﾀ 長 */
			retry,			/* ｴﾗｰ ﾘﾄﾗｲ ｶｳﾝﾀ */
			ret;			/* 戻り値 */
	uint	offset = 0;		/* 読み込み ﾎﾟｲﾝﾀ ｵﾌｾｯﾄ */

	/* ｾｸﾀ 数, ｾｸﾀ ﾚﾝｸﾞｽ, ｼﾘﾝﾀﾞ 数, 設定 */
	switch ( sw ) {
		case TYPE_2HD_12:		/* 2HD 1.2M */
			seccnt = MAXSEC_12;
			maxcylinder = MAXCYL_2HD;
			sectorlen = SECLEN1024;
			break;

		case TYPE_2DD_720:		/* 2DD 720K */
			seccnt = MAXSEC_720;
			maxcylinder = MAXCYL_2DD;
			sectorlen = SECLEN512;
			break;

		case TYPE_2DD_640:		/* 2DD 640K */
			seccnt = MAXSEC_640;
			maxcylinder = MAXCYL_2DD;
			sectorlen = SECLEN512;
			break;

		case TYPE_2HC_12:		/* 2HC 1.2M */
			seccnt = MAXSEC_12C;
			maxcylinder = MAXCYL_2HC;
			sectorlen = SECLEN512;
			break;

		default:
			return NG;
	}

	for ( cylno = 0; cylno < maxcylinder; cylno++ ) {
		retry = 0;
		for ( headno = 0; headno < MAXHEAD; ) {
			/* ﾃﾞｨｽｸ ﾃﾞｰﾀ 読み込み */
			if ( ( ret = DKB_read( devno, cylno, headno, 1,
								seccnt, buf + offset, &secnum ) ) != 0 ) {
				if ( retry < RETRYMAX ) {		/* ｴﾗｰ ﾘﾄﾗｲ */
					retry++;
					continue;
				}
				else {
					ErrMsgPutWord( ERRDISKREAD );	/* ﾃﾞｨｽｸ ﾘｰﾄﾞ ｴﾗｰ */
					return ret;
				}
			}
			else {
				headno++;
				offset += sectorlen * seccnt;
				retry = 0;
			}
		}
	}

	return 0;
}


/************************************************************************
【ディスク書き込み】

		概要	ﾃﾞｨｽｸ の 全 ﾄﾗｯｸ (ｼﾘﾝﾀﾞ) 分の 書き込みを行う。
		用法	WriteDiskAll( devno, buf, sw );
		引数	int		devno			: ﾃﾞﾊﾞｲｽ 番号
				char	*buf			: 書き込み ﾊﾞｯﾌｧ ﾎﾟｲﾝﾀ
				int		sw				: TYPE_2HD_12
										: TYPE_2DD_720
										: TYPE_2DD_640
										: TYPE_2HC_12
		戻り値	int		0x0000			: 正常終了
						0x0002			: ﾃﾞﾊﾞｲｽ 番号 ｴﾗｰ
						0x8???			: ﾊｰﾄﾞ ｴﾗｰ
						NG				: その他の ｴﾗｰ
		注意	無し
************************************************************************/

int WriteDiskAll( int devno, char *buf, int sw )
{
	int		cylno,			/* 書き込み ｼﾘﾝﾀﾞ 番号 */
			headno,			/* 書き込み ﾍｯﾄﾞ 番号 */
			seccnt,			/* 書き込み ｾｸﾀ 数 */
			secnum,			/* 残り ｾｸﾀ 数 */
			maxcylinder,	/* ｼﾘﾝﾀﾞ 最大数 */
			sectorlen,		/* ｾｸﾀ 長 */
			retry,			/* ｴﾗｰ ﾘﾄﾗｲ ｶｳﾝﾀ */
			ret;			/* 戻り値 */
	uint	offset = 0;		/* 書き込み ﾎﾟｲﾝﾀ ｵﾌｾｯﾄ */

	/* ｾｸﾀ 数, ｾｸﾀ ﾚﾝｸﾞｽ, ｼﾘﾝﾀﾞ 数, 設定 */
	switch ( sw ) {
		case TYPE_2HD_12:		/* 2HD 1.2M */
			seccnt = MAXSEC_12;
			maxcylinder = MAXCYL_2HD;
			sectorlen = SECLEN1024;
			break;

		case TYPE_2DD_720:		/* 2DD 720K */
			seccnt = MAXSEC_720;
			maxcylinder = MAXCYL_2DD;
			sectorlen = SECLEN512;
			break;

		case TYPE_2DD_640:		/* 2DD 640K */
			seccnt = MAXSEC_640;
			maxcylinder = MAXCYL_2DD;
			sectorlen = SECLEN512;
			break;

		case TYPE_2HC_12:		/* 2HC 1.2M */
			seccnt = MAXSEC_12C;
			maxcylinder = MAXCYL_2HC;
			sectorlen = SECLEN512;
			break;

		default:
			return NG;
	}

	for ( cylno = 0; cylno < maxcylinder; cylno++ ) {
		retry = 0;
		for ( headno = 0; headno < MAXHEAD; ) {
			if ( FormatFlg == TRUE ) {
				/* ﾌｫｰﾏｯﾄ ﾃﾞｰﾀ 作成 */
				MakeFormData( cylno, headno, sw );
				/* ﾄﾗｯｸ ﾌｫｰﾏｯﾄ */
				if ( ( ret = TrackFormat( devno, cylno, headno ) ) != 0 ) {
					if ( ret & 0x02 ) {
						ErrMsgPutWord( ERRPROTECT );	/* 書き込み禁止 */
						return ret;
					}
					else if ( ret & 0x01 ) {
						ErrMsgPutWord( ERRNOTDISK );	/* ﾄﾞﾗｲﾌﾞ ﾉｯﾄ ﾚﾃﾞｨｰ */
						return ret;
					}
					else {
						if ( retry < RETRYMAX ) {		/* ｴﾗｰ ﾘﾄﾗｲ */
							retry++;
							continue;
						}
						else {
							ErrMsgPutWord( ERRFORMAT );		/* ﾌｫ-ﾏｯﾄ ｴﾗ- */
							return ret;
						}
					}
				}
			}

			/* ﾃﾞｰﾀ ﾃﾞｨｽｸ 書き込み */
			if ( ( ret = DKB_write( devno, cylno, headno, 1,
							seccnt, buf + offset, &secnum ) ) != 0 ) {
				if ( ret & 0x02 ) {
					ErrMsgPutWord( ERRPROTECT );	/* 書き込み禁止 */
					return ret;
				}
				else if ( ret & 0x01 ) {
					ErrMsgPutWord( ERRNOTDISK );	/* ﾄﾞﾗｲﾌﾞ ﾉｯﾄ ﾚﾃﾞｨｰ */
					return ret;
				}
				else {
					if ( retry < RETRYMAX ) {		/* ｴﾗｰ ﾘﾄﾗｲ */
						retry++;
						continue;
					}
					else {
						ErrMsgPutWord( ERRDISKWRITE );	/* ﾃﾞｨｽｸ ﾗｲﾄ ｴﾗｰ */
						return ret;
					}
				}
			}
			else {
				headno++;
				offset += sectorlen * seccnt;
				retry = 0;
 			}
		}
	}

	return 0;
}


/************************************************************************
【１トラックフォーマット】

		概要	ﾃﾞｨｽｸ の 1 ﾄﾗｯｸ (ｼﾘﾝﾀﾞ) 分の ﾌｫｰﾏｯﾄ を行う。
		用法	TrackFormat( devno, cylno, headno );
		引数	int		devno			: ﾃﾞﾊﾞｲｽ 番号
				int		cylno			: ｼﾘﾝﾀﾞ 番号
				int		headno			: ﾍｯﾄﾞ 番号
		戻り値	int		0x0000			: 正常終了
						0x0002			: ﾃﾞﾊﾞｲｽ 番号 ｴﾗｰ
						0x8???			: ﾊｰﾄﾞ ｴﾗｰ
		注意	ﾌｫ-ﾏｯﾄ ﾃﾞｰﾀ は FormDataBuf を使用する
************************************************************************/

int TrackFormat( int devno, int cylno, int headno )
{
	union REGS		regs;
	struct SREGS	sregs;
	ushort			dsdata;
	IntParaBlk		parablk;

/* debug *******************************
	return (DKB_format( devno, cylno, headno, FormDataBuf ));
/***************************************/

	/* ｾｸﾞﾒﾝﾄ ﾃﾞｰﾀ 読み込み */
	_segread( &sregs );
	dsdata = sregs.ds;

	/* 共用 ﾊﾞｯﾌｧ ｱﾄﾞﾚｽ 取得 DOS-Extender ﾌｧﾝｸｼｮﾝ */
	regs.x.ax = 0x250d;
	_int86x( 0x21, &regs, &regs, &sregs );

	/* ﾌｫｰﾏｯﾄ ﾃﾞｰﾀ ﾊﾞｯﾌｧ から 共用 ﾊﾞｯﾌｧ へ ﾃﾞｰﾀ ｺﾋﾟｰ */
	_movedata( (uint)dsdata, (uint)FormDataBuf,
					(uint)sregs.es, regs.x.dx, sizeof(FormDataBuf) );

	/* ﾌｫｰﾏｯﾄ ﾌｧﾝｸｼｮﾝ を DOS-Extender を介して発行 */
	parablk.intno = 0x93;						/* 割り込み番号 */
	parablk.reax = (uint)(0x0a00 | devno);		/* BIOS ﾌｧﾝｸｼｮﾝ 番号 & ﾃﾞﾊﾞｲｽ 番号 */
	regs.x.cx = (uint)cylno;					/* ｼﾘﾝﾀﾞ 番号 */
	parablk.redx = (uint)(headno << 8);			/* ﾍｯﾄﾞ 番号 */
	parablk.rds = (ushort)(regs.x.bx >> 16);	/* 共用 ﾊﾞｯﾌｧ ﾘｱﾙ ｾｸﾞﾒﾝﾄ */
	regs.x.di = regs.x.bx & 0xffff;				/* 共用 ﾊﾞｯﾌｧ ﾘｱﾙ ｵﾌｾｯﾄ */
	parablk.res = 0;							/* 未使用 */
	parablk.rfs = 0;
	parablk.rgs = 0;

	regs.x.ax = 0x2511;							/* ﾘｱﾙ ﾓｰﾄﾞ 割り込み発行 */
	regs.x.dx = (uint)&parablk;					/* ﾊﾟﾗﾒｰﾀ ﾌﾞﾛｯｸ ｵﾌｾｯﾄ */
	sregs.ds = sregs.ss;						/* ﾊﾟﾗﾒｰﾀ ﾌﾞﾛｯｸ ｾｸﾞﾒﾝﾄ */
	_intdosx( &regs, &regs, &sregs );			/* int 21h ax = 2511h 実行 */

	if ( regs.h.ah <= 0x02 )
		return (int)(regs.h.ah);
	else
		return (int)( (regs.x.cx | 0x8000) & 0xffff );
}


/************************************************************************
【フォーマットデータ作成】

		概要	1 ﾄﾗｯｸ (ｼﾘﾝﾀﾞ) 分の ﾌｫｰﾏｯﾄ ﾃﾞｰﾀ 作成を行う。
		用法	MakeFormData( cylno, headno, sw );
		引数	int		cylno			: ｼﾘﾝﾀﾞ 番号
				int		headno			: ﾍｯﾄﾞ 番号
				int		sw				: TYPE_2HD_12
										: TYPE_2DD_720
										: TYPE_2DD_640
										: TYPE_2HC_12
		戻り値	無し
		注意	ﾌｫ-ﾏｯﾄ ﾃﾞｰﾀ は FormDataBuf を使用する
************************************************************************/

void MakeFormData( int cylno, int headno, int sw )
{
	int			i;
	int			secnum,
				secmax;
	char		*p;
	FORMPARA	*secdata;

	/* 作成 ｾｸﾀ 数 & ｾｸﾀ 圧縮 ﾃﾞｰﾀ 設定 */
	switch ( sw ) {
		case TYPE_2DD_640:		/* 2DD 640K */
			secmax = MAXSEC_640;
			secdata = SecData512;
			break;

		case TYPE_2DD_720:		/* 2DD 720K */
			secmax = MAXSEC_720;
			secdata = SecData512;
			break;

		case TYPE_2HC_12:		/* 2HC 1.2M */
			secmax = MAXSEC_12C;
			secdata = SecData512;
			break;

		case TYPE_2HD_12:		/* 2HD 1.2M */
		default:
			secmax = MAXSEC_12;
			secdata = SecData1024;
			break;
	}

	p = FormDataBuf;

	/* ﾌﾟﾚ ｱﾝﾌﾞﾙ ﾃﾞｰﾀ 展開 */
	for ( i = 0; i < PreAmblCnt; i++ ) {
		memset( p, PreAmbl[i].fdata, PreAmbl[i].cnt );
		p += PreAmbl[i].cnt;
	}

	/* ｾｸﾀ ﾃﾞｰﾀ 展開 */
	secdata[3].fdata = cylno;	/* ID TRACK NUMBER */
	secdata[4].fdata = headno;	/* ID SIDE NUMBER */
	for ( secnum = 0; secnum < secmax; secnum++ ) {
		secdata[5].fdata = secnum + 1;	/* ID SECTOR NUMBER */
		for ( i = 0; i < SecData1024Cnt; i++ ) {
			memset( p, secdata[i].fdata, secdata[i].cnt );
			p += secdata[i].cnt;
		}
	}

	/* ﾎﾟｽﾄ ｱﾝﾌﾞﾙ ﾃﾞｰﾀ 展開 */
	memset( p, PosAmbl[0].fdata, PosAmbl[0].cnt );
}


/************************************************************************
【フォーマットタイプチェック】

		概要	ﾃﾞｨｽｸ の ﾌｫ-ﾏｯﾄ ﾀｲﾌﾟ を調べる。
		用法	ChkFormatType( devno );
		引数	int		devno			: ﾃﾞﾊﾞｲｽ 番号
		戻り値	int		TYPE_NOT		: 未対応 ﾃﾞｨｽｸ
						TYPE_2HD_12		: 1.2M 2HD
						TYPE_2DD_720	: 720K 2DD
						TYPE_2DD_640	: 640K 2DD
						TYPE_2HC_12		: 1.2M 2HC
						NG				: ﾃﾞｨｽｸ ｴﾗｰ
		注意	ｼﾘﾝﾀﾞ 2, ﾍｯﾄﾞ 0 の ﾌｫｰﾏｯﾄ ﾁｪｯｸ
				ｾｸﾀ ID を読みだして ﾀｲﾌﾟ を決定する
************************************************************************/

int ChkFormatType( int devno )
{
	DKB_SEC		secid[30];
	uint		mode1tmp,
				mode2tmp,
				cnt;
	int			flg,
				ret;

	/* ｼﾘﾝﾀﾞ 0 ｼ-ｸ & ﾘｾｯﾄ */
	if ( DKB_restore( devno ) != 0 )
		return NG;

	/* ｼﾘﾝﾀﾞ 2 ｼ-ｸ */
	if ( DKB_seek( devno, 2 ) != 0 )
		return NG;

	flg = FALSE;	/* ﾌﾗｸﾞ ｸﾘｱ */
	for ( cnt = 0; cnt < ChkMode1Tbl_Size; cnt++ ) {
		/* ﾄﾞﾗｲﾌﾞ ﾓｰﾄﾞ 仮設定 */
		DKB_setmode( devno, ChkMode1Tbl[cnt], 0x0208 );

		/* ｾｸﾀ ID 取り出し */
		if ( ( ret = DKB_rdsecid( devno, 2, 0, &secid[0] ) ) == 0 ) {
			flg = TRUE;
			break;		/* 正常終了なら ﾙｰﾌﾟ 脱出 */
		}
		else if ( ret & 0x0003 ) {
			return NG;	/* ﾄﾞﾗｲﾌﾞ 異常終了 */
		}
	}

	/* 処理 ﾌﾗｸﾞ ﾁｪｯｸ */
	if ( flg == FALSE )
		return NG;		/* ｾｸﾀ ID 無し */

	/* ﾄﾞﾗｲﾌﾞ ﾓｰﾄﾞ 取り出し */
	DKB_rdmode( devno, &mode1tmp, &mode2tmp );

	/* 30 ｾｸﾀ 分の ID を 読む */
	for ( cnt = 0; cnt < 30; cnt++ ) {
		if ( DKB_rdsecid( devno, 2, 0, &secid[cnt] ) != 0 )
			return NG;
	}

	/* ｾｸﾀ 数の ﾁｪｯｸ */
	flg = FALSE;	/* ﾌﾗｸﾞ ｸﾘｱ */
	for ( cnt = 1; cnt < 30; cnt++ ) {
		if ( secid[0].secno == secid[cnt].secno ) {
			flg = TRUE;
			break;		/* 正常終了なら ﾙｰﾌﾟ 脱出 */
		}
	}

	/* 処理 ﾌﾗｸﾞ ﾁｪｯｸ */
	if ( flg == FALSE )
		return NG;		/* ｾｸﾀ 異常 */

	/* mode 1 作成 */
	mode1tmp &= 0xfc;
	mode1tmp |= (uint)(secid[0].seccnt);

	/* mode 2 作成 */
	mode2tmp &= 0xff00;
	mode2tmp |= cnt;

	/* ﾌｫｰﾏｯﾄ ﾀｲﾌﾟ 選別 */
	if ( mode1tmp == MODE1_12 && mode2tmp == MODE2_12 ) {
		return TYPE_2HD_12;		/* 1.2M 2HD */
	}
	else if ( mode1tmp == MODE1_720 && mode2tmp == MODE2_720 ) {
		return TYPE_2DD_720;	/* 720K 2DD */
	}
	else if ( mode1tmp == MODE1_640 && mode2tmp == MODE2_640 ) {
		return TYPE_2DD_640;	/* 640K 2DD */
	}
	else if ( mode1tmp == MODE1_12C && mode2tmp == MODE2_12C ) {
		return TYPE_2HC_12;		/* 1.2M 2HC */
	}

	return TYPE_NOT;			/* 未対応 ﾃﾞｨｽｸ */
}


/* end of file */
