/* << MSC V5.1 >> [FM-TOWNS] ************************************************
*
*	ｶﾚﾝﾄﾄﾞﾗｲﾌﾞのｾｸﾀﾀﾞﾝﾌﾟﾌﾟﾛｸﾞﾗﾑ(MS-DOS汎用)
*	----------------------------------------------------------------------
*	All Rights Reserved, Copyright (C) Y.Hirata 1993.
*	Programmed by Y.Hirata ( NIFTY-ID: NAB03321  パオパオ )
*
*	NOTE: TAB=4
****************************************************************************/

#include <stdio.h>			/*  printf,putchar	*/
#include <stdlib.h>			/*  exit		*/
#include <string.h>			/*  str*		*/
#include <jctype.h>			/*  iskanji*	*/
#include <direct.h>			/*  getcwd		*/
#include <conio.h>			/*  getch		*/

#include "lib\define.h"		/*  定数宣言	*/
#include "lib\typedef.h"	/*  型宣言		*/
#include "lib\mem.h"		/*  _peek		*/
#include "lib\dirlib.h"		/*  <dos.h>,_aread	*/
#include "lib\doscall.h"	/*  <dos.h>,_getDPB	*/
#include "lib\crt.h"		/*  ANK,･･･		*/

#define isdisp(c)  ((0x20 <= c && c < 0x7F) || (0xA0 <= c && c <= 0xDF))

_DPB	_dpb ;									/*  DPB情報				*/
int		FATbit ;								/*  FATﾋﾞｯﾄｻｲｽﾞ			*/

unsigned	_cdrv ;								/*  ｶﾚﾝﾄﾄﾞﾗｲﾌﾞ			*/
char		*_cdir ;							/*  ｶﾚﾝﾄﾃﾞｨﾚｸﾄﾘ			*/
char		_abspath[128] ;						/*  物理ﾊﾟｽ名			*/
BYTE		*_sctbuf ;							/*  ｾｸﾀ領域				*/
DWORD		_fsector ;							/*  開始ｾｸﾀ番号			*/
DWORD		_nsector ;							/*  読み取りｾｸﾀ数		*/

#define	LINEpPAGE			24					/*  1画面の行数			*/
int			_linecnt ;							/*  表示行数			*/

struct {
	unsigned	critical:1 ;	/*  致命的ｴﾗｰ発生ﾌﾗｸﾞ	*/
	unsigned	fat:1 ;			/*  FAT読み込み済ﾌﾗｸﾞ	*/
	unsigned	sct32:1 ;		/*  32bitｻﾎﾟｰﾄﾌﾗｸﾞ		*/
	unsigned	page:1 ;		/*  ﾍﾟｰｼﾞ制御			*/
} _flg ;										/*  処理ﾌﾗｸﾞ			*/

void putcrlf( void )
/*===========================================================================
*	改行表示
===========================================================================*/
{
	putchar( '\n' ) ;
	if ( !_flg.page ) return ;
	if ( ++_linecnt > LINEpPAGE-2 ) {
		printf( "--- more ---" ) ;
		getch() ;
		putchar( '\n' ) ;
		_linecnt=0 ;
	}
}

void getDPB( void )
/*===========================================================================
*	DPB情報取得
===========================================================================*/
{
	WORD	attr ;

	_getDPB( _cdrv,&_dpb ) ;
	if ( _dpb.maxclst < 0x0FF7 ) {
		FATbit  = 12 ;							/*  12bit FAT		*/
	} else {
		FATbit  = 16 ;							/*  16bit FAT		*/
	}
	if ( _osmajor >= 10 ) {						/*  OS/2互換BOX		*/
		_flg.sct32 = 1 ;
		return ;
	}
	attr = (WORD)_peek( _dpb.dseg,_dpb.doff+4 ) ;
	_flg.sct32 = ( attr & 0x0002 ) ? 1 : 0 ;	/*  32bitｾｸﾀｻﾎﾟｰﾄ?	*/
}

int absRead( WORD nsct,DWORD sctno,void *buf )
/*===========================================================================
*	物理読み込み
*	< IN  >	: nsct	読み込みｾｸﾀ数
*			: sctno	読み込み開始ｾｸﾀ番号
*			: buf	ﾃﾞｰﾀ格納先ｱﾄﾞﾚｽ
*	< OUT >	: buf	読み込んだﾃﾞｰﾀ
*	< RET >	: 下位ﾊﾞｲﾄにｴﾗｰｺｰﾄﾞを返す. (上位ﾊﾞｲﾄ=00h:正常終了, =01h:ｴﾗｰ発生)
*				=00h	書き込み禁止である
*				=01h	ﾕﾆｯﾄが存在しない
*				=02h	ﾄﾞﾗｲﾌﾞの準備ができていない
*				=03h	存在しないｺﾏﾝﾄﾞである
*				=04h	ﾃﾞｰﾀのCRCｴﾗｰ
*				=05h	ﾊﾞｯﾄﾞﾄﾞﾗｲﾌﾞﾘｸｴｽﾄｽﾄﾗｸﾁｬの長さ
*				=06h	ｼｰｸｴﾗｰ
*				=07h	存在しないﾒﾃﾞｨｱﾀｲﾌﾟである
*				=08h	ｾｸﾀが存在しない
*				=09h	ﾌﾟﾘﾝﾀの用紙切れ
*				=0Ah	書き込み不良
*				=0Bh	読み込み不良
*				=0Ch	一般的なﾃﾞｨｽｸ不良
*				=0Fh	不正なﾒﾃﾞｨｱ交換があった
===========================================================================*/
{
	struct {
		DWORD	sctno ;							/*  32bitｾｸﾀ番号		*/
		WORD	nsct ;							/*  R/Wｾｸﾀ数			*/
		WORD	off ;							/*  ﾊﾞｯﾌｧｵﾌｾｯﾄ			*/
		WORD	seg ;							/*  ﾊﾞｯﾌｧｾｸﾞﾒﾝﾄ			*/
	} packet ;

	if ( _flg.sct32 ) {							/*  32bitｾｸﾀｻﾎﾟｰﾄ		*/
		packet.sctno = sctno ;
		packet.nsct  = nsct ;
		packet.off   = _off( buf ) ;
		packet.seg   = _seg( buf ) ;
		return _aread( _cdrv-1,-1,-1,&packet ) ;
	}
	return _aread( _cdrv-1,nsct,(WORD)sctno,buf ) ;
}

void dispTitle( DWORD fsector )
/*===========================================================================
*	ｾｸﾀﾀﾞﾝﾌﾟのﾀｲﾄﾙ表示
*	< IN  >	: fsector	開始ｾｸﾀ番号
===========================================================================*/
{
	putcrlf() ;
	printf( "< セクタ番号 %lXh >",fsector ) ;
	putcrlf() ;
	printf( "---- + -- -- -- -- -- -- -- -- . " ) ;
	printf( "-- -- -- -- -- -- -- -- + -------- -------- " ) ;
	putcrlf() ;
}

int dispKanji( int kanji1,int kanji2 )
/*===========================================================================
*	漢字表示(漢字1ﾊﾞｲﾄ目確定, 2ﾊﾞｲﾄ目非確定時の処理)
*	< IN  >	: kanji1	漢字1ﾊﾞｲﾄ目
*			: kanji2	漢字2ﾊﾞｲﾄ目
*	< RET >	: 漢字表示有無
*				=0	漢字表示(2ﾊﾞｲﾄ表示)
*				=1	非漢字表示(1ﾊﾞｲﾄ表示)
===========================================================================*/
{
	if ( iskanji2( kanji2 ) ) {					/*  漢字表示			*/
		putchar( kanji1 ) ;
		putchar( kanji2 ) ;
		return 0 ;
	} else {									/*  制御文字表示		*/
		putchar( '.' ) ;
		return 1 ;
	}
}

void dispAscii( WORD off,int *prech,int *kanji )
/*===========================================================================
*	ASCII/S-JIS表示
*	< IN  >	: off	ｵﾌｾｯﾄ
*			: prech	ひとつ前の値
*			: kanji	漢字ﾁｪｯｸﾌﾗｸﾞ
*	< OUT >	: prech	最後の値(漢字1ﾊﾞｲﾄ目)
*			: kanji	漢字ﾁｪｯｸﾌﾗｸﾞ
===========================================================================*/
{
	register WORD	cnt ;

	if ( *kanji != ANK ) {						/*  先頭が漢字2ﾊﾞｲﾄ目	*/
		putchar( ' ' ) ;
		*kanji = ANK ;
	} else {
		*kanji = iskanji( _sctbuf[off] ) ? KANJI1 : ANK ;
		if ( *kanji == ANK ) {					/*  漢字1ﾊﾞｲﾄ目以外		*/
			if ( isdisp( _sctbuf[off] ) )		/*  表示可能文字		*/
				putchar( _sctbuf[off] ) ;
			else								/*  制御文字等			*/
				putchar( '.' ) ;
		} else									/*  漢字1ﾊﾞｲﾄ目=保留	*/
			*prech = _sctbuf[off] ;
	}
	off++ ;
	for ( cnt=1; cnt<16; cnt++, off++ ) {		/*  2文字目以降表示		*/
		if ( cnt == 8 && *kanji == ANK ) putchar( ' ' ) ;
		if ( off < _dpb.bps ) {					/*  ﾃﾞｰﾀ読取範囲内		*/
			if ( *kanji != ANK ) {				/*  漢字2ﾊﾞｲﾄ目?		*/
				if ( dispKanji( *prech,_sctbuf[off] ) ) {
					*kanji = iskanji( _sctbuf[off] ) ? KANJI1 : ANK ;
				} else							/*  漢字表示済			*/
					*kanji = KANJI2 ;
				if ( cnt == 8 ) putchar( ' ' ) ;
			} else {							/*  漢字1ﾊﾞｲﾄ目/ANK		*/
				*kanji = iskanji( _sctbuf[off] ) ? KANJI1 : ANK ;
			}
			if ( *kanji == ANK ) {				/*  ANK(漢字以外)		*/
				if ( isdisp( _sctbuf[off] ) )
					putchar( _sctbuf[off] ) ;
				else
					putchar( '.' ) ;
			} else								/*  漢字1ﾊﾞｲﾄ目=保留	*/
				*prech = _sctbuf[off] ;
			if ( *kanji == KANJI2 ) *kanji = ANK ;
		} else									/*  ﾃﾞｰﾀ読取範囲外		*/
			putchar( '.' ) ;
	}
}

int dispSector( DWORD sector )
/*===========================================================================
*	ｾｸﾀ内容表示
*	< IN  >	: sector	ｾｸﾀ番号
*	< RET >	: 最後の表示有無
*				=0	ANK(表示済)
*				=1	未表示(最後の1ﾊﾞｲﾄ表示待ち)
===========================================================================*/
{
	register WORD	cnt, off=0 ;
	static int	prech=0, kanji=ANK ;

	if ( kanji != ANK ) {						/*  前回未表示分あり	*/
		if ( dispKanji( prech,_sctbuf[0] ) ) kanji = ANK ;
	}
	dispTitle( sector ) ;						/*  ﾀｲﾄﾙ表示			*/
	for ( off=0; off<_dpb.bps; off+=16 ) {
		if ( off ) {
			if ( kanji != ANK ) {				/*  前行未表示分あり	*/
				if ( dispKanji( prech,_sctbuf[off] ) ) kanji = ANK ;
			}
			putcrlf() ;							/*  改行				*/
		}
		printf( "%04X |",off ) ;				/*  ｵﾌｾｯﾄ表示			*/
		for ( cnt=0; cnt<16; cnt++, off++ ) {	/*  dump				*/
			if ( cnt == 8 ) printf( " -" ) ;
			if ( off < _dpb.bps )				/*  ﾃﾞｰﾀ読取範囲内		*/
				printf( " %02X",_sctbuf[off] ) ;
			else								/*  ﾃﾞｰﾀ読取範囲外		*/
				printf( " .." ) ;
		}
		off -= 16 ;
		printf( " | " ) ;
		dispAscii( off,&prech,&kanji ) ;		/*  ASCII/S-JIS表示		*/
	}
	return kanji==ANK ? 0 : 1 ;
}

int dump( void )
/*===========================================================================
*	ｾｸﾀﾀﾞﾝﾌﾟ
*	< RET >	: ｴﾗｺｰﾄﾞを返す.
*				=0	正常終了
*				=1	ｾｸﾀ読み込み失敗
===========================================================================*/
{
	DWORD	cnt ;
	int		ret ;

	for ( cnt=0L; cnt<_nsector; cnt++ ) {
		ret = absRead( 1,_fsector+cnt,_sctbuf ) ;
		if ( ret ) {
			printf( "\aセクタ読み込み失敗 _aread error : %02Xh",_lo(ret) ) ;
			printf( ", セクタ番号 %lXh",_fsector+cnt ) ;
			putcrlf() ;
			return 1 ;
		}
		ret = dispSector( _fsector+cnt ) ;		/*  ｾｸﾀ内容表示			*/
	}
	if ( ret ) putchar( '.' ) ;
	putcrlf() ;
	return 0 ;
}

int abschk( void )
/*===========================================================================
*	物理ｱｸｾｽのﾁｪｯｸ
===========================================================================*/
{
	if ( getabspath( _cdir,_abspath ) ) {		/*  物理ﾊﾟｽ名取得		*/
		_flg.critical = 1 ;
		printf( "\a ドライブの指定が違います." ) ;
		putcrlf() ;
		return 1 ;
	}
	if ( isnetdrv( _cdrv ) ) {					/*  ﾘﾓｰﾄ				*/
		putcrlf() ;
		printf( "\a %c: はリモートドライブ",_cdrv+'@' ) ;
		printf( "(DOSによる物理アクセス不可)のため扱えません." ) ;
		putcrlf() ;
		return 1 ;
	}
	if ( isjoindrv( _cdrv ) || stricmp( _cdir,_abspath ) ) {
		putcrlf() ;
		printf( "\a このドライブは再割当されています." ) ;
		putcrlf() ;
		printf( "   物理パス名は %s",_abspath ) ;
		putcrlf() ;
	}
	return 0 ;
}

int init( void )
/*===========================================================================
*	初期処理
*	< RET >	: ｴﾗｺｰﾄﾞを返す.
*				=0	正常終了
*				=1	ﾒﾓﾘ不足
*				=2	物理ｱｸｾｽ不可
===========================================================================*/
{
	_flg.critical = 0 ;
	resetdisk() ;								/*  ﾘｾｯﾄﾃﾞｨｽｸ			*/
	_dos_getdrive( &_cdrv ) ;					/*  ｶﾚﾝﾄﾄﾞﾗｲﾌﾞ			*/
	_cdir = getcwd( NULL,_MAX_DIR ) ;			/*  ｶﾚﾝﾄﾃﾞｨﾚｸﾄﾘ取得		*/
	if ( abschk() ) return 2 ;					/*  物理ｱｸｾｽﾁｪｯｸ		*/
	getDPB() ;									/*  DPB情報取得			*/
	if ( (_sctbuf = (BYTE *)malloc( _dpb.bps )) == NULL ) {
		printf( "\a作業領域(%dbyte)が確保できませんでした.",_dpb.bps ) ;
		putcrlf() ;
		return 1 ;
	}
	return 0 ;
}

void dispDpb( void )
/*===========================================================================
*	ﾃﾞｨｽｸ情報表示
===========================================================================*/
{
	putcrlf() ;
	printf( "< %d bit FAT >",FATbit ) ;
	if ( _flg.sct32 ) printf( " ( 32bitセクタ番号サポート )" ) ;
	putcrlf() ;
	printf( "bytes/sector .................. %u",_dpb.bps ) ;
	putcrlf() ;
	printf( "sectors/cluster ............... %u",_dpb.spc+1 ) ;
	putcrlf() ;
	printf( "reserved sectors .............. %u",_dpb.res ) ;
	putcrlf() ;
	printf( "sectors/FAT ................... %u",_dpb.spf ) ;
	putcrlf() ;
	printf( "first data sector ............. %04Xh",_dpb.fds ) ;
	putcrlf() ;
	printf( "first sector of root directry . %04Xh",_dpb.fsr ) ;
	putcrlf() ;
}

void usage( void )
/*===========================================================================
*	使用方法表示
===========================================================================*/
{
	printf( "セクタダンプ (C) パオパオ 1993.\n\n" ) ;
	printf( "Usage: sdump 開始セクタ番号 [セクタ数] [-p]\n" ) ;
	printf( "       -p   １画面毎表示\n" ) ;
	printf( "( 16進数値は, ********H です. )\n" ) ;
	exit( 1 ) ;
}

void swchk( char *str )
/*===========================================================================
*	ｵﾌﾟｼｮﾝｽｲｯﾁ評価
===========================================================================*/
{
	register int	cnt ;

	for ( cnt=0; cnt<strlen(str); cnt++ ) {
		if ( str[cnt] == '-' || str[cnt] == '/' ) continue ;
		switch ( str[cnt] ) {
		case 'p'	:
		case 'P'	:
			_flg.page = TRUE ;		break ;
		default		:
			usage() ;
		}
	}
}

int atoc( BYTE ch,int radix )
/*===========================================================================
*	文字→数字
===========================================================================*/
{
	if ( ch >= '0' && ch <= '9' ) return ( ch - '0' ) ;
	if ( radix == 16 ) {
		if ( ch >= 'a' && ch <= 'f' ) return ( ch - 'a' + 10 ) ;
		if ( ch >= 'A' && ch <= 'F' ) return ( ch - 'A' + 10 ) ;
	}
	printf( "\a数値の指定に誤りがあります.\n" ) ;
	exit( 1 ) ;
}

DWORD atohl( char *str )
/*===========================================================================
*	文字列→数字(double word)
===========================================================================*/
{
	register int	cnt ;
	int		len=strlen( str ) ;
	BYTE	ch ;
	DWORD	val=0L ;

	ch = str[len-1] ;
	if ( ch == 'h' || ch == 'H' ) {				/*  16進数				*/
		for ( cnt=0; cnt<len-1; cnt++ ) {
			val <<= 4 ;
			val += (DWORD)atoc( str[cnt],16 ) ;
		}
	} else {									/*  10進数				*/
		for ( cnt=0; cnt<len; cnt++ ) {
			val *= 10L ;
			val += (DWORD)atoc( str[cnt],10 ) ;
		}
	}
	return val ;
}

int main( int ac,char *av[] )
/*===========================================================================
*	ﾒｲﾝ
===========================================================================*/
{
	int		ret, cnt ;

	if ( ac < 2 ) usage() ;						/*  使用方法表示		*/
	_flg.page = 0 ;
	_linecnt  = 0 ;
	_nsector  = 1L ;
	for ( ret=0, cnt=1; cnt<ac; cnt++ ) {
		if ( *av[cnt] == '-' || *av[cnt] == '/' )
			swchk( av[cnt]+1 ) ;				/*  引数ﾁｪｯｸ			*/
		else {
			switch ( ret ) {
			case 0	:
				_fsector = atohl( av[cnt] ) ;	/*  開始ｾｸﾀ番号			*/
				ret++ ;
				break ;
			case 1	:
				_nsector = atohl( av[cnt] ) ;	/*  読み取りｾｸﾀ数		*/
				ret++ ;
				break ;
			default	:
				usage() ;						/*  使用方法表示		*/
			}
		}
	}
	ret = init() ;								/*  初期処理			*/
	if ( ret != 2 ) dispDpb() ;					/*  ﾃﾞｨｽｸ情報表示		*/
	if ( !ret ) dump() ;						/*  ｾｸﾀﾀﾞﾝﾌﾟ			*/
	if ( _sctbuf != NULL ) free( _sctbuf ) ;	/*  ﾃﾞｰﾀｸﾘｱ				*/
	resetdisk() ;								/*  ﾘｾｯﾄﾃﾞｨｽｸ			*/

	return 0 ;
}

