home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
sysutl
/
idt.arc
/
IDT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-06-12
|
31KB
|
1,338 lines
#pragma title("IDT - Find Internal Data Table")
#pragma subtitle("Introduction")
/*
** program: idt
**
** purpose: This program finds the internal device
** table used by MS-DOS and reports its
** contents. It includes options to dump
** and/or display each of the various
** structures pointed to by the idt.
**
** usage: idt
**
** switches: -i = List the internal data table
** -p = List the physical device table
** -l = List the logical device table
** -d = List the device driver headers
** -m = List the memory arena
** -b = List buffer control blocks
** -f = List internal file control blocks
** -c = List file control blocks
** -v = Verbose (dump buffers)
** -* = Everything (except verbose)
**
** notes: Much (most) of the information contained in
** the idt (including the method used to find
** it) is undocumented and subject to change
** and/or errors. This version will not work
** for versions of MS-DOS previous to 3.0.
**
** Considering the wealth of information revealed
** in these tables, it may me a reasonable risk
** for an application which takes some care to
** utilize it - even though it is officially
** undocumented and will not be supported by
** the OS vendor (yes, you know who you are!)
**
** author: Bill Parrott
**
** Copyright (c) 1988, Bill Parrott
** All Rights Reserved
**
** Use this code in any way and the information
** contained herein any way you like, without
** restriction. If you accomplish something
** because of what you got here, and if it makes
** you rich, well I just hope you'll remember
** who made it all possible :-). Seriously, a
** little credit would be nice but apart from
** that, have at it!
*/
#define VERSION 1
#define REVISION 0
#define PROGRAMNAME "IDT"
/*
** system includes
*/
#include <stdio.h>
#include <dos.h>
#include <ctype.h>
#include <assert.h>
#include <process.h>
/*
** site includes
*/
#include <local/getargs.h>
#include <local/what.h>
#include "idt.h"
#pragma subtitle("Data and Definitions")
#pragma page()
/*
** global data
*/
IDT *idt; /* address of internal data table */
/*
** this cell is filled by our function rather that
** from the idt just so we can say we really did it.
*/
segment arenastart; /* start of memory arena */
/*
** switch data
*/
static int doidt = 0; /* list the internal data table */
static int dopdpt = 0; /* list the physical device table */
static int doldt = 0; /* list the logical device table */
static int dodevhdr = 0; /* list device driver headers */
static int doarena = 0; /* list memory arena */
static int dobcb = 0; /* list buffer control blocks */
static int verbose = 0; /* verbose listing (dumps buffers) */
static int doifcb = 0; /* list internal file control blocks */
static int dofcbt = 0; /* list file control blocks */
static int doall = 0; /* list everything */
/*
** switch table
*/
ARG swtab[] =
{
{ 'i', BOOLEAN, &doidt, "List internal data table" },
{ 'p', BOOLEAN, &dopdpt, "List physical device table" },
{ 'l', BOOLEAN, &doldt, "List logical device table" },
{ 'd', BOOLEAN, &dodevhdr, "List device driver headers" },
{ 'm', BOOLEAN, &doarena, "List memory arena" },
{ 'b', BOOLEAN, &dobcb, "List buffer control blocks" },
{ 'f', BOOLEAN, &doifcb, "List internal file control blocks" },
{ 'c', BOOLEAN, &dofcbt, "List file control blocks" },
{ 'v', BOOLEAN, &verbose, "Verbose (dump buffers)" },
{ '*', BOOLEAN, &doall, "List everything" }
};
#define TABSIZE (sizeof(swtab) / sizeof(ARG))
/*
** prototypes
*/
int main( int, char ** );
segment findarena( void );
segment isarena( segment, segment );
void showidt( IDT far * );
void showpdpt( PDPT far * );
void showpdpt1( PDPT far * );
void showldt( LDT far * );
void showdevhdr( DEVHDR far * );
void showdevhdr1( DEVHDR far * );
char *trimname( char far *, int );
void showarena( MDB far * );
int isenv( char far * );
int ispsp( char far * );
void showbcb( BCB far * );
void dumpbuffer( byte far * );
void paragraph( byte *, word );
void memkpy( byte *, byte far *, int );
int memkmp( byte *, byte far *, int );
void showifcb( CHAIN far *, int );
void showifcb1( IFCB far * );
/*
** "what" strings
*/
static char *WhatStrings[] =
{
WHATVER(PROGRAMNAME,VERSION,REVISION),
WHATWHEN,
WHATDATE,
WHAT("Copyright (c) 1988, Bill Parrott"),
WHAT(" All Rights Reserved")
};
#pragma subtitle("main()")
#pragma page()
/*
** main (need I say more?)
*/
int main( argc, argv )
int argc;
char *argv[];
{
union REGS r;
struct SREGS s;
IDT safeplaceforidt;
IDT far *p;
int i;
/*
** signon
*/
fprintf( stderr, "\n%s", &WhatStrings[0][4] );
fprintf( stderr, "\n%s\n", &WhatStrings[3][4] );
/*
** check for version
*/
r.h.ah = 0x30;
intdos( &r, &r );
if ( r.h.al < 0 )
{
fprintf( stderr, "\nIncorrect version of MS-DOS.\n" );
return ( 1 );
}
/*
** process the command line
*/
argc = getargs( argc, argv, swtab, TABSIZE );
if ( doall )
doidt = dopdpt = doldt = dodevhdr =
doarena = dobcb = doifcb = dofcbt = 1;
else
{
i = doidt + dopdpt + doldt + dodevhdr +
doarena + dobcb + doifcb + dofcbt;
if ( i == 0 )
{
fprintf( stderr, "\nusage: idt switch(es)\n" );
fprintf( stderr, "\n\t-i = list the internal data table" );
fprintf( stderr, "\n\t-p = list the physical device table" );
fprintf( stderr, "\n\t-l = list the logical device table" );
fprintf( stderr, "\n\t-d = list the device driver headers" );
fprintf( stderr, "\n\t-m = list the memory arena" );
fprintf( stderr, "\n\t-b = list buffer control blocks" );
fprintf( stderr, "\n\t-f = list internal file control blocks" );
fprintf( stderr, "\n\t-c = list file control blocks" );
fprintf( stderr, "\n\t-v = verbose (dump buffers)" );
fprintf( stderr, "\n\t-* = list all tables" );
fprintf( stderr, "\n" );
return ( 1 );
}
}
/*
** find the memory arena on our own first.
*/
if ( (arenastart = findarena()) == 0 )
{
fprintf( stderr, "\n\n\a+++ Can't locate the first memory descriptor!! +++\n" );
return ( 1 );
}
/*
** now look up the internal data table
*/
segread( &s );
r.h.ah = 0x52; /* magic undocumented function */
intdosx( &r, &r, &s );
/*
** get a static copy for playing with
*/
idt = &safeplaceforidt;
FP_SEG(p) = s.es;
FP_OFF(p) = r.x.bx - 8;
memkpy( (byte *) idt, (byte far *) p, sizeof(IDT) );
/*
** process selections
*/
if ( doidt )
showidt( idt );
if ( dopdpt )
showpdpt( idt->pdpt );
if ( doldt )
showldt( idt->ldt );
if ( dodevhdr )
showdevhdr( &idt->nuldev );
if ( doarena )
showarena( idt->arena );
if ( dobcb )
showbcb( idt->bcbhead );
if ( doifcb )
showifcb( idt->ifcb, 1 );
if ( dofcbt )
showifcb( idt->fcbt, 0 );
/*
** clean up
*/
printf( "\n" );
return ( 0 );
}
#pragma subtitle("findarena() - find start of memory arena")
#pragma page()
/*
** function: findarena
**
** purpose: This function demonstrates a well behaved (?)
** technique for finding the first memory control
** block. It uses only information obtained from
** Microsoft literature and documents in this
** task... (hopefully freeing it from version
** dependancies.) We do, however, make the
** assumption that MS-DOS memory descriptors
** are ALWAYS on paragraph boundaries.
**
** usage: first = findarena();
** segment first;
**
** returns: segment of first descriptor if found,
** else 0.
*/
segment findarena()
{
word beginsearch;
word endsearch;
union REGS r;
/*
** find a place to give up the search. For further
** reliability, we make this the end of physical
** memory (as DOS knows it). Besides, the function
** isarena() requires it.
*/
beginsearch = 0x40; /* after interrupt table */
int86( 0x12, &r, &r ); /* get it from the BIOS */
endsearch = r.x.ax << 6; /* last paragraph + 1 */
/*
** find the start of the arena
*/
for ( arenastart = beginsearch; arenastart < endsearch; ++arenastart )
if ( isarena( arenastart, endsearch ) )
break;
/*
** check it, but it can't happen.
*/
if ( arenastart >= endsearch )
{
fprintf( stderr, "\nSomething's REALLY screwed up, Martha!!\n" );
return ( 0 );
}
return ( arenastart );
}
#pragma subtitle("isarena() - is segment is the arena?")
#pragma page()
/*
** function: isarena
**
** purpose: This function determines whether the passed
** segment address points to the start of DOS'
** memory allocation arena.
**
** usage: result = isarena( seg, endsearch );
** segment result;
** segment seg;
** segment endsearch;
**
** returns: 0 if not, else segment of high memory + 1
**
** notes: To perform this test, we first check to see
** if the paragraph appears to be a memory
** descriptor block. If so, add the block
** length to get the address of the next block.
** Then we check that block to see if it's a
** memory descriptor. If so, add the block
** length to get the next block, and so on
** until we reach the end of the arena. If
** any entry is not a descriptor, or if the
** arena does not end at exactly the end of
** memory then the test fails.
**
** The defined value LOOPCHECK (below) is used
** to keep the algorithm from getting into an
** endless loop due to a circular link. The
** value chosen should be sufficiently large
** to keep from prematurely terminating a
** valid (however long) chain of MDBs.
*/
#define LOOPCHECK 1024 /* should be high enuf */
segment isarena( seg, endsearch )
segment seg;
segment endsearch;
{
MDB far *p;
int i;
/*
** check to see if it appears to be a memory descriptor.
*/
FP_SEG(p) = seg;
FP_OFF(p) = 0; /* address possible descriptor */
if ( p->type != 'M' )
return ( 0 ); /* most will fail this test */
/*
** well, it looks like a duck...
*/
for ( i = 0; i < LOOPCHECK; ++i )
{
FP_SEG(p) += p->length + 1; /* find next potential */
if ( FP_SEG(p) > endsearch )
return ( 0 ); /* too far */
if ( p->type == 'Z' )
break; /* found last one */
if ( p->type != 'M' )
return ( 0 ); /* false alarm */
}
if ( i == LOOPCHECK )
return ( 0 ); /* circular loop? */
/*
** looks like a duck, and it walks like a duck...
*/
FP_SEG(p) += p->length + 1; /* last link */
return ( FP_SEG(p) == endsearch ); /* quack! */
}
#pragma subtitle("showidt() - display idt")
#pragma page()
/*
** function: showidt
**
** purpose: This function displays the contents of the
** internal data table upon stdout.
**
** usage: void showidt( idt );
** IDT far *idt;
**
** returns: nothing
*/
void showidt( idt )
IDT far *idt;
{
void far *temp;
printf( "\nInternal Data Table at: %p\n", idt );
printf( "\n\t%p = Current Buffer Control Block", idt->curbcb );
printf( "\n\t%p = Start of MS-DOS Memory Arena", idt->arena );
temp = idt->arena;
if ( FP_SEG(temp) != arenastart )
printf( "\n\t *** Expected %04x ***", arenastart );
printf( "\n\t%p = Physical Drive Parameter Table", idt->pdpt );
printf( "\n\t%p = Internal File Control Blocks", idt->ifcb );
printf( "\n\t%p = Clock Device Driver", idt->clockdev );
printf( "\n\t%p = Console Device Driver", idt->condev );
printf( "\n\t %04x = Maximum Sector Size", idt->max_ssize );
printf( "\n\t%p = Buffer Control Block List", idt->bcbhead );
printf( "\n\t%p = Logical Device Table", idt->ldt );
printf( "\n\t%p = File Control Block Table", idt->fcbt );
printf( "\n\t %5u = Number of protected FCBs", idt->nprotfcbs );
printf( "\n\t %5u = Number of Physical Drives (in PDT)", idt->nphysdrives );
printf( "\n\t %5u = Number of Logical Drives (in LDT)", idt->nlogdrives );
printf( "\n" );
}
#pragma subtitle("showpdpt() - display pdpt")
#pragma page()
/*
** function: showpdpt
**
** purpose: This function displays the contents of the
** physical device table upon stdout.
**
** usage: void showpdpt( pdpt );
** PDPT far *pdpt;
**
** returns: nothing
*/
void showpdpt( pdpt )
PDPT far *pdpt;
{
printf( "\nPhysical Device Table at: %p\n", pdpt );
do
{
showpdpt1( pdpt );
pdpt = pdpt->nextentry;
} while ( FP_OFF(pdpt) != 0xffff );
}
void showpdpt1( pdpt )
PDPT far *pdpt;
{
printf( "\nAddress of this entry: %p\n", pdpt );
printf( "\n\t %02x = Drive (%c:)", pdpt->drive, pdpt->drive + 'A' );
printf( "\n\t %02x = Driver unit number", pdpt->dunit );
printf( "\n\t %5u = Bytes per sector", pdpt->sectorsize );
printf( "\n\t %3u = Sectors per cluster - 1", pdpt->clustersize );
printf( "\n\t %02x = Cluster to sector shift", pdpt->shift );
printf( "\n\t %5u = Number of reserved (boot) sectors", pdpt->bootsectors );
printf( "\n\t %3u = Number of File Allocation Tables (FATs)", pdpt->fats );
printf( "\n\t %5u = Number of root directory entries", pdpt->rootsize );
printf( "\n\t %5u = Sector number of cluster #2 (first data cluster)", pdpt->dataoffset );
printf( "\n\t %5u = Number of clusters + 1", pdpt->lastcluster );
printf( "\n\t %3u = Sectors per File Allocation Table (FAT)", pdpt->fatsize );
printf( "\n\t %5u = Sector number of root directory", pdpt->diroffset );
printf( "\n\t%p = Address of device header", pdpt->devheader );
printf( "\n\t %02x = Media descriptor byte", pdpt->mediabyte );
printf( "\n\t %02x = Access flag", pdpt->accessflag );
printf( "\n\t%p = Address of next DPT pdpt\n", pdpt->nextentry );
printf( "\n\tAssociated Device Header:\n" );
showdevhdr1( pdpt->devheader );
}
#pragma subtitle("showldt() - display ldt")
#pragma page()
/*
** function: showldt
**
** purpose: This function displays the contents of the
** physical device table upon stdout.
**
** usage: void showldt( ldt );
** LDT far *ldt;
**
** returns: nothing
*/
void showldt( ldt )
LDT far *ldt;
{
int i;
printf( "\nLogical Device Table at: %p\n", ldt );
/*
** run through the table
*/
for ( i = 0; i < idt->nlogdrives; ++i, ++ldt )
{
printf( "\n\t %c: = Logical Device", i + 'A' );
printf( "\n\t%p = Entry address", ldt );
printf( "\n\tDirectory = %Fs", ldt->currentdir );
printf( "\n\t %02x = Code (?)", ldt->code );
printf( "\n\t%p = Address of associated physical device entry", ldt->pdpt );
if ( ldt->pdpt )
printf( " (Drive %c:)", ldt->pdpt->drive + 'A' );
printf( "\n\t %5u = Current directory sector", ldt->curdir );
printf( "\n\t %04x = Flag (?)\n", ldt->flag );
}
}
#pragma subtitle("showdevhdr() - display device headers")
#pragma page()
/*
** function: showdevhdr
**
** purpose: This function displays the contents of the
** all device driver headers.
**
** usage: void showdevhdr( devhdr );
** DEVHDR far *devhdr;
**
** returns: nothing
*/
void showdevhdr( devhdr )
DEVHDR far *devhdr;
{
printf( "\nDevice Headers begin at: %p\n", devhdr );
do
{
showdevhdr1( devhdr );
devhdr = devhdr->nextheader;
} while ( FP_OFF(devhdr) != 0xffff );
}
void showdevhdr1( devhdr )
DEVHDR far *devhdr;
{
void far *p;
word attr;
attr = devhdr->attributes;
printf( "\n\t%p = Address of this Device Header", devhdr );
if ( attr & 0x8000 )
{
printf( "\n\t * Character Device" );
printf( "\n\t%9s = Device Name", trimname( devhdr->devname, 8 ) );
}
else
{
printf( "\n\t * Block Device" );
printf( "\n\t %3u = Number of units", (byte) devhdr->devname[0] );
}
printf( "\n\t%p = Address of next device header", devhdr->nextheader );
printf( "\n\t %04x = Device attributes", attr );
if ( attr & 0x8000 )
{
if ( attr & 0x4000 )
printf( "\n\t - Supports IOCTL strings" );
if ( attr & 0x2000 )
printf( "\n\t - Supports output until busy" );
if ( attr & 0x0800 )
printf( "\n\t - Understands open/close" );
if ( attr & 0x0040 )
printf( "\n\t - Supports IOCTL functions" );
if ( attr & 0x0010 )
printf( "\n\t - Is special device" );
if ( attr & 0x0008 )
printf( "\n\t - Is clock device" );
if ( attr & 0x0004 )
printf( "\n\t - Is null device" );
if ( attr & 0x0002 )
printf( "\n\t - Is console output device" );
if ( attr & 0x0001 ) /* paying attention? */
printf( "\n\t - Is console input device" );
if ( attr & 0x17a0 )
printf( "\n\t * Has unidentified bit(s) set" );
}
else
{
if ( attr & 0x4000 )
printf( "\n\t - Supports IOCTL strings" );
if ( attr & 0x2000 )
printf( "\n\t - Uses FAT id byte to find type" );
if ( attr & 0x0800 )
printf( "\n\t - Understands open/close" );
if ( attr & 0x0040 )
printf( "\n\t - Supports IOCTL functions" );
if ( attr & 0x0010 )
printf( "\n\t - Is special device" );
if ( attr & 0x17af )
printf( "\n\t * Has unidentified bit(s) set" );
}
FP_SEG(p) = FP_SEG(devhdr);
FP_OFF(p) = devhdr->strategy;
printf( "\n\t%p = Strategy entry point", p );
FP_OFF(p) = devhdr->intrupt;
printf( "\n\t%p = Driver interrupt entry point\n", p );
}
char *trimname( name, len )
char far *name;
int len;
{
static char buff[9];
int i;
assert( len <= 8 );
for ( i = 0; i < len; ++i )
if ( isprint( *name ) && (*name != ' ') )
buff[i] = *name++;
else
break;
buff[i] = '\0';
return ( buff );
}
#pragma subtitle("showarena() - display memory arena")
#pragma page()
/*
** function: showarena
**
** purpose: This function displays the contents of the
** memory arena.
**
** usage: void showarena( arena );
** MDB far *arena;
**
** returns: nothing
*/
void showarena( arena )
MDB far *arena;
{
double kbytes;
void far *mem;
int done;
printf( "\nMemory Arena begins at: %p\n", arena );
if ( arena->type != 'M' )
{
printf( "\n\t+++ Memory arena not found +++\n" );
return;
}
done = 0;
while ( !done )
{
mem = arena;
++FP_SEG(mem);
printf( "\n\t%04x paragraphs ", arena->length );
kbytes = (double) arena->length / 64.0;
printf( "(%6.2f KB)", kbytes );
printf( " at %p,", arena );
printf( " Owner=%04x,", arena->owner );
if ( arena->owner == NULL )
printf( " Free" );
if ( arena->type == 'M' )
if ( ispsp( mem ) )
printf( " PSP" );
else
if ( isenv( mem ) )
printf( " Environment" );
else
printf( " Data" );
if ( done = (arena->type == 'Z') )
printf( " [Last Block]" );
FP_SEG(arena) += arena->length + 1;
}
printf( "\n" );
}
#pragma subtitle("ispsp() - see if block is a PSP")
#pragma page()
/*
** function: ispsp
**
** purpose: This functions checks a block of memory to
** see if it looks like a program segment prefix.
**
** usage: result = ispsp( p );
** int result;
** char far *;
**
** returns: 0 if not PSP.
**
** notes: The following tests are performed before a
** segment qualifies as a PSP:
**
** 1) The word at offset 00h must contain an
** INT 20h instruction.
** 2) The word at offset 50h must contain an
** INT 21h instruction.
** 3) The byte at offset 52h must contain a
** RETF (far return) instruction.
** 4) The owner of the DOS memory block
** containing the PSP-elect must be the
** PSP itself.
*/
int ispsp( p )
char far *p;
{
PSP far *psp;
/*
** check PSP contents
*/
psp = (PSP far *) p;
if ( psp->wmboot != 0x20cd ) /* test 1 */
return ( 0 );
if ( psp->int21 != 0x21cd ) /* test 2 */
return ( 0 );
if ( psp->farret != 0xcb ) /* test 3 */
return ( 0 );
/*
** external test
*/
--FP_SEG(p);
FP_OFF(p) = 0; /* test 4 */
return ( FP_SEG(psp) == ((MDB far *) p)->owner );
}
#pragma subtitle("isenv() - see if block is environment")
#pragma page()
/*
** function: isenv
**
** purpose: This functions checks a block of memory to
** see if it looks like an environment segment.
**
** usage: result = isenv( p );
** int result;
** char far *;
**
** returns: 0 if not environment.
**
** notes: If the block begins with a series of 1
** or more alphanumeric characters followed
** immediately by an equal '=' followed
** immediately by a string of displayable
** ASCII characters followed immediately by
** a null (0) byte, then it is assumed to be
** an environment block. Ditto.
*/
int isenv( p )
char far *p;
{
char far *q;
/*
** check for a string of the form:
**
** <alphanumeric> <equal> <text> <NULL>
**
** where:
** <alphanumeric> : <alpha> | <numeric>
** <alpha> : <uppercase> | <lowercase>
** <uppercase> : A,B,C,...,Z
** <lowercase> : a,b,c,...,z
** <numeric> : 0,1,2,...,9
** <equal> : =
** <text> : [0x20..0x7e]
** <NULL> : '\0'
*/
q = p;
while ( isalnum( *p ) )
++p;
if ( p == q )
return ( 0 ); /* require at least one char */
if ( *p++ != '=' )
return ( 0 ); /* no = */
q = p;
while ( isprint( *p ) )
++p;
if ( *p != '\0')
return ( 0 ); /* '\0' missing at the end */
return ( !(p == q) );
}
#pragma subtitle("showbcb() - display memory bcb")
#pragma page()
/*
** function: showbcb
**
** purpose: This function displays the contents of the
** buffer control blocks.
**
** usage: void showbcb( bcb );
** BCB far *bcb;
**
** returns: nothing
*/
void showbcb( bcb )
BCB far *bcb;
{
int done;
BCB far *p;
printf( "\nBuffer control blocks begin at: %p\n", bcb );
done = 0;
while ( !done )
{
p = bcb->nextbcb;
printf( "\n\t%p = Address of this control block", bcb );
if ( bcb == idt->curbcb )
printf( " (Current Buffer)" );
printf( "\n\t%p = Next control block", p );
printf( "\n\t %02x = Action code", bcb->action );
printf( "\n\t %5u = Logical sector number", bcb->logsec );
printf( "\n\t %3u = Number of FATs", bcb->nfats );
printf( "\n\t %3u = Sectors per FAT", bcb->sectorsperfat );
printf( "\n\t%p = Associated physical device parameters (%c:)", bcb->pdpt, bcb->pdpt->drive + 'A' );
printf( "\n\t%p = Buffer address\n", bcb->buffer );
if ( verbose )
dumpbuffer( bcb->buffer );
if ( !(done = (FP_OFF(p) == 0xffff)) )
bcb = p;
}
printf( "\n" );
}
#pragma subtitle("dumpbuffer() - hex dump a buffer")
#pragma page()
/*
** function: dumpbuffer
**
** purpose: This function is called to produce a hex
** dump of the addressed buffer. It will
** always dump 512 bytes, however it will
** abbreviate the dump if possible by not
** displaying consecutive duplicate paragraphs.
**
** usage: void dumpbuffer( p );
** byte far *p;
**
** returns: nothing
*/
void dumpbuffer( p )
byte far *p;
{
byte lastpara[16];
int sameaslast;
int para;
printf( "\n\tBuffer Contents:\n" );
for ( sameaslast = para = 0; para < 32; ++para, p += 16 )
{
if ( para && (para < 31) )
{
if ( memkmp( lastpara, p, 16 ) )
{
memkpy( lastpara, p, 16 );
paragraph( lastpara, para << 4 );
sameaslast = 0;
}
else
if ( !sameaslast++ )
printf( "\n\t =======" );
}
else
{
memkpy( lastpara, p, 16 );
paragraph( lastpara, para << 4 );
}
}
printf( "\n" );
}
void paragraph( p, o )
byte *p;
word o;
{
int x;
printf( "\n\t%04x:", o );
/*
** hex part of dump
*/
for ( x = 0; x < 16; ++x )
printf( " %02x", p[x] );
/*
** show ASCII for fun
*/
printf( " " );
for ( x = 0; x < 16; ++x )
printf( "%c", isprint( p[x] ) ? p[x] : '.' );
}
#pragma subtitle("memk..() - near/far memory functions")
#pragma page()
/*
** function: memkpy
**
** purpose: This function if used to copy data from
** far memory to near memory. Is is similar
** to memcpy().
**
** usage: void memkpy( dest, src, len );
** byte *dest;
** byte far *src;
** int len;
**
** returns: nothing
*/
void memkpy( d, s, l )
byte *d;
byte far *s;
int l;
{
while ( l-- )
*d++ = *s++;
}
/*
** function: memkmp
**
** purpose: This function if used to compare data in
** far memory to data in near memory. It is
** similar to memkmp().
**
** usage: void memkmp( p1, p2, len );
** byte *p1;
** byte far *p2;
** int len;
**
** returns: nothing
*/
int memkmp( d, s, l )
byte *d;
byte far *s;
int l;
{
if ( !l )
return ( 0 );
while ( --l && ( *d == *s ) )
++d, ++s;
return ( *d - *s );
}
#pragma subtitle("showifcb() - display internal fcbs")
#pragma page()
/*
** function: showifcb
**
** purpose: This function displays the contents of the
** internal file control block chain.
**
** usage: void showifcb( chain, flag );
** CHAIN far *chain;
** int flag; (* 1 if ifcb, 0 if fcbt *)
**
** returns: nothing
*/
void showifcb( chain, flag )
CHAIN far *chain;
int flag;
{
CHAIN far *c;
IFCB far *ifcb;
int nifcbs;
int nlinks;
int done;
int i;
/*
** get some basic information
*/
c = chain;
nlinks = nifcbs = done = 0;
do
{
nifcbs += c->nentries;
++nlinks;
c = c->nextchain;
} while ( FP_OFF(c) != 0xffff );
if ( flag )
printf( "\nInternal File Control Block Chain at %p contains", chain );
else
printf( "\nFile Control Block Chain at %p contains", chain );
if ( nlinks > 1 )
printf( "\n%d links with a total of %d internal file control blocks.\n", nlinks, nifcbs );
else
printf( "\n1 link with %d internal file control blocks.\n", nifcbs );
/*
** now give the details
*/
c = chain;
do
{
if ( nlinks > 1 )
printf( "\nLink at %p contains %d blocks\n", c, c->nentries );
ifcb = (IFCB far *) c;
FP_OFF(ifcb) += sizeof(CHAIN);
for ( i = 0; i < c->nentries; ++i )
showifcb1( &ifcb[i] );
c = c->nextchain;
} while ( FP_OFF(c) != 0xffff );
printf( "\n" );
}
#define MO (ifcb->filedate.month)
#define DA (ifcb->filedate.day)
#define YR (ifcb->filedate.year + 1980)
#define HR (ifcb->filetime.hour)
#define MIN (ifcb->filetime.minute)
#define SEC (ifcb->filetime.second * 2)
void showifcb1( ifcb )
IFCB far *ifcb;
{
word attr;
int i;
static char *openmode[4] =
{ "Read", "Write", "Read/Write", "Unknown Mode" };
static char flag[] = "??ADVSHR";
printf( "\n\t %p = Address of this control block", ifcb );
if ( ifcb->filename[0] == 0 )
{
printf( " (NEVER USED)\n" );
return;
}
printf( "\n\t %5u = Number of opens", ifcb->nopens );
if ( ifcb->nopens == 0 )
{
printf( " (NOT OPEN)" );
if ( !verbose )
{
printf( "\n" );
return;
}
}
printf( "\n\t %04x = Open mode (%s)", ifcb->mode, openmode[ifcb->mode & 3] );
printf( "\n\t %04x = PSP of owner", ifcb->owner );
printf( "\n\t %04x = Device attributes", attr = ifcb->devattr );
if ( attr & 0x0080 )
{
printf( "\n\t - Opened as device" );
if ( attr & 0x4000 )
printf( "\n\t - Processes control strings" );
else
printf( "\n\t - Cannot process control strings" );
if ( attr & 0x2000 )
printf( "\n\t - Supports output until busy" );
else /* if u cn rd ths u cn gt a gd jb! */
printf( "\n\t - Doesn't support output until busy" );
if ( attr & 0x0800 )
printf( "\n\t - Understands open/close" );
else
printf( "\n\t - Doesn't understand open/close" );
if ( attr & 0x0040 )
printf( "\n\t - Ready" );
else
printf( "\n\t - Not ready" );
if ( attr & 0x0020 )
printf( "\n\t - Raw" );
else
printf( "\n\t - Cooked" );
if ( attr & 0x0010 )
printf( "\n\t - Special device" );
if ( attr & 0x0008 )
printf( "\n\t - Clock device" );
if ( attr & 0x0004 )
printf( "\n\t - Null device" );
if ( attr & 0x0002 )
printf( "\n\t - Console output device" );
if ( attr & 0x0001 )
printf( "\n\t - Console input device" );
if ( attr & 0x9700 )
printf( "\n\t - ?? (%04x)", attr & 0x9700 );
}
else
{
printf( "\n\t - Opened as file" );
if ( attr & 0x0040 )
printf( "\n\t - Not written to" );
else
printf( "\n\t - Written to" );
printf( "\n\t - On drive %c:", (attr & 0x002f) + 'A' );
if ( attr & 0xff00 )
printf( "\n\t - ?? (%04x)", attr & 0xff00 );
}
if ( attr & 0x0080 )
{
printf( "\n\t '%8.8Fs' = Device name", ifcb->filename );
printf( "\n\t %p = Driver header address", ifcb->pdpt );
}
else
{
printf( "\n\t'%8.8Fs.%3.3Fs' = File name", ifcb->filename, ifcb->fileext );
printf( "\n\t %2d/%02d/%04d = File date", MO, DA, YR );
printf( "\n\t %2d:%02d:%02d = File time", HR, MIN, SEC );
printf( "\n\t %02x = Attribute (flags) byte", ifcb->fileattr );
if ( ifcb->fileattr )
{
printf( " [" );
for ( i = 0; i < 8; ++i )
if ( ifcb->fileattr & (0x80 >> i) )
printf( "%c", flag[i] );
else
printf( "%c", '-' );
printf( "]" );
}
printf( "\n\t %5u = First cluster in file", ifcb->firstcluster );
printf( "\n\t %5u = Number of clusters in file", ifcb->nclusters );
printf( "\n\t %5u = Current cluster", ifcb->curcluster );
printf( "\n\t %10lu = File size (bytes)", ifcb->filesize );
printf( "\n\t %10lu = Current file position", ifcb->filepos );
printf( "\n\t %5u = Sector in directory containing file's entry", ifcb->dirsector );
printf( "\n\t %2u = Index of directory entry in sector", ifcb->dirindex );
printf( "\n\t %p = Associated physical device parameters (%c:)", ifcb->pdpt, ifcb->pdpt->drive + 'A' );
}
printf( "\n" );
}