/* << MSC V5.1 >> [FM-TOWNS] ************************************************
*
*	内部FCB情報取得(MS-DOS汎用)
*	----------------------------------------------------------------------
*	All Rights Reserved, Copyright (C) Y.Hirata 1993.
*	Programmed by Y.Hirata ( NIFTY-ID: NAB03321  パオパオ )
*
*	NOTE: TAB=4
****************************************************************************/

#include <stdio.h>			/*  printf		*/
#include <stdlib.h>			/*  exit		*/
#include <string.h>			/*  str**		*/
#include <dos.h>			/*  intdosx		*/
#include <jctype.h>			/*  iskanji		*/
#include "lib\define.h"		/*  定数宣言	*/
#include "lib\typedef.h"	/*  型宣言		*/
#include "lib\mem.h"		/*  _peek,_poke	*/

static WORD	TopMCB ;
static WORD	RootShell ;
static WORD FCBoff ;
static WORD FCBseg ;

static WORD chkmcb( WORD seg )
/*===========================================================================
*	MCBの有無をﾁｪｯｸ
===========================================================================*/
{
	WORD	mcb ;
	BYTE	mark ;

	if ( seg <= 0x0008 ) return 0 ;
	mcb = TopMCB ;
	for ( ;; ) {
		mark = (BYTE)_peekb( mcb,0 ) ;
		if ( mark != 'M' && mark != 'Z' ) return 0 ;
		if ( mcb + 1 == seg ) return mcb ;
		if ( mark == 'Z' ) return 0 ;
		mcb += ( (WORD)_peek( mcb,3 ) + 1 ) ;	/*  次のMCBｾｸﾞﾒﾝﾄ		*/
	}
}

void putsp( void )
/*===========================================================================
*	空白表示
===========================================================================*/
{
	printf( " " ) ;
}

void unknown( WORD psp )
/*===========================================================================
*	不明表示
===========================================================================*/
{
	if ( psp == 0x0000 ) {
		printf( "<free>" ) ;
	} else if ( psp == 0x0008 ) {
		printf( "<config>" ) ;
	} else if ( psp == RootShell ) {
		printf( "<\\command>" ) ;
	} else if ( psp == _peek( psp,0x16 ) ) {
		printf( "<command>" ) ;
	} else {
		printf( "<N/A>" ) ;
	}
	putsp() ;
}

void ownerdisp( WORD psp )
/*===========================================================================
*	環境変数領域名の表示
===========================================================================*/
{
	register WORD	ep ;
	register BYTE	ch ;
	WORD	mcb, env, size ;
	WORD	len ;

	if ( !psp ) return ;
	if ( psp == _psp ) return ;					/*  自分自身			*/
	env = (WORD)_peek( psp,0x2C ) ;
	if ( !(mcb  = chkmcb( env )) ) {
		if ( psp == RootShell ) {
			printf( "<\\command>" ) ;
		} else if ( psp == _peek( psp,0x16 ) ) {
			printf( "<command>" ) ;
		}
		return ;
	}
	size = (WORD)_peek( mcb,3 ) ;				/*  MCB管理のﾒﾓﾘｻｲｽﾞ	*/
	if ( size >= 0x1000 ) return unknown( psp ) ;	/*  64KB以上は無視	*/
	size <<= 4 ;								/*  ﾊﾟﾗｸﾞﾗﾌ→ﾊﾞｲﾄ		*/
	ep = 0 ;
	while ( _peek( env,ep ) != 0x0000 ) ep++ ;	/*  環境変数の終端検索	*/
	ep += 2 ;
	if ( ep >= size ) return unknown( psp ) ;	/*  環境ｾｸﾞﾒﾝﾄ外		*/
	if ( _peek( env,ep ) == 0x0001 ) {			/*  実行ﾌﾟﾛｸﾞﾗﾑ名検索	*/
		ep += 2 ;
		if ( ep >= size ) return unknown( psp ) ;	/*  環境ｾｸﾞﾒﾝﾄ外	*/
	} else {
		return unknown( psp ) ;					/*  環境ｾｸﾞﾒﾝﾄ			*/
	}
	for ( len=ep;; len++ ) {
		ch = (BYTE)_peekb( env,len ) ;
		if ( iskanji( ch ) ) {
			len++ ;
		} else {
			if ( ch == '.' || len >= size ) break ;
			if ( ch == '\\' || ch == '\0' ) ep = len + 1 ;
		}
	}
	for ( len=0; ep<size; ep++, len++ ) {		/*  実行ﾌﾟﾛｸﾞﾗﾑ名表示	*/
		ch = (BYTE)_peekb( env,ep ) ;
		if ( ch == '\0' ) break ;
		printf( "%c",ch ) ;
	}
}

static void fnamedisp( WORD seg,WORD off )
/*===========================================================================
*	ﾌｧｲﾙ名表示(via FCB)
===========================================================================*/
{
	char	fname[9] ;

	movedata( seg,off,_seg( fname ),_off( fname ),8 ) ;
	fname[8] = '\0' ;
	printf( "%-8s.",fname ) ;								/*  fname	*/
	movedata( seg,off+8,_seg( fname ),_off( fname ),3 ) ;
	fname[3] = '\0' ;
	printf( "%-3s ",fname ) ;								/*  ext		*/
}

static void accessdisp( BYTE access )
/*===========================================================================
*	open mode 表示
===========================================================================*/
{
	switch ( ( access & 0x0F ) ) {
	case 0	:
		printf( "R  " ) ;	break ;
	case 1	:
		printf( "  W" ) ;	break ;
	case 2	:
		printf( "R/W" ) ;	break ;
	default	:
		printf( "???" ) ;	break ;
	}
	putsp() ;
}

static void attrdisp( BYTE attr )
/*===========================================================================
*	ﾌｧｲﾙ属性表示
===========================================================================*/
{
	printf( attr & 0x01 ? "r" : "-" ) ;
	printf( attr & 0x02 ? "h" : "-" ) ;
	printf( attr & 0x04 ? "s" : "-" ) ;
	if ( attr & 0x10 ) {
		printf( "d" ) ;
	} else if ( attr & 0x08 ) {
		printf( "v" ) ;
	} else if ( attr & 0x20 ) {
		printf( "a" ) ;
	} else {
		printf( "-" ) ;
	}
	putsp() ;
}

static void dispv2( WORD seg,WORD off )
/*===========================================================================
*	v2.x system file tables
===========================================================================*/
{
	WORD	nseg, noff ;
	WORD	nblk ;
	BYTE	files=0 ;
	DWORD	size ;

	printf( "No. FileTable FileName     Ref R/W Attr Bytes   \n" ) ;
	printf( "--- --------- ------------ --- --- ---- ------- \n" ) ;
	for ( ;; ) {
		if ( off == 0xFFFF ) break ;
		noff = (WORD)_peek( seg,off ) ;
		nseg = (WORD)_peek( seg,off+2 ) ;
		nblk = (WORD)_peek( seg,off+4 ) ;
		off += 6 ;
		while ( nblk-- ) {
			if ( _peekb( seg,off+0x04 ) ) {
				printf( "%3u ",files ) ;					/*  No.		*/
				printf( "%04X:%04X ",seg,off ) ;			/*  table	*/
				fnamedisp( seg,off+0x04 ) ;					/*  fname	*/
				printf( "%3d ",_peekb( seg,off ) ) ;		/*  Ref		*/
				accessdisp( _peekb( seg,off+1 ) ) ;			/*  R/W		*/
				attrdisp( _peekb( seg,off+2 ) ) ;			/*  attr	*/
				size = (DWORD)_peek( seg,off+0x15 ) << 16 ;
				size |= ( (DWORD)_peek( seg,off+0x13 ) & 0xFFFFL ) ;
				printf( "%7lu ",size ) ;					/*  size	*/
				off += 0x28 ;
				printf( "\n" ) ;
			}
			files++ ;
		}
		off = noff ;
		seg = nseg ;
	}
	printf( "\n( FILES=%u )\n",files ) ;
}

static void dispv3( WORD seg,WORD off )
/*===========================================================================
*	v3.x system file tables and FCB tables
===========================================================================*/
{
	WORD	nseg, noff ;
	WORD	nblk, psp ;
	BYTE	files=0 ;
	DWORD	size ;

	printf( "No. FileTable FileName     Ref.  R/W Attr Bytes   " ) ;
	printf( "PSP  Owner       \n" ) ;
	printf( "--- --------- ------------ ----- --- ---- ------- " ) ;
	printf( "---- ------------\n" ) ;
	for ( ;; ) {
		if ( off == 0xFFFF ) break ;
		noff = (WORD)_peek( seg,off ) ;
		nseg = (WORD)_peek( seg,off+2 ) ;
		nblk = (WORD)_peek( seg,off+4 ) ;
		off += 6 ;
		while ( nblk-- ) {
			psp = (WORD)_peek( seg,off+0x31 ) ;
			if ( psp && _peekb( seg,off+0x20 ) ) {
				printf( "%3u ",files ) ;					/*  No.		*/
				printf( "%04X:%04X ",seg,off ) ;			/*  table	*/
				fnamedisp( seg,off+0x20 ) ;					/*  fname	*/
				printf( "%5d ",_peek( seg,off ) ) ;			/*  Ref		*/
				accessdisp( (BYTE)_peek( seg,off+2 ) ) ;	/*  R/W		*/
				attrdisp( _peekb( seg,off+4 ) ) ;			/*  attr	*/
				size = (DWORD)_peek( seg,off+0x13 ) << 16 ;
				size |= ( (DWORD)_peek( seg,off+0x11 ) & 0xFFFFL ) ;
				printf( "%7lu ",size ) ;					/*  size	*/
				printf( "%04X ",psp ) ;						/*	PSP		*/
				ownerdisp( psp ) ;
				off += 0x35 ;
				printf( "\n" ) ;
			}
			files++ ;
		}
		off = noff ;
		seg = nseg ;
	}
	printf( "\n( FILES=%u )\n",files ) ;
}

static void dispv4( WORD seg,WORD off )
/*===========================================================================
*	v4.x system file tables and FCB tables
===========================================================================*/
{
	WORD	nseg, noff ;
	WORD	nblk, psp ;
	BYTE	files=0 ;
	DWORD	size ;

	printf( "No. FileTable FileName     Ref.  R/W Attr Bytes   " ) ;
	printf( "PSP  Owner       \n" ) ;
	printf( "--- --------- ------------ ----- --- ---- ------- " ) ;
	printf( "---- ------------\n" ) ;
	for ( ;; ) {
		if ( off == 0xFFFF ) break ;
		noff = (WORD)_peek( seg,off ) ;
		nseg = (WORD)_peek( seg,off+2 ) ;
		nblk = (WORD)_peek( seg,off+4 ) ;
		off += 6 ;
		while ( nblk-- ) {
			psp = (WORD)_peek( seg,off+0x31 ) ;
			if ( psp && _peekb( seg,off+0x20 ) ) {
				printf( "%3u ",files ) ;					/*  No.		*/
				printf( "%04X:%04X ",seg,off ) ;			/*  table	*/
				fnamedisp( seg,off+0x20 ) ;					/*  fname	*/
				printf( "%5d ",_peek( seg,off ) ) ;			/*  Ref		*/
				accessdisp( (BYTE)_peek( seg,off+2 ) ) ;	/*  R/W		*/
				attrdisp( _peekb( seg,off+4 ) ) ;			/*  attr	*/
				size = (DWORD)_peek( seg,off+0x13 ) << 16 ;
				size |= ( (DWORD)_peek( seg,off+0x11 ) & 0xFFFFL ) ;
				printf( "%7lu ",size ) ;					/*  size	*/
				printf( "%04X ",psp ) ;						/*	PSP		*/
				ownerdisp( psp ) ;
				off += 0x3B ;
				printf( "\n" ) ;
			}
			files++ ;
		}
		off = noff ;
		seg = nseg ;
	}
	printf( "\n( FILES=%u )\n",files ) ;
}

void fcbdisp( void )
/*===========================================================================
*	内部FCB情報表示
===========================================================================*/
{
	union	REGS	regs ;
	struct	SREGS	sregs ;

	regs.h.ah = 0x52 ;							/*  ｼｽﾃﾑﾊﾟﾗﾒﾀﾃｰﾌﾞﾙ取得	*/
	intdosx( &regs,&regs,&sregs ) ;
	TopMCB = (WORD)_peek( sregs.es,regs.x.bx-2 ) ;
	FCBoff = (WORD)_peek( sregs.es,regs.x.bx+4 ) ;
	FCBseg = (WORD)_peek( sregs.es,regs.x.bx+6 ) ;
	RootShell = (WORD)_peek( 0,0x2E*4+2 ) ;		/*  先頭commandｾｸﾞﾒﾝﾄ	*/
#if 0
	printf( "内部FCBﾃｰﾌﾞﾙ=%04X:%04X\n",FCBseg,FCBoff ) ;
#endif

	printf( "\n" ) ;
	if ( _osmajor < 3 ) {						/*  〜v2.x				*/
		dispv2( FCBseg,FCBoff ) ;
	} else if ( _osmajor < 4 ) {				/*  v3.0〜				*/
		dispv3( FCBseg,FCBoff ) ;
	} else {									/*  v4.0〜				*/
		dispv4( FCBseg,FCBoff ) ;
	}
}

static void appendix( void )
/*===========================================================================
*	解説表示
===========================================================================*/
{
	printf( "FCB(File Control Block)情報表示 Version 1.00 " ) ;
	printf( " (C) パオパオ 1993.\n" ) ;
	printf( "\n" ) ;
	printf( "No. FileTable FileName     Ref.  R/W Attr Bytes   " ) ;
	printf( "PSP  Owner       \n" ) ;
	printf( "--- --------- ------------ ----- --- ---- ------- " ) ;
	printf( "---- ------------\n" ) ;
	printf( "No.      : ファイル番号(file handle)\n" ) ;
	printf( "FileTable: file tables and FCB tables 格納アドレス\n" ) ;
	printf( "FileName : ファイル名\n" ) ;
	printf( "Ref.     : このファイルを参照しているファイルハンドルの数\n" ) ;
	printf( "R/W      : ファイルオープン時のアクセスモード\n" ) ;
	printf( "Attr     : ファイル属性" ) ;
	printf( "(R=Read Only, H=Hidden, S=System, A=Archive)\n" ) ;
	printf( "Bytes    : ファイルサイズ\n" ) ;
	printf( "PSP      : ファイルのオープンを要求したPSPセグメント\n" ) ;
	printf( "Owner    : ファイルのオープンを要求したプロセス名\n" ) ;
	exit( 1 ) ;
}

void main( int ac )
/*===========================================================================
*	ﾒｲﾝ
===========================================================================*/
{
	if ( ac > 1 ) appendix() ;
	fcbdisp() ;

	exit( 0 ) ;
}

