/* << MSC V5.1 >> [FM-TOWNS] ************************************************
*
*	MCBリンク表示 (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 <conio.h>			/*  getch		*/
#include "lib\define.h"		/*  定数宣言	*/
#include "lib\typedef.h"	/*  型宣言		*/
#include "lib\mem.h"		/*  _peek,_poke	*/

WORD	TopMCB ;								/*  先頭MCBｾｸﾞﾒﾝﾄ		*/
WORD	TopShell ;								/*  先頭command.com		*/
WORD	DEVoff ;								/*  先頭ﾃﾞﾊﾞｲｽﾍｯﾀﾞ		*/
WORD	DEVseg ;								/*  先頭ﾃﾞﾊﾞｲｽﾍｯﾀﾞ		*/
BYTE	LastDrv = 0 ;							/*  LASTDRIVE(in CONFIG)*/
WORD	Vect[256] ;								/*  ﾍﾞｸﾀﾃｰﾌﾞﾙ			*/
WORD	MYenv ;									/*  自分の環境ｾｸﾞﾒﾝﾄ	*/
WORD	CMDlen = 21 ;							/*  ｺﾏﾝﾄﾞﾗｲﾝ表示文字数	*/
WORD	DOSver ;								/*  MS-DOS Version識別	*/
WORD	ROOTpsp = 0 ;							/*  ﾙｰﾄのCOMMAND.COM	*/
WORD	ROOTenv = 0 ;							/*  ﾙｰﾄの環境ｾｸﾞﾒﾝﾄ		*/
WORD	PSPseg = 0 ;							/*  親のPSPｾｸﾞﾒﾝﾄ		*/
WORD	ENVseg = 0 ;							/*  親の環境ｾｸﾞﾒﾝﾄ		*/

extern int emmdisp( void ) ;					/*  EMS表示				*/

#define	LINEpPAGE			24					/*  1画面の行数			*/
int			_linecnt = 0 ;						/*  表示行数			*/

struct {
	unsigned	env:1 ;							/*  環境ｾｸﾞﾒﾝﾄ表示		*/
	unsigned	dev:1 ;							/*  ﾃﾞﾊﾞｲｽﾄﾞﾗｲﾊﾞ表示	*/
	unsigned	page:1 ;						/*  ﾍﾟｰｼﾞ制御			*/
} _option = { 0 } ;

void putcrlf( void )
/*===========================================================================
*	改行表示
===========================================================================*/
{
	putchar( '\n' ) ;
	_linecnt++ ;
	if ( _option.page && _linecnt > LINEpPAGE-2 ) {
		printf( "--- more ---" ) ;
		getch() ;
		putchar( '\n' ) ;
		_linecnt=0 ;
	}
}

void titledisp( void )
/*===========================================================================
*	ﾀｲﾄﾙ表示
===========================================================================*/
{
	printf( "PSP  MCB  bytes    親  環境 Owner / Parameters    " ) ;
	printf( "Hooked Vectors               " ) ;
	putcrlf() ;
	printf( "---- ---- ------- ---- ---- --------------------- " ) ;
	printf( "-----------------------------" ) ;
	putcrlf() ;
}

void vectdisp( WORD psp,WORD len )
/*===========================================================================
*	ﾌｯｸﾍﾞｸﾀ表示
===========================================================================*/
{
	register WORD	cnt ;
	WORD	ndisp, mcb, next ;

	for ( cnt=len; cnt<=CMDlen; cnt++ ) putchar( ' ' ) ;
	mcb = psp - 1 ;									/*  ﾌﾟﾛｸﾞﾗﾑのMCB	*/
	next = mcb + (WORD)_peek( mcb,3 ) + 1 ;			/*  次のMCBｾｸﾞﾒﾝﾄ	*/
	for ( cnt=ndisp=0; cnt<256; cnt++ ) {			/*  00〜FFのﾍﾞｸﾀ	*/
		if ( Vect[cnt] >= psp && Vect[cnt] < next ) {
			if ( ndisp == 10 || len > CMDlen ) {
				putcrlf() ;
 				printf( "%50s"," " ) ;
				ndisp = len = 0 ;
			}
			if ( ndisp ) putchar( ' ' ) ;
			printf( "%02X",cnt ) ;
			ndisp++ ;
		}
	}
}

WORD devicedisp( WORD mcb,WORD len )
/*===========================================================================
*	ﾃﾞﾊﾞｲｽﾍｯﾀﾞ表示
===========================================================================*/
{
	register int	cnt ;
	WORD	psp, next ;
	WORD	off=DEVoff, seg=DEVseg ;
	WORD	offn, segn ;
	WORD	attr ;
	BYTE	name[9] ;

	psp = mcb + 1 ;
	if ( _peek( mcb,1 ) != psp ) return 0 ;
	next = mcb + (WORD)_peek( mcb,3 ) + 1 ;			/*  次のMCBｾｸﾞﾒﾝﾄ	*/
	for ( ;; ) {
		if ( off == 0xFFFF && seg == 0xFFFF ) return len ;
		offn = (WORD)_peek( seg,off ) ;
		segn = (WORD)_peek( seg,off+2 ) ;
		attr = (WORD)_peek( seg,off+4 ) ;
		if ( seg >= psp && seg < next ) {
			if ( attr & 0x8000 ) {				/*  ｷｬﾗｸﾀﾃﾞﾊﾞｲｽ			*/
				for ( cnt=0; cnt<8; cnt++ )
					name[cnt] = (BYTE)_peekb( seg,off+0x0A+cnt ) ;
				for ( cnt=7; cnt>0; cnt-- ) {
					if ( name[cnt] != ' ' && name[cnt] != '\t' ) {
						name[cnt+1] = '\0' ;
						break ;
					}
				}
				if ( len ) {
					putchar( ' ' ) ;
					len++ ;
				}
				printf( "[%s]",name ) ;
				len += ( strlen( name ) + 2 ) ;
			} else {							/*  ﾌﾞﾛｯｸﾃﾞﾊﾞｲｽ			*/
				if ( len ) {
					putchar( ' ' ) ;
					len++ ;
				}
				printf( "[DISK]" ) ;
				len += 6 ;
			}
		}
		seg = segn ;
		off = offn ;
	}
}

WORD shelldisp( WORD psp )
/*===========================================================================
*	ｼｪﾙ表示
===========================================================================*/
{
	WORD	len=9 ;

	putchar( '<' ) ;
	if ( psp == TopShell ) {
		putchar( '\\' ) ;
		len++ ;
	}
	printf( "command>" ) ;
	return len ;
}

WORD envname( WORD mcb )
/*===========================================================================
*	環境変数領域の名称表示
===========================================================================*/
{
	register WORD	ep ;
	register BYTE	ch ;
	WORD	size, psp, env ;
	WORD	flg, len ;

	psp  = (WORD)_peek( mcb,1 ) ;				/*  MCBを要求したPSP	*/
	size = (WORD)_peek( mcb,3 ) ;				/*  MCB管理のﾒﾓﾘｻｲｽﾞ	*/
	if ( size >= 0x1000 ) return 0 ;			/*  64KB以上は無視		*/
	size <<= 4 ;								/*  ﾊﾟﾗｸﾞﾗﾌ→ﾊﾞｲﾄ		*/
	env = mcb + 1 ;								/*  MCBの次のｾｸﾞﾒﾝﾄ		*/
	ep = 0 ;
	while ( _peek( env,ep ) != 0x0000 ) ep++ ;	/*  環境変数の終端検索	*/
	ep += 2 ;
	if ( ep >= size ) return 0 ;				/*  環境ｾｸﾞﾒﾝﾄ外		*/
	if ( _peek( env,ep ) == 0x0001 ) {			/*  実行ﾌﾟﾛｸﾞﾗﾑ名検索	*/
		ep += 2 ;
		flg = ep < size ? FALSE : TRUE ;
	} else {
		flg = TRUE ;							/*  環境ｾｸﾞﾒﾝﾄ			*/
	}
	if ( flg ) {								/*  環境ｾｸﾞﾒﾝﾄ			*/
		if ( _peek( psp,0 ) == 0x20CD && psp == _peek( psp,0x16 ) ) {
			len = shelldisp( psp ) ;
		} else {
			len = 0 ;
		}
	} else {									/*  実行ﾌﾟﾛｸﾞﾗﾑ環境		*/
		for ( len=0; ep<size; ep++, len++ ) {	/*  実行ﾌﾟﾛｸﾞﾗﾑ名表示	*/
			ch = (BYTE)_peekb( env,ep ) ;
			if ( ch == '\0' ) break ;
			putchar( ch ) ;
		}
	}
	return len ;
}

WORD argdisp( WORD psp,WORD len )
/*===========================================================================
*	ｺﾏﾝﾄﾞﾗｲﾝ表示
===========================================================================*/
{
	register WORD	ep ;
	register BYTE	ch ;
	WORD	nch ;

	if ( _peek( psp,0 ) == 0x20CD ) {			/*  PSP					*/
		nch = _peekb( psp,0x80 ) ;				/*  ｺﾏﾝﾄﾞﾗｲﾝ文字数		*/
		ch  = _peekb( psp,0x81+nch ) ;
		if ( ch == 0x0D || ch == '\0' ) {
			for ( ep=0; ep<nch; ep++, len++ ) {
				ch = (BYTE)_peekb( psp,0x81+ep ) ;
				putchar( ch ) ;
			}
		}
	}
	if ( !len ) {								/*  ｺﾏﾝﾄﾞﾗｲﾝ表示なし	*/
		printf( "<N/A>" ) ;
		len = 5 ;
	}
	return len ;
}

int chkEnviron( WORD mcb )
/*===========================================================================
*	環境変数領域のﾁｪｯｸ
*	< IN  >	: mcb	mcbｾｸﾞﾒﾝﾄ
*	< RET >	: ｴﾗｰｺｰﾄﾞを返す.
*				=0	環境ｾｸﾞﾒﾝﾄを見つけた
*				=1	環境ｾｸﾞﾒﾝﾄではない
===========================================================================*/
{
	register WORD	cnt, cp ;
	WORD	env, size ;
	WORD	sp, len, cmplen ;
	static char	*name="PATH=" ;

	env  = mcb + 1 ;
	size = (WORD)_peek( mcb,3 ) ;
	if ( size >= 0x1000 ) return 1 ;			/*  64KB以上は無視		*/
	size <<= 4 ;								/*  ﾊﾟﾗｸﾞﾗﾌ→ﾊﾞｲﾄ		*/

	cmplen = strlen( name ) ;
	for ( sp=cp=0;; ) {
		while ( _peekb( env,cp ) != '=' ) cp++ ;
		cp++ ;
		if ( cp > size-2 ) return 1 ;
		len = cp - sp ;
		if ( len == cmplen ) {
			for ( cnt=0; cnt<len; cnt++ ) {
				if ( _peekb( env,sp ) != name[cnt] ) break ;
				sp++ ;
			}
			if ( cnt >= len ) {
				for ( cnt=0; cnt<size-1; cnt++ )
					if ( _peek( env,cnt ) == 0x0000 ) break ;
				if ( cnt >= size-1 ) return 1 ;	/*  終端が見つからない	*/
				return 0 ;
			}
		}
		while ( _peekb( env,cp ) != 0x00 ) cp++ ;
		sp = cp + 1 ;
		if ( _peekb( env,sp ) == 0x00 ) return 1 ;
	}
}

int envchk( WORD psp,WORD *envmcb )
/*===========================================================================
*	環境ｾｸﾞﾒﾝﾄの有無ﾁｪｯｸ
===========================================================================*/
{
	WORD	mcb, env ;
	BYTE	mark ;

	mcb = TopMCB ;
	env = (WORD)_peek( psp,0x2C ) ;
	for ( ;; ) {
		mark = (BYTE)_peekb( mcb,0 ) ;			/*  MCB識別子			*/
		if ( mark != 'M' && mark != 'Z' ) return 1 ;
		if ( _peek( mcb,1 ) == psp ) {
			if ( mcb+1 == env || ( !env && !chkEnviron( mcb ) ) ) {
				*envmcb = mcb ;
				return 0 ;
			}
		}
		mcb += ( (WORD)_peek( mcb,3 ) + 1 ) ;	/*  次のMCBｾｸﾞﾒﾝﾄ		*/
		if ( mark == 'Z' ) return 1 ;
	}
}

int mcbchk( WORD *envmcb )
/*===========================================================================
*	MCB情報ﾁｪｯｸ
===========================================================================*/
{
	WORD	mcb, psp, oya, env ;
	int		pspflg, envflg ;

	mcb = *envmcb ;
	psp = (WORD)_peek( mcb,1 ) ;				/*  owner(PSP)			*/
	oya = (WORD)_peek( psp,0x16 ) ;				/*  親のPSPｾｸﾞﾒﾝﾄ		*/
	env = (WORD)_peek( psp,0x2C ) ;				/*  環境ｾｸﾞﾒﾝﾄ			*/
	if ( psp == 0x0000 || psp == _psp ) {
		printf( "< free >  " ) ;
		return 0 ;								/*  free				*/
	} else if ( psp == 0x0008 ) {
		printf( ".... .... ",oya ) ;
		return 1 ;								/*  config				*/
	}
	pspflg = _peek( psp,0 ) == 0x20CD ? 1 : 0 ;	/*  psp check			*/
	envflg = envchk( psp,envmcb ) ;				/*  env check			*/
	if ( psp == mcb+1 ) {
		if ( pspflg ) {							/*  psp ok!				*/
			if ( envflg ) {
				printf( "%04X .... ",oya ) ;
			} else {
				printf( "%04X %04X ",oya,env ) ;
			}
			if ( psp == oya ) return 2 ;		/*  shell				*/
		} else {								/*  pspではない			*/
			printf( "( !PSP )  " ) ;
		}
		return 3 ;								/*  program?			*/
	} else if ( !chkEnviron( mcb ) ) {
		printf( "( env )   " ) ;
		return 4 ;								/*  environ				*/
	} else if ( !_peekb( mcb+1,0 ) && psp == oya ) {
		printf( "( bat )   " ) ;
		return 5 ;								/*  batch				*/
	}
	printf( "( N/A )   " ) ;
	return 6 ;									/*  unknown				*/
}

WORD batname( WORD seg )
/*===========================================================================
*	batch name表示
===========================================================================*/
{
	WORD	len, sp ;
	BYTE	ch ;

	if ( _osmajor < 3 ) return 0 ;				/*  v2.x				*/
	sp = _osmajor > 3 ? 0x20 : 0x19 ;
	if ( _peekb( seg,sp+1 ) != ':' || _peekb( seg,sp+2 ) != '\\' ) return 0 ;
	for ( len=0;; len++ ) {
		ch = _peekb( seg,len+sp ) ;
		if ( ch == '\0' ) break ;
		putchar( ch ) ;
	}
	return len ;
}

void pspdisp( WORD mcb )
/*===========================================================================
*	owner情報表示
===========================================================================*/
{
	WORD	psp, len, envmcb ;
	int		flg ;	/*  0=free,1=config,2=shell,3=prg,4=env,5=bat,6=?	*/

	psp = (WORD)_peek( mcb,1 ) ;
	envmcb = mcb ;
	flg = mcbchk( &envmcb ) ;
	switch ( flg ) {
	case 0	:									/*  free				*/
		len = 0 ;
		break ;
	case 1	:									/*  config				*/
		printf( "<config>" ) ;
		len = 8 ;
		break ;
	case 2	:									/*  shell				*/
	case 3	:									/*  program				*/
	case 6	:									/*  unknown				*/
		len = envname( envmcb ) ;
		len = devicedisp( mcb,len ) ;
		break ;
	case 4	:									/*  environ				*/
		len = envname( mcb ) ;
		break ;
	case 5	:									/*  batch				*/
		len = batname( mcb+1 ) ;
		if ( len == 0 ) len = envname( envmcb ) ;
		break ;
	}

	switch ( flg ) {
	case 0	:									/*  free				*/
	case 1	:									/*  config				*/
		vectdisp( mcb+1,len ) ;					/*  ﾍﾞｸﾀ表示			*/
		break ;
	case 2	:									/*  shell				*/
	case 3	:									/*  program				*/
		len = argdisp( psp,len ) ;				/*  ｺﾏﾝﾄﾞﾗｲﾝ表示		*/
	case 4	:									/*  environ				*/
	case 5	:									/*  batch				*/
	case 6	:									/*  unknown				*/
		vectdisp( mcb+1,len ) ;					/*  ﾍﾞｸﾀ表示			*/
		break ;
	}
}

int disp( WORD mcb )
/*===========================================================================
*	MCB情報表示
===========================================================================*/
{
	WORD	size, psp, next ;
	DWORD	sizel ;
	BYTE	mark, nextmark ;

	mark = (BYTE)_peekb( mcb,0 ) ;				/*  MCB識別子			*/
	psp  = (WORD)_peek( mcb,1 ) ;				/*  owner(PSP)			*/
	size = (WORD)_peek( mcb,3 ) ;				/*  ﾒﾓﾘﾌﾞﾛｯｸｻｲｽﾞ		*/
	if ( mark != 'M' && mark != 'Z' ) {
		printf( "\aメモリの状態が正しくありません." ) ;
		putcrlf() ;
		return 1 ;
	}
	next = mcb + size + 1 ;						/*  次のMCBｾｸﾞﾒﾝﾄ		*/
	nextmark = (BYTE)_peekb( next,0 ) ;			/*  次のMCB識別子		*/
	if ( psp == _psp && nextmark == 'Z' ) {		/*  最後のMCB			*/
		size += (WORD)( _peek( next,3 ) + 1 ) ;
		mark = 'Z' ;
	}
	sizel = (DWORD)size << 4 ;					/*  ﾊﾟﾗｸﾞﾗﾌ→ﾊﾞｲﾄ		*/
	if ( psp ) {
		printf( "%04X %04X %7lu ",psp,mcb,sizel ) ;
	} else {
		printf( ".... %04X %7lu ",mcb,sizel ) ;
	}
	pspdisp( mcb ) ;							/*  owner/parameter表示	*/
	putcrlf() ;

	return mark == 'Z' ? 1 : 0 ;
}

WORD init( void )
/*===========================================================================
*	初期処理(ｼｽﾃﾑﾊﾟﾗﾒﾀﾃｰﾌﾞﾙ表示)
===========================================================================*/
{
	union	REGS	regs ;
	struct	SREGS	sregs ;
	register int	cnt ;
	int		ldrvp ;

	if ( _osmajor > 3 ) {						/*  V4.0以降			*/
		DOSver = 2 ;
	} else if ( _osminor > 0x0A && _osmajor == 3 ) {
		DOSver = 1 ;							/*  V3.2以降			*/
	} else {
		DOSver = 0 ;							/*  V3.1以前			*/
	}
	if ( _osmajor < 3 ) {						/*  v2.x				*/
		DEVoff = 0x17 ;
		ldrvp  = 0 ;	/*  なし	*/
	} else if ( _osmajor < 4 ) {				/*  v3.x				*/
		if ( _osminor < 0x0A ) {				/*  v3.0				*/
			DEVoff = 0x28 ;
			ldrvp  = 0x1B ;
		} else {								/*  v3.1〜				*/
			DEVoff = 0x22 ;
			ldrvp  = 0x21 ;
		}
	} else {									/*  v4.0〜				*/
		DEVoff = 0x22 ;
		ldrvp  = 0x21 ;
	}

	PSPseg = _peek( _psp,0x16 ) ;				/*  親のPSPｾｸﾞﾒﾝﾄ		*/
	MYenv  = (WORD)_peek( _psp,0x2C ) ;			/*  環境ｾｸﾞﾒﾝﾄ			*/

	regs.h.ah = 0x52 ;							/*  ｼｽﾃﾑﾊﾟﾗﾒﾀﾃｰﾌﾞﾙ取得	*/
	intdosx( &regs,&regs,&sregs ) ;
	TopMCB = (WORD)_peek( sregs.es,regs.x.bx-2 ) ;	/*  先頭MCBｾｸﾞﾒﾝﾄ	*/
	DEVoff += regs.x.bx ;						/*  NULﾃﾞﾊﾞｲｽﾍｯﾀﾞ位置	*/
	DEVseg = (WORD)sregs.es ;					/*  NULﾃﾞﾊﾞｲｽﾍｯﾀﾞ位置	*/
	TopShell = (WORD)_peek( 0,0x2E*4+2 ) ;		/*  先頭command.com		*/
	if ( ldrvp ) {
		ldrvp += regs.x.bx ;					/*  LASTDRIVE			*/
		LastDrv = (BYTE)_peekb( sregs.es,ldrvp ) ;
	}

	for ( cnt=0; cnt<256; cnt++ ) {				/*  ﾍﾞｸﾀﾃｰﾌﾞﾙ取得		*/
		Vect[cnt] = _peek( 0,cnt*4+2 ) + ( _peek( 0,cnt*4 ) >> 4 ) ;
	}

	return TopMCB ;								/*  先頭MCB				*/
}

void chkseg( WORD mcb )
/*===========================================================================
*	ﾙｰﾄと親の環境ｾｸﾞﾒﾝﾄを調べる
===========================================================================*/
{
	WORD	psp, oya, env ;

	psp = (WORD)_peek( mcb,1 ) ;				/*  MCBを要求したPSP	*/
	if ( !psp ) return ;
	oya = (WORD)_peek( psp,0x16 ) ;				/*  親のPSPｾｸﾞﾒﾝﾄ		*/
	if ( psp == mcb+1 && psp == oya && !ROOTpsp ) ROOTpsp = psp ;
	if ( ROOTpsp == psp && psp != mcb+1 && !ROOTenv ) ROOTenv = mcb + 1 ;

	if ( psp == PSPseg && psp != mcb+1 ) {
		env = (WORD)_peek( PSPseg,0x2C ) ;		/*  親の環境ｾｸﾞﾒﾝﾄ		*/
		switch ( DOSver ) {
		case 0	:								/*  MS-DOS V3.1以前		*/
			if ( !ENVseg ) ENVseg = mcb + 1 ;
			break ;
		case 1	:								/*  MS-DOS V3.2以降		*/
			if ( env != mcb+1 && !ENVseg ) ENVseg = mcb + 1 ;
			break ;
		case 2	:								/*  MS-DOS V4.0以降		*/
			if ( env ) {
				if ( env == mcb+1 && !ENVseg ) ENVseg = env ;
			} else {
				if ( !ENVseg ) ENVseg = mcb + 1 ;
			}
			break ;
		}
	}
}

void devdisp( void )
/*===========================================================================
*	ﾃﾞﾊﾞｲｽﾍｯﾀﾞのﾘﾝｸ情報表示
===========================================================================*/
{
	register int	cnt ;
	WORD	off=DEVoff, seg=DEVseg ;
	WORD	offn, segn ;
	WORD	attr ;
	BYTE	name[9] ;

	putcrlf() ;
	printf( "Header    T Name     Device Attributes   " ) ;
	putcrlf() ;
	printf( "--------- - -------- --------------------" ) ;
	putcrlf() ;
	name[8] = '\0' ;
	for ( ;; ) {
		if ( off == 0xFFFF && seg == 0xFFFF ) break ;
		offn = (WORD)_peek( seg,off ) ;
		segn = (WORD)_peek( seg,off+2 ) ;
		attr = (WORD)_peek( seg,off+4 ) ;
		printf( "%04X:%04X ",seg,off ) ;
		if ( attr & 0x8000 ) {					/*  ｷｬﾗｸﾀﾃﾞﾊﾞｲｽ			*/
			printf( "C " ) ;
			for ( cnt=0; cnt<8; cnt++ )
				name[cnt] = (BYTE)_peekb( seg,off+0x0A+cnt ) ;
			printf( "%-8s ",name ) ;
			if ( attr & 0x0001 ) printf( "STDIN " ) ;		/*  ﾋﾞｯﾄ0	*/
			if ( attr & 0x0002 ) printf( "STDOUT " ) ;		/*  ﾋﾞｯﾄ1	*/
			if ( attr & 0x0004 ) printf( "NUL " ) ;			/*  ﾋﾞｯﾄ2	*/
			if ( attr & 0x0008 ) printf( "CLOCK " ) ;		/*  ﾋﾞｯﾄ3	*/
			if ( attr & 0x0010 ) printf( "INT29 " ) ;		/*  ﾋﾞｯﾄ4	*/
			if ( attr & 0x0040 ) printf( "G-IOCTL " ) ;		/*  ﾋﾞｯﾄ6	*/
			if ( attr & 0x0800 ) printf( "O/C/RM " ) ;		/*  ﾋﾞｯﾄ11	*/
			if ( attr & 0x2000 ) printf( "BUSY " ) ;		/*  ﾋﾞｯﾄ13	*/
			if ( attr & 0x4000 ) printf( "IOCTL " ) ;		/*  ﾋﾞｯﾄ14	*/
		} else {								/*  ﾌﾞﾛｯｸﾃﾞﾊﾞｲｽ			*/
			printf( "B " ) ;
			name[0] = (BYTE)_peekb( seg,off+0x0A ) ;
			printf( "%-3d(drv) ",name[0] ) ;
			if ( attr & 0x0002 ) printf( "32bit " ) ;		/*  ﾋﾞｯﾄ1	*/
			if ( attr & 0x0040 ) printf( "G-IOCTL " ) ;		/*  ﾋﾞｯﾄ6	*/
			if ( attr & 0x0800 ) printf( "O/C/RM " ) ;		/*  ﾋﾞｯﾄ11	*/
			if ( attr & 0x2000 ) printf( "NON-FAT " ) ;		/*  ﾋﾞｯﾄ13	*/
			if ( attr & 0x4000 ) printf( "IOCTL " ) ;		/*  ﾋﾞｯﾄ14	*/
		}
		putcrlf() ;
		seg = segn ;
		off = offn ;
	}

	if ( LastDrv ) {
		putcrlf() ;
		printf( "( LASTDRIVE=%c )",LastDrv+'@' ) ;
		putcrlf() ;
	}
}

void usage( void )
/*===========================================================================
*	使用方法表示
===========================================================================*/
{
	printf( "Usage: MCB [-e] [-d] [-p]\n" ) ;
	printf( "       -e  環境変数領域のセグメント表示\n" ) ;
	printf( "       -d  デバイスドライバのリンク情報表示\n" ) ;
	printf( "       -p  １画面毎表示\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 'e'	:
		case 'E'	:
			_option.env = 1 ;		break ;
		case 'd'	:
		case 'D'	:
			_option.dev = 1 ;		break ;
		case 'p'	:
		case 'P'	:
			_option.page = 1 ;		break ;
		default		:
			usage() ;
		}
	}
}

int main( int ac,char *av[] )
/*===========================================================================
*	ﾒｲﾝ
===========================================================================*/
{
	WORD	mcb ;
	int		cnt ;

	printf( "MCBリンク情報表示  V1.00  (C) パオパオ 1993.\n\n" ) ;
	if ( ac > 1 ) {								/*  引数あり			*/
		for ( cnt=1; cnt<ac; cnt++ ) {
			if ( *av[cnt] == '-' || *av[cnt] == '/' )
				swchk( av[cnt]+1 ) ;			/*  引数ﾁｪｯｸ			*/
			else
				usage() ;						/*  使用方法表示		*/
		}
	}
	mcb = init() ;
	titledisp() ;
	for ( ;; ) {
		chkseg( mcb ) ;
		if ( disp( mcb ) ) break ;				/*  MCB情報表示			*/
		mcb += ( (WORD)_peek( mcb,3 ) + 1 ) ;	/*  次のMCBｾｸﾞﾒﾝﾄ		*/
	}
	if ( _option.env ) {						/*  環境変数領域表示	*/
		putcrlf() ;
		printf( "MS-DOS v%d.%d",_osmajor,_osminor ) ;
		printf( "  <ﾙｰﾄ> PSP:%04X 環境:%04X",ROOTpsp,ROOTenv ) ;
		printf( "  <親> PSP:%04X 環境:%04X",PSPseg,ENVseg ) ;
		putcrlf() ;
	}
	emmdisp() ;									/*  EMS情報表示			*/
	if ( _option.dev ) devdisp() ;				/*  ﾃﾞﾊﾞｲｽﾍｯﾀﾞ表示		*/

	return 0 ;
}

/*	HISTORY
-----------------------------------------------------------------------------
*	1993.04.03 : CREATE
---------------------------------------------------------------------------*/
